解析 Android 广播(Broadcast)机制的核心原理

423 阅读6分钟

本文深入解析 Android 广播(Broadcast)机制的核心原理,结合 Android 6.0 源码,详细阐述广播的注册、发送、接收流程及不同类型广播的处理逻辑。以下用通俗易懂的语言和结构化逻辑进行解读:

一、广播基础:分类与核心组件

1. 广播类型

  • 按注册方式分

    • 静态广播:在 AndroidManifest.xml 中通过<receiver>标签声明,应用安装时由系统注册,无需代码动态干预(如监听系统开机广播)。
    • 动态广播:通过registerReceiver()动态注册,灵活性高,需手动调用unregisterReceiver()注销(如 Activity 中监听网络变化)。
  • 按发送方式分

    • 普通广播(sendBroadcast) :并行发送,所有接收者可同时处理,无顺序保证。
    • 有序广播(sendOrderedBroadcast) :串行发送,接收者按优先级依次处理,前一个接收者可截断广播或传递结果。
    • 粘性广播(sendStickyBroadcast) :广播发送后持续存在,新注册的接收者仍可获取历史广播数据(需权限BROADCAST_STICKY)。

2. 核心组件

  • BroadcastReceiver:接收广播的组件,需实现onReceive()处理逻辑。
  • ContentResolver:客户端发送广播的入口,通过sendBroadcast()等方法触发。
  • ActivityManagerService(AMS) :系统核心服务,管理广播的注册、发送队列及进程间通信。
  • BroadcastQueue:分为前台队列(mFgBroadcastQueue)和后台队列(mBgBroadcastQueue),分别处理不同优先级的广播。
  • BroadcastRecord:记录广播的元数据(如发送者、接收者、时间戳),用于队列管理。

二、广播注册流程:动态与静态的差异

1. 动态广播注册(registerReceiver

  1. 客户端调用
    在 Activity/Service 中通过ContextImpl.registerReceiver发起注册,传入广播接收者BroadcastReceiver和过滤条件IntentFilter

  2. 创建分发器

    • LoadedApk.getReceiverDispatcher创建ReceiverDispatcher,内部包含InnerReceiver(继承自IIntentReceiver.Stub,作为 Binder 服务端)。
    • InnerReceiver通过 Binder 将注册信息传递给 AMS。
  3. AMS 处理

    • AMS.registerReceiver中,将动态注册的广播保存到mRegisteredReceivers(以ReceiverList记录),并添加到mReceiverResolver供查询。
    • 若为粘性广播,立即从mStickyBroadcasts中获取历史数据并分发。

2. 静态广播注册

  • 应用安装时,系统通过PackageManager解析 Manifest 中的<receiver>标签,注册信息存储在 AMS 的mReceiverResolver中,无需手动代码干预。
  • 发送广播时,AMS 通过collectReceiverComponents查询静态注册的接收者(ResolveInfo),与动态注册的接收者(BroadcastFilter)合并处理。

三、广播发送流程:普通、有序、粘性的区别

1. 通用流程

  1. 客户端触发
    通过Context.sendBroadcast()等方法发送 Intent,携带广播类型(普通 / 有序 / 粘性)和参数。

  2. AMS 预处理

    • 验证权限、添加系统标志(如FLAG_EXCLUDE_STOPPED_PACKAGES排除已停止应用)。
    • 处理系统广播(如包安装、时间变化)和粘性广播(保存到mStickyBroadcasts)。
  3. 队列分发

    • 普通广播:加入mParallelBroadcasts队列,并行分发给所有动态注册的接收者(BroadcastFilter)。
    • 有序广播:加入mOrderedBroadcasts队列,按优先级串行分发给所有接收者(静态 + 动态)。
    • 粘性广播:同时保存到mStickyBroadcasts,新注册的接收者可获取。

2. 关键差异

类型队列处理方式接收者类型超时机制
普通广播mParallel并行,一次性分发仅动态注册
有序广播mOrdered串行,按优先级依次处理静态 + 动态总超时 = 2×N× 超时时间(N 为接收者数)
粘性广播单独存储持续存在,新注册者可获取历史数据所有注册者

四、广播处理流程:从队列到接收者回调

1. 队列调度(scheduleBroadcastsLocked

  • AMS 通过BroadcastQueuescheduleBroadcastsLocked发送消息BROADCAST_INTENT_MSG,触发BroadcastHandler处理队列。
  • 并行广播处理
    mParallelBroadcasts中取出所有BroadcastRecord,逐个分发给动态注册的BroadcastFilter,通过deliverToRegisteredReceiverLocked触发回调。
  • 有序广播处理
    mOrderedBroadcasts中取出首个BroadcastRecord,按顺序分发给静态和动态接收者,支持中途截断(resultAbort)或传递结果(resultCode)。

2. 跨进程通信(IPC)

  • 动态接收者
    通过InnerReceiver(Binder 服务端)的performReceive方法,将广播事件通过 Handler 发送到接收者所在进程的主线程,触发onReceive回调。
  • 静态接收者
    若接收者所在进程未启动,AMS 通过startProcessLocked创建进程,调用scheduleReceiver触发回调。

3. 超时机制

  • 有序广播存在超时风险:

    • 单个接收者处理时间超过mTimeoutPeriod(前台 10 秒,后台 60 秒)。
    • 总处理时间超过2 × N × mTimeoutPeriod(N 为接收者数量),触发 ANR。
  • 普通广播和粘性广播无超时,因并行处理或无需等待。

五、核心机制与开发注意事项

1. 粘性广播的特殊性

  • 发送后存储在mStickyBroadcasts,新注册的接收者通过registerReceiver立即获取历史数据(返回值为该粘性 Intent)。
  • 需谨慎使用,避免内存泄漏(及时调用removeStickyBroadcast清除)。

2. 动态广播的生命周期管理

  • 必须在合适的生命周期阶段注销(如 Activity 的onDestroy),否则可能导致内存泄漏或空指针异常。
  • 使用弱引用或全局单例管理BroadcastReceiver,避免持有 Activity 引用。

3. 有序广播的优先级控制

  • 通过IntentFilterandroid:priority属性(-1000~1000,值越大优先级越高)控制执行顺序。
  • 高优先级接收者可通过abortBroadcast()截断广播,或通过setResult()传递结果给后续接收者。

4. 性能优化

  • 避免在onReceive中执行耗时操作(如网络请求、数据库写入),可通过IntentService或 WorkManager 处理异步任务。
  • 减少静态广播的使用,避免应用启动时触发大量注册,影响启动速度。

六、总结:流程时序与核心要点

1. 时序图(动态广播接收)

plaintext

客户端进程          AMS进程          接收者进程
───────────────┬───────────────┬───────────────
1. registerReceiver() │           │
2. 创建InnerReceiver  │           │
3. AMP.registerReceiver() │           │
4. AMS保存ReceiverList │           │
5. sendBroadcast()      │           │
6. AMP.broadcastIntent() │           │
7. AMS入队广播到队列   │           │
8. BroadcastHandler处理 │           │
9. deliverToRegisteredReceiverLocked() │
10. ATP.scheduleRegisteredReceiver() │  10. 接收者Binder线程
11. InnerReceiver.performReceive()   │  11. 发送Handler消息
12. 主线程调用onReceive()           │  12. 回调onReceive()
───────────────┴───────────────┴───────────────

2. 核心要点

  • Binder 是基础:广播的跨进程通信依赖 Binder 机制,InnerReceiverApplicationThread是通信桥梁。

  • 队列决定顺序:普通广播并行处理动态接收者,有序广播串行处理所有接收者,静态接收者始终串行。

  • 生命周期管理:动态广播需手动注销,粘性广播需主动清除,避免资源泄漏。

通过理解广播机制的底层流程,开发者可更精准地选择广播类型,优化性能,避免常见问题(如 ANR、内存泄漏),确保应用在跨进程通信场景下的稳定性和效率。