当前位置: 首页 > news >正文

广播分发中心-广播注册流程

广播是怎么注册的呢?

0

阶段

组件/数据结构

作用描述

存储位置/关联关系

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的数据结构关系图

0

广播注册流程小结

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

快递派送车

分前台/后台/离线三种车队,决定广播的派送优先级

http://www.dtcms.com/a/293391.html

相关文章:

  • 秋招Day17 - Spring - AOP
  • 构建RAG智能体(2):运行状态链
  • C#文件操作(创建、读取、修改)
  • 【世纪龙科技】电动汽车原理与构造-汽车专业数字课程资源
  • [c++11]final和override
  • 黄山派lvgl8学习笔记(2)导入头文件和新建一个按钮控件
  • 标记语言---XML
  • linux 驱动-power_supply 与 mtk 充电框架
  • 工业互联网时代,如何通过混合SD-WAN提升煤炭行业智能化网络安全
  • 【Pytorch】数据集的加载和处理(一)
  • 使用ubuntu:20.04和ubuntu:jammy构建secretflow环境
  • ndarray的创建(小白五分钟从入门到精通)
  • 嵌入式开发学习(第三阶段 Linux系统开发)
  • 数据资产——解读数据资产全过程管理手册2025【附全文阅读】
  • [c++11]constexpr
  • 考研数据结构Part1——单链表知识点总结
  • 陷波滤波器设计全解析:原理、传递函数与MATLAB实现
  • Netty中AbstractReferenceCountedByteBuf对AtomicIntegerFieldUpdater的使用
  • 威胁情报:Solana 开源机器人盗币分析
  • Automotive SPICE
  • git的版本冲突
  • 大模型——Data Agent:超越 BI 与 AI 的边界
  • 用ESP32打造全3D打印四驱遥控车:无需APP的Wi-Fi控制方案
  • 从0开始的中后台管理系统-2
  • 课题学习笔记2——中华心法问答系统
  • 汽车行业数字化——解读52页汽车设计制造一体化整车产品生命周期PLM解决方案【附全文阅读】
  • 记录更新时间用java的new date还是数据库的now
  • 深入理解 C 语言数据类型:从内存到应用的全面解析
  • CAN基础知识 - 进阶版
  • 消息推送功能设计指南:精准触达与用户体验的平衡之道