第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播

第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播

所属板块:第二板块 --- Android 四大组件标准化学理

前置知识:第八篇中的 Service 优先级、Binder IPC、AMS 调度机制

本篇定位 :BroadcastReceiver 是 Android 系统中最轻量级、最松散耦合 的组件。它不提供 UI,也不直接执行长时间任务,而是作为一个系统级事件的中转站(Event Hub) 。本篇将彻底拆解广播的异步分发模型 、AMS 中的队列管理机制 、静态注册与动态注册的权限鸿沟 、有序广播(Ordered Broadcast)的拦截与修改机制 、粘性广播(Sticky Broadcast)的历史遗留问题 、LocalBroadcastManager 的进程内通信本质 。我们将深入 ActivityManagerService (AMS) 与 BroadcastQueue 的源码级逻辑,揭示广播为何被称为"冷启动炸弹"以及如何正确规避。


1. 核心结论先行(Thesis Statement)

BroadcastReceiver 是 Android 操作系统中用于接收系统或应用发出的异步消息(Intent)的组件。它不是线程 ,也不是服务 ,而是一个由系统服务(AMS)管理的、具有极短生命周期的、运行在主线程中的回调实体。

  • Receiver 的本质 :一个事件监听器(Event Listener) 。它监听特定的 Intent 广播,并在接收到广播时执行一段简短的逻辑。
  • 分发模型 :异步发布-订阅模型(Pub-Sub)。发送者(Publisher)发出广播,AMS 作为中介(Broker)将广播分发给所有符合条件的接收者(Subscriber)。
  • 生命周期悖论 :Receiver 的 onReceive() 方法执行完毕后,系统会立即销毁 Receiver 实例。它不能执行耗时操作,否则会阻塞主线程导致 ANR。
  • 注册鸿沟 :静态注册 (Manifest)由系统唤醒,即使应用未运行也能接收;动态注册(Context.registerReceiver)依附于组件生命周期,组件销毁后失效。

2. BroadcastReceiver 的两种注册范式

2.1 静态注册(Manifest-declared)

在 AndroidManifest.xml 中声明 Receiver。这是系统级的注册方式。

学术定义:

  • 常驻性:Receiver 信息在应用安装时由 PMS(PackageManagerService)解析并注册到系统中。
  • 唤醒能力:即使应用进程未运行,当广播到达时,AMS 会通过 Zygote 启动应用进程并实例化 Receiver。
  • 权限控制 :可以通过 android:permission 限制谁能发送广播给我。

Manifest 示例:

xml 复制代码
<receiver
    android:name=".BootCompletedReceiver"
    android:enabled="true"
    android:exported="true"
    android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
    </intent-filter>
</receiver>

2.2 动态注册(Context-registered)

在代码中通过 Context.registerReceiver() 注册。这是应用级的注册方式。

学术定义:

  • 临时性:Receiver 的生命周期与注册它的 Context(通常是 Activity 或 Service)绑定。
  • 灵活性:可以随时注册和注销,适合监听与 UI 状态相关的广播。
  • 无唤醒能力:如果应用进程已死,动态注册的 Receiver 无法接收广播。

代码示例(系统规范):

java 复制代码
public class MainActivity extends Activity {
    private MyReceiver receiver;

    @Override
    protected void onStart() {
        super.onStart();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(receiver, filter);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(receiver); // 必须注销,否则内存泄漏
    }
}

2.3 两种注册方式的对比

维度 静态注册 动态注册
注册地点 AndroidManifest.xml Java/Kotlin 代码
生命周期 独立于应用进程 依附于 Context
唤醒能力 能(冷启动应用) 不能
执行时机 系统随时可能唤醒 仅在应用运行时
适用场景 系统事件(开机、电量、网络) 应用内事件(UI 更新)

3. 广播的分类与分发算法

3.1 普通广播(Normal Broadcast)

异步发送,所有 Receiver 同时接收,无法被拦截或修改。

学术定义:

  • 并行分发:AMS 将广播发送给所有符合条件的 Receiver,不保证顺序。
  • 不可控:发送者无法知道 Receiver 是否接收成功,也无法修改数据。

3.2 有序广播(Ordered Broadcast)

同步发送,Receiver 按优先级依次接收,可以拦截或修改数据。

学术定义:

  • 串行分发 :Receiver 按 android:priority 从高到低依次执行。
  • 拦截机制 :高优先级的 Receiver 可以调用 abortBroadcast() 阻止广播继续向下传递。
  • 数据修改 :Receiver 可以通过 setResultExtras() 修改数据,供下一个 Receiver 使用。

Manifest 示例:

xml 复制代码
<receiver android:name=".HighPriorityReceiver">
    <intent-filter android:priority="1000">
        <action android:name="com.example.MY_ORDERED_BROADCAST" />
    </intent-filter>
</receiver>
<receiver android:name=".LowPriorityReceiver">
    <intent-filter android:priority="-1000">
        <action android:name="com.example.MY_ORDERED_BROADCAST" />
    </intent-filter>
</receiver>

3.3 粘性广播(Sticky Broadcast)【已废弃】

Android 5.0 (L) 起废弃。它允许广播"粘"在系统上,后来注册的 Receiver 也能收到之前的广播。

学术定义:

  • 历史缓存:AMS 会缓存最后一条粘性广播。
  • 安全风险:任何应用都可以接收敏感信息,已被禁止。

4. 广播的分发流程(AMS 源码级解析)

4.1 广播发送流程

sequenceDiagram participant Sender as 发送者进程 participant AMS as ActivityManagerService participant BQ as BroadcastQueue participant Receiver as 接收者进程 Sender->>AMS: sendBroadcast(intent) AMS->>AMS: 检查权限 (checkBroadcastFromSystem) AMS->>BQ: enqueueParallelBroadcastLocked() / enqueueOrderedBroadcastLocked() BQ->>BQ: 构建 BroadcastRecord BQ->>Receiver: scheduleReceiver() (Binder IPC) Receiver->>Receiver: 实例化 Receiver Receiver->>Receiver: onReceive() Receiver->>AMS: finishReceiver()

4.2 BroadcastQueue 的内部机制

AMS 中有两个 BroadcastQueue:

  1. Foreground Broadcast Queue:前台广播,优先级高,超时时间短(10秒)。
  2. Background Broadcast Queue:后台广播,优先级低,超时时间长(60秒)。

源码解析:

java 复制代码
// ActivityManagerService.java
public void broadcastIntent(...) {
    // 1. 检查调用者权限
    enforceNotIsolatedCaller("broadcastIntent");

    // 2. 处理粘性广播
    if (sticky) {
        // ...
    }

    // 3. 选择队列
    BroadcastQueue queue = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0
            ? mFgBroadcastQueue : mBgBroadcastQueue;

    // 4. 入队
    queue.enqueueOrderedBroadcastLocked(r);
    queue.scheduleBroadcastsLocked();
}

4.3 BroadcastRecord 数据结构

java 复制代码
// com.android.server.am.BroadcastRecord
class BroadcastRecord extends Binder {
    final Intent intent;                 // 广播 Intent
    final ProcessRecord callerApp;       // 发送者进程
    final String[] requiredPermissions;  // 接收者需要的权限
    final int receiversSize;             // 接收者数量
    final ArrayList<BroadcastFilter> receivers; // 动态接收者
    final ResolveInfo[] resolveInfo;     // 静态接收者
    int nextReceiver;                    // 下一个要处理的接收者索引(有序广播用)
    boolean ordered;                    // 是否是有序广播
}

5. 广播的安全性机制

5.1 发送权限(Send Permission)

发送广播时可以指定权限,只有拥有该权限的应用才能接收。

java 复制代码
// 发送者
sendBroadcast(intent, "com.example.permission.MY_PERMISSION");

// 接收者 Manifest
<uses-permission android:name="com.example.permission.MY_PERMISSION" />

5.2 接收权限(Receive Permission)

在 Manifest 中声明 Receiver 时指定权限,只有拥有该权限的发送者才能发送广播给我。

xml 复制代码
<receiver
    android:name=".MyReceiver"
    android:permission="com.example.permission.ANOTHER_PERMISSION">
    <intent-filter>
        <action android:name="com.example.MY_ACTION" />
    </intent-filter>
</receiver>

5.3 LocalBroadcastManager(进程内安全广播)

LocalBroadcastManager 是 Support Library 提供的进程内广播 工具。它不使用 Binder IPC,也不通过 AMS,而是直接在应用进程内分发。

学术定义:

  • 安全性:广播数据不会离开应用进程,不会被其他应用截获。
  • 效率:避免了 IPC 开销,速度更快。
  • 现状 :已被 LiveData 或 RxJava 等响应式编程库取代,但在理解广播机制时仍具学术价值。

6. 广播的陷阱与系统限制

6.1 ANR 风险

onReceive() 运行在主线程,且只有 10 秒 (前台广播) 或 60 秒(后台广播)的执行时间。

学术定义:

  • ANR(Application Not Responding) :如果 onReceive() 执行超过规定时间,系统会弹出 ANR 对话框。
  • 禁忌 :绝对不能在 onReceive() 中执行网络请求、数据库读写、文件 IO 或睡眠操作。

6.2 广播延迟与排队

当系统繁忙时,广播可能会被延迟。特别是在 Android 8.0 (O) 之后,系统对后台广播进行了严格限制。

Android 8.0+ 的限制:

  • 后台执行限制:应用在后台时,无法注册隐式广播的静态 Receiver(部分系统广播除外,如开机广播)。
  • 原因:防止应用滥用广播在后台唤醒,消耗电量。

6.3 替代方案

由于广播的局限性,现代 Android 开发推荐使用以下方案:

场景 推荐方案 学术理由
应用内通信 LiveData / RxJava / Flow 响应式编程,解耦更彻底,无 IPC 开销。
跨进程通信 Messenger / AIDL 需要双向通信或复杂数据结构时。
后台任务 WorkManager / JobScheduler 系统调度,省电,符合后台限制。
系统事件 静态注册广播 唯一合法场景,如开机、电量变化。

7. 关键源码解析:广播的匹配算法

AMS 如何找到符合条件的 Receiver?

java 复制代码
// PackageManagerService.java
public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
    // 1. 查询静态 Receiver (Manifest)
    List<ResolveInfo> receivers = mReceivers.queryIntent(intent, resolvedType, flags, userId);

    // 2. 过滤权限
    for (ResolveInfo ri : receivers) {
        if (!grantImplicitAccess(userId, ri, uid, owningUid, false)) {
            continue; // 权限不足,过滤掉
        }
    }
    return receivers;
}

8. 广播的冷启动效应与性能影响

8.1 冷启动炸弹(Cold Start Bomb)

静态注册的 Receiver 具有唤醒能力,这意味着一个广播可以启动一个已经死亡的应用进程。

学术定义:

  • 进程创建开销:每次唤醒都需要 Zygote fork 新进程,加载 ART 虚拟机,初始化 Application。
  • 累积效应:如果多个应用都监听同一个高频广播(如网络变化),会导致系统频繁创建和销毁进程,造成严重的性能损耗和电量消耗。

8.2 广播的序列化执行

即使是普通广播,在同一个应用进程中,Receiver 的 onReceive() 也是串行执行的。如果一个 Receiver 执行时间过长,会阻塞后续 Receiver 的执行。


9. 关键数据结构与源码定义(续)

9.1 BroadcastFilter(动态注册记录)

java 复制代码
// com.android.server.am.BroadcastFilter
class BroadcastFilter extends IntentFilter {
    final String packageName;
    final String receiverClassName;
    final int owningUid;
    final int owningPid;
    final boolean instantApp;
}

9.2 ReceiverList(Receiver 列表)

java 复制代码
// com.android.server.am.ReceiverList
class ReceiverList extends ArrayList<BroadcastFilter> {
    final ProcessRecord app;            // 所属进程
    final int pid;                     // 进程 ID
    final int uid;                     // 用户 ID
    final String packageName;          // 包名
}

10. 本篇总结(Knowledge Closure)

关键点 纯学术定义
Receiver 的本质 由 AMS 管理的事件监听器,生命周期极短,运行在主线程。
注册范式 静态注册(系统级,可唤醒)与动态注册(应用级,依附生命周期)。
分发模型 异步 Pub-Sub 模型,有序广播提供拦截和修改能力。
安全性 通过发送权限和接收权限实现双向保护。
系统限制 Android 8.0+ 严格限制后台静态广播,防止滥用。
性能陷阱 冷启动开销大,执行时间长会导致 ANR。

下一篇预告 :第二板块:Android 四大组件标准化学理 | 第十篇:ContentProvider 数据共享与 SQLite 引擎

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui