Android 四大组件(Activity、Service、BroadcastReceiver、ContentProvider)是应用开发的基础。它们的启动、运行和调度均由 AMS(及 ATMS)统一管理,通过 Binder IPC 与 App 进程通信。本文从源码角度系统地分析四大组件各自的工作过程,揭示其跨进程调度的核心机制。
一、Activity 的工作过程
1.1 完整调用链
App 进程: Activity.startActivity() |
1.2 关键 Binder 接口
App 进程 → system_server: IActivityTaskManager.startActivity()(Android 10+)
system_server → App 进程: IApplicationThread.scheduleTransaction()(Android 10+ 统一为 ClientTransaction)
// App 端 AIDL |
1.3 进程不存在时的处理
如果目标 Activity 所在进程尚未启动,AMS 通过 Zygote fork 新进程:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java |
Zygote fork 的流程:
AMS.startProcessLocked() |
1.4 ActivityStarter:启动决策引擎
ActivityStarter 是 Activity 启动流程中最核心的决策类:
// frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java |
二、Service 的工作过程
2.1 startService 调用链
Service 有两种启动方式:startService 和 bindService。这里分析 startService:
App 进程: ContextWrapper.startService() |
2.2 ActiveServices——Service 的管理器
ActiveServices 是 AMS 内部管理所有 Service 的核心类:
// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java |
2.3 ServiceRecord 数据结构
// frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java |
2.4 bindService 与混合生命周期
// bindService 的核心:跨进程传递 IBinder |
三、BroadcastReceiver 的工作过程
3.1 广播注册(registerReceiver)
// App 进程: |
3.2 广播发送(sendBroadcast)
App 进程: Context.sendBroadcast(intent) |
3.3 BroadcastQueue——双队列模型
// frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java |
前台广播队列超时 10 秒,后台广播队列超时 60 秒。如果接收者超时未返回,触发 ANR。
3.4 有序广播 vs 无序广播
无序广播(sendBroadcast):所有接收者同时收到,不能中断。
有序广播(sendOrderedBroadcast):按 priority 排序依次接收,前面的接收者可以通过 abortBroadcast() 截断广播。
3.5 粘性广播(Sticky Broadcast,已废弃)
// Android 5.0 (API 21) 废弃 |
粘性广播在发送后缓存,后续注册的接收者也能收到。但由于安全和内存原因(无限制缓存、任何应用都能读取),Google 在 API 21 废弃了此 API。
四、ContentProvider 的工作过程
4.1 Provider 的发布与获取
ContentProvider 在应用进程启动时(Application.onCreate 之前)就被安装和发布到 AMS:
App 进程启动: |
4.2 ContentProviderHolder——跨进程传输的容器
// frameworks/base/core/java/android/app/ContentProviderHolder.java |
4.3 Transport——Provider 端的 Binder 实现
每个 ContentProvider 在创建时,内部会创建一个 Transport 对象作为 Binder 服务端:
// frameworks/base/core/java/android/content/ContentProvider.java |
4.4 CRUD 操作的完整链路
Client App: |
CursorWindow 的作用:减少跨进程的往返。Provider 端将多行查询结果写入共享内存(ashmem 或 memfd),客户端直接从这个共享区域读取。只有游标移出窗口时(如 moveToPosition 超出已加载行数),才触发新的 Binder IPC 获取下一批数据。
五、四大组件的统一调度框架
Android 10 引入 ClientTransaction 和 ClientLifecycleManager 统一了组件生命周期调度。AMS/ATMS 端构建 ClientTransaction 对象,包含多个 ClientTransactionItem,通过 IApplicationThread.scheduleTransaction() 发送到 App 进程执行。
// frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java |
ClientTransactionItem 的子类:
LaunchActivityItem— 启动 ActivityResumeActivityItem— Resume ActivityPauseActivityItem— Pause ActivityStopActivityItem— Stop ActivityDestroyActivityItem— Destroy ActivityNewIntentItem— 处理新 Intent(onNewIntent)ActivityConfigurationChangeItem— 配置变更
这背后的设计思想是:系统不应该直接告诉 App “你该到某状态了”,而是发送一组事务项,App 进程根据自身状态和事务项计算出最终状态并执行过渡。这减少了 App 端生命周期处理的复杂度。
六、进程优先级与回收顺序
Android 的 LMK(Low Memory Killer / lmkd)按以下优先级回收进程:
| 优先级(oom_adj) | 说明 | 典型进程 |
|---|---|---|
| -1000 | 系统进程 | system_server |
| -900 ~ -800 | 持久化系统进程 | PhoneApp, NFC |
| 0 | 前台进程 | 正在交互的 Activity |
| 100 | 可见进程 | 被 Dialog 覆盖的 Activity |
| 200 | 可感知进程 | 运行前台 Service |
| 300 | 服务进程 | 运行后台 Service |
| 700 | 缓存进程(上层) | 不可见但所需 Activity 仍在栈中 |
| 900 | 缓存进程(底层) | 空进程、finish 的 Activity |
| 906 | 缓存进程(终结) | 最快被 LMK 杀死的进程 |
| 1000 | 已标记要杀死的进程 | 待回收 |
七、核心面试题
Q1:为什么 ContentProvider 的 onCreate 在 Application 的 onCreate 之前执行?
这是 Android 的设计约定。ContentProvider 可能被其他应用在 Application.onCreate 之前通过 getContentResolver().query() 访问。为了保证 ContentProvider 随时可用,系统在 Application.onCreate 之前就初始化了本进程声明的所有 ContentProvider。这对应用的启动性能有显著影响——如果定义了多个 Provider,每个 Provider 的 onCreate 都执行完后才轮到 Application.onCreate。这就是为什么 Firebase 等 SDK 的初始化从 ContentProvider 迁移到了其他方式(如 App Startup 库)。
Q2:有序广播和无序广播在系统实现层面最大的区别是什么?
在 AMS 端,无序广播对应的 BroadcastRecord 放入 mParallelBroadcasts 列表,一次性对所有匹配接收者发送。有序广播则放入 mOrderedBroadcasts 链表,依次发送给每个接收者,需要等待前一个接收者完成(BroadcastReceiver.goAsync() 或 onReceive() 返回)后才发送给下一个。这个”等待”机制通过 BroadcastQueue.processNextBroadcast() 的循环实现——每次收到接收者的完成通知后才调用 processNextBroadcast() 继续分发。
Q3:startService 和 bindService 混用时,Service 的生命周期遵循什么规则?
当同时调用 startService 和 bindService 时,Service 的停止需要同时满足两个条件:调用了 stopService(或 stopSelf)且所有绑定都已解除。具体表现为:startService 使 Service 进入 started 状态(onStartCommand 回调),bindService 使 Service 进入 bound 状态(onBind 回调)。只有当 stopService 被调用且 unbindService 全部完成后,onDestroy 才会被调用。
Q4:ClientTransaction 统一调度相比 Android 9 之前的独立 Binder 调用有什么优势?
(1) 原子性:多个生命周期回调可以打包为一个事务,减少 Binder 往返次数。(2) 一致性:系统端构建事务后发送,App 端按事务描述执行——而不是系统端逐条发送指令,App 被动响应。(3) 可组合性:事务中可以灵活组合 callbacks 和最终状态请求,支持复杂的生命周期路径(如 Pause → Stop → Destroy 合并为一次事务)。(4) 代码清晰度:所有生命周期指令统一为一个入口(scheduleTransaction),而非分散在多个 AIDL 方法中。
Q5:Cursor 跨进程传输为什么使用 CursorWindow 而不是逐行 Binder 传递?
CursorWindow 使用共享内存(ashmem/memfd)传递查询结果,客户端的 cursor moveToNext 操作直接读取共享内存中的数据,无需 Binder IPC。如果逐行通过 Binder 传递,1000 行结果需要 1000 次 Binder 调用,每次至少一次上下文切换。而 CursorWindow 只需一次 Binder 调用传输 file descriptor,后续所有 cursor 操作都是在本地内存中完成,性能差异巨大(毫秒 vs 秒)。
6.1 静态广播接收者的注册时机
静态广播(在 AndroidManifest 中声明的 <receiver>)不需要运行时 registerReceiver。它们在 PKMS 扫描 APK 时被注册。注册流程:
PKMS 扫描 AndroidManifest |
但从 Android 8.0 开始,大部分隐式广播不再发给静态接收者(Google 限制以减少后台进程唤醒)。仅少数白名单广播(如 BOOT_COMPLETED、LOCALE_CHANGED)依然对静态接收者生效。
6.2 goAsync() 机制详解
BroadcastReceiver.goAsync() 允许接收者在 onReceive 返回后继续处理广播:
public class MyReceiver extends BroadcastReceiver { |
goAsync() 返回的 PendingResult 包含一个 Binder token,AMS 通过这个 token 跟踪广播处理进度。如果 finish() 未在超时(前台 10 秒/后台 60 秒)内调用,AMS 触发 ANR。
6.3 前台 Service 的限制演进
Android 8.0 (API 26) 引入了前台 Service 的通知要求,后续版本持续收紧:
- Android 8.0:startForegroundService() + 必须 5 秒内调用 startForeground(id, notification)
- Android 9.0:需要 FOREGROUND_SERVICE 权限
- **Android 10+**:后台启动前台 Service 受限(BOOT_COMPLETED 后不可用)
- **Android 12+**:前台 Service 启动更受限制,新增
foregroundServiceType声明(如 location、camera、microphone) - **Android 14+**:进一步要求前台 Service 必须有可见的用户界面或持续通知
这些限制通过 AMS 在 startServiceLocked 中检查,不满足条件则抛出 SecurityException 或 ForegroundServiceDidNotStartInTimeException。
AOSP 核心路径参考:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaframeworks/base/services/core/java/com/android/server/am/ActiveServices.javaframeworks/base/services/core/java/com/android/server/am/BroadcastQueue.javaframeworks/base/services/core/java/com/android/server/am/ContentProviderRecord.javaframeworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.javaframeworks/base/services/core/java/com/android/server/wm/ActivityStarter.javaframeworks/base/core/java/android/app/ActivityThread.javaframeworks/base/core/java/android/app/ContextImpl.javaframeworks/base/core/java/android/content/ContentProvider.javaframeworks/base/core/java/android/app/servertransaction/ClientTransaction.java







