美文网首页Android知识
Broadcast(三)sendBroadcast

Broadcast(三)sendBroadcast

作者: 风风风筝 | 来源:发表于2016-09-13 21:22 被阅读2203次

    sendBroadcast、sendStickyBroadcast、sendOrderedBroadcast基本一样,只差一个参数broadcastIntent方法倒数第二个参数代表sticky,倒数第三个参数代表serialized

    @Override
    @Deprecated
    public void sendStickyBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            // 这个true就代表是sticky
            ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
                getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    ActivityManagerService.java
    broadcastIntent→broadcastIntentLocked

    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        // step1:设置flag
        // step2:广播权限校验
        // step3:处理系统广播
        // step4:增加sticky广播
        // step5:查询receivers(静态注册的接收者)和registeredReceivers(动态注册的接收者)
        // step6:处理无序广播
        // step7:合并registeredReceivers到receivers
        // step8:处理有序广播
        return ActivityManager.BROADCAST_SUCCESS;
    }
    

    sendBroadcast→→→→→1 2 3 x 5 6 7 8
    sendStickyBroadcast→→1 2 3 4 5 6 7 8
    sendOrderedBroadcast→1 2 3 x 5 x 7 8
    注意这3个方法执行的step,下面会详细说明

    step1:设置广播flag

    intent = new Intent(intent);
    //广播不会发送给已停止的package
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    
    //当没有启动完成时,不允许启动新进程
    if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    }
    userId = handleIncomingUser(callingPid, callingUid, userId,
            true, ALLOW_NON_FULL, "broadcast", callerPackage);
    
    //当非USER_ALL广播且当前用户并没有处于Running的情况下,除非是系统升级广播或者关机广播,否则直接返回
    if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
        if ((callingUid != Process.SYSTEM_UID
                || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
            return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
        }
    }
    

    BroadcastReceiver还有其他flag,位于Intent.java常量

    FLAG_RECEIVER_REGISTERED_ONLY //只允许已注册receiver接收广播
    FLAG_RECEIVER_REPLACE_PENDING //新广播会替代相同广播
    FLAG_RECEIVER_FOREGROUND //只允许前台receiver接收广播
    FLAG_RECEIVER_NO_ABORT //对于有序广播,先接收到的receiver无权抛弃广播
    FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT //Boot完成之前,只允许已注册receiver接收广播
    FLAG_RECEIVER_BOOT_UPGRADE //升级模式下,允许系统准备就绪前可以发送广播
    

    step2:广播权限验证

    //对于callingAppId为SYSTEM_UID,PHONE_UID,SHELL_UID,BLUETOOTH_UID,NFC_UID或者callingUid == 0时直接通过
    int callingAppId = UserHandle.getAppId(callingUid);
    if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
        || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
        || callingAppId == Process.NFC_UID || callingUid == 0) {
        //直接通过
    } else if (callerApp == null || !callerApp.persistent) {
        try {
            if (AppGlobals.getPackageManager().isProtectedBroadcast(
                    intent.getAction())) {
                //不允许发送给受保护的广播
                throw new SecurityException(msg);
            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
                ...
            }
        } catch (RemoteException e) {
            return ActivityManager.BROADCAST_SUCCESS;
        }
    }
    

    step3:处理系统相关广播

    final String action = intent.getAction();
    if (action != null) {
        switch (action) {
            case Intent.ACTION_UID_REMOVED:
            case Intent.ACTION_PACKAGE_REMOVED:
            case Intent.ACTION_PACKAGE_CHANGED:
            case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
            case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                // Handle special intents: if this broadcast is from the package
                // manager about a package being removed, we need to remove all of
                // its activities from the history stack.
                if (checkComponentPermission(
                        android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
                        callingPid, callingUid, -1, true)
                        != PackageManager.PERMISSION_GRANTED) {
                    String msg = "Permission Denial: " + intent.getAction()
                            + " broadcast from " + callerPackage + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")"
                            + " requires "
                            + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
                switch (action) {
                    case Intent.ACTION_UID_REMOVED:
                        final Bundle intentExtras = intent.getExtras();
                        final int uid = intentExtras != null
                                ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
                        if (uid >= 0) {
                            mBatteryStatsService.removeUid(uid);
                            mAppOpsService.uidRemoved(uid);
                        }
                        break;
                    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                        // If resources are unavailable just force stop all those packages
                        // and flush the attribute cache as well.
                        String list[] =
                                intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                        if (list != null && list.length > 0) {
                            for (int i = 0; i < list.length; i++) {
                                forceStopPackageLocked(list[i], -1, false, true, true,
                                        false, false, userId, "storage unmount");
                            }
                            mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                            sendPackageBroadcastLocked(
                                    IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
                                    userId);
                        }
                        break;
                    case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                        mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                        break;
                    case Intent.ACTION_PACKAGE_REMOVED:
                    case Intent.ACTION_PACKAGE_CHANGED:
                        Uri data = intent.getData();
                        String ssp;
                        if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                            boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
                            boolean fullUninstall = removed &&
                                    !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                            if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
                                forceStopPackageLocked(ssp, UserHandle.getAppId(
                                        intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                        false, true, true, false, fullUninstall, userId,
                                        removed ? "pkg removed" : "pkg changed");
                            }
                            if (removed) {
                                sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                        new String[] {ssp}, userId);
                                if (fullUninstall) {
                                    mAppOpsService.packageRemoved(
                                            intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
    
                                    // Remove all permissions granted from/to this package
                                    removeUriPermissionsForPackageLocked(ssp, userId, true);
    
                                    removeTasksByPackageNameLocked(ssp, userId);
                                    mBatteryStatsService.notePackageUninstalled(ssp);
                                }
                            } else {
                                cleanupDisabledPackageComponentsLocked(ssp, userId,
                                        intent.getStringArrayExtra(
                                                Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                            }
                        }
                        break;
                }
                break;
            case Intent.ACTION_PACKAGE_ADDED:
                // Special case for adding a package: by default turn on compatibility mode.
                Uri data = intent.getData();
                String ssp;
                if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                    final boolean replacing =
                            intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                    mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
    
                    try {
                        ApplicationInfo ai = AppGlobals.getPackageManager().
                                getApplicationInfo(ssp, 0, 0);
                        mBatteryStatsService.notePackageInstalled(ssp,
                                ai != null ? ai.versionCode : 0);
                    } catch (RemoteException e) {
                    }
                }
                break;
            case Intent.ACTION_TIMEZONE_CHANGED:
                // If this is the time zone changed action, queue up a message that will reset
                // the timezone of all currently running processes. This message will get
                // queued up before the broadcast happens.
                mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
                break;
            case Intent.ACTION_TIME_CHANGED:
                // If the user set the time, let all running processes know.
                final int is24Hour =
                        intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1
                                : 0;
                mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
                BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
                synchronized (stats) {
                    stats.noteCurrentTimeChangedLocked();
                }
                break;
            case Intent.ACTION_CLEAR_DNS_CACHE:
                mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                break;
            case Proxy.PROXY_CHANGE_ACTION:
                ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
                mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
                break;
        }
    }
    

    主要处理系统相关的广播,10个case

    case Intent.ACTION_UID_REMOVED: //uid移除
    case Intent.ACTION_PACKAGE_REMOVED: //package移除,
    case Intent.ACTION_PACKAGE_CHANGED: //package改变
    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: //外部设备不可用时,强制停止所有波及的应用并清空cache数据
    case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: //外部设备可用
    case Intent.ACTION_PACKAGE_ADDED: //增加package,处于兼容考虑
    
    case Intent.ACTION_TIMEZONE_CHANGED: //时区改变,通知所有运行中的进程
    case Intent.ACTION_TIME_CHANGED: //时间改变,通知所有运行中的进程
    case Intent.ACTION_CLEAR_DNS_CACHE: //dns缓存清空
    case Proxy.PROXY_CHANGE_ACTION: //网络代理改变
    

    step4:增加sticky广播

    // Add to the sticky list if requested.
    if (sticky) {
        if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                    callingPid, callingUid)
                    != PackageManager.PERMISSION_GRANTED) {
              throw new SecurityException(msg);
        }
        if (requiredPermissions != null && requiredPermissions.length > 0) {
            return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
        }
        if (intent.getComponent() != null) {
            throw new SecurityException(
                        "Sticky broadcasts can't target a specific component");
        }
        // We use userId directly here, since the "all" target is maintained
        // as a separate set of sticky broadcasts.
        if (userId != UserHandle.USER_ALL) {
            // But first, if this is not a broadcast to all users, then
            // make sure it doesn't conflict with an existing broadcast to
            // all users.
            ...
        }
        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
        if (stickies == null) {
            stickies = new ArrayMap<>();
            mStickyBroadcasts.put(userId, stickies);
        }
        ArrayList<Intent> list = stickies.get(intent.getAction());
        if (list == null) {
            list = new ArrayList<>();
            stickies.put(intent.getAction(), list);
        }
        final int stickiesCount = list.size();
        int i;
        for (i = 0; i < stickiesCount; i++) {
            if (intent.filterEquals(list.get(i))) {
                // This sticky already exists, replace it.
                list.set(i, new Intent(intent));
                break;
            }
        }
        // 新的intent追加到list
        if (i >= stickiesCount) {
            list.add(new Intent(intent));
        }
    }
    

    简单说,就是如果sticky==true,则mStickyBroadcasts增加一条广播
    step5:查询receivers和registeredReceivers

    int[] users;
    if (userId == UserHandle.USER_ALL) {
        // 广播给所有已启动用户
        // Caller wants broadcast to go to all started users.
        users = mStartedUserArray;
    } else {
        // Caller wants broadcast to go to one specific user.
        users = new int[] {userId};
    }
    
    // Figure out who all will receive this broadcast.
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = null;
    // Need to resolve the intent to interested receivers...
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
             == 0) {
        // 根据intent查找静态注册的广播,已经按priority(默认值是0)从高到低排好顺序
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }
    if (intent.getComponent() == null) {
        if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
            // Query one target user at a time, excluding shell-restricted users
            UserManagerService ums = getUserManagerLocked();
            for (int i = 0; i < users.length; i++) {
                if (ums.hasUserRestriction(
                        UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                    continue;
                }
                // 查询动态注册的广播,已经按priority从高到低排好顺序
                List<BroadcastFilter> registeredReceiversForUser =
                        mReceiverResolver.queryIntent(intent,
                                resolvedType, false, users[i]);
                if (registeredReceivers == null) {
                    registeredReceivers = registeredReceiversForUser;
                } else if (registeredReceiversForUser != null) {
                    registeredReceivers.addAll(registeredReceiversForUser);
                }
            }
        } else {
            // 查询动态注册的广播,已经按priority从高到低排好顺序
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                    resolvedType, false, userId);
        }
    }
    

    查询静态注册的广播

    private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
            int callingUid, int[] users) {
        List<ResolveInfo> receivers = null;
        try {
            HashSet<ComponentName> singleUserReceivers = null;
            boolean scannedFirstReceivers = false;
            for (int user : users) {
                // Skip users that have Shell restrictions
                if (callingUid == Process.SHELL_UID
                        && getUserManagerLocked().hasUserRestriction(
                                UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
                    continue;
                }
                // 调用PackageManagerService.queryIntentReceivers,获取AndroidManifest.xml声明的接收者信息
                List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                        .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
                if (user != UserHandle.USER_OWNER && newReceivers != null) {
                    // If this is not the primary user, we need to check for
                    // any receivers that should be filtered out.
                    for (int i=0; i<newReceivers.size(); i++) {
                        ResolveInfo ri = newReceivers.get(i);
                        if ((ri.activityInfo.flags&ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
                            // 移除FLAG_PRIMARY_USER_ONLY的receiver
                            newReceivers.remove(i);
                            i--;
                        }
                    }
                }
                if (newReceivers != null && newReceivers.size() == 0) {
                    newReceivers = null;
                }
                if (receivers == null) {
                    receivers = newReceivers;
                } else if (newReceivers != null) {
                    // We need to concatenate the additional receivers
                    // found with what we have do far.  This would be easy,
                    // but we also need to de-dup any receivers that are
                    // singleUser.
                    // 将所有用户的receiver整合到receivers
                    ...
                }
            }
        } catch (RemoteException ex) {
            // pm is in same process, this will never happen.
        }
        return receivers;
    }
    

    step6:处理无序广播
    如果ordered ==false,并且有动态注册的接收者,那么就会进入这个步骤。
    在无序广播队列增加一条广播,然后遍历动态注册的接收者并通知。

    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    
    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    if (!ordered && NR > 0) {
        // If we are not serializing this broadcast, then send the
        // registered receivers separately so they don't wait for the
        // components to be launched.
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
                resultExtras, ordered, sticky, false, userId);
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
        final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
        if (!replaced) {
            // 详情参考[Broadcast(二)registerReceiver时sticky广播]
            queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
        // 注意这2变量重置
        registeredReceivers = null;
        NR = 0;
    }
    

    step7:合并registeredReceivers到receivers
    按priority从高到低,把动态注册的接收者和静态注册的接收者合并。相同的priority,动态注册的接收者优先

    // Merge into one list.
    int ir = 0;
    if (receivers != null) {
        // A special case for PACKAGE_ADDED: do not allow the package
        // being added to see this broadcast.  This prevents them from
        // using this as a back door to get run as soon as they are
        // installed.  Maybe in the future we want to have a special install
        // broadcast or such for apps, but we'd like to deliberately make
        // this decision.
        // 防止应用监听该广播,在安装时直接运行
        String skipPackages[] = null;
        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
                || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
                || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
            Uri data = intent.getData();
            if (data != null) {
                String pkgName = data.getSchemeSpecificPart();
                if (pkgName != null) {
                    skipPackages = new String[] { pkgName };
                }
            }
        } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
            skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
        }
        // 将skipPackages相关的广播接收者从receivers中移除
        if (skipPackages != null && (skipPackages.length > 0)) {
            for (String skipPackage : skipPackages) {
                if (skipPackage != null) {
                    int NT = receivers.size();
                    for (int it=0; it<NT; it++) {
                        ResolveInfo curt = (ResolveInfo)receivers.get(it);
                        if (curt.activityInfo.packageName.equals(skipPackage)) {
                            receivers.remove(it);
                            it--;
                            NT--;
                        }
                    }
                }
            }
        }
    
        int NT = receivers != null ? receivers.size() : 0;
        int it = 0;
        ResolveInfo curt = null;
        BroadcastFilter curr = null;
        // 如果处理了无序广播,那么NR=0
        while (it < NT && ir < NR) {
            if (curt == null) {
                curt = (ResolveInfo)receivers.get(it);
            }
            if (curr == null) {
                curr = registeredReceivers.get(ir);
            }
            if (curr.getPriority() >= curt.priority) {
                // Insert this broadcast record into the final list.
                receivers.add(it, curr);
                ir++;
                curr = null;
                it++;
                NT++;
            } else {
                // Skip to the next ResolveInfo in the final list.
                it++;
                curt = null;
            }
        }
    }
    while (ir < NR) {
        if (receivers == null) {
            receivers = new ArrayList();
        }
        receivers.add(registeredReceivers.get(ir));
        ir++;
    }
    

    step8:处理有序广播
    如果你明白上面7步做了什么,那你应该知道当ordered==true或者有静态注册的接收者的时候(显然只有这2个条件至少满足一个,receivers.size()才会大于0)就会进入这个步骤。

    if ((receivers != null && receivers.size() > 0)
            || resultTo != null) {
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, resolvedType,
                requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId);
        boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
        if (!replaced) {
            // 见[Broadcast (四)有序广播和ANR]
            queue.enqueueOrderedBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
    }
    

    参考引用

    Gityuan Android Broadcast广播机制分析

    相关文章

      网友评论

        本文标题:Broadcast(三)sendBroadcast

        本文链接:https://www.haomeiwen.com/subject/wawyettx.html