# android BroadcastReceiver详解 站点:答源(https://www.dandroid.cn/) 原文:https://www.dandroid.cn/archives/18872 Canonical:https://www.dandroid.cn/archives/18872 作者:dandroid004 发布日期:2023-09-04 最后更新:2023-09-12 16:40 分类:Android系统开发 / Framework源码 内容类型:post 说明:本页是原文的纯文本镜像,供大模型与检索器完整读取;不含导航、广告、付费框。引用请以上方「原文」链接为准。 ## 正文 这篇文章本来应该是继续看VirtualApk中关于插件BroadcastReceiver的处理的。不过由于处理逻辑比较简单(在加载插件的时候把插件的所有BroadcastReceiver转为动态广播并注册),所以这里就不看了。 本文就从Android源码(8.0)来看一下系统对BroadcastReceiver的处理逻辑(广播接收者注册、发送广播),BroadcastReceiver的源码处理逻辑很多也很复杂,我们只看重点,所以对于广播一些很细致的点是看不到了。本文的目标是了解系统对广播的整个处理的过程。 BroadcastReceiver的注册 动态注册广播接收者 我们从动态注册开始看 : context.registerReceiver(mBroadcastReceiver, intentFilter), 最终调用的方法是ContextImpl.registerReceiverInternal(): private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context, int flags) { IIntentReceiver rd = null; ... rd = new LoadedApk.ReceiverDispatcher( receiver, context, scheduler, null, true).getIIntentReceiver() ... ActivityManager.getService().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId, flags) } 即构造了一个LoadedApk.ReceiverDispatcher, 然后就转到ActivityManagerService去注册。那LoadedApk.ReceiverDispatcher是什么呢? LoadedApk : 这个类是用来保存当前运行app的状态的类,它保存着app的Application、类加载器、receiver、service等信息。 LoadedApk.ReceiverDispatcher : 这个类含有一个InnerReceiver(Stub Binder),用来和服务端通信,当ActivityManagerService分发广播时,就会通过这个(Stub)Binder调用BroadcastReceiver.onReceiver()。这个我们到后续看广播接收的时候再讲。先知道这个类可以被ActivityManagerService用来和客户端通信即可。 ActivityManagerService.registerReceiver() 这个方法的注册逻辑也比较简单,这里我们不看粘性广播(已被废弃)的注册部分: public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter ...) { ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); if (rl.app != null) { ... rl.app.receivers.add(rl); } else { ... } mRegisteredReceivers.put(receiver.asBinder(), rl); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId, instantApp, visibleToInstantApps); rl.add(bf); mReceiverResolver.addFilter(bf); } 即把一个BroadcastFilter放入ReceiverList和mReceiverResolver中。那这两个又是什么呢? BroadcastFilter : 它是IntentFilter的子类,即一个BroadcastReceiver的IntentFilter,保存一些BroadcastReceiver特有的一些信息,比如权限等。 ReceiverList : 我们知道一个BroadcastReceiver可以有多个BroadcastFilter(IntentFilter)。它是用来保存一个BroadcastReceiver的BroadcastFilter列表的。 mRegisteredReceivers是一个保存ReceiverList的map。它的key是一个Binder,即LoadedApk.ReceiverDispatcher中的InnerReceiver(Stub Binder)。value就是ReceiverList。Binder作为key是为了方便和BroadcastReceiver的客户端通信。 mReceiverResolver 看一下它的类型 : IntentResolver mReceiverResolver IntentResolver这个类还是比较熟悉的,它可以解析一个intent。 我们知道可以使用IntentFilter来匹配一个Intent。BroadcastFilter就是来匹配BroadcastReceiver的Intent。mReceiverResolver里面维护了一个BroadcastFilter列表。所以mReceiverResolver就是可以用来解析一个广播的Intent。找出其匹配的BroadcastReceiver。 即注册过程可以使用下图表示: 即广播的注册过程就是把注册的BroadcastFilter(IntentFilter)放到系统的BroadcastFilter维护列表(mRegisteredReceivers和mReceiverResolver)中。目的是为了在接收广播时好找到对应的广播接收者 BroadcastReceiver的接收 在我们注册了BroadcastReceiver之后,系统在收到广播时,是如何正确的分发的呢?还是先找一个入口点,我们从发送一个无序广播ContextImpl.sendBroadcast()开始看: public void sendBroadcast(Intent intent) { ... ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } 即直接转发到了ActivityManagerService.broadcastIntentLocked(), 这个方法很长,我们去除对于系统特殊广播和粘性广播接收逻辑的处理来看: int broadcastIntentLocked(...Intent intent, String resolvedType, IIntentReceiver resultTo, ...,boolean ordered,...){ ... 对于特定系统广播的分发处理 以及 粘性广播的处理 List receivers = null; // manifest注册的广播 List registeredReceivers = null; // 动态注册 //动态注册的广播接收者也可以接收这个广播 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); //收集在Manifest中注册的可以接收这个intent的广播接收者 } //没有显示指明广播接收者 if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { ...对于全部用户符合条件的广播接收者的收集 }else{ //收集当前的符合条件的广播接收者。 mReceiverResolver保存着动态注册的广播信息 registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false /*defaultOnly*/, userId); } } //处理代码动态注册的广播 int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { ... //这个queue的作用是把广播分发给广播接收者 final BroadcastQueue queue = broadcastQueueForIntent(intent); //利用 registeredReceivers 构建一个 BroadcastRecord BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, callerInstantApp, resolvedType, requiredPermissions, appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); ... queue.enqueueParallelBroadcastLocked(r); //并发分发广播到广播接收者 queue.scheduleBroadcastsLocked(); } ... 根据广播接收者的 priority 调整 receivers中广播接收者的顺序 //处理manifest静态注册的广播 if ((receivers != null && receivers.size() > 0) || resultTo != null) { 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); .... queue.enqueueOrderedBroadcastLocked(r); //串行分发广播到广播接收者 queue.scheduleBroadcastsLocked(); } } 大体逻辑我就不解释了,上面代码还是加了挺详细的注释的。可以看到最终对于广播的分发过程是: 根据一个广播的Intent获取对应的BroadcastQueue 根据一个广播接收者列表创建一个BroadcastRecord 把BroadcastRecord添加到BroadcastQueue中 BroadcastQueue开始分发广播给广播接收者queue.scheduleBroadcastsLocked() BroadcastQueue 源码中一共存在两个BroadcastQueue, 一个是前台广播队列(mFgBroadcastQueue),一个是后台广播队列(mBgBroadcastQueue)。这两广播队列最直接的区别是mFgBroadcastQueue在分发广播时超时时间为10s,mBgBroadcastQueue在分发广播时超时时间是60s。 所以我们继续看BroadcastQueue是如何把广播分发给广播接收者的queue.scheduleBroadcastsLocked(), 这个方法最终调用的是BroadcastQueue.processNextBroadcastLocked(),这个方法代码也很长,分成两个部分来看: 无序广播的分发 final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) { BroadcastRecord r; while (mParallelBroadcasts.size() > 0) { //处理广播接收者并行集合 r = mParallelBroadcasts.remove(0); // 获得一个`BroadcastRecord` .... final int N = r.receivers.size(); for (int i=0; i