3. AMS核心数据结构

3.1 模块边界与层次划分

AMS 对 Android 四大组件的管理依赖四个核心数据对象,它们构成了从“进程 → 栈 → 任务 → 活动”的逐层嵌套关系。以下表格定义了各对象的职能范围与生命周期归属:

数据结构所属层级实例化时机销毁时机关键标识
ProcessRecord进程级应用进程创建/绑定进程死亡或被杀pid, processName
ActivityStack显示级系统启动/创建多屏幕栈栈被移除或销毁stackId, mStackState
TaskRecord任务级启动 Activity(新任务)任务内 Activity 全部 finishtaskId, affinity
ActivityRecord活动级每次启动/恢复 ActivityActivity 完全销毁intent, activityType
层次边界要点:一个 ProcessRecord 可绑定多个 ActivityRecord(同一进程内的 Activity);但 ActivityStack 是 UI 显示容器,一个栈内可以有多个 TaskRecord,每个任务又包含多个 ActivityRecord。跨进程的 Activity 通过 Binder 通信,数据对象本身不持有对方进程的引用。

3.2 核心组件职责

3.2.1 ProcessRecord —— 进程生命周期的“护照”

ProcessRecord 记录一个 Android 应用进程的所有元信息,包括 pid / uid、已注册的 BroadcastReceiver、正在运行的服务列表、LRU 排名等。AMS 通过它判断进程的“重要程度”以执行 LMK(Low Memory Killer)策略。

其关键字段在源码中可视为:

// 简化后的 ProcessRecord 核心成员
public final class ProcessRecord {
    final String processName;   // 进程名
    int pid;                    // 进程 ID
    int uid;                    // 用户 ID
    boolean killed;             // 是否已杀
    final ArrayList<ActivityRecord> activities;  // 该进程下的 Activity 列表
    final ArrayList<ServiceRecord> services;     // 已注册的服务
    final ProcessStateRecord state;              // 进程状态
}

3.2.2 ActivityStack —— 显示器抽象的“栈容器”

每个物理显示器(或虚拟屏幕)对应一个 ActivityStack,负责管理该屏幕上的所有 TaskRecord 栈。Stack 提供 resumeTopActivityInnerLocked() 核心方法,决定哪个 Activity 获得焦点。栈分为全屏栈、分屏栈、自由窗口栈等类型,每个类型有不同的布局策略。

设计权衡:ActivityStack 将 UI 层次与任务逻辑解耦,但多栈模型导致焦点切换逻辑复杂度上升(例如手势导航在分屏模式下需要跨栈判断)。Android 10 之后引入的 DisplayContent 进一步包裹了多个 Stack,形成“Display → Stack → Task → Activity”的四层结构。

3.2.3 TaskRecord —— 用户任务的“活动历史链”

TaskRecord 维护一个 ActivityRecord 的链表(mActivities),按启动顺序排列。它负责返回栈(back stack)的导航逻辑,决定按 Back 键时回到哪个 Activity。每个 TaskRecord 还有自己的 affinity、launchMode、taskId,用于匹配 Intent 的 FLAG_ACTIVITY_NEW_TASK 行为。

3.2.4 ActivityRecord —— Activity 实例的“身份证”

每个 Activity 在 AMS 中唯一对应一个 ActivityRecord,持有 Intent、launchMode、processName、状态(initialized→resumed→paused→stopped→destroyed)等。它是 AMS 与 WMS 交互的最小单元,所有生命周期回调(onCreate/onResume…)都通过它触发。

3.3 数据流 / 控制流 / 信任链路

一次 Activity 的启动请求(例如从 Launcher 点击图标)会依次经过:

  1. Launcher 进程向 AMS 发送 startActivity() Binder 调用
  2. AMS 根据 Intent 解析目标 ActivityRecord,查找或创建 TaskRecord
  3. 确定 TaskRecord 所属的 ActivityStack(当前焦点栈或指定栈)
  4. 通过 ProcessRecord 判断目标进程是否已启动,若未启动则 fork 新进程
  5. 新进程初始化后,AMS 通过 ApplicationThread 回调 ActivityThread 创建 Activity 实例

以下 SVG 图展示了四者在一次启动流程中的关系与数据流向:

AMS 核心数据结构关系与启动控制流 AMS 调度器 ProcessRecord ActivityStack TaskRecord ActivityRecord 包含 链式包含 拥有 控制流关键路径 ① AMS 收到 startActivity → ② 确定目标 ActivityRecord ③ 通过 ActivityStack 找到所属 TaskRecord → ④ 绑定到对应 ProcessRecord ⑤ AMS 回调 ActivityThread 创建实际 Activity 实例
信任链路分析:Binder 调用经过 AMS 的 ActivityManagerService.startActivity() 时,必须持有全局锁(mServiceLock)才能修改这些数据结构。启动链中每个环节都需验证 caller 的权限(如 ACTIVITY_NEW_TASK 标志是否合法),信任边界从 SystemServer 进程延伸至目标进程的 ApplicationThread。

3.4 设计权衡

  • ActivityRecord 粒度 vs 内存开销:每个 Activity 实例都维系一个完整的状态机对象,在低端设备上大量 Activity 回退栈会导致内存暴涨。Android 12 引入的 ActivityRecordPersistent 优化了冷启动恢复场景,但未改变核心设计。
  • ActivityStack 多栈 vs 焦点管理:多窗口、多显示器场景需要多个栈共存,但焦点栈的切换逻辑必须兼顾动画、输入法、窗口层级,这些逻辑全部集中在 ActivityStackSupervisor 中,导致单点复杂度。
  • TaskRecord 的 affinity 爆炸:每个应用可以声明多个 affinity,AMS 需要匹配 Intent 的 taskAffinity 和栈顶 Activity 的 affinity,这种匹配在多任务启动时可能引起 O(n²) 遍历查找。工程上通过 mTaskHistory 哈希表缓解,但嵌套启动场景仍存在性能风险。

3.5 风险点

风险场景涉及数据结构后果防范措施
进程被 LMK 杀掉后 ActivityRecord 残留ProcessRecord, ActivityRecordActivity 无法恢复,界面白屏AMS 在进程死亡时调用 cleanUpApplicationRecordLocked() 清理关联的 ActivityRecord
栈顶 Activity 被意外关闭导致 TaskRecord 空栈TaskRecord, ActivityStack返回栈断裂,用户无法返回AMS 在移除最后一个 ActivityRecord 时同时移除整个 TaskRecord
多用户场景下 ActivityStack 混淆ActivityStack显示异常(例如副用户界面出现在主用户)按 userId 隔离 stack 创建,StackId 包含用户标识
ActivityRecord 的 state 被异步并发修改ActivityRecord生命周期错乱,crash必须持有 mServiceLock 单线程修改,内部使用事务计数器保证一致性

3.6 落地步骤(面向系统开发者的理解路径)

  1. 从源码 trace 入手:在 ActivityManagerService.java 中搜索 new ActivityRecord( 和 new TaskRecord(,观察构造参数,理解各字段来源。
  2. 调试启动流程:使用 adb shell dumpsys activity activities 实时查看当前栈中 ActivityRecord 的 taskId 和 stackId,与源码对照。
  3. 手动构造分屏场景:通过 ADB 启动两个应用并进入分屏模式,抓取 dumpsys activity stack 确认 ActivityStack 新增实例,观察 TaskRecord 被复用的次数。
  4. 实现自定义 LaunchMode 验证:编写一个测试 App,设置 singleInstance 或 singleTask,在 AMS 关键路径日志中跟踪 ProcessRecord 的 activities 列表变化。
  5. 压力测试多任务:使用 MonkeyRunner 快速启动 100 个 Activity,观察 AMS heap 中 ActivityRecord 和 TaskRecord 的数量与 GC 频率。

3.7 验收标准

  • ✅ 能准确画出 ProcessRecord / ActivityStack / TaskRecord / ActivityRecord 之间的 UML 关联(组合 vs 聚合)关系。
  • ✅ 通过 dumpsys 输出的栈信息,可反向推断出当前前台 Activity 的 ProcessRecord pid 和所属 TaskRecord taskId。
  • ✅ 在一个模拟的 AMS 环境中,成功插入一条新的 ActivityRecord 到指定 TaskRecord 并触发其 Resume 状态,而不引发死锁或空指针。
  • ✅ 针对上述风险点表,针对每一条给出至少一种可复现的测试用例(如通过 ADB 模拟进程被杀)。
下一步学习建议:理解这四个核心数据结构后,可以深入分析 “ActivityStackSupervisor” 是如何协调多个 ActivityStack 的焦点切换以及如何与 WindowManagerService 通信布局窗口。第 4 章将解剖 AMS 的启动流程全过程。