广播 Broadcast 属于 Android 四大组件之一,通过观察者模式,用于实现进程间的异步通信。
广播的实现机制是观察者模式;消息发布/订阅模式的事件驱动模型,消息的生产者发布事件,而使用者订阅感兴趣的事件。Broadcast 机制和 Binder 机制不一样的地方在于:广播的发送者和接收者事先是不需要知道对方的存在的,这也是观察者模式的特点,显而易见的优点是系统的各个组件可以松耦合地组织在一起,所有的广播发送和接收都是通过系统 AMS 来调度的,它充当了广播总线的功能。
基础
广播实现进程间异步交互:进程间通信时通过 Binder 来实现的,异步通信是通过 Handler 实现。
广播接收器的分类
- 静态注册广播接收器:
Manifest-declared receivers
在AndroidManifest.xml文件中通过<receiver>声明的广播接收器。 - 动态注册广播接收器:
Context-registered receivers
通过registerReceiver注册的广播接收器。
广播的分类
- 普通广播
通过sendBroadcast发出的广播。 - 有序广播
通过sendOrderedBroadcast发出的广播;有序广播对应的广播接收器存在优先级关系,优先级越高越先收到广播。有序广播还可以有回调广播接收器,即广播匹配的所有广播接收器处理完毕后,系统会再向广播发送者,发回这个回调。 - 粘性广播
通过sendStickyBroadcast发出的广播。粘性广播发送后,系统会把代表这个广播的Intent保存下来,如果后面在动态注册相同Action的广播接收器时,系统就将最后发出的粘性广播重新发送给这个广播接收器。也就是说,尽管广播早就发送处理完毕了,但是后续如果有新注册的广播接收器能匹配这个广播,还是会响应广播事件的。但是粘性广播从Android 5.0开始就将相关系统接口全部标注为@Deprecated。它们不提供安全性(任何人都可以访问它们),没有保护(任何人都可以修改它们)以及许多其他问题。所以Android平台已经弃用,本文也不做介绍。
广播的标记
根据发送广播 Intent 设置的标记来区分:
FLAG_RECEIVER_FOREGROUND
表示广播为前台广播,允许接收者以前台的优先级运行,有更短的时间间隔。默认情况下广播都是后台广播FLAG_RECEIVER_REPLACE_PENDING
表示新的广播会替换掉那些已存在的相同广播。相同的定义是通过Intent.filterEquals方法对两个广播的Intent比较,当匹配到相同的,新的广播和对应的接收器会将待发送的广播列表中已存在的替换掉,在列表中保留同样的位置。这个标志通常被粘性广播使用,只保证将最新的广播的值传递给接收器。
广播的 ANR
前台广播的 ANR 时间是 10 秒,后台广播是 60 秒。因为默认为后台广播,所以通常情况下,需要在 60 秒内处理完所有的广播事件。广播的 ANR 只会出现在有序处理的广播队列中(包含有序广播和静态注册的广播接收器匹配的普通广播)中。
1 | // ActivityManagerService.java |
相关类文件
速查表
1 | framework/base |
类简介
BroadCastReceiver
广播接收器,用于处理接收的每个广播事件。IIntentReceiver
是AIDL文件,每个BroadCastReceiver都会转换为一个IIntentReceiver,用来跨进程传递数据。LoadedApk.ReceiverDispatcher
广播接收发布器,BroadCastReceiver都是在这转换为IIntentReceiver的。每个动态注册的广播接收器BroadcastReceiver都对应一个LoadedApk.ReceiverDispatcher,最终都是在这进行响应调用onReceive的。BroadcastFilter
是IntentFilter的子类,广播过滤器,用于匹配广播Intent;包含广播接收者相关信息,权限等。只有动态注册广播广播接收器会用到。ReceiverList
是ArrayList的子类,是一个集合用来存储BroadcastFilter。记录广播接收器相关信息等,只有动态注册的广播接收器会用到,每个BroadCastReceiver对应一个ReceiverList,而每个ReceiverList可以包含多个BroadcastFilter,表示能够监听多个广播。BroadcastRecord
继承了Binder,用来跨进程传递数据。发送的每个广播Intent,最后都会对应一个BroadcastRecord;它记录了广播的发送时间,发送者,接受者,广播携带的数据,回调,所在BroadcastQueue等等。BroadcastQueue
广播队列,有两个ArrayList<BroadcastRecord>用于存储BroadcastRecord分别是:mParallelBroadcasts存储并行处理的广播;mOrderedBroadcasts存储有序处理的广播。ContextImpl
广播发送,广播接收器动态注册的入口。ActivityThread
应用主线程,广播发送过程都是由它进入系统进程AMS,广播接收器响应事件是有系统AMS进入它。ActivityManagerServiceAMS系统四大组件大管家,类似广播总线:管理广播接收器的注册,管理广播的发送到匹配的广播接收器中处理。PackageParser
包解析类,会从AndroidManifest.xml中解析出静态注册的广播接收器。PackageManagerServicePMS系统包管家,负责静态注册广播接收器的存储,查询。
BroadcastFilter 类详解
BroadcastFilter 继承了 IntentFilter 类,广播信息过滤器,即动态注册广播接收器时,注册的是哪个广播过滤器。
源码分析
1 | final class BroadcastFilter extends IntentFilter { |
成员变量
receiverList:当前对象属于哪个接收列表packageName:动态注册广播发起者的包名requiredPermission:设置发送广播时需要的权限owningUid:动态注册广播发起者UidowningUserId:动态注册广播发起者UserId
这里简单介绍下 uid, userId 的区别:
uid
是Linux下的概念,表示Linux系统下的用户ID。userId
是Android的多用户概念,从 4.2 开始系统支持多用户登录,记录登录用户的ID;不支持多用户登录的系统上,这个值是唯一的。多用户支持是在frameworks/base/core/res/res/values/config.xml文件中,config_multiuserMaximumUsers值来决定的。
ReceiverList 类详解
ReceiverList 继承了 ArrayList ,本质上是一个数据集合,数据类型为 BroadcastFilter。动态注册广播接收器时,每个广播接收器 BroadCastReceiver 对应一个 ReceiverList ,记录了一系列 BroadcastFilter 的列表,表示这个广播接收器注册了一个或多个广播过滤器。
源码分析
1 | final class ReceiverList extends ArrayList<BroadcastFilter> |
成员变量
ActivityManagerService owner:AMS对象IIntentReceiver receiver:当前ReceiverList对应的IIntentReceiverProcessRecord app:动态注册广播发起者进程相关信息pid:动态注册广播发起者进程Iduid:动态注册广播发起者uiduserId:动态注册广播发起者userIdBroadcastRecord curBroadcast:动态注册的广播,其详细信息linkedToDeath:Binder通信机制是否断开stringName:ReceiverList转换成的字符串
BroadCastReceiver 类详解
BroadCastReceiver 广播接收器,用来处理监听的广播事件。BroadcastReceiver 是抽象类,抽象方法为 onReceive ,注册广播接收器前,需要在其子类中实现。
PendingResult 类
PendingResult 是广播接收器待处理的结果类,是异步结果类;简要介绍下这个类存在的意义:
通常情况下,UI 主线程阻塞超过 5 秒就会产生 ANR,更不用说卡顿现象 UI Jank;所以广播接收器中如果有耗时工作(比如磁盘读写,网络下载等),需要及时切换到后台工作线程中执行;而 PendingResult 就存储了广播处理器接收到广播所有相关信息,将 PendingResult 对象传递到后台工作线程完成广播处理,处理完后需要调用 PendingResult.finish() 通过系统该广播接收器已经处理完毕。 PendingResult 类有两个注意事项:
PendingResult类中的状态不是线程安全的,使用时将整个对象交给后台工作线程,避免并发竞争,该线程将负责设置结果并最终调用finish()- 系统中关于广播接收器的
ANR:前台广播接收器允许运行时间大概是 10 秒,后台广播是 60 秒,如果广播处理器没有处理完毕就会产生ANR。注意这个过程的计算时间是:从广播分发到广播处理器,直到广播处理器通知系统处理完毕的总时间。即使通过PendingResult切换到后台工作线程,直到调用PendingResult.finish(),这整个过程都受到了这个ANR时间的限制。所以长时间的工作是不能放到BroadCastReceiver中来实现的,PendingResult仅仅是多争取到了几秒钟
PendingResult 类的两个子类
PendingResult 类的构造方法是 @hide 隐藏的,通常在 BroadcastReceiver.onReceive() 中调用 goAsync() 返回得到;而实际构造是在其子类中,静态注册广播和动态注册广播对应不同的子类:
ActivityThread.ReceiverData对应静态注册广播1
2
3
4
5
6
7
8
9
10
11
12
13
14
15static final class ReceiverData extends
BroadcastReceiver.PendingResult {
public ReceiverData(Intent intent,int resultCode,String resultData,
Bundle resultExtras, boolean ordered, boolean sticky,
IBinder token, int sendingUser) {
super(resultCode, resultData, resultExtras, TYPE_COMPONENT,
ordered, sticky,token, sendingUser, intent.getFlags());
this.intent = intent;
}
Intent intent;
ActivityInfo info;
CompatibilityInfo compatInfo;
public String toString() {...}
}LoadedApk.ReceiverDispatcher.Args对应动态注册广播1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19final class Args extends BroadcastReceiver.PendingResult
implements Runnable {
private Intent mCurIntent;
private final boolean mOrdered;
private boolean mDispatched;
public Args(Intent intent, int resultCode, String resultData,
Bundle resultExtras, boolean ordered,
boolean sticky, int sendingUser) {
super(resultCode, resultData, resultExtras,
mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED,
ordered, sticky, mIIntentReceiver.asBinder(),
sendingUser, intent.getFlags());
mCurIntent = intent;
mOrdered = ordered;
}
public void run() {...}
}
PendingResult 类源码分析
PendingResult 对应的广播类型有三种:
TYPE_COMPONENT:静态注册广播TYPE_REGISTERED:动态注册广播TYPE_UNREGISTERED:取消广播注册
1 | public static class PendingResult { |
BroadcastReceiver 源码分析
1 | public abstract class BroadcastReceiver { |
BroadcastReceiver 重要方法
BroadcastReceiver 大部分数据存储都是通过 PendingResult 实例来保存的。
onReceive
抽象方法,子类必须实现;广播接收器处理的入口。goAsync
异步广播,返回PendingResult实例,进入后台线程处理;处理完毕后必须调用PendingResult.finish()结束。abortBroadcast
如果广播接收器收到的是有序广播,则终止有序广播继续向下传递。
IIntentReceiver 详解
IIntentReceiver 是一个 AIDL 文件,所以 IIntentReceiver 接口继承了 Binder 机制中的 IInterface ,表示服务端拥有的能力或者说能提供的功能。 IIntentReceiver 声明的方法,是在 LoadedApk.ReceiverDispatcher.InnerReceiver 中实现的。IIntentReceiver.aidl 源码如下:
1 | // frameworks/base/core/java/android/content/IIntentReceiver.aidl |
BroadCastReceiver 是系统组件,并不支持跨进程传输,Android Broadcast 机制使用 IIntentReceiver 来进行代替 BroadCastReceiver 来进行跨进程传输。
可以看出 IIntentReceiver 只提供了一个方法 performReceive ,该方法仅仅在动态注册的广播接收器中会触发调用(静态注册广播接收器在 ActivityThread 中通过反射直接调用 onReceive 回调);系统进程 AMS 在分发广播处理事件时,会向注册了广播接收的应用进程调用该方法,最终调用 BroadcastReceiver.onReceive 触发回调。注意:方法使用了 oneway 关键字,表示非阻塞调用;即 AMS 进程分发广播事件时,不需要等待每个应用接收者执行完 onReceive 。
LoadedApk 类
LoadedApk 类存储了当前加载的 Apk 相关信息,包括主线程,文件所在路径,类加载器,注册的广播列表,启动的服务列表等等;LoadedApk 类是在每个应用加载初始化进程、主线程时实例化的,每个应用对应一个 LoadedApk 实例。
本文只分析和广播 Broadcast 相关内容,LoadedApk 中存储了当前 Apk 中所有的普通广播接收器 BroadCastReceiver ,即通过 registerReceiver 注册到系统中的广播接收器。
而有序广播中的回调广播接收器,即广播发送出去后,等待所有广播接收器处理完毕,最后产生一个回调给广播发送者,作用类似 startActivityForResult 。回调 BroadCastReceiver 不需要通过 registerReceiver 注册到系统中,是以参数的形式在 sendOrderedBroadcast() 发送广播时传递出去,这类广播不会存储到 LoadedApk 中。
在 ContextImpl 代码中可以看到:LoadedApk 对这两类广播接收器的处理过程:
1 | // ContextImpl.java |
部分源码分析
1 | public final class LoadedApk { |
成员变量
mReceivers:当前Apk注册的广播列表mUnregisteredReceivers:当前Apk取消广播注册的列表
这两个成员变量都是 Map 结构,Key 值都是 Context,Value 仍然是一个 Map 结构:
Key: Context
每个Activity或者每个Service注册的广播分开记录,方便快速查找某个Context实例注册的所有广播。Value: ArrayMap<BroadcastReceiver, ReceiverDispatcher>
BroadcastReceiver 和 ReceiverDispatcher 是一一对应的,每个广播接收器都会对应一个广播接收分发器。ContextImpl.sendOrderedBroadcast, ContextImpl.registerReceiver 会对每个广播接收器 BroadCastReceiver ,通过 LoadedApk 找到或者生成对应的 ReceiverDispatcher ;在发送有序广播或者注册广播接收器,等到广播接收者开始执行时,AMS 通过 ReceiverDispatcher.InnerReceiver 来触发回调,即调用 BroadCastReceiver.onReceive 。
ReceiverDispatcher 静态内部类
ReceiverDispatcher 是 LoadedApk 的静态内部类,同时它自己还包含两个内部类:
- 静态内部类
InnerReceiver
实现了IIntentReceiver.performReceive方法,实际最终调用的是外部类ReceiverDispatcher.performReceive方法。 - 成员内部类
Args
继承了BroadCastReceiver.PendingResult类,可以执行部分异步操作;同时实现了Runnable,通过传入的Handler发布这个任务,并调用BroadCastReceiver.onReceive,处理广播接收器回调事件。处理完后,通知系统该广播接收器处理完毕。 - 成员变量
mRegistered:记录该广播接收器是否通过registerReceiver注册的,即是否为动态注册的广播接收器。
ReceiverDispatcher 的几个重要方法:
getIIntentReceiver:返回广播接收器BroadCastReceiver对应的IIntentReceiver对象performReceive:使用当前线程Handler发送Args对象并执行;所有动态注册的广播接收器,都是在这里回调onReceive方法
广播相关方法
getReceiverDispatcher
根据广播接收器获取广播接收分发器的IIntentReceiver,用于跨进程传递。主要是从mReceivers中获取;如果不存在则新建。forgetReceiverDispatcher
从mReceivers中移除指定回调广播接收器,并放入mUnregisteredReceivers中,返回值也是该广播接收器对应的IIntentReceiver。
BroadcastRecord 类详解
BroadcastRecord 继承了 Binder ,表明该对象作为数据容器,能被跨进程通信。BroadcastRecord 保存了广播发送者相关信息,包含发送者的:包名,进程信息,广播是否有序,请求的权限等等。
源码分析
1 | /** |
重要成员变量
Intent intent:广播发送时的IntentComponentName targetComp:广播发送者组件名称ProcessRecord callerApp:广播发送者进程记录String callerPackage:广播发送者包名callingPid:广播发送者PidcallingUid:广播发送者UiduserId:广播发送者userIdordered:广播是否有序发送sticky:广播是否为粘性广播initialSticky:广播是否一开始就设置为粘性广播resolvedType:Intent的类型String[] requiredPermissions:广播发送者拥有的广播权限appOp:广播对应的应用管理权限BroadcastOptions options:广播发送者设定的选项List receivers:广播接收者列表,特别需要注意的是:它包含了两种类型数据ResolveInfo, BroadcastFilter,分别对应静态注册广播接收器和动态注册广播接收器,取出时需要做类型判断int[] delivery:每个广播接收者的投递状态,状态分为四种IIntentReceiver resultTo:有序广播中回调的广播接收器,它也是有序广播的最后一个接收者enqueueClockTime:广播进入队列的时间dispatchTime:开始分派广播的开机时间dispatchClockTime:开始分派广播的系统绝对时间receiverTime:广播接收者接收到的时间finishTime:广播接收者处理完广播的完成时间resultCode:广播处理完毕的结果码resultData:广播处理完毕的简单数据resultExtras:广播处理完毕的复杂数据resultAbort:广播是否被终止int nextReceiver:下一个广播接收者索引IBinder receiver:广播当前接收者int state:广播的当前状态,状态分为五种anrCount:当前广播出现的ANR次数manifestCount:分发给静态注册广播接收者的次数manifestSkipCount:分发给静态注册广播接收者跳过的次数BroadcastQueue queue:处理当前广播所在队列BroadcastFilter curFilter:处理广播时当前广播过滤器ProcessRecord curApp:广播当前接收者的进程信息ComponentName curComponent:广播当前接收者的组件信息ActivityInfo curReceiver:广播当前接收者的信息
cleanupDisabledPackageReceiversLocked 方法
BroadcastRecord 中只有一个包内可见的方法 cleanupDisabledPackageReceiversLocked ,该方法功能是从 List receivers 清理掉已经取消注册的广播注册接收者。
BroadcastQueue 类详解
BroadcastQueue 用来保存系统和应用发出的广播信息;通常使用两个广播队列 BroadcastQueue :一个用来保存前台广播,一个用来保存后台广播;而每个广播队列 BroadcastQueue 包含两个列表:一个用来并行处理;一个用来有序处理。
重要成员变量
ArrayList<BroadcastRecord> mParallelBroadcasts
存储并行处理的广播:首先它是普通广播,其次这些广播匹配的广播接收器必须是动态注册的。ArrayList<BroadcastRecord> mOrderedBroadcasts
存储有序处理的广播:包含有序广播和普通广播(匹配的广播接收器时静态注册的)。mTimeoutPeriod
广播接收器ANR超时时间阀值。前台广播是 10 秒,后台广播是 60 秒。
BroadcastHandler 类
BroadcastHandler 是成员内部类,用来处理下一条广播,或者处理广播超时 ANR 。
1 | static final int BROADCAST_INTENT_MSG = |
AppNotResponding 类
AppNotResponding 成员内部类,广播接收器处理广播事件时发生 ANR 。
1 | private final class AppNotResponding implements Runnable { |
静态注册广播接收器流程分析
静态注册的广播接收器,又称为 Manifest 文件声明广播接收器,是在 PMS 扫描 AndroidManifest.xml 信息时解析的;所有静态注册的广播接收器,统一由 PMS 保存,广播在发送过程中,查找匹配的静态注册广播接收器也是在 PMS 中查询。
流程图

PackageParser.parseBaseApplication 详解
PackageParser 主要用于详细解析包内相关信息,而 parseBaseApplication 主要解析 AndroidManifest.xml ,将每个 TAG 都解析并保存,其中静态注册的广播接收器存储到 receivers 中,而 PMS 会根据每个包解析的数据,保存整个系统全部的静态注册广播接收器(当然也保存其他 Activity, Services, ContentProvider 等信息)。
1 | // PackageParser.java |
PMS 静态注册广播接收器
PMS 在调用完 PackageParser.parsePackage 解析完指定包名信息后,将存储在 PackageParser.Package.receivers 的静态广播接收器信息,再保存到 PMS.mReceivers 中,方便后续全局查询。
1 | // PackageManageServices.java |
PMS 查询静态注册广播接收器
AMS 在发送广播时,会从 PMS 中查询匹配的静态广播接收器;PMS.queryIntentReceiversInternal 根据广播 Intent ,从 mReceivers 中查询匹配的 ResolveInfo,而 ResolveInfo.activityInfo 存储了对应的广播接收器。
1 | // PackageManageServices.java |
protected-broadcast 受保护的广播
在 AndroidManifest.xml 中声明的 protected-broadcast 受保护广播 ACTION ,表示它们只能被有系统权限的广播接收器接收。在 PackageParser.Package.protectedBroadcasts 中保存,同时 PMS.mProtectedBroadcasts 会做系统全局保存, AMS 发送广播时会查询 PMS 做权限检查,如果没有权限则不会分发给该广播接收器。
动态注册/取消广播接收器流程分析
流程图

动态注册 ContextImpl/LoadedApk
动态注册时统一由 ContextImpl.registerReceiverInternal 向系统注册广播接收器。这个过程主要功能:
- 将
BroadCastReceiver转换为对应的IIntentReceiver,用于跨进程通信 LoadedApk.getReceiverDispatcher会将当前Apk注册的每个广播接收器保存到mReceivers中;如果是有序广播的回调广播接收器则不保存- 向
AMS中注册IIntentReceiver
1 | // LoadedApk.java |
动态注册 AMS
广播接收器动态注册时,广播接收器的相关信息保存在 AMS 中:
mRegisteredReceivers
保存所有动态注册的广播接收器对应的ReceiverList。mRegisteredReceivers并没有太多作用,注册保存信息,取消注册时从这里删除。mReceiverResolver
保存所有所有动态注册广播接收器时对应的广播过滤器BroadcastFilter。广播发送过程中,会根据Intent从mReceiverResolver中查找BroadcastFilter;每个BroadcastFilter都保存了它所属的ReceiverList;而ReceiverList保存了BroadCastReceiver对应的IIntentReceiver;动态注册广播接收器事件处理时,使用IIntentReceiver处理onReceive回调。
主要功能:
- 获取动态注册广播接收器,应用进程相关信息
- 处理粘性广播事件
BroadCastReceiver生成对应的ReceiverList和BroadcastFilter- 将
ReceiverList添加到mRegisteredReceivers中 - 将
BroadcastFilter添加到mReceiverResolver中
1 | // ActivityManagerService.java |
取消注册 ContextImpl/LoadedApk
取消注册时统一由 ContextImpl.unregisterReceiver 向系统取消注册广播接收器。这个过程主要功能:
- 将
BroadCastReceiver转换为对应的IIntentReceiver,用于跨进程通信 LoadedApk.forgetReceiverDispatcher会将当前需要取消注册的广播接收器,从mReceivers中移除;如果需要调试,会同时将它加入mUnregisteredReceivers中- 向
AMS中取消注册IIntentReceiver
1 |
|
取消注册 AMS
广播接收器取消注册时,从 AMS 中移除对应的数据,主要功能为:
- 从
mRegisteredReceivers中移除ReceiverList - 从
mReceiverResolver中移除ReceiverList中所有的BroadcastFilter - 如果还存在没有处理完的广播接收器,触发
BroadcastQueue.processNextBroadcast继续处理
1 | // ActivityManagerService.java |
广播发送流程分析
先回顾下基础概念,广播的类型:
- 普通广播:通过
sendBroadcast发送的广播 - 有序广播:通过
sendOrderedBroadcast发送的广播
系统对广播响应并处理的方式分为:
- 并行处理
广播存储位置:BroadcastQueue.mParallelBroadcasts;并行处理的广播为:普通广播,且它对应的广播接收器一定是动态注册的。 - 有序处理
广播存储位置:BroadcastQueue.mOrderedBroadcasts;有序处理的广播为:有序广播和普通广播(对应的广播接收器是静态注册的)。mOrderedBroadcasts中处理普通广播(对应的广播接收器时静态注册的)非常费解,初看代码时很容易搞错,存储逻辑是在AMS调度时决定的。
流程图
- 广播发送过程,从广播发送所在应用进程进入系统进程
Context -> AMS -> BroadcastQueue

- 广播发送过程,从系统进程进入广播接收器应用所在进程
BroadcastQueue -> ActivityThread -> BroadCastReceiver.onReceive

ContextImpl.sendBroadcast 发送普通广播
ContextImpl 对于普通广播并不做特别处理,比较简单,直接将 Intent 和广播发送应用相关信息传递给 AMS ,进入系统来处理分发流程。
1 |
|
ContextImpl.sendOrderedBroadcast 发送有序广播
有序广播支持广播接收器回调,所以进入系统 AMS 处理前,会先将 BroadCastReceiver 转换为 IIntentReceiver ,回调广播接收器在 LoadedApk 中不做保存。
1 | void sendOrderedBroadcast(Intent intent, String receiverPermission, |
AMS.broadcastIntentLocked 广播发送解析
不管是普通广播还是有序广播,在 AMS 中都是进入了 broadcastIntentLocked(Intent, ...) 方法来调度处理的。这个方法中会处理很多系统级广播,比如 Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_TIME_CHANGED 等等,在 AMS 做预处理或者直接处理完毕。该方法主要功能:
- 各种权限检查
- 系统广播处理
- 收集该广播匹配的所有动态注册广播接收器
- 收集该广播匹配的所有静态注册广播接收器
- 将广播对应的广播记录存入广播队列(如果是有序广播,会按照优先级先排序再存入)
代码分析(代码有简化和调整位置)如下:
1 | // ActivityManagerService.java |
BroadcastQueue.processNextBroadcast 广播发送解析
不管是并行处理还是有序处理,在 BroadcastQueue 中都是进入 processNextBroadcast(boolean fromMsg) 方法处理的。该方法主要功能:
- 并行处理的广播接收器,一次全部处理完
- 有序广播处理完毕后,处理回调广播接收器
- 各种权限检查
- 调用
deliverToRegisteredReceiverLocked处理所有动态注册的广播接收器 - 如果是静态广播接收器,开启对应的应用进程
- 调用
processCurBroadcastLocked处理所有静态注册的广播接收器
1 | // BroadcastQueue.java |
deliverToRegisteredReceiverLocked 方法解析
BroadcastQueue.deliverToRegisteredReceiverLocked 专门用来处理动态注册的广播接收器,最终是在 performReceiveLocked 方法中调用了 ActivityThread.scheduleRegisteredReceiver ,进入广播接收器所在进程处理具体的回调 onReceive。这个阶段主要功能:
- 各种权限检查
- 添加完善广播记录
- 跨进程进入广播接收器所在应用进程,调用
onReceive
1 | private void deliverToRegisteredReceiverLocked(BroadcastRecord r, |
ActivityThread.scheduleRegisteredReceiver 方法解析
每个应用的主线程中 ActivityThread.scheduleRegisteredReceiver 来执行广播处理事件,performReceive 对应的是 LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive 方法。
1 | public void scheduleRegisteredReceiver(IIntentReceiver receiver, |
processCurBroadcastLocked 方法解析
BroadcastQueue.processCurBroadcastLocked 专门处理静态注册的广播接收器。该方法主要功能:
- 将
BroadCastReceiver子类存储到intent中 - 跨进程进入静态广播接收器所在进程,通过反射调用
onReceive
1 | private final void processCurBroadcastLocked(BroadcastRecord r, |
ActivityThread.scheduleReceiver 方法解析
ActivityThread.scheduleReceiver 处理静态注册的广播接收器,从 intent 中获取具体的广播接收器子类组件名,在 handleReceiver 中使用反射技术生成对应的实例对象,并调用其 onReceive 方法。
1 | public final void scheduleReceiver(Intent intent, ActivityInfo info, |
AMS.finishReceiver 结束广播
所有的广播接收器处理完毕后,最终会调用系统 ActivityManagerService.finishReceiver 结束整个流程。结束流程前会再次检查确认,是否还有广播接收器没有处理完(静态注册的广播接收器,如果应用没有启动,会先启动应用进程),存在的话就触发 BroadcastQueue.processNextBroadcast 继续分发。
1 | // ActivityManagerService.java |
广播 ANR
processNextBroadcast 中可以看到,广播的 ANR 只会出现在有序处理的广播队列 mOrderedBroadcasts 中,也就是普通广播匹配的动态注册的广播接收器不会出现 ANR 。
setBroadcastTimeoutLocked:设置广播超时延时消息broadcastTimeoutLocked:当广播接收者等待时间过长,触发ANR机制cancelBroadcastTimeoutLocked:当广播正常执行完毕清除
超时时间计算方式:从队列中取出有效广播开始计时,直到所有的广播接收器处理完毕,才取消计时。
示例:发送一个有序广播,AndroidManifest.xml 中静态注册的广播接收器和一个动态注册的广播接收器都能匹配到,同时有序广播带有回调广播接收器,也就是说该广播一共会有三个 BroadCastReceiver.onReceive 响应处理。看对应的 Log 文件:
1 | // 1. AMS.broadcastIntent 发送广播 |
示例
静态注册广播接收器
BroadCastReceiver子类文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class BroadcastReceiverMy extends BroadcastReceiver {
private static final String TAG = "XMT:BroadcastReceiverMy";
public void onReceive(Context context, Intent intent) {
if (intent != null){
// broadcast ANR 60s
//Log.d(TAG, "BroadcastReceiverMy: sleep...");
//try{
// Thread.sleep(65*1000);
//} catch(Exception e){}
String value = intent.getStringExtra("key");
Log.d(TAG, "BroadcastReceiverMy: onReceive = " + value);
}
}
}在
AndroidManifest.xml中声明1
2
3
4
5
6
7
8
9
10
11<receiver
android:name=".ipc.BroadcastReceiverMy"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="broadcast.service.normal"></action>
</intent-filter>
<intent-filter>
<action android:name="broadcast.service.order"></action>
</intent-filter>
</receiver>
动态注册广播接收器
动态注册和取消注册广播必须在生命周期中成对出现,比如在 onCreate/onDestroy, onResume/onPause, onStart/onStop 对应出现。
1 | private boolean registeredOrder; |
广播发送
1 | // 发送有序广播,并包含回调广播接收器 |
小结
广播接收器静态注册过程
静态注册的广播接收器,是开机时 PMS 启动后解析扫描所有包时注册的,保存在每个包的 PackageParser.Package.receivers 中,系统 PMS.mReceivers 会全局保存所有静态注册的广播接收器。 AMS 中并不会保存静态注册的广播接收器信息,而是直接向 PMS 中查询。
AMS 中存储的广播相关信息
- 广播队列:前台广播队列
mFgBroadcastQueue和后台广播队列mBgBroadcastQueue - 广播接收器哈希表
mRegisteredReceivers:所有动态注册的广播接收器 - 广播过滤器符号表
mReceiverResolver:所有动态注册的广播过滤器
1 | BroadcastQueue mFgBroadcastQueue; |
权限检查
广播在发送的过程中,会有大量的权限检查,比如 AMS.broadcastIntentLocked, BroadcastQueue.processNextBroadcast, BroadcastQueue.deliverToRegisteredReceiverLocked 都会反复做权限检查。
广播接收器优先级
数字越大表示优先级越高,接收有序广播时优先级高的先接收到。
静态注册广播接收器
1
2
3
4
5<receiver android:name=".smsReceiver">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>动态注册广播接收器
1
2
3
4IntentFilter intentFilter = new IntentFilter(
"android.provider.Telephony.SMS_RECEIVED");
intentFilter.setPriority(1000);
registerReceiver(broadcastReceiver, intentFilter);
广播接收器响应
广播接收器回调 onReceive 触发响应的位置
- 静态注册的广播接收器
ActivityThread.handleReceiver中使用反射,触发onReceive方法。静态注册的广播接收器并不会对应ReceiverDispatcher。 - 动态注册的广播接收器
动态注册的广播接收器对应一个ReceiverDispatcher,通过它找到LoadedApk.Args,在Runnable.run中触发onReceive方法。
前后台广播及 ANR
广播发送时,通过 Intent 是否设置 FLAG_RECEIVER_FOREGROUND 来区分,如果设置了表示前台广播,对应 ANR 超时为 10 秒;默认为后台广播,对应超时为 60 秒。
广播的 ANR 是会出现在有序处理广播队列中,在 BroadcastQueue.processNextBroadcast 中计算的,从有序队列 mOrderedBroadcasts 取出有效广播后开始计时,直到有序广播匹配的所有广播接收器包括有序广播的回调广播接收器,全部处理完毕才会取消计时。具体可以看“广播 ANR” 这一节的 Log 分析。
注意:如果广播接收器的 onReceive 是在主线程中处理,同时还会受到 Activity 超时 5 秒产生 ANR 的限制!也就是说等不到 60 秒,可能 Activity 就出现 ANR 了。如果 onReceive 有耗时任务,请新开线程处理。
有序广播
- 可以被终止
优先级高的广播接收者接收到后,可以通过abortBroadcast来终止继续向下传递广播。 - 可以有回调
BroadCastReceiver
广播接收器回调,发送有序广播时,可以同时指定一个BroadCastReceiver回调;当有序广播全部被执行完后,会触发这个回调。也就是说有序广播,在顺序接收过程中,每个广播接收者都可以在回调BroadCastReceiver中向发送者写回数据。
广播发送过程
- 整个广播发送及响应过程都是异步的,大量使用
Handler异步处理 - 源码中可以看到大量
synchronized关键字,而且大多使用AMS作为对象锁,所以系统处理广播的过程有大量同步过程
并行处理和有序处理
mParallelBroadcasts广播队列
存储的广播为普通广播(对应的广播接收器是动态注册的),该队列的所有广播都是并行处理的,在processNextBroadcast中一次全部处理完。mOrderedBroadcasts广播队列
存储的广播为有序广播和普通广播(对应的广播接收器时静态注册的)该队列的所有广播都是有序处理的,在processNextBroadcast中从队列中取出一个有效广播,处理完一个广播接收器后,会触发AMS.finishReceiver结束整个广播过程。但是finishReceiver方法每次都会调用BroadcastQueue.finishReceiverLocked检查mOrderedBroadcasts是否全部处理完毕。如果没有,调用processNextBroadcast继续从有序队列中取出广播处理。具体可以参考“广播ANR” 中的Log分析。
进程和线程间交互
Handler线程间异步通信LocalBroadcastManager同一个应用相同进程内异步通信,本质上仍然是通过Handler实现的BroadCastReceiver进程间异步通信,不同应用不同进程间的通信,通过系统广播总线统一管理广播,用户使用很简单方便Messenger进程间异步通信,相同应用不同进程间的通信,常用于Activity, Service不在同一进程时使用AIDL进程间同步通信