AMS 为什么越拆越强?从 Android 早期“大总管”到 AMS、ATMS、WMS 协同架构

1 阅读12分钟

如果把早期 Android Framework 看成一家刚起步的公司,AMS 很像那个什么都管的负责人:Activity 怎么启动、进程何时创建、Service 怎么运行、广播发给谁、Provider 是否存活,都由它统筹。

后来 Android 支持了多窗口、多屏、多用户、画中画、复杂动画和更严格的后台限制。AMS 没有消失,却不再独自维护所有状态。今天的 Android 16 中,AMS、ATMS、WMS 形成了一组分工明确的控制面。

这段历史经常被概括成“AMS 拆成了 AMS、ATMS、WMS”,但这个说法并不严谨:WMS 从早期 Android 就是独立服务,真正从 AMS 领域迁出的主要是 Activity 与 Task 管理。

本文沿着这条主线回答四个问题:早期 AMS 为什么要做成“大总管”;它为什么遇到瓶颈;Activity/Task 为什么最终形成 ATMS;Android 16 中 AMS、ATMS、WMS 到底怎样协作。

本文当前实现以 Android 16 产品 Framework 基线为准,Android 17 源码只用于观察趋势,不替代 Android 16 的函数与策略结论。

一张图看懂演进:拆的不是代码,而是状态所有权

AMS 从单体组件总管到 AMS、ATMS、WMS 协同架构转存失败,建议直接上传图片文件

图 1:WMS 始终独立存在;Android 的主线变化是 Activity/Task 从 AMS 领域迁出并形成 ATMS,AMS 则收敛为应用运行态与资源策略中枢。

早期架构可以简化为:

AMS:Activity + Task + Process + Service + Broadcast + Provider
  ↕
WMS:Window + Display + Surface

现代架构则变成:

ATMS:Activity / Task / Display 上的活动组织
  ↕
WMS:Window / Display / Surface / 输入窗口
  ↕ 可见性与进程投影
AMS:Process / Service / Broadcast / Provider / OOM / 后台策略

表面看是类和接口的迁移,真正变化的是“谁拥有最终解释权”:

  • Activity 位于哪个 Task、哪个 Display,由 ATMS 决定;
  • 窗口怎样布局、显示和提交 Surface,由 WMS 决定;
  • 进程为何重要、是否可冻结、Service 和 Provider 是否存活,由 AMS 决定。

早期 AMS 为什么必须是“大总管”

Android 四大组件不是四套互不相关的机制。

启动 Activity 时,目标进程可能还不存在;绑定 Service 会改变服务进程的重要性;获取 Provider 会建立跨进程存活依赖;Broadcast 可能拉起前三类组件。早期设备单屏为主、任务模型简单,把这些状态放在 AMS 的同一套管理体系里,反而最容易保证一致性。

当时 AMS 领域大致包括:

子系统主要职责
Activity/Task启动、栈和任务、生命周期、前后台切换
Processfork、attach、LRU、OOM adj、死亡清理
Servicestart/bind、超时、前台服务
Broadcast并行/有序广播、超时、进程拉起
Provider发布、获取、引用计数、死亡处理
User/Error多用户运行态、ANR、Crash 与权限协同

WMS 此时已经独立负责窗口。AMS 决定“哪个 Activity 应当运行”,WMS 决定“它的窗口怎样显示”。

这种设计的优势是直接:一个全局协调者可以在组件变化后立即更新进程优先级。它的缺点也埋在这里——Activity 历史与 Window 层级分别保存在两个强耦合系统中。

真正逼出 ATMS 的,不是 AMS 文件太长

如果只是代码量大,把类拆成几个 Helper 就够了。ATMS 出现的根本原因,是 Activity、Task、Window 和 Display 逐渐形成同一套拓扑。

从一块屏到多块屏

早期 Activity Stack 相对简单。后来 Android 陆续加入多 Stack、分屏、画中画、自由窗口、TaskFragment 和多 Display。到了 AAOS,一台车同时拥有中控、仪表、副驾和后排屏已经不是边缘情况。

Activity 位于哪个 Display、采用什么 windowing mode、是否可见,都会立即影响窗口层级、焦点、配置和动画。如果 AMS 维护一棵 Activity 树,WMS 再维护一棵 Window 树,系统就必须持续同步两份真相。

两类状态的节奏完全不同

窗口焦点、旋转、动画和 Transition 是高频界面状态;Service、Provider、进程 LRU 和 OOM adj 是应用运行态。让它们长期共享一个巨型状态机,会放大锁竞争,也让窗口功能的改动穿透到进程治理。

于是 Android 采用了一条渐进路线:

  1. 先用 ActivityStackSupervisor、ActivityStarter 等对象从 AMS 主类提炼职责;
  2. 再让 Activity、Task、Display 相关实现向 com.android.server.wm 聚合;
  3. 最终在 Android 10 形成 IActivityTaskManager 与 ActivityTaskManagerService;
  4. 继续以统一的 WindowContainer 体系承载 Display、Task、Activity 和 Window 之间的结构关系。

这是一种很典型的架构演进:先在单体内部建立边界,再移动状态所有权,最后才形成稳定服务接口。

Android 10 之后:AMS 为什么还保留 startActivity()

阅读源码时很容易产生疑问:Android 16 的 ActivityManagerService 中仍然能找到 startActivity(),是不是 Activity 其实还归 AMS?

看调用方向就清楚了:

// ActivityManagerService.java(省略参数)
public int startActivity(...) {
    return mActivityTaskManager.startActivity(...);
}

这是兼容入口,不是权威状态仍留在 AMS 的证据。真正的启动流程进入 ATMS:

ActivityTaskManagerService.startActivityAsUser()
  -> ActivityStartController.obtainStarter(...).execute()
  -> ActivityStarter:解析、权限/BAL、Task 与 Display 选择
  -> RootWindowContainer / Task:更新容器和可见性

判断一个功能属于谁,不能只看“哪个类还能收到入口调用”,而要看:核心状态存在哪里、谁能修改它、锁由谁持有、最终裁决发生在哪里。

Android 16 中,三大服务各自管什么

AAOS_AOSP_Android16_AMS_Evolution-01-架构演进.drawio.svg

图 2:ATMS/WMS 拥有界面容器状态,AMS 拥有应用运行态;LMKD、cgroup/freezer 等位于策略执行层。

AMS:应用运行态与资源策略中枢

Android 16 的 AMS 继承 IActivityManager.Stub,主要子系统包括:

  • ProcessList:进程表、LRU、进程创建与退出记录;
  • ProcessStateController、OomAdjusterImpl:根据组件和跨进程依赖计算 proc state、adj 与调度组;
  • CachedAppOptimizer:缓存进程 compaction 与 freezer;
  • ActiveServices:Service/FGS 生命周期、超时和后台准入;
  • BroadcastController、BroadcastQueueImpl:广播解析与调度;
  • ContentProviderHelper:Provider 获取、发布和引用;
  • AppRestrictionController:应用后台限制聚合;
  • AppStartInfoTracker、AppExitInfoTracker:启动与退出原因的结构化记录;
  • UserController:用户运行态。

AMS 回答的是:进程为什么存在、因什么组件而重要、后台执行是否允许、何时应压缩或冻结、一次启动和退出为何发生。

ATMS:Activity 与 Task 的权威状态

ATMS 继承 IActivityTaskManager.Stub。源码对它的定义很直接:管理 Activity 及其容器,包括 Task 和 Display。

它的关键模块有:

  • ActivityStartController / ActivityStarter:启动入口与单次启动状态机;
  • ActivityTaskSupervisor:跨 Task/Display 调度和应用 attach;
  • RootWindowContainer:显示与任务容器树根;
  • RecentTasks:最近任务;
  • BackgroundActivityStartController:后台 Activity 启动裁决;
  • LockTaskController:锁定任务模式;
  • WindowProcessController:进程在 wm 领域的界面状态投影。

ATMS 回答的是:Activity 应进入哪个 Task、落在哪个 Display、谁可见、谁 resumed、生命周期下一步是什么。

WMS:窗口与显示系统

WMS 继承 IWindowManager.Stub,负责 Window session、WindowState、焦点、输入窗口、布局、Surface、DisplayContent、旋转和配置等。

它回答的是:窗口在哪里、层级如何、怎样布局和提交 Surface。它不负责判断一个 Service 是否应抬高进程优先级,也不管理 Broadcast 和 Provider。

ATMS 与 WMS 位于同一个 server.wm 领域并共享窗口管理全局锁,是因为 Activity/Task 与 Window/Display 必须保持同一棵容器拓扑;但它们仍保留不同的 Binder 契约和职责。

一次 Activity 启动,三大服务怎样接力

Android 16 Activity 启动中的 ATMS、AMS、WMS 协作转存失败,建议直接上传图片文件

图 3:ATMS 主导任务与生命周期,AMS 提供进程并计算资源优先级,WMS 完成窗口呈现。

把调用链压缩到架构层,大致是:

App
  -> IActivityTaskManager.startActivity
  -> ATMS / ActivityStarter
  -> 解析 Intent、检查权限和 BAL、选择 Task/Display
  -> 更新 RootWindowContainer
  -> 判断目标进程是否存在
       ├─ 存在:调度 Activity 生命周期
       └─ 不存在:请求 AMS / ProcessList 创建进程
  -> Zygote fork
  -> AMS.attachApplication
  -> ATMS attachApplication(WindowProcessController)
  -> 应用 ActivityThread 执行 launch/resume
  -> WMS 创建、布局窗口并参与 Transition
  -> 可见性反馈给 AMS
  -> ProcessStateController / OomAdjuster 更新优先级

这条链解释了为什么拆分后系统仍需要紧密协作:

  • ATMS 拥有“界面应该是什么状态”的真相;
  • AMS 拥有“运行这个界面需要什么进程和资源”的真相;
  • WMS 拥有“这个状态如何成为屏幕上的窗口”的真相。

拆分没有消灭复杂度,而是阻止复杂度继续集中在一个状态机里。

为什么 Service、Broadcast、Provider 仍留在 AMS

它们的共同特点是:权威状态与进程依赖强相关,却不属于窗口容器树。

以 Service 为例:

ActivityManagerService.startService
  -> ActiveServices.startServiceLocked
  -> 后台/FGS 准入
  -> bringUpServiceLocked
  -> 必要时 ProcessList.startProcessLocked
  -> realStartServiceLocked
  -> 更新 OOM 依赖

以 Provider 为例:客户端获得 Provider 后,连接本身就可能提升 Provider 进程的重要性。ContentProviderHelper.getContentProviderImpl() 不只是“查一个地址”,还需要处理权限、用户、进程拉起、引用计数和死亡传播。

Broadcast 同样可能触发冷启动,并影响系统吞吐与公平性。Android 16 的现代广播队列以目标进程为重要调度维度,解决的是冷启动风暴、紧急广播延迟和应用间公平问题。

这些能力留在 AMS,不是历史遗留,而是遵循“组件运行态与进程资源放在同一领域”的设计。

拆分后最难的部分:同一进程有两种视图

AMS 中有 ProcessRecord,ATMS/WMS 中有 WindowProcessController。

前者关心 pid、UID、Service、Provider、LRU、proc state 和 adj;后者关心 Activity、窗口可见性、配置和界面调度。它们不是两份平级真相,而应当是“权威状态 + 跨域投影”。

例如 Activity 可见性在 wm 领域产生,再反馈给 AMS 参与 OOM 计算;Service 绑定关系在 am 领域产生,不应该复制进窗口容器树。

这也是定制 Framework 时最重要的评审问题:

这个字段的权威所有者是谁?其他模块拿到的是事件、快照,还是另一份可写状态?

如果这个问题答不清,最终通常会出现三类 Bug:

  • 窗口已经不可见,进程仍被错误地当作可见进程;
  • 两侧字段更新顺序不同,导致偶现 Task 或 OOM 状态错乱;
  • AMS lock 与 WindowManagerGlobalLock 交叉获取,形成 system_server 死锁。

对 AAOS 来说,这套架构不是“手机遗产”

AAOS 反而把拆分的价值放大了。

第一,多 Display 是默认场景。中控、仪表、副驾和后排屏要求 ATMS/WMS 明确管理 displayId、Task 归属、焦点和可见性,不能让进程管理代码凭经验猜测。

第二,多用户可能同时可见。驾驶员、乘员、访客和可见后台用户会共同影响组件启动与 Display 选择。“当前用户 + 默认屏”的隐含假设在车机中很危险。

第三,长生命周期业务容易诱发永久保活。车辆信号、媒体、电源和系统 UI 确实重要,但正确做法是把重要性映射为受约束、可撤销、可解释的 Service/FGS、绑定关系或系统身份,而不是直接写死 oom_score_adj。

第四,平台能力与产品配置必须分开。Android 16 支持缓存进程 freezer,不代表每条产品分支默认开启。当前分析的产品基线就在 CachedAppOptimizer 中带有关闭 freezer 的产品补丁。机制、AOSP 策略和产品默认值是三个层次。

从这次演进能学到什么

AMS 的变化提供了四条很通用的架构经验。

第一,按状态所有权拆,而不是按文件大小拆。

Activity 与 Task 迁入 ATMS,是因为它们与 Display/Window 形成统一容器拓扑;Service 留在 AMS,是因为它与进程依赖和后台策略形成闭环。

第二,兼容入口不等于权威状态。

AMS 中仍有转发式 startActivity()。阅读大型系统时,应追踪最终裁决和数据归属,而不是看到方法名就停止。

第三,服务拆分不等于进程隔离。

AMS、ATMS、WMS 都在 system_server。逻辑边界能改善架构,却不会自动消除锁、重入和慢调用风险。

第四,投影必须单向且可解释。

ProcessRecord 与 WindowProcessController 可以分别服务两个领域,但每类字段都应有明确权威来源。两份都可写的“缓存”迟早会成为两份真相。

结语

从早期 Android 到 Android 16,AMS 的演进并不是一个“大服务被越拆越小”的故事。

它更像一次持续多年的状态重构:Activity/Task 的权威状态进入 ATMS,Window/Display 继续由 WMS 负责,进程和非界面组件运行态留在 AMS;三者通过内部接口和受控投影,共同完成一次应用启动、呈现和资源治理。

所以今天再读 AMS,最有效的方法不是从一个 Binder 方法一路追到底,而是同时追四条线:

  • 状态由谁拥有;
  • 策略由谁裁决;
  • 机制由谁执行;
  • 结果由谁记录。

当这四条线对齐时,AMS、ATMS、WMS 就不再是三个容易混淆的缩写,而是现代 Android 应用运行控制面的三块清晰拼图。

参考源码

  • services/core/java/com/android/server/am/ActivityManagerService.java
  • services/core/java/com/android/server/am/ProcessList.java
  • services/core/java/com/android/server/am/ProcessStateController.java
  • services/core/java/com/android/server/am/OomAdjusterImpl.java
  • services/core/java/com/android/server/am/ActiveServices.java
  • services/core/java/com/android/server/am/BroadcastQueueImpl.java
  • services/core/java/com/android/server/am/ContentProviderHelper.java
  • services/core/java/com/android/server/am/CachedAppOptimizer.java
  • services/core/java/com/android/server/wm/ActivityTaskManagerService.java
  • services/core/java/com/android/server/wm/ActivityStartController.java
  • services/core/java/com/android/server/wm/ActivityStarter.java
  • services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
  • services/core/java/com/android/server/wm/RootWindowContainer.java
  • services/core/java/com/android/server/wm/WindowProcessController.java
  • services/core/java/com/android/server/wm/WindowManagerService.java
  • services/java/com/android/server/SystemServer.java