BroadcastReceiver 静态注册与动态注册
前言
BroadcastReceiver 很容易被误用成"轻量消息总线"或"后台唤醒入口"。这两个理解都不完整。
它真正解决的问题是:系统或应用中发生了某个事件,Android 需要把一个 Intent 分发给符合条件的接收者,并在很短时间内完成回调。这个模型适合电量变化、开机完成、下载完成、自定义应用内事件、短信验证码、蓝牙状态等"事件通知",不适合承载长任务。
线上广播问题通常集中在四类:
- Manifest 里声明了接收器,但 Android 8.0+ 设备收不到大多数隐式系统广播。
- 动态注册忘记在正确生命周期注销,Activity 退出后泄漏 Context。
- targetSdk 升到 Android 14 后,
registerReceiver()因缺少RECEIVER_EXPORTED或RECEIVER_NOT_EXPORTED抛SecurityException。 onReceive()里做网络、数据库或大 JSON 解析,主线程卡顿,甚至触发广播 ANR。
本文按"使用方式 -> 版本规则 -> Framework 调用链 -> 工程实践"的顺序重建 BroadcastReceiver 的模型。版本结论以 2026-07-01 查阅的 Android Developers 文档和 AOSP refs/heads/main 为准。
前置知识
建议先掌握:
- A019:Android 应用进程、组件与系统架构概览。
- A020:Activity 生命周期完整解析。
- A023:Intent 显式、隐式与 PendingIntent。
- A024:Service、前台服务与后台限制。
- Manifest 组件声明、
IntentFilter、主线程、进程优先级和后台执行限制。
A023 解释了 Intent 如何描述一次请求。本文继续回答:这个 Intent 如果是广播,系统如何找到接收者、如何分发、为什么有些广播不能再靠 manifest 静态接收。
核心概念
BroadcastReceiver 是短回调组件
BroadcastReceiver.onReceive(context, intent) 默认在应用主线程执行。官方 API 文档和 AOSP BroadcastReceiver.java 都明确提醒:主线程中不能执行长耗时操作;即使使用 goAsync() 把工作移到后台线程,也仍然受广播执行时限约束,并且必须调用 PendingResult.finish()。
所以它适合做三件事:
- 校验
intent.action、读取少量 extras。 - 更新轻量内存状态或发送应用内事件。
- 把长任务转交给 WorkManager、JobScheduler、前台服务或业务队列。
它不适合做这些事:
- 在
onReceive()中直接访问网络。 - 同步读写大文件或数据库。
- 试图通过大量隐式广播长期保活。
- 把自定义跨应用广播当成无需权限的公开接口。
静态注册与动态注册
| 维度 | 静态注册 | 动态注册 |
|---|---|---|
| 入口 | AndroidManifest.xml 的 <receiver> |
Context.registerReceiver() |
| 生命周期 | 由系统按 manifest 发现,可冷启动进程 | 跟注册时使用的 Context 生命周期相关 |
| 适合场景 | 少量必须由系统唤醒的事件,例如允许的系统广播、显式发给本应用的广播 | UI 可见期间监听、应用进程内事件、只在登录/连接期间有效的事件 |
| Android 8.0+ 限制 | target 26+ 不能用 manifest 接收大多数隐式广播,例外清单除外 | 用户正在使用应用时仍可注册接收 |
| Android 13/14 安全 | Manifest 接收器依赖 android:exported、permission 等声明 |
Android 13 引入 exported flags;target 34+ 多数动态注册必须显式传 flag |
| 常见风险 | 误以为能接收所有系统广播;组件暴露面过大 | 忘记注销;flag 选错导致安全漏洞或收不到广播 |
选择规则很简单:需要系统在进程不活跃时仍能把事件投递给你,才考虑静态注册;只在某个页面、会话或进程存活期间有意义,优先动态注册。
有序广播、普通广播与粘性广播
| 类型 | API | 特点 | 现代建议 |
|---|---|---|---|
| 普通广播 | sendBroadcast() |
系统可并行或按策略分发,接收者不能依赖全局顺序 | 常用,但要限制 action 范围和权限 |
| 有序广播 | sendOrderedBroadcast() |
接收者可读写结果并影响后续接收者 | 谨慎使用,避免把业务正确性建立在优先级上 |
| 粘性广播 | sendStickyBroadcast() |
最后一次广播会被系统保留 | 已废弃,不应用作状态存储 |
广播不是可靠消息队列。需要"至少一次执行""失败重试""网络约束""进程死亡后恢复"的任务,应该交给 WorkManager 或服务端任务系统。
整体架构
BroadcastReceiver 的分发跨过 App 进程和 system_server。动态注册和静态注册在入口不同,但最终都围绕 BroadcastRecord、广播队列和应用进程回调运转。
这张图的关键点是:接收器不是直接被发送方调用。发送方把 Intent 交给系统,系统解析接收者、建立 BroadcastRecord、进入广播队列,然后通过应用进程的 ActivityThread 或注册时保存的 IIntentReceiver 回调到 onReceive()。
工作流程
静态注册流程
静态注册的接收器写在 manifest 中:
xml
<receiver
android:name=".boot.BootCompletedReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
系统在解析包信息时知道这个接收器。广播发送后,如果 Intent 能匹配到该接收器,系统可能启动应用进程,再调用接收器。对开发者来说,这种方式的价值是"应用没打开时也可能收到事件";代价是它受后台限制、安全声明和系统例外清单严格约束。
从 Android 8.0 API 26 开始,target 26+ 的应用不能在 manifest 中声明大多数隐式广播接收器,除非该广播属于官方例外列表,或广播显式指向你的应用。官方这样做的核心原因是减少大量应用被同一系统事件同时唤醒,降低后台资源消耗。
动态注册流程
动态注册在运行时完成:
kotlin
private val timeTickReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_TIME_TICK) {
viewModel.refreshClock()
}
}
}
override fun onStart() {
super.onStart()
val filter = IntentFilter(Intent.ACTION_TIME_TICK)
ContextCompat.registerReceiver(
this,
timeTickReceiver,
filter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
}
override fun onStop() {
unregisterReceiver(timeTickReceiver)
super.onStop()
}
动态注册的核心不是"更高级",而是"作用域更清晰"。上面的接收器只在 Activity 可见期间监听分钟变化,页面停止后立即注销,既避免泄漏,也避免后台无意义工作。
Android 13/14 的动态注册 flag
Android 13 引入了更安全的 context-registered receiver exported 配置。Android 14 进一步要求 target 34+ 的应用在注册非纯系统广播接收器时,必须指定 RECEIVER_EXPORTED 或 RECEIVER_NOT_EXPORTED,否则会抛 SecurityException。
选择方式:
| 场景 | flag |
|---|---|
| 只接收本应用发送的广播 | RECEIVER_NOT_EXPORTED |
| 接收其他普通应用发送的广播 | RECEIVER_EXPORTED,同时考虑自定义 permission |
| 接收所有系统广播,包括部分高权限系统应用发出的广播 | 通常需要 RECEIVER_EXPORTED |
| 只注册系统广播 | Android 14 文档说明可不指定 exported flag,但实际项目中建议用 AndroidX 兼容 API,并按官方要求区分 |
这里最容易犯的错是:为了"省事"全部用 exported。这样会扩大攻击面,尤其是自定义 action 如果没有权限保护,其他应用也可能构造 Intent 触发你的接收逻辑。
API 使用
1. Manifest 静态注册:只做分发,不做长任务
kotlin
class BootCompletedReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
val request = OneTimeWorkRequestBuilder<WarmUpWorker>()
.setInitialDelay(30, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context.applicationContext)
.enqueueUniqueWork(
"boot-warm-up",
ExistingWorkPolicy.KEEP,
request,
)
}
}
Manifest 中还需要权限:
xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name=".boot.BootCompletedReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
onReceive() 只负责判断 action 和投递任务。真正的网络、数据库、重试和约束交给 WorkManager。
2. 动态注册:跟随生命周期
在 Compose 或现代 Activity 中,不要把注册逻辑散在多个回调里。可以封装为生命周期感知组件:
kotlin
class BatteryReceiver(
private val onBatteryLow: () -> Unit,
) : DefaultLifecycleObserver {
private var registered = false
private val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BATTERY_LOW) {
onBatteryLow()
}
}
}
override fun onStart(owner: LifecycleOwner) {
val context = (owner as? ComponentActivity) ?: return
ContextCompat.registerReceiver(
context,
receiver,
IntentFilter(Intent.ACTION_BATTERY_LOW),
ContextCompat.RECEIVER_NOT_EXPORTED,
)
registered = true
}
override fun onStop(owner: LifecycleOwner) {
if (registered) {
val context = owner as? ComponentActivity ?: return
context.unregisterReceiver(receiver)
registered = false
}
}
}
真实项目里可以进一步把 Context 作为构造参数传入,并使用 applicationContext 或 Activity Context 明确作用域。原则是:在哪里注册,就要能证明在哪里注销。
3. 自定义应用内广播:优先显式、加权限
如果仍要用广播做模块间通知,至少让 Intent 显式指向本应用:
kotlin
private const val ACTION_SYNC_STATE_CHANGED =
"com.example.app.action.SYNC_STATE_CHANGED"
fun Context.sendSyncStateChanged(state: String) {
val intent = Intent(ACTION_SYNC_STATE_CHANGED)
.setPackage(packageName)
.putExtra("state", state)
sendBroadcast(intent)
}
跨应用广播要额外考虑发送权限和接收权限。不要把用户 ID、token、定位、设备标识等敏感信息直接放进公开广播 extras。
源码分析
版本与源码路径
本文参考 AOSP refs/heads/main:
| 类 | 路径 | 作用 |
|---|---|---|
BroadcastReceiver |
frameworks/base/core/java/android/content/BroadcastReceiver.java |
定义 onReceive()、goAsync()、PendingResult.finish() |
Context |
frameworks/base/core/java/android/content/Context.java |
定义 registerReceiver()、RECEIVER_EXPORTED、RECEIVER_NOT_EXPORTED |
ContextImpl |
frameworks/base/core/java/android/app/ContextImpl.java |
动态注册实现入口,调用 AMS |
LoadedApk.ReceiverDispatcher |
frameworks/base/core/java/android/app/LoadedApk.java |
保存动态注册 receiver 与 IIntentReceiver 桥接对象 |
ActivityThread |
frameworks/base/core/java/android/app/ActivityThread.java |
应用进程中调度静态和动态 receiver 回调 |
BroadcastQueueModernImpl |
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java |
system_server 中的广播队列调度 |
BroadcastRecord |
frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java |
保存 Intent、接收者列表、分发状态、超时统计 |
动态注册调用链
ContextImpl.registerReceiverInternal() 会为普通 BroadcastReceiver 找到或创建 LoadedApk.ReceiverDispatcher,拿到内部 IIntentReceiver,再通过 ActivityManager.getService().registerReceiverWithFeature() 注册到系统服务。后续广播到达时,system_server 根据注册信息找到目标进程,再通过这个 Binder 回调回来。
这个设计解释了两个常见现象:
- 动态 receiver 跟注册对象相关,忘记注销会留下
ReceiverDispatcher和 Context 关联,导致泄漏。 - 如果注册时传入
Handler scheduler,onReceive()可以被调度到指定线程;不传时默认走主线程。
静态接收调用链
静态接收器在 BroadcastRecord.receivers 中通常表现为 ResolveInfo;动态接收器通常是 BroadcastFilter。BroadcastQueueModernImpl 会把广播放入按进程组织的队列,冷进程可能触发进程启动,热进程则直接调度。AOSP 源码中 scheduleReceiverWarmLocked() 会把广播状态标记为 DELIVERY_SCHEDULED,然后调用应用进程的 scheduleReceiver() 或动态注册 receiver 的 performReceive()。
BroadcastRecord 保存了什么
BroadcastRecord 是理解广播分发状态的核心对象。它保存:
- 原始
Intent和目标组件。 - 发送方包名、uid、pid。
- 接收者列表,元素可能是静态接收器
ResolveInfo或动态接收器BroadcastFilter。 ordered、sticky、timeoutExempt、resultCode、resultData等分发属性。- 每个接收者的
delivery状态,例如PENDING、SCHEDULED、DELIVERED、SKIPPED、TIMEOUT、FAILURE。 enqueueTime、dispatchTime、receiverTime、finishTime等时间指标。
这说明广播不是简单的 forEach(receiver) receiver.onReceive()。系统会记录状态、跳过策略、超时、进程冷启动、ordered broadcast 的阻塞关系和统计信息。
线程和进程边界
| 阶段 | 进程 | 线程/调度 |
|---|---|---|
| 发送广播 | 发送方 App 或 system_server | 调用方线程进入 Binder |
| 匹配和排队 | system_server |
AMS/BroadcastQueue 持锁维护状态 |
| 冷启动静态接收器 | system_server -> 目标 App |
可能启动目标进程 |
调用 onReceive() |
目标 App | 默认主线程;动态注册可指定 Handler |
goAsync().finish() |
目标 App -> system_server |
后台线程可 finish,但仍受广播时限 |
因此,不要在 onReceive() 里持有锁等待其他主线程任务,也不要在 ordered broadcast 中做慢操作。慢 receiver 会阻塞后续分发,并可能把问题放大到系统级事件延迟。
实战案例
案例:登录态变化通知多个页面
假设旧项目用全局广播通知登录态变化:
kotlin
fun Context.broadcastLoginChanged(loggedIn: Boolean) {
sendBroadcast(
Intent("com.example.LOGIN_CHANGED")
.putExtra("loggedIn", loggedIn),
)
}
这个写法有两个问题:
- Intent 是隐式的,其他应用可能构造同名 action。
- 接收侧如果是 manifest receiver,Android 8.0+ 还会遇到隐式广播限制。
改造方式:
kotlin
private const val ACTION_LOGIN_CHANGED =
"com.example.app.action.LOGIN_CHANGED"
fun Context.notifyLoginChanged(loggedIn: Boolean) {
sendBroadcast(
Intent(ACTION_LOGIN_CHANGED)
.setPackage(packageName)
.putExtra("loggedIn", loggedIn),
)
}
class LoginChangedReceiver(
private val onChanged: (Boolean) -> Unit,
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != ACTION_LOGIN_CHANGED) return
onChanged(intent.getBooleanExtra("loggedIn", false))
}
}
如果只在本进程内通信,更现代的方案是 StateFlow、共享 Repository、Navigation result 或进程内事件流。广播适合组件边界较老、模块解耦成本较高或必须与系统/其他应用交互的场景,不应作为默认状态管理工具。
案例:下载完成后刷新数据库
系统 DownloadManager.ACTION_DOWNLOAD_COMPLETE 可以由动态注册 receiver 在页面可见时监听;如果希望无 UI 也处理下载结果,应确认系统广播和业务限制,再把处理转交给 Worker:
kotlin
class DownloadCompleteReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != DownloadManager.ACTION_DOWNLOAD_COMPLETE) return
val downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1L)
if (downloadId <= 0L) return
val work = OneTimeWorkRequestBuilder<ImportDownloadedFileWorker>()
.setInputData(workDataOf("download_id" to downloadId))
.build()
WorkManager.getInstance(context.applicationContext).enqueue(work)
}
}
这样做的收益是:receiver 快速返回,导入文件的 IO、失败重试和约束由 Worker 管理。
性能优化
1. 让 onReceive() 像中断处理一样短
把 receiver 当成"事件中断"处理:验证 action、解析少量参数、投递任务、返回。任何不可控耗时都移出 receiver。
不推荐:
kotlin
override fun onReceive(context: Context, intent: Intent) {
val payload = URL(intent.getStringExtra("url")).readText()
database.record(payload)
}
推荐:
kotlin
override fun onReceive(context: Context, intent: Intent) {
val url = intent.getStringExtra("url") ?: return
val request = OneTimeWorkRequestBuilder<FetchPayloadWorker>()
.setInputData(workDataOf("url" to url))
.build()
WorkManager.getInstance(context.applicationContext).enqueue(request)
}
2. 减少静态隐式广播唤醒
Android 8.0 的限制背后是性能问题:一个系统事件如果唤醒几十个应用,会造成 CPU、内存和电量浪费。现代应用应优先使用:
- WorkManager 处理延迟、约束、重试任务。
- JobScheduler 处理系统级计划任务。
- 明确的回调 API,例如网络状态使用
ConnectivityManager.NetworkCallback。 - 前台服务处理用户可见的持续任务。
3. 控制动态注册作用域
动态注册 receiver 的作用域要和业务需要一致:
| 业务需要 | 推荐作用域 |
|---|---|
| 页面可见才刷新 UI | onStart() 注册,onStop() 注销 |
| Activity 存活期间即可 | onCreate() 注册,onDestroy() 注销 |
| 整个进程期间监听 | Application 注册,并提供明确关闭路径 |
| Compose 页面监听 | DisposableEffect 中注册和注销 |
Compose 中可以这样写:
kotlin
@Composable
fun BatteryBanner(
onBatteryLow: () -> Unit,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val currentCallback by rememberUpdatedState(onBatteryLow)
DisposableEffect(context) {
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BATTERY_LOW) {
currentCallback()
}
}
}
ContextCompat.registerReceiver(
context,
receiver,
IntentFilter(Intent.ACTION_BATTERY_LOW),
ContextCompat.RECEIVER_NOT_EXPORTED,
)
onDispose {
context.unregisterReceiver(receiver)
}
}
Box(modifier)
}
关键点是使用 rememberUpdatedState 避免 receiver 捕获过期 lambda,并在 onDispose 中注销。
4. 用权限保护跨应用广播
如果广播必须跨应用,至少做三层保护:
- action 使用反向域名,避免与其他应用冲突。
- 发送时
setPackage()或setComponent()限制目标。 - 对敏感广播使用 signature 级别 permission 或
sendBroadcast(intent, permission)。
RECEIVER_NOT_EXPORTED 是动态 receiver 的默认安全选择。只有确实需要接收外部应用或高权限系统应用广播时,才考虑 exported。
常见问题
Q1:静态注册是不是已经不能用了?
不是。静态注册仍然存在,也仍适合少量系统允许的唤醒场景和显式发给本应用的广播。变化在于:Android 8.0+ 对 target 26+ 应用限制了大多数 manifest 隐式广播,不能再把它当成通用后台入口。
Q2:动态注册一定收不到 App 进程外事件吗?
不是。动态注册的 receiver 可以接收系统或其他应用广播,但前提是你的进程已经存在且 receiver 已注册。它不负责冷启动你的应用。
Q3:goAsync() 能不能把任务跑很久?
不能。goAsync() 只是允许 onReceive() 先返回并把处理挪到其他线程;广播仍处于 active 状态,系统仍期望你快速调用 PendingResult.finish()。长任务应该交给 WorkManager、JobScheduler、Service 或前台服务。
Q4:为什么 target 34 后 registerReceiver 崩了?
如果不是只注册系统广播,target Android 14 API 34+ 时需要指定 RECEIVER_EXPORTED 或 RECEIVER_NOT_EXPORTED。可以使用 AndroidX ContextCompat.registerReceiver() 做兼容,并按接收来源选择 flag。
Q5:LocalBroadcastManager 还能用吗?
不建议。LocalBroadcastManager 已废弃。进程内事件优先使用 Flow、LiveData、Repository 状态、依赖注入的事件分发器或明确的回调接口。
Q6:广播优先级还能决定全局顺序吗?
不能依赖它做跨应用全局排序。现代 Android 对广播优先级和调度策略有更多限制。即使 ordered broadcast 仍有结果链路,也不应把核心业务正确性建立在其他应用的接收顺序上。
面试考点
-
BroadcastReceiver 的静态注册和动态注册有什么区别?
静态注册由 manifest 声明,系统可在匹配广播时启动应用进程;动态注册在运行时调用
registerReceiver(),生命周期跟注册 Context 相关,适合页面或会话期间监听。 -
Android 8.0 对广播做了什么限制?
target 26+ 应用不能在 manifest 中声明接收大多数隐式广播,官方例外列表和显式广播除外。动态注册在应用活跃时仍可使用。
-
Android 14 target 34 下动态注册 receiver 为什么需要 flag?
为了让 context-registered receiver 的导出行为显式化,降低未保护动态 receiver 被其他应用触发的风险。非纯系统广播注册通常必须指定
RECEIVER_EXPORTED或RECEIVER_NOT_EXPORTED。 -
onReceive()运行在哪个线程?默认运行在应用主线程。动态注册时如果传入
Handler scheduler,可以调度到指定线程,但仍要遵守广播执行时限。 -
goAsync()的作用和限制是什么?它返回
PendingResult,允许onReceive()返回后继续异步处理,并最终调用finish()。它不是长任务通道,执行总时长仍受系统限制。 -
AOSP 中动态注册 receiver 如何回调?
ContextImpl.registerReceiverInternal()创建或获取LoadedApk.ReceiverDispatcher,通过 AMS 注册IIntentReceiver。广播到达后 system_server 调用performReceive(),再由ReceiverDispatcher调用应用的onReceive()。 -
AOSP 中静态 receiver 如何被调起?
系统匹配 manifest receiver 得到
ResolveInfo,构建BroadcastRecord并进入BroadcastQueueModernImpl。目标进程冷启动或热调度后,ActivityThread.scheduleReceiver()/handleReceiver()创建 receiver 并调用onReceive()。 -
为什么不建议用广播做应用内状态总线?
广播是系统级事件分发机制,存在生命周期、权限、调度、后台限制和性能成本。进程内状态用 Flow、Repository、回调或导航结果更直接、更可测。
总结
BroadcastReceiver 的核心模型可以压缩成四句话:
- 它是短生命周期事件回调,不是后台任务执行器。
- 静态注册用于少数需要系统唤醒的场景,Android 8.0+ 对 manifest 隐式广播有限制。
- 动态注册用于运行时作用域,Android 13/14 后要认真选择 exported flag。
- 源码层面,广播由 system_server 排队、记录状态、跨 Binder 回到应用进程,
onReceive()默认主线程且必须快速完成。
工程上最稳的实践是:默认动态注册、默认 RECEIVER_NOT_EXPORTED、默认快速返回;只有在明确需要系统唤醒或跨应用通信时,才扩大注册范围和导出面。
扩展阅读
- Android Developers: Broadcasts overview
developer.android.com/develop/bac... - Android Developers: Implicit broadcast exceptions
developer.android.com/develop/bac... - Android Developers: Android 14 behavior changes - runtime-registered broadcasts receivers must specify export behavior
developer.android.com/about/versi... - Android Developers: Android 13 features - safer exporting of context-registered receivers
developer.android.com/about/versi... - Android API Reference:
BroadcastReceiver
developer.android.com/reference/a... - Android API Reference:
Context.registerReceiver()and receiver flags
developer.android.com/reference/a... - AOSP:
frameworks/base/core/java/android/content/BroadcastReceiver.java
android.googlesource.com/platform/fr... - AOSP:
frameworks/base/core/java/android/app/ContextImpl.java
android.googlesource.com/platform/fr... - AOSP:
frameworks/base/core/java/android/app/LoadedApk.java
android.googlesource.com/platform/fr... - AOSP:
frameworks/base/core/java/android/app/ActivityThread.java
android.googlesource.com/platform/fr... - AOSP:
frameworks/base/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
android.googlesource.com/platform/fr... - AOSP:
frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java
android.googlesource.com/platform/fr... - 系列上一篇:A024 Service、前台服务与后台限制
- 系列下一篇:A026 ContentProvider 与跨进程数据访问