广播是怎么注册的呢?
阶段 | 组件/数据结构 | 作用描述 | 存储位置/关联关系 |
App进程阶段 | BroadcastReceiver | 开发者自定义的广播接收器,实现onReceive 方法处理事件。 | App进程(Activity/Service等组件内) |
ReceiverDispatcher | 将BroadcastReceiver封装为跨进程可调用的 IIntentReceiver接口对象。 | LoadedApk中创建,关联InnerReceiver | |
InnerReceiver | 继承IIntentReceiver.Stub的Binder实体,AMS通过它回调App主线程的onReceive | 作为Binder服务端存在于App进程,代理对象传递至AMS | |
SystemServer进程阶段 | ReceiverList | 以InnerReceiver的Binder为Key,管理同一接收器的多个BroadcastFilter | 存储在AMS的mRegisteredReceivers(HashMap) |
BroadcastFilter | 关联IntentFilter与ReceiverList,描述接收器感兴趣的广播类型。 | 注册到mReceiverResolver(全局匹配引擎)和ReceiverList | |
BroadcastQueue | 管理待分发的广播,分为有序和无序队列。 | AMS中维护,异步分发广播 | |
核心数据结构 | mRegisteredReceivers | 维护所有动态注册的ReceiverList,避免重复注册。 | AMS内存(HashMap结构) |
mReceiverResolver | 基于IntentFilter的快速匹配引擎,优化广播分发效率。 | AMS内存(IntentResolver子类) | |
mStickyBroadcasts | 缓存粘性广播,按用户ID和Action分类存储。 | AMS内存(SparseArray结构),供新注册接收器匹配历史广播 |
源码流程:
app.registerReceiver()->Context.registerReceiver(BroadcastReceiver, IntentFilter)
#Context.registerReceiver(BroadcastReceiver, IntentFilter)->Context.registerReceiverInternal()
##Context.registerReceiverInternal()->LoadedApk.getReceiverDispatcher:返回一个为IIntentReceiver类型的ReceiverDispatcher(广播快递员)
###LoadedApk.getReceiverDispatcher->ReceiverDispatcher实例化
####ReceiverDispatcher实例化->InnerReceiver实例化:可以看到 InnerReceiver extends IIntentReceiver.Stub 是跨进程对象的一个实体
##Context.registerReceiverInternal()->ActivityManagerService.registerReceiverWithFeature(IIntentReceiver)
###ActivityManagerService.registerReceiverWithFeature(IIntentReceiver)->ActivityManagerService.registerReceiverWithFeatureTraced
####ActivityManagerService.registerReceiverWithFeatureTraced->RegisteredReceivers.get(receiver.asBinder())创建ReceiverList,并mRegisteredReceivers全局注册表记录
####ActivityManagerService.registerReceiverWithFeatureTraced->new BroadcastFilter:创建BroadcastFilter并注册到Resolver,并mReceiverResolver注册到全局过滤器
####ActivityManagerService.registerReceiverWithFeatureTraced->new BroadcastRecord创建广播记录并加入队列,并mBroadcastQueue.enqueueBroadcastLocked(r)异步分发
源码重点函数分析:
注册广播接收器
registerReceiver来时往里面看,因为Activity是Context的子类,这个注册的方法的实现则是在ContextImpl当中,其中最终调用的方法为registerReceiverInternal,代码如下
/**
* 动态注册广播接收器的核心方法,完成跨进程通信的Binder封装和AMS注册
* @param receiver 开发者定义的广播接收器实例
* @param userId 用户ID(多用户支持)
* @param filter 意图过滤器,描述接收器感兴趣的广播类型
* @param broadcastPermission 接收广播所需的权限(可选)
* @param scheduler 指定回调线程的Handler(null则使用主线程Handler)
* @param context 关联的Context对象
* @param flags 注册标志位
* @return 匹配的粘性广播Intent(若无则返回null)
*/
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
// 1. 创建跨进程通信对象IIntentReceiver
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
// 1.1 使用主线程Handler(若未指定)
if (scheduler == null) {
scheduler = mMainThread.getHandler(); // 获取ActivityThread的H主线程Handler[1,3](@ref)
}
// 1.2 通过LoadedApk获取ReceiverDispatcher(封装跨进程Binder对象)
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true); // true表示需要注册[1,5](@ref)
} else {
// 1.3 备用路径:直接创建ReceiverDispatcher(非标准场景)
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
// 2. 跨进程调用AMS注册广播
final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
mMainThread.getApplicationThread(), // 应用主线程的IApplicationThread对象
mBasePackageName, // 包名标识
getAttributionTag(), // 归因标签(用于权限跟踪)
AppOpsManager.toReceiverId(receiver), // 接收器唯一ID
rd, // 跨进程回调接口
filter, // 意图过滤器
broadcastPermission, // 所需权限
userId, // 用户ID
flags); // 标志位[5](@ref)
// 3. 处理返回的粘性广播(若存在)
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
// 3.1 准备Intent数据安全传输到应用进程
intent.prepareToEnterProcess(
ActivityThread.isProtectedBroadcast(intent),
getAttributionSource()); // 检查签名权限保护[3](@ref)
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer(); // 处理Binder通信异常
}
}
通过 LoadedApk.getReceiverDispatcher() 将 BroadcastReceiver 包装为 IIntentReceiver(Binder接口),内部创建 ReceiverDispatcher 和 InnerReceiver(IIntentReceiver.Stub 实现类),构成双向通信桥梁
获取广播分发器 getReceiverDispatcher
桥接BroadcastReceiver和Binder通信,含InnerReceiver和Handler
/**
* 为BroadcastReceiver创建/获取跨进程通信的IIntentReceiver对象
* @param r 开发者定义的广播接收器实例
* @param context 关联的Context对象(通常为Activity/Service)
* @param handler 指定回调线程的Handler(主线程Handler)
* @param instrumentation 测试工具类(正常场景为null)
* @param registered 是否为持久化注册(动态注册通常为true)
* @return IIntentReceiver Binder接口对象,用于AMS跨进程回调
*/
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
// 线程安全:通过synchronized保护mReceivers数据结构
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
// 1. 尝试从缓存中获取已注册的ReceiverDispatcher
if (registered) {
// 1.1 获取当前Context对应的接收器映射表
map = mReceivers.get(context); // mReceivers: ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>
if (map != null) {
rd = map.get(r); // 检查是否已存在相同接收器的Dispatcher
}
}
// 2. 缓存未命中时创建新对象
if (rd == null) {
// 2.1 构造ReceiverDispatcher(含跨进程Binder对象)
rd = new ReceiverDispatcher(
mActivityThread.getApplicationThread(), // IApplicationThread对象
r, // 用户定义的BroadcastReceiver
context,
handler, // 主线程Handler(确保onReceive在主线程执行)
instrumentation,
registered
);
// 2.2 持久化注册时加入缓存
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map); // 建立Context到接收器映射的关系
}
map.put(r, rd); // 缓存键:BroadcastReceiver对象
}
} else {
// 3. 缓存命中时校验有效性
rd.validate(context, handler); // 检查Context和Handler是否匹配
}
// 4. 标记为活跃状态(防止被意外回收)
rd.mForgotten = false;
// 5. 返回InnerReceiver(IIntentReceiver.Stub的实现类)
return rd.getIIntentReceiver();
}
}
AMS注册广播接收器方法
动态注册核心步骤
ReceiverList管理:同一IIntentReceiver Binder对象对应一个ReceiverList,避免重复注册。
BroadcastFilter注册:将广播过滤器加入全局mReceiverResolver,后续广播分发时快速匹配
private Intent registerReceiverWithFeatureTraced(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
// 1. 权限与调用者验证
enforceNotIsolatedCaller("registerReceiver"); // 禁止隔离进程调用
ProcessRecord callerApp = getRecordForAppLOSP(caller); // 获取调用者进程记录
// 验证调用者包名与进程匹配性(防止伪造身份)
if (!UserHandle.isCore(callerApp.info.uid) && !callerApp.getPkgList().containsKey(callerPackage)) {
throw new SecurityException("Package/Process mismatch");
}
// 2. 用户ID处理与优先级检查
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, ...);
if (UserHandle.isCore(callingUid)) {
// 系统进程注册重要广播时需设置优先级(如USER_ACTION/PACKAGE_ACTION等)
if (filter.getPriority() == 0) {
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); // 默认高优先级
}
}
// 3. 粘性广播(Sticky Broadcast)匹配
ArrayList<StickyBroadcast> stickyBroadcasts = null;
synchronized (mStickyBroadcasts) {
// 遍历IntentFilter的Action,查找匹配的粘性广播
for (String action : filter.actionsIterator()) {
for (int userId : {UserHandle.USER_ALL, callingUserId}) {
ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId);
if (stickies != null && stickies.containsKey(action)) {
stickyBroadcasts.addAll(stickies.get(action)); // 收集匹配的粘性广播
}
}
}
}
// 4. 动态接收器注册核心逻辑
synchronized (this) {
// 4.1 创建或获取ReceiverList(同一Binder对象对应一个ReceiverList)
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver);
if (rl.app != null) {
rl.app.mReceivers.addReceiver(rl); // 关联到进程记录
} else {
receiver.asBinder().linkToDeath(rl, 0); // 跨进程死亡监听
}
mRegisteredReceivers.put(receiver.asBinder(), rl); // 全局注册表记录
}
// 4.2 创建BroadcastFilter并注册到Resolver
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, ...);
if (!rl.containsFilter(filter)) {
rl.add(bf); // 添加到ReceiverList
mReceiverResolver.addFilter(bf); // 注册到全局过滤器
}
// 5. 处理匹配的粘性广播(立即分发给新注册的接收器)
if (stickyBroadcasts != null) {
ArrayList<BroadcastFilter> receivers = new ArrayList<>();
receivers.add(bf);
for (StickyBroadcast broadcast : stickyBroadcasts) {
// 创建广播记录并加入队列
BroadcastRecord r = new BroadcastRecord(..., broadcast.intent, ..., receivers);
mBroadcastQueue.enqueueBroadcastLocked(r); // 异步分发
}
}
return stickyBroadcasts != null ? stickyBroadcasts.get(0).intent : null; // 返回首个粘性Intent
}
}
广播注册流程中的LoaderApk和AMS的数据结构关系图
广播注册流程小结
1. App进程:打包“快递员”
需求发起:App调用registerReceiver,就像下单寄快递,告诉系统要接收哪种广播(IntentFilter)
包装处理:
ReceiverDispatcher:系统把开发者写的BroadcastReceiver打包成“快递员”,负责跨进程送货(IIntentReceiver接口)
InnerReceiver:这个“快递员”有个Binder工牌(IIntentReceiver.Stub),AMS凭工牌找到App的家(主线程)送货
2. 跨进程:向AMS“登记收货地址”
Binder快递:把“快递员”的工牌和收货要求(IntentFilter)通过Binder寄给AMS(registerReceiverWithFeature)
防重复注册:AMS用工牌(Binder对象)当身份证,检查是否已登记过,避免重复注册
3. AMS:建立“收货档案”
档案管理:
ReceiverList:以Binder工牌为Key,建一个“收货清单”,记录同一接收器的所有过滤条件
BroadcastFilter:把IntentFilter和接收器绑定,存到全局“快递分拣系统”(mReceiverResolver)
粘性广播:如果历史广播中有匹配的“包裹”,直接塞进分发队列(mBroadcastQueue)马上派送
关键角色比喻
组件 | 比喻 | 作用 |
ReceiverDispatcher | 快递员+物流单 | 连接App和AMS,确保广播送到主线程 |
mRegisteredReceivers | 客户档案库 | 用Binder工牌管理所有注册的接收器,避免重复 |
mReceiverResolver | 智能分拣机 | 根据IntentFilter快速匹配接收器,类似快递分拣中心 |
mBroadcastQueue | 快递派送车 | 分前台/后台/离线三种车队,决定广播的派送优先级 |