
BroadcastReceiver
BroadcastReceiver(广播接收器)是 Android 四大组件中负责 "事件通知" 的核心组件,其核心价值在于实现跨进程、跨组件的解耦通信(如系统启动完成通知、网络状态变化、应用安装卸载等)。
理解其注册机制与跨进程分发原理,是掌握 Android 组件通信与系统服务交互的关键。
本文将从注册方式拆解、跨进程架构、分发流程三个层面,结合源码关键逻辑,全面解析其底层机制。
核心概念与角色定位
在分析原理前,需明确参与广播通信的三大核心角色,以及广播的分类特征:
1. 核心角色
| 角色 | 职责 | 核心组件 / 服务 |
|---|---|---|
| 广播发送者 | 发起广播(如应用、系统服务) | Context.sendBroadcast()、Intent |
| 广播接收者 | 接收并处理广播(自定义 BroadcastReceiver 子类) | BroadcastReceiver.onReceive() |
| 系统调度中心 | 管理接收者注册、匹配广播、跨进程分发 | AMS(ActivityManagerService) 、PMS(PackageManagerService) |
2. 广播分类(按分发特性)
| 类型 | 特点 | 典型场景 |
|---|---|---|
| 普通广播(Normal) | 异步分发、无优先级、无法中断 | 应用内通知、非关键系统事件 |
| 有序广播(Ordered) | 同步分发、按优先级排序、可中断 | 系统权限验证(如开机启动权限) |
| 粘性广播(Sticky) | 广播发送后留存,新注册接收者可接收 | 系统状态持久通知(如电池电量) |
| 本地广播(Local) | 仅本应用内分发、无跨进程能力 | 应用内组件通信(如 Activity→Service) |
BroadcastReceiver 注册机制
BroadcastReceiver 的注册分为静态注册 (Manifest 声明)和动态注册(代码调用),二者的核心区别在于 "注册时机" 与 "依赖的系统服务" 不同,最终均需将接收者信息注册到 AMS 中统一管理。
1. 静态注册:PMS 解析 + AMS 存储
静态注册是在AndroidManifest.xml中声明接收者,由系统在应用安装时解析,适用于 "需接收广播但应用未启动" 的场景(如接收开机广播)。
注册流程(核心四步)
关键细节
-
Manifest 声明格式 :需指定
action(广播匹配标识)、permission(接收权限,可选)、enabled(是否启用)等属性: -
PMS 的作用 :应用安装时,PMS 通过
PackageParser.parsePackage()解析AndroidManifest.xml,将<receiver>标签对应的组件信息(类名、action、权限)存储到PackageInfo中,再写入系统数据库(/data/system/packages.xml)。 -
AMS 的同步 :当应用首次启动(或系统重启)时,AMS 通过
PMS.getPackageInfo()获取该应用的静态接收者信息,创建ReceiverInfo对象(包含接收者类名、匹配规则、权限),并存储到 AMS 内部的 "接收者注册表"(mReceiverResolver,一个 IntentFilter 匹配器)。
2. 动态注册:Context→AMS 直接注册
动态注册是在代码中通过Context.registerReceiver()主动注册,适用于 "仅在应用运行时需要接收广播" 的场景(如监听网络变化),需在组件销毁时调用unregisterReceiver()注销,避免内存泄漏。
注册流程(核心五步,基于 Android 13 源码)
应用(如Activity) ContextImpl AMS registerReceiver(receiver, filter) Binder调用 registerReceiver()(传递Receiver、Filter、权限) 验证权限(如接收者是否有权限、是否为系统广播) 创建IReceiverProxy(Binder代理,用于跨进程回调) 将ReceiverInfo+IReceiverProxy存入mReceiverResolver 应用(如Activity) ContextImpl AMS
关键细节
- 核心代码示例:
java
// 动态注册网络变化广播
MyDynamicReceiver receiver = new MyDynamicReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY\_ACTION); // 网络变化action
// 注册(ContextImpl的registerReceiver方法)
registerReceiver(receiver, filter);
// 组件销毁时注销(必须!)
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
-
Binder 代理的作用 :动态注册时,AMS 不会直接持有接收者对象(跨进程无法持有),而是创建
IReceiverProxy(Binder 代理对象),存储在 AMS 的接收者注册表中。当有匹配广播时,AMS 通过IReceiverProxy的performReceive()方法,跨进程回调接收者的onReceive()。 -
生命周期绑定 :动态注册的接收者与注册时的
Context生命周期绑定(如 Activity 注册则随 Activity 销毁而失效),若未注销,Context会被 AMS 的IReceiverProxy引用,导致内存泄漏。
3. 两种注册方式的核心差异
| 维度 | 静态注册 | 动态注册 |
|---|---|---|
| 注册时机 | 应用安装时(PMS 解析) | 应用运行时(代码调用) |
| 依赖服务 | PMS(解析存储)+ AMS(同步管理) | 直接依赖 AMS |
| 进程启动逻辑 | 接收广播时 AMS 自动启动进程 | 需进程已运行(否则无法注册) |
| 灵活性 | 固定配置(Manifest 不可动态修改) | 可动态添加 / 移除 action、权限 |
| Android 8.0 + 限制 | 无法接收隐式广播(需指定包名) | 无隐式广播限制 |
跨进程分发原理
Android 中广播的跨进程分发,本质是以 AMS 为核心,通过 Binder 通信实现 "发送者→AMS→接收者" 的双向跨进程调用。以下以 "普通广播" 为例,拆解完整分发流程(有序广播、粘性广播仅在过滤和分发阶段有差异)。
1. 整体架构:三大角色的跨进程交互
┌───────────────┐ Binder ┌───────────────┐ Binder ┌───────────────┐
│ 广播发送者进程 │>│ AMS ││ 接收者进程 │
│(如应用、系统)│ │(调度中心) │ │(静态/动态) │
└───────────────┘ └───────────────┘ └───────────────┘
-
发送者→AMS :发送者调用
sendBroadcast(),通过 Binder 将Intent(包含 action、数据、类型)发送到 AMS 的broadcastIntent()方法。 -
AMS→接收者 :AMS 匹配到接收者后,通过 Binder 通知接收者进程(静态注册需先启动进程,动态注册直接回调),触发
onReceive()。
2. 详细分发流程(普通广播,分 6 步)
步骤 1:发送者发起广播
应用或系统服务调用Context.sendBroadcast(Intent intent),最终通过ContextImpl的sendBroadcast()方法,将Intent封装为BroadcastIntentData,通过 Binder 跨进程发送到 AMS。
关键代码(ContextImpl):
java
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
// 调用AMS的broadcastIntent方法(Binder跨进程)
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, null, null,
0, null, null, null, false, false, 0);
}
步骤 2:AMS 接收广播并验证
AMS 的broadcastIntent()方法首先进行合法性验证,过滤无效广播:
-
权限验证 :若发送者指定了
sendPermission,验证发送者是否有该权限; -
广播类型验证 :如粘性广播需
android.permission.BROADCAST_STICKY权限,Android 12 后已废弃大部分粘性广播; -
隐式广播限制 :Android 8.0 + 对静态注册接收者,仅允许接收 "显式广播"(指定
ComponentName)或系统白名单广播(如BOOT_COMPLETED)。
步骤 3:AMS 匹配接收者(核心:IntentFilter 匹配)
AMS 通过内部的mReceiverResolver(IntentResolver类型,基于 action、category、data 类型构建的匹配树),从 "接收者注册表" 中筛选出符合条件的接收者:
-
action 匹配 :接收者的
IntentFilter必须包含广播Intent的action; -
category 匹配 :若广播
Intent包含category,接收者的IntentFilter必须包含所有category; -
data 匹配 :若广播
Intent指定了data(如content://),接收者需配置对应的dataScheme/dataType; -
权限匹配 :若接收者注册时指定了
permission,发送者必须拥有该权限才能向其分发。
匹配结果:AMS 会将符合条件的接收者按类型分类(普通 / 有序 / 粘性),存储到BroadcastQueue(AMS 的广播队列,分前台 / 后台队列,前台优先级高)。
步骤 4:AMS 处理接收者进程状态(静态注册专属)
-
动态注册接收者:若接收者进程已运行(动态注册时进程必然存活),直接进入下一步分发;
-
静态注册接收者 :若接收者进程未启动,AMS 会通过
startProcessLocked()方法启动该进程(基于接收者的PackageName和ClassName),进程启动后会自动将静态接收者信息同步到 AMS,再进入分发。
步骤 5:AMS 通过 Binder 分发广播到接收者
AMS 的BroadcastQueue会遍历匹配到的接收者列表,通过IReceiverProxy(动态注册)或ReceiverDispatcher(静态注册)发起 Binder 跨进程调用:
-
动态注册 :AMS 调用
IReceiverProxy.performReceive(),直接回调接收者进程中BroadcastReceiver的onReceive()方法; -
静态注册 :AMS 通过
ActivityThread的scheduleReceiver()方法,将广播发送到接收者进程的主线程消息队列,主线程Looper处理消息时调用onReceive()。
关键注意点:onReceive()运行在主线程(系统进程的接收者可能在其他线程),执行时间不能超过 10 秒,否则会触发 ANR(Application Not Responding)。
步骤 6:接收者处理广播
接收者在onReceive(Context context, Intent intent)中处理广播逻辑,如更新 UI、启动 Service 等。处理完成后:
-
动态注册接收者:保持注册状态,等待下一次广播;
-
静态注册接收者:若进程仅为接收广播启动,且无其他组件运行,AMS 会在短时间内回收该进程(节省内存)。
3. 有序广播的特殊分发逻辑
与普通广播相比,有序广播的核心差异在 "同步分发" 和 "优先级控制":
-
优先级排序 :AMS 按接收者注册时的
priority(-1000~1000,默认 0)从高到低排序,优先级相同则静态注册在前; -
同步分发 :AMS 先向优先级最高的接收者分发广播,待其
onReceive()执行完成后,再向下一个接收者分发; -
中断机制 :接收者可调用
abortBroadcast()中断广播,后续优先级低的接收者将无法收到。
关键特性与实践中的核心问题
1. 权限控制:双向权限校验
为防止广播被恶意发送或接收,Android 提供双向权限控制:
-
发送者权限 :发送广播时指定
sendPermission(如Context.sendBroadcast(intent, "com.example.PERMISSION_SEND")),接收者必须在 Manifest 中声明该权限才能接收; -
接收者权限 :接收者注册时指定
permission(如:permission="com.example.PERMISSION_RECEIVE">),发送者必须声明该权限才能向其发送广播。
2. Android 版本兼容性问题(高频坑点)
| Android 版本 | 关键限制 | 解决方案 |
|---|---|---|
| 8.0(API 26) | 静态注册接收者无法接收隐式广播 | 1. 发送显式广播(指定 ComponentName);2. 改用动态注册;3. 若为系统广播,加入白名单 |
| 12(API 31) | 禁止发送 / 接收大部分粘性广播 | 改用WorkManager或本地广播替代 |
| 13(API 33) | 接收POST_NOTIFICATIONS等广播需申请运行时权限 |
在代码中请求Manifest.permission.POST_NOTIFICATIONS权限 |
3. 常见问题定位思路
- 静态注册接收者收不到广播:
-
检查是否为 Android 8.0 + 隐式广播限制,尝试发送显式广播;
-
检查
enabled和exported属性是否为true; -
检查广播是否在系统白名单(如
BOOT_COMPLETED需申请RECEIVE_BOOT_COMPLETED权限)。
- 动态注册接收者内存泄漏:
-
确保在
onDestroy()中调用unregisterReceiver(); -
若在 Service 中注册,需在
onDestroy()或onStop()中注销。
- 广播分发延迟:
-
检查接收者是否在后台队列(可改用
sendBroadcastAsUser()指定前台队列); -
避免在
onReceive()中执行耗时操作(需启动 Service 处理)。
总结
BroadcastReceiver 的注册与跨进程分发,本质是以 AMS 为中央调度中心,通过 Binder 实现跨进程通信,结合 PMS 完成组件信息管理的机制:
-
注册 :静态注册靠 PMS 解析 Manifest,动态注册靠 Context 直连 AMS,最终均将接收者信息存入 AMS 的
mReceiverResolver; -
分发 :发送者通过 Binder 将广播提交给 AMS,AMS 按规则匹配接收者,再通过 Binder 跨进程通知接收者进程,触发
onReceive(); -
关键保障:权限校验防止恶意通信,队列调度保障分发优先级,生命周期绑定避免内存泄漏。
