broadcast 学习

2022-10-25 16:21:30 浏览数 (2)

本篇介绍

android的广播在应用开发中使用的场景很多,本篇就介绍下广播的基本内容,然后侧重介绍广播的几个关键流程,包含广播的注册,注销,还有广播的发送,本篇侧重的是流程的学习,希望通过学习该流程可以对Android的广播有一个清晰的过程了解,这块知识在分析anr问题的时候很有帮助。

基础知识介绍

android中的broadcast包含动态注册, 静态注册, 有序广播,本地广播。

名词

介绍

静态注册

直接在manifest文件中之名注册广播,不支持注销广播,在广播接受的时候优先级不如动态注册,后续代码会看到

动态注册

在代码中显示调用registerReceiver注册广播,支持注册与注销,灵活性比较高

无序广播

并行通知的就是无序广播

有序广播

通过sendOrderedBroadcast发送,接受者按优先级排序,一个处理完后传递给下一个,同时也可以在本应用中设置数据,这样数据就可以传递给下一个接受者

本地广播

只在应用内部有效的广播,安全性高

粘性广播

注册广播的时候如果系统中有广播,那么马上就能收到,而非粘性广播是需要注册完,系统再次接收到广播,应用才可以接收到

这儿只是介绍下基础概念,重点看下代码流程,分三个,广播的注册,注销,发送。接下来挨个看下。

广播的注册

广播的注册要从registerReceiver开始:

代码语言:javascript复制
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            int flags) {
        return registerReceiver(receiver, filter, null, null, flags);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler, int flags) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), flags);
    }

可以看到有多种形式的registerReceiver,不过内部都是调用了registerReceiverInternal, 其他的几个参数是全新,handler,flags,看下registerReceiverInternal的实现:

代码语言:javascript复制
    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();
                } // 广播的默认handler是主线程handler
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true); 
// 获取intentreceiver,如果看过bindService流程,这块应该就会觉得比较熟悉了吧?
//套路就是搞一个匿名binder,然后将匿名binder和当前的receiver绑定起来
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
                    filter, broadcastPermission, userId, flags); // 走ams 注册
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

这块流程和bindService基本是一致的,搞一个内部对象,然后和一个匿名binder绑定到一个封装对象里面,然后把这个匿名binder的proxy传递到ams中。 在进入AMS之前再简单看下IIntentReceiver的过程:

代码语言:javascript复制
    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            } 
// 还是以context为key管理receivers,每个receiver对应一个receiverdispater
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }

现在也能猜出来ReceiverDispatcher的实现,基本就是内部搞一个匿名binder做一下关联,通过代码证实一下:

代码语言:javascript复制
    static final class ReceiverDispatcher {
        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }

            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
              
                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser); 
//如果非空就通知对应的receiver,可以看到这儿的dispatcher用的是弱应用,这儿是因为匿名binder 记录到ams后,
//receiver对象是不需要或者没必要保证一定存活的,这样如果应用已经把这个对象释放了,那么就不调用了,直接向ams回一个消息就可以了
                } else {
                    // The activity manager dispatched a broadcast to a registered
                    // receiver in this process, but before it could be delivered the
                    // receiver was unregistered.  Acknowledge the broadcast on its
                    // behalf so that the system's broadcast sequence can continue.
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to unregistered receiver");
                    IActivityManager mgr = ActivityManager.getService();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
 // 直接向ams 回一个完成消息,具体逻辑在消息通知那部分细看
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        }

接下来就开始进入ams看ams里面是如何注册receiver的,入口函数就是registerReceiverWithFeature,在此之前先看下传递了哪些参数:

参数

含义

mMainThread.getApplicationThread()

当前应用的binder

mBasePackageName

包名

getAttributionTag

属性tag

rd

IIntentReceiver的binder

filter

过滤广播的Intent

broadcastPermission

权限相关

userId

用户id

flags

标识符

代码比较多,还是分开阅读:

代码语言:javascript复制
    public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
            String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
            String permission, int userId, int flags) {
        enforceNotIsolatedCaller("registerReceiver");
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        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();
            }

            // 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()); // 按binder 查找该receiver对应的ReceiverList
            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);
                    }// 单个应用注册的广播不超过1000个
                    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);
            } 
...
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    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); //为调用方应用添加filter
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                mReceiverResolver.addFilter(bf);
//在ams中添加filter,到了这儿普通的广播注册流程已经结束了
//再往下就是粘性广播了,如果是粘性广播,还需要通知下业务
            }

            // 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, 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;
        }
    }

到了这儿广播的注册就介绍完了,流程很清晰,就是应用把receiver对应的binder传递到ams中,并记录到ams的对应结构中就可以了,记录的时候,在应用对应的结构中记录一份,在ams的全局mReceiverResolver也记录一份,这个也是用内存换效率的例子了。如果是有粘性广播,则还需要立马通知下注册方。

广播的注销

看了广播的注册后,注销就差不多能猜到了,可以简单看下:

代码语言:javascript复制
    public void unregisterReceiver(BroadcastReceiver receiver) {
        if (mPackageInfo != null) {
            IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
                    getOuterContext(), receiver);
            try {
                ActivityManager.getService().unregisterReceiver(rd);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
    }

可以看到流程基本是先从本地应用记录的receiver 中删除掉记录,然后再发一个请求到AMS删除ams保存的记录。

代码语言:javascript复制
    public IIntentReceiver forgetReceiverDispatcher(Context context,
            BroadcastReceiver r) {
        synchronized (mReceivers) {
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = mReceivers.get(context);
            LoadedApk.ReceiverDispatcher rd = null;
            if (map != null) {
                rd = map.get(r);
                if (rd != null) {
                    map.remove(r); // 删除receiver 
                    if (map.size() == 0) {
                        mReceivers.remove(context);
                    }
                    if (r.getDebugUnregister()) {
                        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
                                = mUnregisteredReceivers.get(context);
                        if (holder == null) {
                            holder = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                            mUnregisteredReceivers.put(context, holder); //记录已删除的receiver
                        }
                        RuntimeException ex = new IllegalArgumentException(
                                "Originally unregistered here:");
                        ex.fillInStackTrace();
                        rd.setUnregisterLocation(ex);
                        holder.put(r, rd);
                    }
                    rd.mForgotten = true;
                    return rd.getIIntentReceiver();
                }
            }
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> holder
                    = mUnregisteredReceivers.get(context);
            if (holder != null) {
                rd = holder.get(r);
                if (rd != null) {
                    RuntimeException ex = rd.getUnregisterLocation();
                    throw new IllegalArgumentException( //重复删除会抛异常
                            "Unregistering Receiver "   r
                              " that was already unregistered", ex);
                }
            }
            if (context == null) {
                throw new IllegalStateException("Unbinding Receiver "   r
                          " from Context that is no longer in use: "   context);
            } else {
                throw new IllegalArgumentException("Receiver not registered: "   r);
            }

        }
    }

接下来看下ams的实现

代码语言:javascript复制
    public void unregisterReceiver(IIntentReceiver receiver) {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Unregister receiver: "   receiver);

        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doTrim = false;

            synchronized(this) {
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                if (rl != null) {
                    final BroadcastRecord r = rl.curBroadcast;
                    if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) { // 获取当前正在处理的广播,并且接收者是发起的注销方
                        final boolean doNext = r.queue.finishReceiverLocked( //从通知队列里面删除当前receiver
                                r, r.resultCode, r.resultData, r.resultExtras,
                                r.resultAbort, false);
                        if (doNext) {
                            doTrim = true;
                            r.queue.processNextBroadcast(false); //如果broadcastrecord状态是APP_RECEIVE 或者WAITING_SERVICES,那就继续处理下一个接收者
                        }
                    }

                    if (rl.app != null) {
                        rl.app.receivers.remove(rl);
                    }
                    removeReceiverLocked(rl);
                    if (rl.linkedToDeath) {
                        rl.linkedToDeath = false;
                        rl.receiver.asBinder().unlinkToDeath(rl, 0);
                    }
                }
            }

            // If we actually concluded any broadcasts, we might now be able
            // to trim the recipients' apps from our working set
            if (doTrim) {
                trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
                return;
            }

        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

接下来看下removeReceiverLocked的内容:

代码语言:javascript复制
   void removeReceiverLocked(ReceiverList rl) {
       mRegisteredReceivers.remove(rl.receiver.asBinder()); //从ams的记录里面删除这个receiver
       for (int i = rl.size() - 1; i >= 0; i--) {
           mReceiverResolver.removeFilter(rl.get(i)); // 从ams里面删除该receiver对应的filter
       }
   }

这时候注销广播也介绍完了,流程比较直接,就是请求方自己删除后,再调用到ams里面删除一把,不涉及发广播的应用。

广播的发送

这个应该是本篇最复杂的流程了,这块是应用方发送一个广播到ams,然后ams通知给订阅方,起点是sendBroadcast

代码语言:javascript复制
    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, receiverPermissions,
                    AppOpsManager.OP_NONE, null, false, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
            String[] receiverPermissions) {
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, receiverPermissions,
                    AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        String[] receiverPermissions = receiverPermission == null ? null
                : new String[] {receiverPermission};
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, receiverPermissions,
                    AppOpsManager.OP_NONE, options, false, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        String[] receiverPermissions = receiverPermission == null ? null
                : new String[] {receiverPermission};
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
                    false, getUserId()); // 注意下倒数第二个参数sticky,这儿发的是非粘性广播
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

可以看到sendBroadcast有多种形式,不过一样的是本地基本没做啥逻辑,都是一下子到了ams的broadcastIntentWithFeature,现在就进入ams看下:

代码语言:javascript复制
    public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
            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); //对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, callingFeatureId,
                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                        requiredPermissions, appOp, bOptions, serialized, sticky,
                        callingPid, callingUid, callingUid, callingPid, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }

接下来看下broadcastIntentLocked,这个函数比较长,只能分阶段看了

代码语言:javascript复制
  final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
            @Nullable String callerFeatureId, 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,
            @Nullable int[] broadcastWhitelist) {
// 可以看到入参里面有resultTo,放心调用的时候传入的是null
        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);
        }

        if (userId == UserHandle.USER_ALL && broadcastWhitelist != null) {
                Slog.e(TAG, "broadcastWhitelist only applies when sending to individual users. "
                          "Assuming restrictive whitelist.");
                broadcastWhitelist = new int[]{};
        }

        // By default broadcasts do not go to stopped apps.
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); // 默认广播不发给已经停止的app

        // 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;
            }
        }

第一阶段修改了下intent,标注默认不发给已经结束运行的app,如果当前用户或父用户账号不在运行,则直接返回广播失败。接下来看第二阶段:

代码语言:javascript复制
     final String action = intent.getAction();
        BroadcastOptions brOptions = null;
        if (bOptions != null) { 
 // 对于sendBroadcast,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;
                }
            }
        }

第二阶段就是做了一个权限检查,并没有主要逻辑,看下第三阶段:

代码语言:javascript复制
        // 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);
                }
            }
        }

第三阶段还是检查,不知道以前是否有人想过,既然android好多行为都依赖于系统广播,那是否可以自己搞一个app专门假冒发这些系统广播,看到这块逻辑就死心了吧,这块就是保证系统广播是需要系统应用才可以发送的。接下来的第五阶段就是一些需要ams介入处理的广播逻辑,这块和主要流程关系不大,因此直接略过。再接着第六阶段就是粘性广播的逻辑了,sendBroadcast发送的是非粘性广播,因此也和该流程影响不大,不过这儿还是需要看下,了解下粘性广播的特殊之处

代码语言:javascript复制
       // 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");
                            }
                        }
                    }
                }
            }
            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)); // 这个就是关键的,将当前广播加入到粘性广播stickies中
            }
        }

接下来还是一堆检查,没权限的,指定目标的,和现有粘性广播冲突的,都是不合法的。接下来看第七阶段的内容:

代码语言:javascript复制
        // 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) {
            receivers = collectReceiverComponents(
                    intent, resolvedType, callingUid, users, broadcastWhitelist); 
// 从pms中查询receivers,主要是静态注册的应用
        }
        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]); // 查询多用户对应的receivers
                    if (registeredReceivers == null) {
                        registeredReceivers = registeredReceiversForUser;
                    } else if (registeredReceiversForUser != null) {
                        registeredReceivers.addAll(registeredReceiversForUser);  将两个receiver列表合并起来
                    }
                }
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId); // 查询单用户的receivers
            }
        }

       final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: "   intent.getAction()
                  " replacePending="   replacePending);
        if (registeredReceivers != null && broadcastWhitelist != null) {
            // if a uid whitelist was provided, remove anything in the application space that wasn't
            // in it.
            for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
                final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
                if (owningAppId >= Process.FIRST_APPLICATION_UID
                        && Arrays.binarySearch(broadcastWhitelist, owningAppId) < 0) {
                    registeredReceivers.remove(i); //如果receiver是三方应用(uid > 10000),并且不在白名单中,则从接收方列表中移除
                }
            }
        }

看下第八阶段的流程,目前处理的是动态注册的广播,之前有人问过同一个广播,是动态注册还是静态注册先接收到,看到这儿答案就出来了吧,当然是动态注册的先接收到了。

代码语言:javascript复制
        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,
                    callerFeatureId, 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;
        }

这一段针对的是无序广播,无序广播不会拉起静态注册的应用,只会通知给动态注册的应用,这是为了防止一个广播过来了,然后把n个应用拉起来了,这儿比较关键。继续看第九阶段吧

代码语言:javascript复制
   // 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--;
                            }
                        }
                    }
                }
            }

接下来看第十阶段:

代码语言:javascript复制
            int NT = receivers != null ? receivers.size() : 0;
            int it = 0;
            ResolveInfo curt = null;
            BroadcastFilter curr = null;
            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  ;
        }

可以看到这时候就是动态注册和静态注册的receiver合并,需要注意的是如果是无序广播的话,动态注册的已经都通知过了,这儿就全是静态注册的receiver了。如果是有序广播的话,这儿就会按照优先级合并起来。接下来看下最后一个阶段:

代码语言:javascript复制
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, 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;
    }

现在就需要看下scheduleBroadcastsLocked 的逻辑了,广播如何通知给订阅方的逻辑就在里面:

代码语言:javascript复制
    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;
    }

发送了一个looper消息,是异步操作,对应的处理函数是processNextBroadcast, 看下实现逻辑:

代码语言:javascript复制
    final void processNextBroadcast(boolean fromMsg) {
        synchronized (mService) {
            processNextBroadcastLocked(fromMsg, false);
        }
    }

接着再看下processNextBroadcastLocked,注意这儿的fromMsg 是true, 这里面的逻辑也很多,我们只拿出关键的看看

代码语言:javascript复制
 final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        // First, deliver any non-serialized broadcasts right away.
        while (mParallelBroadcasts.size() > 0) {
            r = mParallelBroadcasts.remove(0);
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchClockTime = System.currentTimeMillis();

            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));
            }

            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); //挨个通知接收方
            }
            addBroadcastToHistoryLocked(r);
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                      mQueueName   "] "   r);
        }
...
  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; // 接下来没有广播了,所以就退出去了
            }

            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 //按照广播数量和时间计算,已经超时了,因此报一个anr问题
                    forceReceive = true;
                    r.state = BroadcastRecord.IDLE;
                }
            }
...
            if (r.receivers == null || r.nextReceiver >= numReceivers
                    || r.resultAbort || forceReceive) {
...
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                cancelBroadcastTimeoutLocked(); // 能走到这里,说明广播都投递结束了,发一个广播超时取消消息,这样就不会anr了。

       // 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) {
                FrameworkStatsLog.write(
                        FrameworkStatsLog.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);  // 给下一个广播设置超时消息,如果在规定时间内没有移除,那么超时函数就会被调用
        }

...
       // 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, //最麻烦的一种是还需要把接收者进程给拉起来
//有几种情况可以通过广播把应用拉起来,一种是指定了广播flags。一种是指定了广播接收者
                info.activityInfo.applicationInfo, true,
                r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                new HostingRecord("broadcast", r.curComponent),
                isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
                (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;

第一个阶段先拿出并行广播,然后开始发送,对应的实现就是deliverToRegisteredReceiverLocked,这里面也会有很多检查,不满足条件的receiver就不会投递了,不过不影响主流程,就一块略去了,只看关键部分:

代码语言:javascript复制
    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
...
        if (ordered) {
            r.receiver = filter.receiverList.receiver.asBinder();
            r.curFilter = filter;
            filter.receiverList.curBroadcast = r;
            r.state = BroadcastRecord.CALL_IN_RECEIVE;
            if (filter.receiverList.app != null) {
                // Bump hosting application to no longer be in background
                // scheduling class.  Note that we can't do that if there
                // isn't an app...  but we can only be in that case for
                // things that directly call the IActivityManager API, which
                // are already core system stuff so don't matter for this.
                r.curApp = filter.receiverList.app;
                filter.receiverList.app.curReceivers.add(r);
                mService.updateOomAdjLocked(r.curApp, true,
                        OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
            }
        } else if (filter.receiverList.app != null) {
            mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
        }

        try {
            if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                    "Delivering to "   filter   " : "   r);
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                // Skip delivery if full backup in progress
                // If it's an ordered broadcast, we need to continue to the next receiver.
                if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                r.receiverTime = SystemClock.uptimeMillis();
                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId); // 投递广播
                // parallel broadcasts are fire-and-forget, not bookended by a call to
                // finishReceiverLocked(), so we manage their activity-start token here
                if (filter.receiverList.app != null
                        && r.allowBackgroundActivityStarts && !r.ordered) {
                    postActivityStartTokenRemoval(filter.receiverList.app, r);
                }
            }
            if (ordered) {
                r.state = BroadcastRecord.CALL_DONE_RECEIVE;
            }

继续看下performReceiveLocked

代码语言:javascript复制
    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser)
            throws RemoteException {
        // Send the intent to the receiver asynchronously using one-way binder calls.
        if (app != null) {
            if (app.thread != null) {
                // If we have an app thread, do the call through that so it is
                // correctly ordered with other one-way calls.
                try {
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState()); // 异步通知广播
                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                // DeadObjectException when the process isn't actually dead.
                //} catch (DeadObjectException ex) {
                // Failed to call into the process.  It's dying so just let it die and move on.
                //    throw ex;
                } catch (RemoteException ex) {
                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
                    synchronized (mService) {
                        Slog.w(TAG, "Can't deliver broadcast to "   app.processName
                                  " (pid "   app.pid   "). Crashing it.");
                        app.scheduleCrash("can't deliver broadcast");
                    }
                    throw ex;
                }
            } else {
                // Application has died. Receiver doesn't exist.
                throw new RemoteException("app.thread must not be null");
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser); // 通知广播
        }
    }

可以看到这儿有两种投递广播的方法,一种是通过应用的主线程投递的,一种是直接走receiver的匿名binder投递的,先看下第一种:

代码语言:javascript复制
        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser, int processState) throws RemoteException {
            updateProcessState(processState, false);
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }

可以看到第一种的实现到了订阅方进程中也是执行的performReceive,区别就是第一种可以是异步的形式,第二种就成同步了。现在就开始看下performReceive的实现吧。

代码语言:javascript复制
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Receiving broadcast "   intent.getAction()
                              " seq="   seq   " to "   (rd != null ? rd.mReceiver : null));
                }
                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);  // 继续投递
                } else {
                    // The activity manager dispatched a broadcast to a registered
                    // receiver in this process, but before it could be delivered the
                    // receiver was unregistered.  Acknowledge the broadcast on its
                    // behalf so that the system's broadcast sequence can continue.
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to unregistered receiver");
                    IActivityManager mgr = ActivityManager.getService();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); // 如果对应的ReceiverDispatcher已经被注销了,那么就直接通知ams
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        }

继续看下performReceive:

代码语言:javascript复制
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast "   intent.getAction()
                              " seq="   seq   " to "   mReceiver);
                }
            }
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to "   mReceiver);
                    args.sendFinished(mgr); // 如果是有序广播,则需要再回复下ams
                }
            }
        }

可以看到具体的广播通知是在Args里面,这个是类似Runnable的东西,看下实现:

代码语言:javascript复制
  public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    final boolean ordered = mOrdered;

                    if (ActivityThread.DEBUG_BROADCAST) {
                        int seq = mCurIntent.getIntExtra("seq", -1);
                        Slog.i(ActivityThread.TAG, "Dispatching broadcast "   mCurIntent.getAction()
                                  " seq="   seq   " to "   mReceiver);
                        Slog.i(ActivityThread.TAG, "  mRegistered="   mRegistered
                                  " mOrderedHint="   ordered);
                    }

                    final IActivityManager mgr = ActivityManager.getService();
                    final Intent intent = mCurIntent;
                    if (intent == null) {
                        Log.wtf(TAG, "Null intent being dispatched, mDispatched="   mDispatched
                                  (mRunCalled ? ", run() has already been called" : ""));
                    }

                    mCurIntent = null;
                    mDispatched = true;
                    mRunCalled = true;
                    if (receiver == null || intent == null || mForgotten) {
                        if (mRegistered && ordered) {
                            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                    "Finishing null broadcast to "   mReceiver);
                            sendFinished(mgr);
                        }
                        return;
                    }

                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
                    try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        receiver.onReceive(mContext, intent); // 调用业务重载的onReceive方法,这时候就通知到业务了
                    } catch (Exception e) {
                        if (mRegistered && ordered) {
                            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                    "Finishing failed broadcast to "   mReceiver);
                            sendFinished(mgr);
                        }
                        if (mInstrumentation == null ||
                                !mInstrumentation.onException(mReceiver, e)) {
                            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                            throw new RuntimeException(
                                    "Error receiving broadcast "   intent
                                              " in "   mReceiver, e);
                        }
                    }

                    if (receiver.getPendingResult() != null) {
                        finish(); // 调用的也是sendFinished通知ams
                    }
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                };
            }
        }

这儿就看到广播终于可以通知给业务了,但还没有结束,还需要在通知后,再回复下ams,看下sendFinished:

代码语言:javascript复制
        public void sendFinished(IActivityManager am) {
            synchronized (this) {
                if (mFinished) {
                    throw new IllegalStateException("Broadcast already finished");
                }
                mFinished = true;

                try {
                    if (mResultExtras != null) {
                        mResultExtras.setAllowFds(false);
                    }
                    if (mOrderedHint) {
                        am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                                mAbortBroadcast, mFlags);
                    } else {
                        // This broadcast was sent to a component; it is not ordered,
                        // but we still need to tell the activity manager we are done.
                        am.finishReceiver(mToken, 0, null, null, false, mFlags);
                    }
                } catch (RemoteException ex) {
                }
            }
        }

可以看到是调用了finishReceiver来通知的,看下ams那边接收到后,做了哪些事情:

代码语言:javascript复制
    public void finishReceiver(IBinder who, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: "   who);

        // Refuse possible leaked file descriptors
        if (resultExtras != null && resultExtras.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Bundle");
        }

        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doNext = false;
            BroadcastRecord r;
            BroadcastQueue queue;

            synchronized(this) {
                if (isOnOffloadQueue(flags)) {
                    queue = mOffloadBroadcastQueue;
                } else {
                    queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                            ? mFgBroadcastQueue : mBgBroadcastQueue;
                }

                r = queue.getMatchingOrderedReceiver(who); //获取当前的binder对应的BroadcastRecord
                if (r != null) {
                    doNext = r.queue.finishReceiverLocked(r, resultCode,
                        resultData, resultExtras, resultAbort, true); // 通知广播通知结束
                }
                if (doNext) {
                    r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
                }
                // updateOomAdjLocked() will be done here
                trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
            }

        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

看下finishReceiverLocked的逻辑:

代码语言:javascript复制
   public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
        final int state = r.state;
        final ActivityInfo receiver = r.curReceiver;
        final long finishTime = SystemClock.uptimeMillis();
        final long elapsed = finishTime - r.receiverTime;
        r.state = BroadcastRecord.IDLE;
        if (state == BroadcastRecord.IDLE) {
            Slog.w(TAG_BROADCAST, "finishReceiver ["   mQueueName   "] called but state is IDLE");
        }
        if (r.allowBackgroundActivityStarts && r.curApp != null) {
            if (elapsed > mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT) {
                // if the receiver has run for more than allowed bg activity start timeout,
                // just remove the token for this process now and we're done
                r.curApp.removeAllowBackgroundActivityStartsToken(r);
            } else {
                // It gets more time; post the removal to happen at the appropriate moment
                postActivityStartTokenRemoval(r.curApp, r);
            }
        }
        // If we're abandoning this broadcast before any receivers were actually spun up,
        // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
        if (r.nextReceiver > 0) {
            r.duration[r.nextReceiver - 1] = elapsed;
        }

        // if this receiver was slow, impose deferral policy on the app.  This will kick in
        // when processNextBroadcastLocked() next finds this uid as a receiver identity.
        if (!r.timeoutExempt) {
            // r.curApp can be null if finish has raced with process death - benign
            // edge case, and we just ignore it because we're already cleaning up
            // as expected.
            if (r.curApp != null
                    && mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
                // Core system packages are exempt from deferral policy
                if (!UserHandle.isCore(r.curApp.uid)) {
                    if (DEBUG_BROADCAST_DEFERRAL) {
                        Slog.i(TAG_BROADCAST, "Broadcast receiver "   (r.nextReceiver - 1)
                                  " was slow: "   receiver   " br="   r);
                    }
                    mDispatcher.startDeferring(r.curApp.uid);
                } else {
                    if (DEBUG_BROADCAST_DEFERRAL) {
                        Slog.i(TAG_BROADCAST, "Core uid "   r.curApp.uid
                                  " receiver was slow but not deferring: "
                                  receiver   " br="   r);
                    }
                }
            }
        } else {
            if (DEBUG_BROADCAST_DEFERRAL) {
                Slog.i(TAG_BROADCAST, "Finished broadcast "   r.intent.getAction()
                          " is exempt from deferral policy");
            }
        }

        r.receiver = null;
        r.intent.setComponent(null);
        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
            r.curApp.curReceivers.remove(r);
        }
        if (r.curFilter != null) {
            r.curFilter.receiverList.curBroadcast = null;
        }
        r.curFilter = null;
        r.curReceiver = null;
        r.curApp = null;
        mPendingBroadcast = null;

        r.resultCode = resultCode;
        r.resultData = resultData;
        r.resultExtras = resultExtras;
        if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
            r.resultAbort = resultAbort;
        } else {
            r.resultAbort = false;
        }

        // If we want to wait behind services *AND* we're finishing the head/
        // active broadcast on its queue
        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
                && r.queue.mDispatcher.getActiveBroadcastLocked() == r) {
            ActivityInfo nextReceiver;
            if (r.nextReceiver < r.receivers.size()) {
                Object obj = r.receivers.get(r.nextReceiver);
                nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
            } else {
                nextReceiver = null;
            }
            // Don't do this if the next receive is in the same process as the current one.
            if (receiver == null || nextReceiver == null
                    || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                    || !receiver.processName.equals(nextReceiver.processName)) {
                // In this case, we are ready to process the next receiver for the current broadcast,
                // but are on a queue that would like to wait for services to finish before moving
                // on.  If there are background services currently starting, then we will go into a
                // special state where we hold off on continuing this broadcast until they are done.
                if (mService.mServices.hasBackgroundServicesLocked(r.userId)) {
                    Slog.i(TAG, "Delay finish: "   r.curComponent.flattenToShortString());
                    r.state = BroadcastRecord.WAITING_SERVICES;
                    return false;
                }
            }
        }

        r.curComponent = null;

        // We will process the next receiver right now if this is finishing
        // an app receiver (which is always asynchronous) or after we have
        // come back from calling a receiver.
        return state == BroadcastRecord.APP_RECEIVE
                || state == BroadcastRecord.CALL_DONE_RECEIVE;
    }

这里就完成了广播记录的更新,并且返回了当前BroadcastRecord的状态。 看到这里,应该是整个流程就梳理完了。 最后的最后再补充下广播anr的处理,前面有介绍过在发送广播的时候就会检查广播有没有超时,同时也会给新的广播设置超时消息,处理完后删除超时消息,那么广播anr是如何报的呢,处理逻辑就在broadcastTimeoutLocked里:

代码语言:javascript复制
 final void broadcastTimeoutLocked(boolean fromMsg) {
        if (fromMsg) {
            mPendingBroadcastTimeoutMessage = false;
        }

        if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {
            return;
        }

        long now = SystemClock.uptimeMillis();
        BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
        if (fromMsg) {
            if (!mService.mProcessesReady) {
                // Only process broadcast timeouts if the system is ready; some early
                // broadcasts do heavy work setting up system facilities
                return;
            }

            // If the broadcast is generally exempt from timeout tracking, we're done
            if (r.timeoutExempt) {
                if (DEBUG_BROADCAST) {
                    Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: "
                              r.intent.getAction());
                }
                return;
            }

            long timeoutTime = r.receiverTime   mConstants.TIMEOUT;
            if (timeoutTime > now) {
                // We can observe premature timeouts because we do not cancel and reset the
                // broadcast timeout message after each receiver finishes.  Instead, we set up
                // an initial timeout then kick it down the road a little further as needed
                // when it expires.
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                        "Premature timeout ["
                          mQueueName   "] @ "   now   ": resetting BROADCAST_TIMEOUT_MSG for "
                          timeoutTime);
                setBroadcastTimeoutLocked(timeoutTime);
                return;
            }
        }

       if (r.state == BroadcastRecord.WAITING_SERVICES) { // 等待服务启动场景不算,直接传递下一个广播
            // In this case the broadcast had already finished, but we had decided to wait
            // for started services to finish as well before going on.  So if we have actually
            // waited long enough time timeout the broadcast, let's give up on the whole thing
            // and just move on to the next.
            Slog.i(TAG, "Waited long enough for: "   (r.curComponent != null
                    ? r.curComponent.flattenToShortString() : "(null)"));
            r.curComponent = null;
            r.state = BroadcastRecord.IDLE;
            processNextBroadcast(false);
            return;
        }
        // If the receiver app is being debugged we quietly ignore unresponsiveness, just
        // tidying up and moving on to the next broadcast without crashing or ANRing this
        // app just because it's stopped at a breakpoint.
        final boolean debugging = (r.curApp != null && r.curApp.isDebugging());

        Slog.w(TAG, "Timeout of broadcast "   r   " - receiver="   r.receiver
                  ", started "   (now - r.receiverTime)   "ms ago"); // 这句log应该是很熟悉得了吧,看到广播anr,就是这儿搞的
        r.receiverTime = now;
        if (!debugging) {
            r.anrCount  ;
        }

        ProcessRecord app = null;
        String anrMessage = null;

        Object curReceiver;
        if (r.nextReceiver > 0) {
            curReceiver = r.receivers.get(r.nextReceiver-1);
            r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
        } else {
            curReceiver = r.curReceiver;
        }
        Slog.w(TAG, "Receiver during timeout of "   r   " : "   curReceiver);
        logBroadcastReceiverDiscardLocked(r);
        if (curReceiver != null && curReceiver instanceof BroadcastFilter) {
            BroadcastFilter bf = (BroadcastFilter)curReceiver;
            if (bf.receiverList.pid != 0
                    && bf.receiverList.pid != ActivityManagerService.MY_PID) {
                synchronized (mService.mPidsSelfLocked) {
                    app = mService.mPidsSelfLocked.get(
                            bf.receiverList.pid);
                }
            }
        } else {
            app = r.curApp;
        }

        if (app != null) {
            anrMessage = "Broadcast of "   r.intent.toString();
        }

        if (mPendingBroadcast == r) {
            mPendingBroadcast = null;
        }

        // Move on to the next receiver.
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false); // 跳过当前receiver,直接给下一个receiver传递
        scheduleBroadcastsLocked();

        if (!debugging && anrMessage != null) {
            mService.mAnrHelper.appNotResponding(app, anrMessage); //让当前超时的receiver 发生anr
        }
    }

这里面的逻辑主要就是找到当前超时的receiver和下一个receiver,然后安排给下一个receiver发送广播,并且把当前超时的receiver 搞一个anr。

本篇总结

broadcast的流程还是比较复杂的,本篇把广播的大致流程介绍了下,这样以后不管广播出什么问题,应该都有思路分析了吧。

0 人点赞