AMS 与 ATMS 的区别解析

自 Android 10 (API 29) 开始,Google 对原本庞大的 ActivityManagerService (AMS) 进行了结构性重构,将其核心的 Activity 管理职能抽离出来,成立了 ActivityTaskManagerService (ATMS)。

1. 为什么要进行拆分?

在早期的 Android 版本中,AMS 承载了太多的职责。这种“巨石”设计导致了严重的工程问题:

核心痛点 详细解析与举例
代码耦合严重 现象:Activity 栈管理逻辑与广播分发逻辑共用同一个线程/锁。
举例:在计算复杂的 Task 切换(如分屏模式下的 Activity 移动)时,如果逻辑出错产生死锁或耗时过长,会直接阻塞同一进程内的广播分发 Handler,导致无关的广播接收者出现 ANR。
职责不清晰 现象:WMS 需要频繁跨模块获取 Activity 状态。
举例:WMS 在准备窗口切换动画时,必须知道 Activity 是否可见。旧版 WMS 需通过繁琐的 IPC 调用 AMS 的 ActivityRecord 状态,这不仅产生了大量的跨模块冗余代码,还增加了同步状态时的延迟。拆分后,ATMS 与 WMS 深度融合,共同管理 WindowContainer 层级结构。
维护成本极高 现象:单文件行数爆炸,合并冲突不断。
举例ActivityManagerService.java 的源码量曾一度突破 30,000 行。开发者 A 在修复 Service 粘性启动的 Bug,开发者 B 在优化 Activity 的启动速度,由于两人都在操作同一个文件,导致每次版本合并时都会产生极其复杂的代码冲突。

核心管理对象:Record 体系

为了实现职责分离,AMS 与 ATMS 分别维护了不同的核心数据对象:

对象名称 所属服务 核心职责
ProcessRecord AMS 进程管家。描述一个应用进程的实体,记录了进程的 PID、UID、包含的组件(Service, Receiver)、进程优先级(Adj)以及内存状态。AMS 通过它来决定系统内存不足时该“杀掉”哪个进程。
ActivityRecord ATMS Activity 档案。描述一个 Activity 实例的最小单位。记录了 Intent、所属 Task、状态(Resumed, Paused 等)、对应的 WindowToken。它与应用端的 Activity 实例一一对应。
TaskRecord ATMS 任务容器。描述一个“最近任务”或“任务栈”。管理一组相关的 ActivityRecord,决定了 Activity 的回退顺序(LIFO,后进先出)以及在多窗口模式下的显示分组。

2. AMS vs ATMS 职责对比

维度 ActivityManagerService (AMS) ActivityTaskManagerService (ATMS)
核心职责 管理应用生命周期(进程、四大组件中的后三者)。 专门管理 Activity 及其容器(Task, Stack, Display)。
组件管理 Service, BroadcastReceiver, ContentProvider。 Activity 启动、生命周期、Task 切换。
进程管理 负责 OOM Adjuster、进程启动与回收。 不直接参与进程管理。
交互对象 主要与 ProcessRecord 交互。 主要与 ActivityRecordTaskRecord 交互。
WMS 关系 间接交互。 强绑定。与 WMS 共同管理窗口 and Activity。

3. 架构演进的关键点

3.1 跨进程通信的变化

  • Android 9 以前:App -> AMS (startActivity)。
  • Android 10 以后:App -> ATMS (startActivity)。

3.2 内部协作流程

  1. ATMS 负责判断 Activity 应该在哪个 Task 启动,并管理其生命周期状态。
  2. 当需要启动一个新的进程来承载 Activity 时,ATMS 会回调 AMSstartProcessAsync 方法。
  3. AMS 负责与 Zygote 通信并完成进程的创建。

4. 总结:一句话区分

  • ATMS 是“Activity 管家”:只关心 Activity 怎么跳、怎么显示、怎么分组。
  • AMS 是“应用管家”:关心进程还在不在、Service 跑没跑、广播发没发。

这种拆分使得 Android 系统在支持 多窗口模式 (Multi-Window)折叠屏 (Foldables) 时,逻辑更加清晰和独立。

Handler 与 ActivityThread 的协作机制

在 AMS 管理 Activity 生命周期的过程中,Handler 扮演了“线程切换器”的关键角色。理解 ActivityThread 如何通过 Handler 接收并执行来自 AMS 的指令,是掌握 Framework 通信模型的核心。

1. 协作模型:从 Binder 线程到主线程

AMS 运行在 system_server 进程中,通过 IApplicationThread (Binder 接口) 向应用进程发送指令。

步骤 运行环境 执行动作
1. 跨进程调用 Binder 线程池 应用进程收到 AMS 的 Binder 调用(如 scheduleTransaction)。
2. 线程切换 Handler 发送消息 Binder 线程不直接操作 UI,而是将任务通过 H (Handler) 发送到主线程。
3. 消息排队 MessageQueue 任务作为 Message 进入主线程的消息队列,遵循优先级排序。
4. 执行任务 主线程 (Looper) Looper 取出消息并回调 handleMessage,最终执行 Activity 的生命周期。

2. ActivityThread 内部的管家:类 H

ActivityThread 源码中,定义了一个内部类 H,它继承自 Handler。它是应用进程中最重要的消息处理中心。

核心消息常量 (Message Type) 对应场景
EXECUTE_TRANSACTION Android 9.0+ 引入,统一处理绝大多数生命周期事务(Start, Resume 等)。
BIND_APPLICATION 应用进程启动后的初始化指令。
EXIT_APPLICATION 请求应用退出。
RECEIVER 广播处理指令。
1
2
3
4
5
6
7
8
9
10
11
12
// ActivityThread.java 中的内部类 H
class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
// ... 其他消息处理
}
}
}

3. 同步屏障 (Sync Barrier) 在 AMS 场景下的应用

当 AMS 请求启动一个 Activity 或执行渲染任务时,为了保证 UI 能够以 60fps/120fps 的频率流畅刷新,系统会使用同步屏障机制。

概念 作用机制 在 AMS 场景的应用
插入屏障 MessageQueue 头部插入一个 target 为空的特殊消息。 Choreographer 接收到 VSync 信号,或者 AMS 触发界面刷新时发送。
优先异步 此时 Looper 会跳过普通消息,只执行标记为 isAsynchronous 的消息。 确保 UI 绘制任务、某些关键生命周期事务不会被队列中积压的普通消息(如日志、数据上报)阻塞。
移除屏障 渲染完成后移除,恢复普通消息的处理。 保证系统吞吐量与 UI 流畅度的平衡。

4. 总结:为什么要通过 Handler?

  1. 线程安全:Android 的 UI 控件是非线程安全的,必须保证所有对 Activity 状态的修改都在主线程完成。
  2. 异步缓冲:AMS 往往是“发后即忘”的异步调用。Handler 提供的消息队列可以缓冲来自系统的密集请求,防止应用进程因瞬间过载而崩溃。
  3. 优先级调度:配合同步屏障,Handler 机制能确保最重要的“显示”任务永远被优先执行。

ActivityThread 接收并处理 AMS 指令全过程

在 Android 的系统架构中,AMS(System Server 进程)与 ActivityThread(应用进程)之间的通信是典型的 C/S 架构。AMS 作为服务端下发指令,ActivityThread 作为客户端接收并执行。

1. 通信架构:Binder 边界

AMS 并不直接持有 ActivityThread 对象,而是通过 IApplicationThread 这一 Binder 接口进行通信。

角色 实现类 物理位置 职责
Binder 服务端 ActivityThread.ApplicationThread 应用进程 继承自 IApplicationThread.Stub,开启 Binder 线程池等待调用。
Binder 代理端 ApplicationThreadProxy System Server 进程 AMS 持有该代理,用于向 App 进程发送指令。

2. 指令接收流程:从 Binder 线程到主线程

当 AMS 发起一个指令(如启动 Activity)时,数据流转如下:

第一步:Binder 线程接收

AMS 调用 app.thread.scheduleTransaction(transaction)。此时,App 进程中的 Binder 线程池 会随机选择一个线程来执行 ApplicationThread 对应的接口方法。

第二步:向主线程分发

由于 Binder 线程不能直接操作 UI 或执行 Activity 生命周期,ApplicationThread 会通过内部类 H(Handler)将任务发送到主线程。

1
2
3
4
5
// ActivityThread.java 内部代码逻辑
public void scheduleTransaction(ClientTransaction transaction) {
// 这里的 this 指向 H (Handler)
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

第三步:主线程消息循环 (Looper)

主线程的 Looper 不断从 MessageQueue 中取出消息。当收到 EXECUTE_TRANSACTION 时,回调 HhandleMessage

第四步:执行具体逻辑

对于生命周期相关的指令,ActivityThread 会委派给 TransactionExecutor 执行,最终调用到 ActivityonCreate/onStart 等方法。


3. 核心处理中心:类 H

ActivityThread 内部维护的 Handler H 是所有系统指令的汇聚点。它处理的消息类型决定了应用的行为。

关键消息 (What) 来源与作用
BIND_APPLICATION AMS 要求进程进行初始化(创建 Application, 加载 Provider)。
EXECUTE_TRANSACTION Android 9.0+ 引入,聚合了几乎所有生命周期回调(Launch, Resume, Stop 等)。
RECEIVER 处理非动态注册的广播接收者。
SERVICE_ARGS 启动或分发 Service 任务。

4. 协作机制总结

关键环节 核心机制 核心目的
跨进程传输 Binder 实现 System Server 与 App 进程的通信边界。
线程切换 Handler (类 H) 将异步的系统指令切换到单线程的 UI 线程执行,确保线程安全。
顺序保证 MessageQueue 确保来自系统的多个指令(如先 Create 后 Resume)按序执行。
事务封装 ClientTransaction 在现代 Android 版本中简化生命周期管理,支持复杂的组合状态切换。

💡 面试要点:

  1. ActivityThread 的主线程循环是什么?
    答:是 Looper.loop(),它不仅处理用户交互,还处理来自 AMS 的所有生命周期指令。
  2. 为什么 ApplicationThread 里的方法不直接改 UI?
    答:因为 ApplicationThread 的方法运行在 Binder 线程 中,而 Android 的 UI 系统是非线程安全的,必须通过 Handler 切换到主线程。
  3. Handler H 的作用?
    答:它是应用进程的“神经中枢”,负责将系统的异步调用同步化到主线程执行。

Activity 启动之栈管理与 LaunchMode 判定

当 Activity 的启动请求进入 ATMS 后,最核心的逻辑就是:这个 Activity 应该放在哪个任务栈(Task)里? 这涉及到对 LaunchMode、Intent Flags 以及 TaskAffinity 的综合判定。

1. 核心角色:ActivityStarter

ActivityStarter 是启动流程中的“决策者”。它负责解析启动参数,并调用 startActivityUnchecked 开始处理栈逻辑。

2. LaunchMode 与 栈分配逻辑表

启动模式 ATMS 的核心逻辑 典型表现
standard 不做检查,直接创建新实例。 每次启动都会压入当前栈顶。
singleTop 检查目标栈顶。若已是该实例,回调 onNewIntent 防止栈顶重复创建。
singleTask 在全局寻找是否存在对应 taskAffinity 的栈。若有则移至前台并清理其上方所有 Activity (Clear Top)。 确保一个任务栈中只有一个实例。
singleInstance 强制创建一个新的任务栈,且该栈只能有这一个实例。 独占一个任务栈(如电话界面)。

3. Intent Flags 的影响

代码中通过 Intent.setFlags() 设置的参数优先级高于 XML 定义。

  • FLAG_ACTIVITY_NEW_TASK:对应 singleTask 的基本行为,寻找或创建新栈。
  • FLAG_ACTIVITY_CLEAR_TOP:如果栈中已存在该实例,销毁其上的所有 Activity。
  • FLAG_ACTIVITY_REORDER_TO_FRONT:将已存在的实例移到栈顶,不销毁中间的 Activity。

4. 栈管理的关键步骤

  1. findTask:根据 taskAffinityFlags 寻找匹配的 TaskRecord
  2. computeStack:确定目标 Activity 应该落在哪个 ActivityStack(在 Android 10+ 主要是 DisplayContent 下的容器)。
  3. resumeFocusedStacksTopActivities:将目标栈移到最前台,准备执行显示逻辑。

5. 调试技巧

使用以下命令可以实时观察栈的变化,这是理解栈管理逻辑的“神技”:

1
adb shell dumpsys activity activities

关注点: 寻找 TaskRecord 节点,查看其内部的 ActivityRecord 列表及其 intent 信息。

Activity 启动之进程创建流程(AMS 与 Zygote 的握手)

在启动 Activity 时,如果 ATMS 发现目标进程(ProcessRecord)不存在,就会触发进程创建流程。这是 Android 系统中典型的“按需启动”机制。

1. 触发点:AMS.startProcessLocked

当 ATMS 判定需要新进程来承载 Activity 时,会跨模块回调 AMS:

1
2
3
4
5
// 核心逻辑简述
if (app == null) {
// 进程不存在,开始启动进程
mService.startProcessLocked(processName, info, ...);
}

2. AMS 与 Zygote 的通信流程表

阶段 核心方法 动作描述
1. 决策 startProcessLocked AMS 确定进程参数(UID, GID, 启动类 ActivityThread)。
2. 发起请求 Process.start 通过 ZygoteProcess 建立与 Zygote 的 Socket 连接。
3. 通信 ZygoteState.connect /dev/socket/zygote 写入启动参数字符串。
4. 孵化 Zygote.fork() Zygote 接收信号,Fork 自身进程(利用 COW 机制)。
5. 诞生 RuntimeInit 子进程初始化运行环境,并抛出 MethodAndArgsCaller 异常以进入 Java 入口。

3. 为什么是 Socket 而不是 Binder?

这是一个经典考点。Zygote 使用 LocalSocket 监听请求而非 Binder,主要是为了规避 Fork 机制与多线程锁冲突 导致的死锁风险。在 fork 瞬间,子进程只会拷贝发起调用的线程,其他线程持有的锁将永远无法在子进程中释放。


4. 子进程的“觉醒”:ActivityThread.main()

fork 成功后,子进程会执行 ActivityThread.main() 方法,这标志着应用主线程正式开始工作:

  1. **Looper.prepareMainLooper()**:初始化主线程消息循环。
  2. attach:跨进程向 AMS 报告:“我启动好了(attachApplication)”。
  3. BIND_APPLICATION:AMS 发回应用配置信息,App 开始创建 Application 实例并调用 onCreate
  4. **Looper.loop()**:主线程进入死循环,开始处理 AMS 发来的生命周期指令(如 LAUNCH_ACTIVITY)。

5. 总结

进程创建是一个“从 C++ 到 Java”的过程,也是“从系统服务到应用代码”的过程。掌握了从 startProcessLockedattachApplication 的闭环,就掌握了 Android 进程管理的精髓。

Android Framework 专项 - WMS 学习路线指南

WindowManagerService (WMS) 是 Android 系统中负责窗口管理的核心服务。与 AMS 相比,WMS 与图形显示、输入系统及 View 系统的交互更为紧密。设计一套科学的 WMS 学习路线,建议遵循“从基础支撑到核心模型,再到显示原理”的原则。


第一阶段:支撑系统(底层依赖知识)

在深入 WMS 源码前,必须掌握 WMS 运行的基础设施。

模块 关键考点 学习目的
SurfaceFlinger 图形缓冲区、Layer、合成原理 理解 WMS 最终的渲染产物是如何被合成并显示的。
Input 系统 IMS、事件分发、InputChannel 理解 WMS 如何协助将点击事件派发到正确的窗口。
View 系统 ViewRootImpl、DecorView、Measure/Layout 理解应用端是如何通过 View 系统与 WMS 建立联系的。

第二阶段:核心模型(窗口的骨架)

WMS 服务端通过一组对象来维护窗口的层级、属性和状态。

核心类 职责描述 对应现实模型
WindowToken 标识一组窗口(如 Activity 下的所有 Window),用于权限和组织。 分组标签
WindowState 服务端对单个窗口的建模,存储大小、位置、可见性等信息。 窗口本体
DisplayContent 对应物理或虚拟屏幕,管理该屏幕下的所有窗口。 整个屏幕
Session 应用进程与 WMS 之间的 Binder 通道,每个进程一个。 通信信道

第三阶段:核心流程(窗口的诞生与消亡)

通过追踪一个 Activity 窗口从无到有的过程,理清 WMS 的运行逻辑。

学习步骤 核心关键点 关注重点
1. 窗口添加 (Add) WindowManagerGlobal -> WMS.addWindow 权限校验、WindowState 创建、Z-Order 分配。
2. 布局计算 (Relayout) WMS.relayoutWindow 窗口框架计算(Frame)、显示区域(Insets)的处理。
3. Surface 分配 WindowSurfaceController 理解 Surface 如何从 WMS 传递到应用进程。
4. 窗口移除 (Remove) removeWindow 状态同步、资源清理、窗口退出动画。

第四阶段:进阶专题(高级显示控制)

了解现代 Android 在复杂显示场景下的处理机制。

进阶专题 核心内容 学习意义
层级管理 (Z-Order) BaseLayer、SubLayer 计算规则。 理解窗口遮挡关系与叠加顺序。
窗口动画 WindowAnimationSpec、Remote Animation。 掌握 App 切换动画及系统动画的底层实现。
多窗口与分屏 TaskStack 组织、多任务焦点管理。 适配大屏、折叠屏等现代设备。
输入法窗口 (IME) IME 窗口的特殊层级与生命周期。 解决输入法遮挡及交互的疑难杂症。

💡 学习建议:

  1. 结合 Winscope 工具:利用 Android 提供的 Winscope 录制并查看窗口层级和 Surface 状态,将抽象代码可视化。
  2. 理解 Insets 机制:现代 Android 窗口管理很大一部分精力在于处理状态栏、导航栏、挖孔屏等带来的 WindowInsets
  3. 分层阅读:WMS 源码逻辑分散在 services 的核心包中,建议从 WindowManagerService.java 入手,先理清 addWindow 这一条主线。

WMS 专项 - 窗口添加流程解析 (AddWindow)

当应用端调用 WindowManager.addView 时,窗口的添加流程正式开启。这是一个跨越应用进程与 WMS 服务端的重要 IPC 过程。

1. 应用端:ViewRootImpl 的建立

WindowManagerGlobal 中,每添加一个窗口都会创建一个对应的 ViewRootImpl。它负责:

  • 触发第一次 requestLayout
  • 通过 mWindowSession.addToDisplay 向 WMS 发起跨进程调用。

2. 服务端:WMS.addWindow 核心逻辑

关键步骤 内部行为 目的
1. 权限与令牌校验 检查 WindowToken 是否合法。 确保如子窗口、Activity 窗口拥有正确的宿主权限。
2. 创建 WindowState 在 WMS 内部为该窗口建立“档案”。 存储窗口的所有几何属性、标志位及父子关系。
3. Z-Order 计算 根据 WindowType 分配显示层级。 决定窗口在垂直方向上谁盖住谁。
4. 关联 Session 将窗口与发起进程的 Session 绑定。 便于后续的 IPC 通信与异常清理。

3. 核心对象关系图

App 进程 (ViewRootImpl) <— IWindowSession (Binder) —> SystemServer (WMS)

  • WMS 持有 WindowToken (管理组)
  • WindowToken 包含多个 WindowState (管理个体)

WMS 核心概念与窗口管理流程

WindowManagerService (WMS) 是 Android 系统中负责窗口 management 的核心服务。它主要处理窗口的布局、显示次序、窗口动画以及输入事件的派发。

1. WMS 的职责

WMS 的主要工作可以概括为以下四个核心领域:

职责领域 核心功能描述
窗口管理 控制窗口的添加、删除、更新,并维护窗口的层级(Z-Order)关系。
窗口布局 根据窗口属性(LayoutParams)动态计算每个窗口在屏幕上的大小和位置。
输入事件中转 作为输入系统的中间站,协助 InputManagerService 将触控等事件派发给正确的窗口。
动画与渲染 管理窗口切换动画,并与 SurfaceFlinger 协作完成最终屏幕内容的渲染绘制。

2. 核心类解析

理解 WMS 的源码,必须先搞清楚这几个核心类及其职责:

核心类 职责描述
Window (PhoneWindow) 屏幕窗口的抽象,承载了 ViewTree 及 DecorView。
WindowManager 应用端操作窗口的入口,负责与 WMS 通信。
WMS 服务端核心,负责全局窗口调度、布局、动画及输入分发。
Session 应用进程与 WMS 通信的单向 Binder 通道。
WindowState WMS 服务端窗口实体,存储了窗口的几何属性及状态信息。
WindowToken 窗口令牌,用于标识和组织一组相关的窗口(如 Activity 的所有窗口)。

3. 窗口的层级管理 (Z-Order)

WMS 使用 WindowType 来区分窗口的层级。层级越高,显示在越上层:

窗口类型 层级范围 (Z-Order) 典型示例 备注
应用窗口 1 - 99 Activity 窗口 基础窗口类型
子窗口 1000 - 1999 PopupWindow, Dialog 必须依附于父窗口
系统窗口 2000 - 2999 StatusBar, Toast, Alert 通常需要特定系统权限

4. 窗口添加流程简述

当我们在 Activity 中调用 setContentView 后,窗口诞生的核心步骤如下:

关键步骤 执行角色 核心行为
创建核心纽带 ViewRootImpl 创建实例,作为连接 WindowManager 与 DecorView 的纽带。
发起布局请求 应用进程 调用 requestLayout 触发视图树的测量、布局与绘制流程。
跨进程添加 WMS 通过 IWindowSession 发起 IPC,在服务端创建 WindowState 并分配显示层级。

5. 接下来我们将深入探讨

  • WMS 的启动流程
  • Surface 的创建与渲染链路
  • WMS 动画框架解析

WMS 专项 - 窗口布局与 Relayout 机制

窗口添加后,其大小和位置并非一成不变。每当窗口属性变化、输入法弹出或屏幕旋转时,都会触发 relayoutWindow

1. 什么是 Relayout?

relayout 是 WMS 及其客户端(应用进程)最频繁的交互点。它主要完成:

  • 尺寸计算:WMS 根据屏幕大小、Insets(状态栏等占位)计算窗口的最终 Frame。
  • 配置同步:将最新的 Configuration(如横竖屏、语言)同步给应用。
  • Surface 状态变更:控制 Surface 的显示、隐藏或尺寸调整。

2. 核心算法:窗口框架 (Frame) 计算

框架术语 含义描述
parentFrame 父容器(如 Display 或包含它的 Task)给出的参考范围。
displayFrame 窗口在当前屏幕中的可用范围。
contentFrame 扣除状态栏、导航栏等装饰后,真正用于显示内容的范围。
finalFrame 经过 WMS 策略计算后,窗口最终在屏幕上的物理坐标。

3. Insets 机制(现代 Android 重点)

现代 Android 不再简单地减去状态栏高度,而是使用 WindowInsets 机制。WMS 负责计算这些 Insets(如键盘、手势区域)并将其分发给 View 系统,从而实现沉浸式状态栏或避让输入法。

WMS 专项 - Surface 创建与渲染链路

WMS 不仅管理窗口逻辑,还是图形渲染的“中转站”。它协助应用获取绘制所需的画布 —— Surface

1. Surface 的本质

在 Android 中,Surface 对应 SurfaceFlinger 中的一个 Layer。它本质上是一块图形缓冲区队列(BufferQueue)的生产者端。

2. 创建流程:从 WMS 到 SurfaceFlinger

角色 执行动作
应用进程 relayout 请求中设置 SURFACE_CREATING 标志。
WMS 调用 WindowSurfaceController 开始创建流程。
SurfaceControl WMS 与 Native 层的桥梁,向 SurfaceFlinger 申请创建 Layer。
SurfaceFlinger 分配内存缓冲区,并返回句柄。

3. 渲染“三步走”

  1. **申请 (Lock)**:应用通过 lockCanvas() 或 EGL 申请缓冲区。
  2. **绘制 (Draw)**:应用调用 Canvas 或 GPU 绘图指令。
  3. **提交 (Unlock & Post)**:将绘制好的缓冲区入队,通知 SurfaceFlinger 进行合成显示。