美文网首页
Broadcast流程源码分析

Broadcast流程源码分析

作者: 月止风溟 | 来源:发表于2020-02-05 19:45 被阅读0次

    1.Broadcast种类

    Android广播大体可以分为几类:

    1. App应用内广播(LocalBroadcast)
      这个应用自己发给自己的,通过LocalBroadcastManager管理。这里不做介绍。
    2. 系统广播
      这种不是普通应用发出来的,比如包的安装移除,(userId)用户的添加删除。当然,这些广播一般的普通应用也能接收得到。否则我们很多应用行为就异常了。这里列出一些应用,可以看到在Android Q上,这些系统广播发出后,先触发了system_server的一些行为,才进入广播发送流程。
                    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:
                    case Intent.ACTION_PACKAGES_SUSPENDED:
                    case Intent.ACTION_PACKAGES_UNSUSPENDED:
    
    1. 粘性广播
      android 5.0/api 21中deprecated,不再推荐使用。当然,源码里当前还支持粘性广播。

    2. 无序广播
      完全异步的广播,广播的接收者们不会互相干扰广播的接收。

    3. 有序广播
      同步的广播,广播的接收者门会按照优先级,依次接收到广播。

    按最新的android Q设计来看的话,当前应该只需要关注两种广播,有序广播无序广播 就好了。其他的倒不是有很大助益。

    2.BroadCast时序图

    老规矩,看代码前先放图。这里放得简单些,描述大体流程,把一些类似Activity的交互给省去。具体的细分业务逻辑,从代码里来看。

    registerReciver和sendBroadcast

    3.广播动态注册

    对应还有静态注册,主要是PMS相关逻辑,后续介绍。

    我们调用registerRecevier还是一路调用到ContextImplregisterReceiverInternal方法。从这里可以可以看到,它将一个BroadcastReceiver对象封装成了一个LoadedApk.ReceiverDispatcher对象,然后返回了一个IIntentReceiver(在这里是InnerReceiver)进行注册。

    在前面我们已经说到过,android跨进程调用,是通过aidl的方式。BroadcastReceiver作为一个普通的类对象,肯定是不能直接跨进程调用的。所以这里的应用链关系为InnerReceiver->ReceiverDispatcher->BroadcastReceiver,保证了BroadcastReceiver的调用准确。
    ContextImpl

        @Override
        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                String broadcastPermission, Handler scheduler) {
            return registerReceiverInternal(receiver, getUserId(),
                    filter, broadcastPermission, scheduler, getOuterContext(), 0);
        }
    
        private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                IntentFilter filter, String broadcastPermission,
                Handler scheduler, Context context, int flags) {
            IIntentReceiver rd = null;
            if (receiver != null) {
                if (mPackageInfo != null && context != null) {
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    //往getReceiverDispatcher这个里面看,
                    //getOuterContext()获取到的外层的Context被作为Key存贮到了LoadedApk的mReceivers里。
                    //这也就是常见得广播不解注册会导致内存泄漏
                    rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
                } else {
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    rd = new LoadedApk.ReceiverDispatcher(
                            receiver, context, scheduler, null, true).getIIntentReceiver();
                }
            }
            try {
                final Intent intent = ActivityManager.getService().registerReceiver(
                        mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                        broadcastPermission, userId, flags);
                if (intent != null) {
                    intent.setExtrasClassLoader(getClassLoader());
                    intent.prepareToEnterProcess();
                }
                return intent;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    从Server端来看,ActivityManagerService调用registerReceiver方法,就是将RecevierFilter封装成一个BroadcastFilter,添加到了mReceiverResolver里。
    ActivityManagerService

        public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
                int flags) {
            enforceNotIsolatedCaller("registerReceiver");
            ArrayList<Intent> stickyIntents = null;
            ProcessRecord callerApp = null;
            //谷歌的Instant Apps
            final boolean visibleToInstantApps
                    = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
            int callingUid;
            int callingPid;
            boolean instantApp;
            synchronized(this) {
                if (caller != null) {
                    callerApp = getRecordForAppLocked(caller);
                    if (callerApp == null) {
                        throw new SecurityException(
                                "Unable to find app for caller " + caller
                                + " (pid=" + Binder.getCallingPid()
                                + ") when registering receiver " + receiver);
                    }
                    if (callerApp.info.uid != SYSTEM_UID &&
                            !callerApp.pkgList.containsKey(callerPackage) &&
                            !"android".equals(callerPackage)) {
                        throw new SecurityException("Given caller package " + callerPackage
                                + " is not running in process " + callerApp);
                    }
                    callingUid = callerApp.info.uid;
                    callingPid = callerApp.pid;
                } else {
                    callerPackage = null;
                    callingUid = Binder.getCallingUid();
                    callingPid = Binder.getCallingPid();
                }
    
                instantApp = isInstantApp(callerApp, callerPackage, callingUid);
                userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                        ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
    
                Iterator<String> actions = filter.actionsIterator();
                if (actions == null) {
                    ArrayList<String> noAction = new ArrayList<String>(1);
                    noAction.add(null);
                    actions = noAction.iterator();
                }
    
                //先查出是不是有符合Action的粘性广播
                // Collect stickies of users
                int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
                while (actions.hasNext()) {
                    String action = actions.next();
                    for (int id : userIds) {
                        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                        if (stickies != null) {
                            ArrayList<Intent> intents = stickies.get(action);
                            if (intents != null) {
                                if (stickyIntents == null) {
                                    stickyIntents = new ArrayList<Intent>();
                                }
                                stickyIntents.addAll(intents);
                            }
                        }
                    }
                }
            }
    
            ArrayList<Intent> allSticky = null;
            if (stickyIntents != null) {
                final ContentResolver resolver = mContext.getContentResolver();
                // Look for any matching sticky broadcasts...
                for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                    Intent intent = stickyIntents.get(i);
                    // Don't provided intents that aren't available to instant apps.
                    if (instantApp &&
                            (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                        continue;
                    }
                    // If intent has scheme "content", it will need to acccess
                    // provider that needs to lock mProviderMap in ActivityThread
                    // and also it may need to wait application response, so we
                    // cannot lock ActivityManagerService here.
                    if (filter.match(resolver, intent, true, TAG) >= 0) {
                        if (allSticky == null) {
                            allSticky = new ArrayList<Intent>();
                        }
                        allSticky.add(intent);
                    }
                }
            }
    
            // The first sticky in the list is returned directly back to the client.
            Intent sticky = allSticky != null ? allSticky.get(0) : null;
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
            if (receiver == null) {
                return sticky;
            }
    
            synchronized (this) {
                if (callerApp != null && (callerApp.thread == null
                        || callerApp.thread.asBinder() != caller.asBinder())) {
                    // Original caller already died
                    return null;
                }
                //这里还蛮奇怪的,看着应该不需要是一个列表才对
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                if (rl == null) {
                    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                            userId, receiver);
                    if (rl.app != null) {
                        final int totalReceiversForApp = rl.app.receivers.size();
                        if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                            throw new IllegalStateException("Too many receivers, total of "
                                    + totalReceiversForApp + ", registered for pid: "
                                    + rl.pid + ", callerPackage: " + callerPackage);
                        }
                        rl.app.receivers.add(rl);
                    } else {
                        try {
                            receiver.asBinder().linkToDeath(rl, 0);
                        } catch (RemoteException e) {
                            return sticky;
                        }
                        rl.linkedToDeath = true;
                    }
                    mRegisteredReceivers.put(receiver.asBinder(), rl);
                } else if (rl.uid != callingUid) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for uid " + callingUid
                            + " was previously registered for uid " + rl.uid
                            + " callerPackage is " + callerPackage);
                } else if (rl.pid != callingPid) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for pid " + callingPid
                            + " was previously registered for pid " + rl.pid
                            + " callerPackage is " + callerPackage);
                } else if (rl.userId != userId) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for user " + userId
                            + " was previously registered for user " + rl.userId
                            + " callerPackage is " + callerPackage);
                }
                //这里将cast和filter封装成了一个BroadcastFilter
                //静态注册不是BroadcastFilter对象
                BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                        permission, callingUid, userId, instantApp, visibleToInstantApps);
                if (rl.containsFilter(filter)) {
                    Slog.w(TAG, "Receiver with filter " + filter
                            + " already registered for pid " + rl.pid
                            + ", callerPackage is " + callerPackage);
                } else {
                    rl.add(bf);
                    if (!bf.debugCheck()) {
                        Slog.w(TAG, "==> For Dynamic broadcast");
                    }
                    mReceiverResolver.addFilter(bf);
                }
    
                //有粘性广播需要被执行,这里就会执行粘性广播
                // Enqueue broadcasts for all existing stickies that match
                // this filter.
                if (allSticky != null) {
                    ArrayList receivers = new ArrayList();
                    receivers.add(bf);
    
                    final int stickyCount = allSticky.size();
                    for (int i = 0; i < stickyCount; i++) {
                        Intent intent = allSticky.get(i);
                        BroadcastQueue queue = broadcastQueueForIntent(intent);
                        BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                                null, -1, -1, false, null, null, OP_NONE, null, receivers,
                                null, 0, null, null, false, true, true, -1, false,
                                false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                        queue.enqueueParallelBroadcastLocked(r);
                        queue.scheduleBroadcastsLocked();
                    }
                }
    
                return sticky;
            }
    

    4.发送广播

    ContextImpl

    
        @Override
        public void sendBroadcast(Intent intent) {
            warnIfCallingFromSystemProcess();
            String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
            try {
                intent.prepareToLeaveProcess(this);
                //注意一下,这里倒数第三个参数false声明了是无序广播
                ActivityManager.getService().broadcastIntent(
                        mMainThread.getApplicationThread(), intent, resolvedType, null,
                        Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                        getUserId());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    ActivityManagerService的逻辑里,发送广播的逻辑分成了两种情形:

    1. 粘性广播条件到粘性广播列表ActivityManagerService#mStickyBroadcasts
    2. 无序广播:把动态注册的广播直接就添加到无序广播列表BroadcastQueue#mParallelBroadcasts,然后静态注册的Receiver添加到有序广播列表BroadcastDispatcher#mOrderedBroadcasts
    3. 有序广播:把动态和静态注册的广播合成一个列表,然后添加到receivers里。

    然后触发了queue.scheduleBroadcastsLocked()逻辑。那我们再看它到底做了什么动作。

    ActivityManagerService

        public final int broadcastIntent(IApplicationThread caller,
                Intent intent, String resolvedType, IIntentReceiver resultTo,
                int resultCode, String resultData, Bundle resultExtras,
                String[] requiredPermissions, int appOp, Bundle bOptions,
                boolean serialized, boolean sticky, int userId) {
            enforceNotIsolatedCaller("broadcastIntent");
            synchronized(this) {
                intent = verifyBroadcastLocked(intent);
    
                final ProcessRecord callerApp = getRecordForAppLocked(caller);
                final int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
    
                final long origId = Binder.clearCallingIdentity();
                try {
                    return broadcastIntentLocked(callerApp,
                            callerApp != null ? callerApp.info.packageName : null,
                            intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                            requiredPermissions, appOp, bOptions, serialized, sticky,
                            callingPid, callingUid, callingUid, callingPid, userId);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
    
        //处理的过程就要慢慢看了
        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 realCallingUid,
                int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
            intent = new Intent(intent);
    
            final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
            // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
            if (callerInstantApp) {
                intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
            }
    
            //默认不会拉活停用的App
            //所以如果要拉活应用,发广播的时候要添加标志FLAG_INCLUDE_STOPED_PACKAGES
            // By default broadcasts do not go to stopped apps.
            intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    
            // If we have not finished booting, don't allow this to launch new processes.
            if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            }
    
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                    (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
                    + " ordered=" + ordered + " userid=" + userId);
            if ((resultTo != null) && !ordered) {
                Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
            }
    
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_NON_FULL, "broadcast", callerPackage);
    
            // Make sure that the user who is receiving this broadcast or its parent is running.
            // If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.
            if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
                if ((callingUid != SYSTEM_UID
                        || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                        && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                    Slog.w(TAG, "Skipping broadcast of " + intent
                            + ": user " + userId + " and its parent (if any) are stopped");
                    return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
                }
            }
    
            //权限校验
            final String action = intent.getAction();
            BroadcastOptions brOptions = null;
            if (bOptions != null) {
                brOptions = new BroadcastOptions(bOptions);
                if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
                    // See if the caller is allowed to do this.  Note we are checking against
                    // the actual real caller (not whoever provided the operation as say a
                    // PendingIntent), because that who is actually supplied the arguments.
                    if (checkComponentPermission(
                            android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                            realCallingPid, realCallingUid, -1, true)
                            != PackageManager.PERMISSION_GRANTED) {
                        String msg = "Permission Denial: " + intent.getAction()
                                + " broadcast from " + callerPackage + " (pid=" + callingPid
                                + ", uid=" + callingUid + ")"
                                + " requires "
                                + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                }
                if (brOptions.isDontSendToRestrictedApps()
                        && !isUidActiveLocked(callingUid)
                        && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
                    Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage
                            + " has background restrictions");
                    return ActivityManager.START_CANCELED;
                }
                if (brOptions.allowsBackgroundActivityStarts()) {
                    // See if the caller is allowed to do this.  Note we are checking against
                    // the actual real caller (not whoever provided the operation as say a
                    // PendingIntent), because that who is actually supplied the arguments.
                    if (checkComponentPermission(
                            android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
                            realCallingPid, realCallingUid, -1, true)
                            != PackageManager.PERMISSION_GRANTED) {
                        String msg = "Permission Denial: " + intent.getAction()
                                + " broadcast from " + callerPackage + " (pid=" + callingPid
                                + ", uid=" + callingUid + ")"
                                + " requires "
                                + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    } else {
                        allowBackgroundActivityStarts = true;
                    }
                }
            }
    
            //一大段校验系统广播和处理系统广播的逻辑
            // Verify that protected broadcasts are only being sent by system code,
            // and that system code is only sending protected broadcasts.
            final boolean isProtectedBroadcast;
            try {
                isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception", e);
                return ActivityManager.BROADCAST_SUCCESS;
            }
    
            final boolean isCallerSystem;
            switch (UserHandle.getAppId(callingUid)) {
                case ROOT_UID:
                case SYSTEM_UID:
                case PHONE_UID:
                case BLUETOOTH_UID:
                case NFC_UID:
                case SE_UID:
                case NETWORK_STACK_UID:
                    isCallerSystem = true;
                    break;
                default:
                    isCallerSystem = (callerApp != null) && callerApp.isPersistent();
                    break;
            }
    
            // First line security check before anything else: stop non-system apps from
            // sending protected broadcasts.
            if (!isCallerSystem) {
                if (isProtectedBroadcast) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + action + " from pid="
                            + callingPid + ", uid=" + callingUid;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
    
                } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                        || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
                    // Special case for compatibility: we don't want apps to send this,
                    // but historically it has not been protected and apps may be using it
                    // to poke their own app widget.  So, instead of making it protected,
                    // just limit it to the caller.
                    if (callerPackage == null) {
                        String msg = "Permission Denial: not allowed to send broadcast "
                                + action + " from unknown caller.";
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    } else if (intent.getComponent() != null) {
                        // They are good enough to send to an explicit component...  verify
                        // it is being sent to the calling app.
                        if (!intent.getComponent().getPackageName().equals(
                                callerPackage)) {
                            String msg = "Permission Denial: not allowed to send broadcast "
                                    + action + " to "
                                    + intent.getComponent().getPackageName() + " from "
                                    + callerPackage;
                            Slog.w(TAG, msg);
                            throw new SecurityException(msg);
                        }
                    } else {
                        // Limit broadcast to their own package.
                        intent.setPackage(callerPackage);
                    }
                }
            }
    
            boolean timeoutExempt = false;
    
            if (action != null) {
                if (getBackgroundLaunchBroadcasts().contains(action)) {
                    if (DEBUG_BACKGROUND_CHECK) {
                        Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
                    }
                    intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                }
    
                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:
                    case Intent.ACTION_PACKAGES_SUSPENDED:
                    case Intent.ACTION_PACKAGES_UNSUSPENDED:
                        // 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 int uid = getUidFromIntent(intent);
                                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");
                                    }
                                    mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                                    sendPackageBroadcastLocked(
                                            ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,
                                            list, userId);
                                }
                                break;
                            case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                                mAtmInternal.cleanupRecentTasksForUser(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);
                                    final boolean replacing =
                                            intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                                    final boolean killProcess =
                                            !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
                                    final boolean fullUninstall = removed && !replacing;
                                    if (removed) {
                                        if (killProcess) {
                                            forceStopPackageLocked(ssp, UserHandle.getAppId(
                                                    intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                                    false, true, true, false, fullUninstall, userId,
                                                    removed ? "pkg removed" : "pkg changed");
                                        }
                                        final int cmd = killProcess
                                                ? ApplicationThreadConstants.PACKAGE_REMOVED
                                                : ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;
                                        sendPackageBroadcastLocked(cmd,
                                                new String[] {ssp}, userId);
                                        if (fullUninstall) {
                                            mAppOpsService.packageRemoved(
                                                    intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
    
                                            // Remove all permissions granted from/to this package
                                            mUgmInternal.removeUriPermissionsForPackage(ssp, userId,
                                                    true, false);
    
                                            mAtmInternal.removeRecentTasksByPackageName(ssp, userId);
    
                                            mServices.forceStopPackageLocked(ssp, userId);
                                            mAtmInternal.onPackageUninstalled(ssp);
                                            mBatteryStatsService.notePackageUninstalled(ssp);
                                        }
                                    } else {
                                        if (killProcess) {
                                            final int extraUid = intent.getIntExtra(Intent.EXTRA_UID,
                                                    -1);
                                            mProcessList.killPackageProcessesLocked(ssp,
                                                    UserHandle.getAppId(extraUid),
                                                    userId, ProcessList.INVALID_ADJ, "change " + ssp);
                                        }
                                        cleanupDisabledPackageComponentsLocked(ssp, userId,
                                                intent.getStringArrayExtra(
                                                        Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                    }
                                }
                                break;
                            case Intent.ACTION_PACKAGES_SUSPENDED:
                            case Intent.ACTION_PACKAGES_UNSUSPENDED:
                                final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.equals(
                                        intent.getAction());
                                final String[] packageNames = intent.getStringArrayExtra(
                                        Intent.EXTRA_CHANGED_PACKAGE_LIST);
                                final int userHandle = intent.getIntExtra(
                                        Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
    
                                mAtmInternal.onPackagesSuspendedChanged(packageNames, suspended,
                                        userHandle);
                                break;
                        }
                        break;
                    case Intent.ACTION_PACKAGE_REPLACED:
                    {
                        final Uri data = intent.getData();
                        final String ssp;
                        if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                            ApplicationInfo aInfo = null;
                            try {
                                aInfo = AppGlobals.getPackageManager()
                                        .getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
                            } catch (RemoteException ignore) {}
                            if (aInfo == null) {
                                Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
                                        + " ssp=" + ssp + " data=" + data);
                                return ActivityManager.BROADCAST_SUCCESS;
                            }
                            updateAssociationForApp(aInfo);
                            mAtmInternal.onPackageReplaced(aInfo);
                            mServices.updateServiceApplicationInfoLocked(aInfo);
                            sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
                                    new String[] {ssp}, userId);
                        }
                        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);
                            mAtmInternal.onPackageAdded(ssp, replacing);
    
                            try {
                                ApplicationInfo ai = AppGlobals.getPackageManager().
                                        getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
                                mBatteryStatsService.notePackageInstalled(ssp,
                                        ai != null ? ai.longVersionCode : 0);
                            } catch (RemoteException e) {
                            }
                        }
                        break;
                    }
                    case Intent.ACTION_PACKAGE_DATA_CLEARED:
                    {
                        Uri data = intent.getData();
                        String ssp;
                        if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                            mAtmInternal.onPackageDataCleared(ssp);
                        }
                        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:
                        // EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between
                        // the tri-state value it may contain and "unknown".
                        // For convenience we re-use the Intent extra values.
                        final int NO_EXTRA_VALUE_FOUND = -1;
                        final int timeFormatPreferenceMsgValue = intent.getIntExtra(
                                Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,
                                NO_EXTRA_VALUE_FOUND /* defaultValue */);
                        // Only send a message if the time preference is available.
                        if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {
                            Message updateTimePreferenceMsg =
                                    mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,
                                            timeFormatPreferenceMsgValue, 0);
                            mHandler.sendMessage(updateTimePreferenceMsg);
                        }
                        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:
                        mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));
                        break;
                    case android.hardware.Camera.ACTION_NEW_PICTURE:
                    case android.hardware.Camera.ACTION_NEW_VIDEO:
                        // In N we just turned these off; in O we are turing them back on partly,
                        // only for registered receivers.  This will still address the main problem
                        // (a spam of apps waking up when a picture is taken putting significant
                        // memory pressure on the system at a bad point), while still allowing apps
                        // that are already actively running to know about this happening.
                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                        break;
                    case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
                        mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);
                        break;
                    case "com.android.launcher.action.INSTALL_SHORTCUT":
                        // As of O, we no longer support this broadcasts, even for pre-O apps.
                        // Apps should now be using ShortcutManager.pinRequestShortcut().
                        Log.w(TAG, "Broadcast " + action
                                + " no longer supported. It will not be delivered.");
                        return ActivityManager.BROADCAST_SUCCESS;
                    case Intent.ACTION_PRE_BOOT_COMPLETED:
                        timeoutExempt = true;
                        break;
                }
    
                if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
                        Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
                        Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                    final int uid = getUidFromIntent(intent);
                    if (uid != -1) {
                        final UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
                        if (uidRec != null) {
                            uidRec.updateHasInternetPermission();
                        }
                    }
                }
            }
    
            //终于跳过了系统广播处理!!!
    
    
            //先处理粘性广播
            // Add to the sticky list if requested.
            if (sticky) {
                if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                        callingPid, callingUid)
                        != PackageManager.PERMISSION_GRANTED) {
                    String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
                            + callingPid + ", uid=" + callingUid
                            + " requires " + android.Manifest.permission.BROADCAST_STICKY;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
                if (requiredPermissions != null && requiredPermissions.length > 0) {
                    Slog.w(TAG, "Can't broadcast sticky intent " + intent
                            + " and enforce permissions " + Arrays.toString(requiredPermissions));
                    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(
                            UserHandle.USER_ALL);
                    if (stickies != null) {
                        ArrayList<Intent> list = stickies.get(intent.getAction());
                        if (list != null) {
                            int N = list.size();
                            int i;
                            for (i=0; i<N; i++) {
                                if (intent.filterEquals(list.get(i))) {
                                    throw new IllegalArgumentException(
                                            "Sticky broadcast " + intent + " for user "
                                            + userId + " conflicts with existing global broadcast");
                                }
                            }
                        }
                    }
                }
                //将粘性广播保存在mStickyBroadcasts里了
                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;
                    }
                }
                if (i >= stickiesCount) {
                    list.add(new Intent(intent));
                }
            }
    
            int[] users;
            if (userId == UserHandle.USER_ALL) {
                // Caller wants broadcast to go to all started users.
                users = mUserController.getStartedUserArray();
            } 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) {
                //这里通过PMS,查出对应接收的静态广播接收者
                receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
            }
            if (intent.getComponent() == null) {
                if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                    // Query one target user at a time, excluding shell-restricted users
                    for (int i = 0; i < users.length; i++) {
                        if (mUserController.hasUserRestriction(
                                UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                            continue;
                        }
                        List<BroadcastFilter> registeredReceiversForUser =
                                mReceiverResolver.queryIntent(intent,
                                        resolvedType, false /*defaultOnly*/, users[i]);
                        if (registeredReceivers == null) {
                            registeredReceivers = registeredReceiversForUser;
                        } else if (registeredReceiversForUser != null) {
                            registeredReceivers.addAll(registeredReceiversForUser);
                        }
                    }
                } else {
                    //这里就从我们上面动态注册的列表里
                    //查询可以消费Intent的Receiver
                    registeredReceivers = mReceiverResolver.queryIntent(intent,
                            resolvedType, false /*defaultOnly*/, userId);
                }
            }
    
            final boolean replacePending =
                    (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
                    + " replacePending=" + replacePending);
    
            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.
                if (isCallerSystem) {
                    checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                            isProtectedBroadcast, registeredReceivers);
                }
                final BroadcastQueue queue = broadcastQueueForIntent(intent);
                BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                        callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                        requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                        resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                        allowBackgroundActivityStarts, timeoutExempt);
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
                final boolean replaced = replacePending
                        && (queue.replaceParallelBroadcastLocked(r) != null);
                // Note: We assume resultTo is null for non-ordered broadcasts.
                if (!replaced) {
                    //添加到无序广播队列
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
                registeredReceivers = null;
                NR = 0;
            }
    
            // 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);
                }
                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++;
            }
    
            if (isCallerSystem) {
                checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                        isProtectedBroadcast, receivers);
            }
    
            if ((receivers != null && receivers.size() > 0)
                    || resultTo != null) {
                //下面这段,把有序广播合成的(receivers + registeredReceivers)->receivers
                //或者是无序广播的静态注册receivers
                //enqueueOrderedBroadcastLocked 添加到了有序广播列表?
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                        callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                        requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                        resultData, resultExtras, ordered, sticky, false, userId,
                        allowBackgroundActivityStarts, timeoutExempt);
    
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
    
                final BroadcastRecord oldRecord =
                        replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
                if (oldRecord != null) {
                    // Replaced, fire the result-to receiver.
                    if (oldRecord.resultTo != null) {
                        final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                        try {
                            oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                    oldRecord.intent,
                                    Activity.RESULT_CANCELED, null, null,
                                    false, false, oldRecord.userId);
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Failure ["
                                    + queue.mQueueName + "] sending broadcast result of "
                                    + intent, e);
    
                        }
                    }
                } else {
                    queue.enqueueOrderedBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            } else {
                // There was nobody interested in the broadcast, but we still want to record
                // that it happened.
                if (intent.getComponent() == null && intent.getPackage() == null
                        && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                    // This was an implicit broadcast... let's record it for posterity.
                    addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
                }
            }
    
            return ActivityManager.BROADCAST_SUCCESS;
        }
    
    

    那么分发逻辑的话,接着往下看:
    BroadcastQueue

        public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
    
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }
    

    BroadcastQueue的一个内部类Handler进行了处理。
    BroadcastQueue

        private final class BroadcastHandler extends Handler {
            public BroadcastHandler(Looper looper) {
                super(looper, null, true);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case BROADCAST_INTENT_MSG: {
                        if (DEBUG_BROADCAST) Slog.v(
                                TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
                                + mQueueName + "]");
                        processNextBroadcast(true);
                    } break;
                    case BROADCAST_TIMEOUT_MSG: {
                        synchronized (mService) {
                            broadcastTimeoutLocked(true);
                        }
                    } break;
                }
            }
        }
    

    processNextBroadcast->processNextBroadcastLocked。这个也是一个比较长的方法。它主要的处理逻辑如下:

    主要分成几个部分:
    1.通过deliverToRegisteredReceiverLocked方法,把mParallelBroadcasts里动态注册的无序广播Reciver都给触发了
    2.剩下的有序动态广播Reciver或是静态广播Receiver,它先判断了动态注册的Reciver,通过scheduleRegisteredReceiver调用到对应的Receiver。
    3.静态广播,则通过scheduleReceiver一路调用,还是ApplicationThread->H->ActivityThread三范式操作。

    可以看到,第一部分是一次处理了多条,第二和第三部分都只处理一个Receiver。那有序广播里是怎么依次执行的呢?
    需要看到LoadedApk.ReceiverDispatcher.Args#sendFinished方法。调用到AMSfinishReceiver,触发了下一个Receiver执行。
    .0
    BroadcastQueue

        final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
            BroadcastRecord r;
    
            //这边是把所有的无序广播的动态Receiver给处理了
            // First, deliver any non-serialized broadcasts right away.
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();
                
                ...
    
                final int N = r.receivers.size();
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                        + mQueueName + "] " + r);
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                            "Delivering non-ordered on [" + mQueueName + "] to registered "
                            + target + ": " + r);
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                ...
            }
    
            // Now take care of the next serialized one...
    
            //等待进程拉起的Broadcast,Activity也有类似机制
            ...
    
            boolean looped = false;
    
            //这里是拿到了当前需要处理的BroadcastRecoard
            //有可能是有序广播Receiver,也有可能是无序的静态广播
            do {
                final long now = SystemClock.uptimeMillis();
                r = mDispatcher.getNextBroadcastLocked(now);
    
                if (r == null) {
                    // No more broadcasts are deliverable right now, so all done!
                    mDispatcher.scheduleDeferralCheckLocked(false);
                    mService.scheduleAppGcsLocked();
                    if (looped) {
                        // If we had finished the last ordered broadcast, then
                        // make sure all processes have correct oom and sched
                        // adjustments.
                        mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
                    }
    
                    // when we have no more ordered broadcast on this queue, stop logging
                    if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
                        mLogLatencyMetrics = false;
                    }
    
                    return;
                }
    
                boolean forceReceive = false;
    
                // Ensure that even if something goes awry with the timeout
                // detection, we catch "hung" broadcasts here, discard them,
                // and continue to make progress.
                //
                // This is only done if the system is ready so that early-stage receivers
                // don't get executed with timeouts; and of course other timeout-
                // exempt broadcasts are ignored.
                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
                if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
                    if ((numReceivers > 0) &&
                            (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                        Slog.w(TAG, "Hung broadcast ["
                                + mQueueName + "] discarded after timeout failure:"
                                + " now=" + now
                                + " dispatchTime=" + r.dispatchTime
                                + " startTime=" + r.receiverTime
                                + " intent=" + r.intent
                                + " numReceivers=" + numReceivers
                                + " nextReceiver=" + r.nextReceiver
                                + " state=" + r.state);
                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
                        forceReceive = true;
                        r.state = BroadcastRecord.IDLE;
                    }
                }
    
                if (r.state != BroadcastRecord.IDLE) {
                    if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                            "processNextBroadcast("
                            + mQueueName + ") called when not idle (state="
                            + r.state + ")");
                    return;
                }
    
                // Is the current broadcast is done for any reason?
                if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {
                    // Send the final result if requested
                    if (r.resultTo != null) {
                        boolean sendResult = true;
    
                        // if this was part of a split/deferral complex, update the refcount and only
                        // send the completion when we clear all of them
                        if (r.splitToken != 0) {
                            int newCount = mSplitRefcounts.get(r.splitToken) - 1;
                            if (newCount == 0) {
                                // done!  clear out this record's bookkeeping and deliver
                                if (DEBUG_BROADCAST_DEFERRAL) {
                                    Slog.i(TAG_BROADCAST,
                                            "Sending broadcast completion for split token "
                                            + r.splitToken + " : " + r.intent.getAction());
                                }
                                mSplitRefcounts.delete(r.splitToken);
                            } else {
                                // still have some split broadcast records in flight; update refcount
                                // and hold off on the callback
                                if (DEBUG_BROADCAST_DEFERRAL) {
                                    Slog.i(TAG_BROADCAST,
                                            "Result refcount now " + newCount + " for split token "
                                            + r.splitToken + " : " + r.intent.getAction()
                                            + " - not sending completion yet");
                                }
                                sendResult = false;
                                mSplitRefcounts.put(r.splitToken, newCount);
                            }
                        }
                        if (sendResult) {
                            try {
                                if (DEBUG_BROADCAST) {
                                    Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
                                            + r.intent.getAction() + " app=" + r.callerApp);
                                }
                                performReceiveLocked(r.callerApp, r.resultTo,
                                        new Intent(r.intent), r.resultCode,
                                        r.resultData, r.resultExtras, false, false, r.userId);
                                // Set this to null so that the reference
                                // (local and remote) isn't kept in the mBroadcastHistory.
                                r.resultTo = null;
                            } catch (RemoteException e) {
                                r.resultTo = null;
                                Slog.w(TAG, "Failure ["
                                        + mQueueName + "] sending broadcast result of "
                                        + r.intent, e);
                            }
                        }
                    }
    
                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                    cancelBroadcastTimeoutLocked();
    
                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                            "Finished with ordered broadcast " + r);
    
                    // ... and on to the next...
                    addBroadcastToHistoryLocked(r);
                    if (r.intent.getComponent() == null && r.intent.getPackage() == null
                            && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                        // This was an implicit broadcast... let's record it for posterity.
                        mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                                r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
                    }
                    mDispatcher.retireBroadcastLocked(r);
                    r = null;
                    looped = true;
                    continue;
                }
    
                // Check whether the next receiver is under deferral policy, and handle that
                // accordingly.  If the current broadcast was already part of deferred-delivery
                // tracking, we know that it must now be deliverable as-is without re-deferral.
                if (!r.deferred) {
                    final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
                    if (mDispatcher.isDeferringLocked(receiverUid)) {
                        if (DEBUG_BROADCAST_DEFERRAL) {
                            Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid
                                    + " at " + r.nextReceiver + " is under deferral");
                        }
                        // If this is the only (remaining) receiver in the broadcast, "splitting"
                        // doesn't make sense -- just defer it as-is and retire it as the
                        // currently active outgoing broadcast.
                        BroadcastRecord defer;
                        if (r.nextReceiver + 1 == numReceivers) {
                            if (DEBUG_BROADCAST_DEFERRAL) {
                                Slog.i(TAG_BROADCAST, "Sole receiver of " + r
                                        + " is under deferral; setting aside and proceeding");
                            }
                            defer = r;
                            mDispatcher.retireBroadcastLocked(r);
                        } else {
                            // Nontrivial case; split out 'uid's receivers to a new broadcast record
                            // and defer that, then loop and pick up continuing delivery of the current
                            // record (now absent those receivers).
    
                            // The split operation is guaranteed to match at least at 'nextReceiver'
                            defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
                            if (DEBUG_BROADCAST_DEFERRAL) {
                                Slog.i(TAG_BROADCAST, "Post split:");
                                Slog.i(TAG_BROADCAST, "Original broadcast receivers:");
                                for (int i = 0; i < r.receivers.size(); i++) {
                                    Slog.i(TAG_BROADCAST, "  " + r.receivers.get(i));
                                }
                                Slog.i(TAG_BROADCAST, "Split receivers:");
                                for (int i = 0; i < defer.receivers.size(); i++) {
                                    Slog.i(TAG_BROADCAST, "  " + defer.receivers.get(i));
                                }
                            }
                            // Track completion refcount as well if relevant
                            if (r.resultTo != null) {
                                int token = r.splitToken;
                                if (token == 0) {
                                    // first split of this record; refcount for 'r' and 'deferred'
                                    r.splitToken = defer.splitToken = nextSplitTokenLocked();
                                    mSplitRefcounts.put(r.splitToken, 2);
                                    if (DEBUG_BROADCAST_DEFERRAL) {
                                        Slog.i(TAG_BROADCAST,
                                                "Broadcast needs split refcount; using new token "
                                                + r.splitToken);
                                    }
                                } else {
                                    // new split from an already-refcounted situation; increment count
                                    final int curCount = mSplitRefcounts.get(token);
                                    if (DEBUG_BROADCAST_DEFERRAL) {
                                        if (curCount == 0) {
                                            Slog.wtf(TAG_BROADCAST,
                                                    "Split refcount is zero with token for " + r);
                                        }
                                    }
                                    mSplitRefcounts.put(token, curCount + 1);
                                    if (DEBUG_BROADCAST_DEFERRAL) {
                                        Slog.i(TAG_BROADCAST, "New split count for token " + token
                                                + " is " + (curCount + 1));
                                    }
                                }
                            }
                        }
                        mDispatcher.addDeferredBroadcast(receiverUid, defer);
                        r = null;
                        looped = true;
                        continue;
                    }
                }
            } while (r == null);
    
            // Get the next receiver...
            int recIdx = r.nextReceiver++;
    
            // Keep track of when this receiver started, and make sure there
            // is a timeout message pending to kill it if need be.
            r.receiverTime = SystemClock.uptimeMillis();
            if (recIdx == 0) {
                r.dispatchTime = r.receiverTime;
                r.dispatchClockTime = System.currentTimeMillis();
    
                if (mLogLatencyMetrics) {
                    StatsLog.write(
                            StatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,
                            r.dispatchClockTime - r.enqueueClockTime);
                }
    
                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                        System.identityHashCode(r));
                    Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                        System.identityHashCode(r));
                }
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
                        + mQueueName + "] " + r);
            }
            if (! mPendingBroadcastTimeoutMessage) {
                long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                        "Submitting BROADCAST_TIMEOUT_MSG ["
                        + mQueueName + "] for " + r + " at " + timeoutTime);
                setBroadcastTimeoutLocked(timeoutTime);
            }
    
            final BroadcastOptions brOptions = r.options;
            final Object nextReceiver = r.receivers.get(recIdx);
    
            //这里走入了动态广播Receiver的逻辑
            if (nextReceiver instanceof BroadcastFilter) {
                // Simple case: this is a registered receiver who gets
                // a direct call.
                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                        "Delivering ordered ["
                        + mQueueName + "] to registered "
                        + filter + ": " + r);
                //这里也是发送给动态注册广播
                deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
                if (r.receiver == null || !r.ordered) {
                    //在处理广播的过程performReceiveLocked中,如果receiver所在进程被kill,则会将r.receiver = null; r.curFilter = null;
                    //这里看着应该全部是有序广播?!r.ordered不知道意义何在
                    // The receiver has already finished, so schedule to
                    // process the next one.
                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                            + mQueueName + "]: ordered="
                            + r.ordered + " receiver=" + r.receiver);
                    r.state = BroadcastRecord.IDLE;
                    scheduleBroadcastsLocked();
                } else {
                    if (filter.receiverList != null) {
                        maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                        // r is guaranteed ordered at this point, so we know finishReceiverLocked()
                        // will get a callback and handle the activity start token lifecycle.
                    }
                    if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                        scheduleTempWhitelistLocked(filter.owningUid,
                                brOptions.getTemporaryAppWhitelistDuration(), r);
                    }
                }
                return;
            }
    
            // Hard case: need to instantiate the receiver, possibly
            // starting its application process to host it.
    
            //上面都是动态Receiver,这里自然是静态Receiver
            ResolveInfo info =
                (ResolveInfo)nextReceiver;
            ComponentName component = new ComponentName(
                    info.activityInfo.applicationInfo.packageName,
                    info.activityInfo.name);
    
            boolean skip = false;
            if (brOptions != null &&
                    (info.activityInfo.applicationInfo.targetSdkVersion
                            < brOptions.getMinManifestReceiverApiLevel() ||
                    info.activityInfo.applicationInfo.targetSdkVersion
                            > brOptions.getMaxManifestReceiverApiLevel())) {
                skip = true;
            }
            if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
                    component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
                Slog.w(TAG, "Association not allowed: broadcasting "
                        + r.intent.toString()
                        + " from " + r.callerPackage + " (pid=" + r.callingPid
                        + ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
                skip = true;
            }
            if (!skip) {
                skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
                        r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
                if (skip) {
                    Slog.w(TAG, "Firewall blocked: broadcasting "
                            + r.intent.toString()
                            + " from " + r.callerPackage + " (pid=" + r.callingPid
                            + ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
                }
            }
            int perm = mService.checkComponentPermission(info.activityInfo.permission,
                    r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
                    info.activityInfo.exported);
            if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
                if (!info.activityInfo.exported) {
                    Slog.w(TAG, "Permission Denial: broadcasting "
                            + r.intent.toString()
                            + " from " + r.callerPackage + " (pid=" + r.callingPid
                            + ", uid=" + r.callingUid + ")"
                            + " is not exported from uid " + info.activityInfo.applicationInfo.uid
                            + " due to receiver " + component.flattenToShortString());
                } else {
                    Slog.w(TAG, "Permission Denial: broadcasting "
                            + r.intent.toString()
                            + " from " + r.callerPackage + " (pid=" + r.callingPid
                            + ", uid=" + r.callingUid + ")"
                            + " requires " + info.activityInfo.permission
                            + " due to receiver " + component.flattenToShortString());
                }
                skip = true;
            } else if (!skip && info.activityInfo.permission != null) {
                final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
                if (opCode != AppOpsManager.OP_NONE
                        && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
                                r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
                    Slog.w(TAG, "Appop Denial: broadcasting "
                            + r.intent.toString()
                            + " from " + r.callerPackage + " (pid="
                            + r.callingPid + ", uid=" + r.callingUid + ")"
                            + " requires appop " + AppOpsManager.permissionToOp(
                                    info.activityInfo.permission)
                            + " due to registered receiver "
                            + component.flattenToShortString());
                    skip = true;
                }
            }
            if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
                r.requiredPermissions != null && r.requiredPermissions.length > 0) {
                for (int i = 0; i < r.requiredPermissions.length; i++) {
                    String requiredPermission = r.requiredPermissions[i];
                    try {
                        perm = AppGlobals.getPackageManager().
                                checkPermission(requiredPermission,
                                        info.activityInfo.applicationInfo.packageName,
                                        UserHandle
                                                .getUserId(info.activityInfo.applicationInfo.uid));
                    } catch (RemoteException e) {
                        perm = PackageManager.PERMISSION_DENIED;
                    }
                    if (perm != PackageManager.PERMISSION_GRANTED) {
                        Slog.w(TAG, "Permission Denial: receiving "
                                + r.intent + " to "
                                + component.flattenToShortString()
                                + " requires " + requiredPermission
                                + " due to sender " + r.callerPackage
                                + " (uid " + r.callingUid + ")");
                        skip = true;
                        break;
                    }
                    int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
                    if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                            && mService.mAppOpsService.noteOperation(appOp,
                            info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
                            != AppOpsManager.MODE_ALLOWED) {
                        Slog.w(TAG, "Appop Denial: receiving "
                                + r.intent + " to "
                                + component.flattenToShortString()
                                + " requires appop " + AppOpsManager.permissionToOp(
                                requiredPermission)
                                + " due to sender " + r.callerPackage
                                + " (uid " + r.callingUid + ")");
                        skip = true;
                        break;
                    }
                }
            }
            if (!skip && r.appOp != AppOpsManager.OP_NONE
                    && mService.mAppOpsService.noteOperation(r.appOp,
                    info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
                    != AppOpsManager.MODE_ALLOWED) {
                Slog.w(TAG, "Appop Denial: receiving "
                        + r.intent + " to "
                        + component.flattenToShortString()
                        + " requires appop " + AppOpsManager.opToName(r.appOp)
                        + " due to sender " + r.callerPackage
                        + " (uid " + r.callingUid + ")");
                skip = true;
            }
            boolean isSingleton = false;
            try {
                isSingleton = mService.isSingleton(info.activityInfo.processName,
                        info.activityInfo.applicationInfo,
                        info.activityInfo.name, info.activityInfo.flags);
            } catch (SecurityException e) {
                Slog.w(TAG, e.getMessage());
                skip = true;
            }
            if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
                if (ActivityManager.checkUidPermission(
                        android.Manifest.permission.INTERACT_ACROSS_USERS,
                        info.activityInfo.applicationInfo.uid)
                                != PackageManager.PERMISSION_GRANTED) {
                    Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
                            + " requests FLAG_SINGLE_USER, but app does not hold "
                            + android.Manifest.permission.INTERACT_ACROSS_USERS);
                    skip = true;
                }
            }
            if (!skip && info.activityInfo.applicationInfo.isInstantApp()
                    && r.callingUid != info.activityInfo.applicationInfo.uid) {
                Slog.w(TAG, "Instant App Denial: receiving "
                        + r.intent
                        + " to " + component.flattenToShortString()
                        + " due to sender " + r.callerPackage
                        + " (uid " + r.callingUid + ")"
                        + " Instant Apps do not support manifest receivers");
                skip = true;
            }
            if (!skip && r.callerInstantApp
                    && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
                    && r.callingUid != info.activityInfo.applicationInfo.uid) {
                Slog.w(TAG, "Instant App Denial: receiving "
                        + r.intent
                        + " to " + component.flattenToShortString()
                        + " requires receiver have visibleToInstantApps set"
                        + " due to sender " + r.callerPackage
                        + " (uid " + r.callingUid + ")");
                skip = true;
            }
            if (r.curApp != null && r.curApp.isCrashing()) {
                // If the target process is crashing, just skip it.
                Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
                        + " to " + r.curApp + ": process crashing");
                skip = true;
            }
            if (!skip) {
                boolean isAvailable = false;
                try {
                    isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
                            info.activityInfo.packageName,
                            UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
                } catch (Exception e) {
                    // all such failures mean we skip this receiver
                    Slog.w(TAG, "Exception getting recipient info for "
                            + info.activityInfo.packageName, e);
                }
                if (!isAvailable) {
                    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                            "Skipping delivery to " + info.activityInfo.packageName + " / "
                            + info.activityInfo.applicationInfo.uid
                            + " : package no longer available");
                    skip = true;
                }
            }
    
            // If permissions need a review before any of the app components can run, we drop
            // the broadcast and if the calling app is in the foreground and the broadcast is
            // explicit we launch the review UI passing it a pending intent to send the skipped
            // broadcast.
            if (!skip) {
                if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
                        info.activityInfo.packageName, UserHandle.getUserId(
                                info.activityInfo.applicationInfo.uid))) {
                    skip = true;
                }
            }
    
            // This is safe to do even if we are skipping the broadcast, and we need
            // this information now to evaluate whether it is going to be allowed to run.
            final int receiverUid = info.activityInfo.applicationInfo.uid;
            // If it's a singleton, it needs to be the same app or a special app
            if (r.callingUid != Process.SYSTEM_UID && isSingleton
                    && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
            }
            String targetProcess = info.activityInfo.processName;
            ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
                    info.activityInfo.applicationInfo.uid, false);
    
            if (!skip) {
                final int allowed = mService.getAppStartModeLocked(
                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
                        info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
                if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                    // We won't allow this receiver to be launched if the app has been
                    // completely disabled from launches, or it was not explicitly sent
                    // to it and the app is in a state that should not receive it
                    // (depending on how getAppStartModeLocked has determined that).
                    if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                        Slog.w(TAG, "Background execution disabled: receiving "
                                + r.intent + " to "
                                + component.flattenToShortString());
                        skip = true;
                    } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                            || (r.intent.getComponent() == null
                                && r.intent.getPackage() == null
                                && ((r.intent.getFlags()
                                        & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
                                && !isSignaturePerm(r.requiredPermissions))) {
                        mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
                                component.getPackageName());
                        Slog.w(TAG, "Background execution not allowed: receiving "
                                + r.intent + " to "
                                + component.flattenToShortString());
                        skip = true;
                    }
                }
            }
    
            if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())
                    && !mService.mUserController
                    .isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
                            0 /* flags */)) {
                skip = true;
                Slog.w(TAG,
                        "Skipping delivery to " + info.activityInfo.packageName + " / "
                                + info.activityInfo.applicationInfo.uid + " : user is not running");
            }
    
            if (skip) {
                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                        "Skipping delivery of ordered [" + mQueueName + "] "
                        + r + " for reason described above");
                r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
                r.receiver = null;
                r.curFilter = null;
                r.state = BroadcastRecord.IDLE;
                r.manifestSkipCount++;
                scheduleBroadcastsLocked();
                return;
            }
            r.manifestCount++;
    
            r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
            r.state = BroadcastRecord.APP_RECEIVE;
            r.curComponent = component;
            r.curReceiver = info.activityInfo;
            if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
                Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
                        + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
                        + receiverUid);
            }
    
            if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                scheduleTempWhitelistLocked(receiverUid,
                        brOptions.getTemporaryAppWhitelistDuration(), r);
            }
    
            // Broadcast is being executed, its package can't be stopped.
            try {
                AppGlobals.getPackageManager().setPackageStoppedState(
                        r.curComponent.getPackageName(), false, r.userId);
            } catch (RemoteException e) {
            } catch (IllegalArgumentException e) {
                Slog.w(TAG, "Failed trying to unstop package "
                        + r.curComponent.getPackageName() + ": " + e);
            }
    
            // Is this receiver's application already running?
            if (app != null && app.thread != null && !app.killed) {
                try {
                    app.addPackage(info.activityInfo.packageName,
                            info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
                    maybeAddAllowBackgroundActivityStartsToken(app, r);
                    processCurBroadcastLocked(r, app, skipOomAdj);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when sending broadcast to "
                          + r.curComponent, e);
                } catch (RuntimeException e) {
                    Slog.wtf(TAG, "Failed sending broadcast to "
                            + r.curComponent + " with " + r.intent, e);
                    // If some unexpected exception happened, just skip
                    // this broadcast.  At this point we are not in the call
                    // from a client, so throwing an exception out from here
                    // will crash the entire system instead of just whoever
                    // sent the broadcast.
                    logBroadcastReceiverDiscardLocked(r);
                    finishReceiverLocked(r, r.resultCode, r.resultData,
                            r.resultExtras, r.resultAbort, false);
                    scheduleBroadcastsLocked();
                    // We need to reset the state if we failed to start the receiver.
                    r.state = BroadcastRecord.IDLE;
                    return;
                }
    
                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
    
            //进程没启动的逻辑,这个参照Activity进程拉起逻辑
            // Not running -- get it started, to be executed when the app comes up.
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Need to start app ["
                    + mQueueName + "] " + targetProcess + " for broadcast " + r);
            if ((r.curApp=mService.startProcessLocked(targetProcess,
                    info.activityInfo.applicationInfo, true,
                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                    new HostingRecord("broadcast", r.curComponent),
                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                            == null) {
                // Ah, this recipient is unavailable.  Finish it if necessary,
                // and mark the broadcast record as ready for the next.
                Slog.w(TAG, "Unable to launch app "
                        + info.activityInfo.applicationInfo.packageName + "/"
                        + receiverUid + " for broadcast "
                        + r.intent + ": process is bad");
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                scheduleBroadcastsLocked();
                r.state = BroadcastRecord.IDLE;
                return;
            }
    
            maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
            mPendingBroadcast = r;
            mPendingBroadcastRecvIndex = recIdx;
        }
    

    因为这篇代码贴得比较长,不往下继续贴代码。从代码里可以看到一般难以注意的几个细节:

    1. 静态注册的广播Receiver,不管是发送有序广播还是无序广播,它都是串行执行的。
    2. 动态注册的广播,通过InnerReceiver直接调用它的存在实例类。静态注册的广播,是反射生成的Receiver类,和Activity类似。
    3. 无序广播,动态注册的Reciver优先于静态注册的Receiver执行。有序广播,同优先级动态注册的Reciver优先于静态注册的Receiver执行。

    参考文档:

    1. Android源码解析四大组件系列(七)---广播的发送过程
    2. Android 静态广播和动态广播接收顺序
    3. FrameWork源码解析(5)-广播处理过程源码解析
    4. 广播相关学习-processNextBroadcast逻辑

    相关文章

      网友评论

          本文标题:Broadcast流程源码分析

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