2. AMS核心类与数据结构解析:ActivityRecord、TaskRecord、ProcessRecord

ActivityManagerService(AMS)作为Android框架中管理Activity生命周期的核心服务,其内部数据结构的组织方式直接影响任务的调度、进程的分配以及用户交互的流畅性。本章深入剖析三个最关键的类:ActivityRecord(Activity记录)、TaskRecord(任务栈记录)和ProcessRecord(进程记录),理解它们之间的关联关系是定制AMS行为的基础。

学习前提:本章假设读者已具备Android四大组件基本认知,了解Activity的启动模式(Standard、SingleTop、SingleTask、SingleInstance)。建议在阅读前快速回顾第一章:AMS整体架构与启动流程。

2.1 三个核心类的角色与职责

AMS内部通过三大记录类来维护系统状态:

  • ActivityRecord:描述一个具体的Activity实例,包含其标识、状态、所属进程、所在任务栈等信息。
  • TaskRecord:描述一个任务(Task)的集合,即一组有顺序关系的Activity栈(通常称为“返回栈”)。每个TaskRecord维护一个ArrayList<ActivityRecord>作为其成员栈。
  • ProcessRecord:描述一个正在运行的Android应用进程,包含进程ID、UID、运行的Activity列表、服务列表、广播接收器等。

它们之间的关系可以用一句话概括:一个ProcessRecord可以包含多个TaskRecord;一个TaskRecord可以包含多个ActivityRecord;一个ActivityRecord只能属于一个TaskRecord,且运行在一个ProcessRecord中。

关键工程视角:在AMS定制场景中(如修改任务栈策略、冻结后台进程、调整启动模式),绝大多数改动都会直接操作这三个类的成员变量及其交叉引用。因此,对字段的深入理解是避免内存泄漏、死锁或状态不一致的前提。

2.2 关键字段速查表

以下表格列出各记录类的核心字段及其在生产环境中的典型值范围或作用。定制AMS时,这些字段是Hook或拦截的常见目标。

类名 字段名 类型 说明
ActivityRecord int userId int 所属用户ID(多用户场景)
Intent intent Intent 启动该Activity的原始Intent,包含action/data
ActivityInfo info ActivityInfo 从PackageManager解析得到的Activity元信息(主题、启动模式、TaskAffinity等)
ProcessRecord app ProcessRecord 当前运行该Activity的进程记录;若为空表示尚未附加到进程
TaskRecord task TaskRecord 所属的任务栈记录
TaskRecord int taskId int 全局唯一的任务ID(由TaskPersister分配)
String affinity String 任务亲和性字符串,通常与taskAffinity属性一致
ArrayList<ActivityRecord> mActivities ArrayList 任务栈内所有ActivityRecord的有序列表(栈底到栈顶)
int mCallingUid int 该任务创建者的UID,用于权限检查
ProcessRecord int pid int 进程PID
int uid int 应用UID
ArrayList<ActivityRecord> activities ArrayList 该进程中所有已启动的ActivityRecord(不管属于哪个Task)
int curProcState int 当前进程状态(如PROCESS_STATE_TOP、PROCESS_STATE_BOUND_FOREGROUND_SERVICE等)

2.3 三者关联关系图

下方SVG展示了AMS中三条核心记录类的实例化关系以及它们与系统全局对象(如ActivityStackSupervisor/ActivityStack)的协作。注意每个ProcessRecord可挂多个TaskRecord,每个TaskRecord可挂多个ActivityRecord,并且ActivityRecord自身持有对所在TaskRecord和ProcessRecord的引用。

AMS核心类关联关系图 ActivityRecord · TaskRecord · ProcessRecord 关联关系 ProcessRecord pid: 10234 uid: 10123 activities: [活动列表] curProcState: TOP (持有TaskRecord引用) TaskRecord taskId: 3 affinity: “:task1” mActivities: [AR1, AR2] mCallingUid: 10123 (持有ActivityRecord列表) ActivityRecord intent: MainActivity task: TaskRecord#3 app: ProcessRecord ActivityRecord intent: SecondActivity task: TaskRecord#3 app: ProcessRecord 1 N 1 N app 引用 task 引用 说明:虚线表示反向引用,ActivityRecord 同时持有所在 TaskRecord 和 ProcessRecord 的强引用。 AMS 通过 ActivityStackSupervisor 管理所有 TaskRecord;ActivityStack 负责特定显示区域的栈操作。

2.4 关键源码片段分析

以下是从Android 14(API 34)源码中摘录的三个类的精简定义,重点关注字段声明和构造逻辑。注意,为了定制方便,我们常常需要直接操作这些字段(例如通过反射或Binder拦截)。

2.4.1 ActivityRecord 核心构造

// frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
public class ActivityRecord extends  {
    final int userId;
    final Intent intent;
    final ActivityInfo info;
    final int launchMode;  // 直接从 ActivityInfo 解析

    // 运行时关联
    ProcessRecord app;
    TaskRecord task;
    boolean visible;    // 当前是否可见
    int state;          // 生命周期状态

    public ActivityRecord(…, ActivityManagerService _service, Intent _intent,
                           ActivityInfo _info, …) {
        userId = _intent.getUserId();
        intent = _intent;
        info = _info;
        launchMode = info.launchMode;
        // ...
    }
}

2.4.2 TaskRecord 核心构造

// frameworks/base/services/core/java/com/android/server/wm/TaskRecord.java
public class TaskRecord {
    final int taskId;
    final String affinity;
    final ArrayList<ActivityRecord> mActivities;
    int mCallingUid;
    int mCallingPid;

    // 构造函数由 ActivityStackSupervisor 调用
    public TaskRecord(..., int _taskId, String _affinity, ...) {
        taskId = _taskId;
        affinity = _affinity;
        mActivities = new ArrayList<>();
        // ...
    }
}

2.4.3 ProcessRecord 核心构造

// frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
public class ProcessRecord {
    final int pid;
    final int uid;
    final String processName;
    ArrayList<ActivityRecord> activities;         // 当前进程的所有Activity
    ArrayList<ServiceRecord> services;
    int curProcState;                              // 当前调度优先级

    public ProcessRecord(..., ApplicationInfo _info, String _processName, int _uid) {
        pid = -1;  // 启动后由系统分配
        uid = _uid;
        processName = _processName;
        activities = new ArrayList<>();
        services = new ArrayList<>();
        curProcState = PROCESS_STATE_IMPORTANT_BACKGROUND;
        // ...
    }
}
定制陷阱提示:直接修改 ActivityRecord.app 或 TaskRecord.mActivities 字段时,必须注意线程安全——AMS核心方法运行在 ActivityManagerService.mHandler 线程。如果是在Binder调用线程中修改,需要通过 mHandler.post() 或 synchronized(mService) 保证一致性。错误操作会导致 IndexOutOfBoundsException 或 NullPointerException,严重时引发SystemServer无响应(ANR)。

2.5 组件关联生命周期示例

以一个常见场景为例:用户从桌面点击应用图标,依次启动Activity A、B,然后按返回键回到桌面。下表展示关键时刻三个记录对象的变化:

时刻 ProcessRecord TaskRecord ActivityRecord列表
1. 启动A 新进程创建,pid=1234,activities=[AR_A] 新任务taskId=5,mActivities=[AR_A] AR_A.app=ProcessRecord#1234, AR_A.task=TaskRecord#5
2. 启动B activities=[AR_A, AR_B] mActivities=[AR_A, AR_B] AR_B.app=ProcessRecord#1234, AR_B.task=TaskRecord#5
3. 按返回键B→A activities=[AR_A](B被移除) mActivities=[AR_A] AR_B被finish,app=null,task=null
4. 返回桌面 curProcState变为PROCESS_STATE_TOP_SLEEPING TaskRecord#5仍存在(未销毁) AR_A状态变为STOPPED

2.6 常见定制切入点

基于以上数据结构,以下列出AMS定制中常见的修改目标及对应的类字段:

  • 调整Activity启动规则:重写ActivityRecord.shouldBeVisible() 或修改launchMode解析逻辑。
  • 修改任务栈行为:在TaskRecord.addActivityAtTop() 中插入自定义栈策略(如限制最大深度、强制SingleTop)。
  • 进程优先级管控:通过ProcessRecord.curProcState 的阈值调整,在内存压力下快速降低后台进程权重。
  • 多用户/多显示场景:利用ActivityRecord.userId 和TaskRecord.affinity 实现用户隔离或跨屏拖拽。
进阶建议:实际定制AMS时,推荐优先阅读ActivityStackSupervisor.java 中的startActivityLocked() 方法,该方法同时操纵三个记录类,是理解三者交互流程的最佳入口。后续章节(第4~6章)将基于此处展开具体的定制代码实战。