作为常年跟system_server打交道的人,每次带新人梳理 Android 启动流程,看他们在Zygote、SystemServer、AMS之间迷路,我都想写一篇能一口气讲透AMS 启动过程的文章。这个主题表面上是"系统服务如何被创建",实际牵涉Binder注册、SystemServer启动时序、ActivityThread与系统进程的关系、以及systemReady()之后整个 Android 世界的唤醒逻辑。今天这篇就顺着我实际调试源码的路线,把AMS从"进程诞生"到"真正开始干活"的完整链路拆开聊,顺便把那些源码里不容易看出来的坑点一并交代清楚。
1. 启动链路第一条线:AMS是怎么"出生"在system_server里的
1.1 先搞清楚AMS到底住在哪个进程
很多人以为AMS是独立进程,其实它一直住在system_server进程里。system_server又是谁生的?是Zygote通过fork出来的。Android 设备启动时,init进程拉起Zygote,Zygote完成 Java 虚拟机初始化后,会收到来自socket的指令去 fork 出system_server。
system_server的入口是SystemServer.main(),经过若干初始化后进入SystemServer.run()。你可以在frameworks/base/services/java/com/android/server/SystemServer.java里看到这段代码,整个函数骨架大致是:
public static void main(String[] args) { new SystemServer().run(); } private void run() { // 设置系统属性、线程池、Looper 等 ... // 引导服务、核心服务、其他服务三大阶段 startBootstrapServices(); startCoreServices(); startOtherServices(); ... }关键点在这里:AMS不是在哪一个阶段里被"无条件 new"出来,而是被包在ActivityManagerService.Lifecycle这个壳里,通过SystemServiceRegistry或者直接new的方式加入服务管理。如果你读过 Android 10 前后的源码会发现,startBootstrapServices()里有这样一段经典代码:
mActivityManagerService = ActivityManagerService.Lifecycle.startService( context, mSystemServiceManager, atmInternal);不过不同安卓版本写法略有差异,比如较新的版本里AMS的创建直接通过Lifecycle构造,ActivityTaskManagerService被独立拆分后才把ATMS的引用传给AMS。这就是我为什么总跟人说:看 AMS 启动流程,一定要锁定一个具体 Android 版本,否则不同源码里setSystemProcess()、installSystemProviders()的调用位置可能都不一样。
1.2 从init到Zygote再到system_server,中间隔着什么
完整的开机链路可以缩写成这样:
init -> Zygote -> fork system_server -> SystemServer.run() -> startBootstrapServices() -> 创建AMS其中Zygote的作用不只是 fork 进程,它还会预加载一批通用类资源,这样system_server和后续所有应用进程都能共享内存页。AMS 所在进程的启动时机早于绝大多数系统服务,是一切系统服务的"母体"。
这块常见的理解误区是:误以为 AMS 是Zygote直接持有的对象。实际上Zygote只负责 fork 出system_server进程并执行SystemServer.main(),AMS 对象是跑到 Java 层SystemServer类里之后才 new 出来的。也就是说,AMS 的"出生地"是system_server进程内存空间,不是Zygote。
如果你在源码里全局搜索ActivityManagerService的构造点,最终会看到它构造时传入SystemServer构造好的Context,这个 Context 是整个系统服务共享的基础上下文。
1.3 构造、SystemServiceManager、Lifecycle三个角色
ActivityManagerService.Lifecycle是理解 AMS 启动的一把钥匙。它继承自SystemService,这个SystemService是系统服务的统一封装,供SystemServiceManager统一管理。它的核心逻辑大致是:
public static class Lifecycle extends SystemService { private final ActivityManagerService mService; public Lifecycle(Context context) { super(context); mService = new ActivityManagerService(context, ...); } @Override public void onStart() { mService.start(); } public ActivityManagerService getService() { return mService; } }你只要盯住new ActivityManagerService(...)这个构造点,后续一切工作都从构造函数展开。AMS 构造函数极其庞大,内部会初始化mHandlerThread、mUiThread、mActivityThread、mContext、相关Handler、mServices(ActiveServices)、mBroadcastQueues、mActivityStarter等成员。有些成员不是直接 new,而是通过工厂创建。这也是源码阅读里比较费劲的地方。
2. 构造函数里的"大興土木":AMS内部到底初始化了什么
2.1 ActivityThread与系统上下文:system_server也有"ActivityThread"
AMS 构造函数可以说是整个启动流程中工作量最大的一个。它首先要创建一个属于system_server自己的ActivityThread,注意这不是普通应用的 UI 主线程,而是系统服务用来承载 context、resource、content provider 等能力的"宿主线程"。
源码里常常能看到类似这样的逻辑:
mSystemThread = new ActivityThread(); mSystemContext = mSystemThread.getSystemContext(); mSystemContext.setTheme(com.android.internal.R.style.Theme_DeviceDefault_Light);这里解释了很多人问过我的问题:为什么系统服务能拿到Context?因为ActivityThread在 system_server 内部被手动创建,ContextImpl随之创建。可以说,AMS 的内部世界一开始就有完整的"应用环境",只是没有界面而已。
mSystemContext创建之后,AMS 后续很多操作都要用到它:注册系统服务收到广播、查询系统设置、启动 Activity、绑定进程等。没有这个 Context,AMS 根本无法正常工作。
2.2 各种子模块的初始化:ActiveServices、BroadcastQueue、ActivityStarter
进入构造函数后,你会看到 AMS 把一堆子系统拉起来。为了讲清楚启动过程,我挑几个关键的:
mServices:类型是ActiveServices,负责Service的启动、绑定、调度。AMS 本身不管具体 Service 逻辑,而是委托给它。mBroadcastQueues:这是一个BroadcastQueue数组,分为前台、后台两个队列。广播顺序、ANR 超时的计算都在这里。mActivityStarter:负责 Activity 启动的规则解析、任务栈调配。它内部引用着ActivityTaskManagerInternal、RootWindowContainer等。mH:指向一个以mUiThread为 Looper 的 Handler,处理ActivityManagerService主线程上的消息,比如START_ACTIVITY、BROADCAST_INTENT。mProcessList:进程管理列表,所有运行中的应用进程都由它记录。
这些子模块不是全部立即"开始工作",大部分是等systemReady()之后才真正响应外部请求。构造函数做的只是把房子盖好,家具摆好,还没开业。
2.3 自定义线程与Handler:system_server不能卡主线程
AMS 构造函数里还干了一件非常重要的杂活:创建一堆专属线程,比如后台线程、Binder 线程池、mHandlerThread。为什么要单独搞线程?因为 AMS 作为系统服务,会同时接受来自大量应用进程的 Binder 调用,不能都压在SystemServer主线程或者 UI 线程上处理,否则一个慢操作会拖垮整台设备的系统响应。
通常你会看到:
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_FOREGROUND, false); mHandlerThread.start(); mUiHandler = new Handler(mHandlerThread.getLooper());这些线程的优先级、名称、Looper 都有讲究。调试系统问题的时候,经常要在线程列表里找android.fg、android.bg、ActivityManager等线程名,它们大多是在 AMS 构造阶段创建出来的。搞明白这些,读systrace或ANR trace才不至于一头雾水。
3. 让AMS成为"系统服务中心"的两个关键动作
3.1 setSystemProcess():把自己注册进ServiceManager
构造函数只是把 AMS 对象创建出来了,此时它还没有把自己暴露给整个系统。应用进程想要调用 AMS 的能力,必须通过ServiceManager拿到 Binder 代理。这个注册动作发生在setSystemProcess()里。
Android 10 前后代表性能不同,这里不抠具体行号,重点讲它的职责。它会调用:
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ false);这行代码意味着:其他进程可以通过ServiceManager.getService("activity")拿到 AMS 的 Binder 引用。此后 Activity 启动、Service 绑定、进程优先级调整等请求才能从应用进程流入 system_server 的 AMS 里。
setSystemProcess()同时还会往内部进程注册表里登记关键进程,比如persistent进程、系统进程自身。注意,这一步做完之后,AMS 的 Binder 通道已经对外开放了,但业务能力还没有完全就绪,所以还会有后面的installSystemProviders()和systemReady()。
3.2 installSystemProviders():系统上下文里的ContentProvider
AMS 启动过程中还有一个很容易被忽略的动作:加载系统级 ContentProvider。installSystemProviders()的调用细节和系统属性和配置有关,但它的大头是扫描并启动系统进程所属的Provider。
有些核心数据提供方,比如SettingsProvider、Watchdog相关的 provider,都依赖这个时机。SettingsProvider没起来,系统里很多依赖配置项的流程都会卡住。所以installSystemProviders()必须在 AMS 对外正常响应前执行。
如果你跟踪开机日志,会看到类似Install System Providers的阶段标记,这一步完成后,SettingsProvider注册到ActivityThread的 provider 管理器里,Settings.Global这类接口才能被系统服务正常调用。
3.3 为什么AMS这么早需要Provider?
这个问题值得展开:AMS 启动阶段为什么要跟 ContentProvider 扯上关系?因为 AMS 要维护 Android 系统的"生活常识",比如判断一个进程能否使用某项权限、某一项系统配置是否允许某种行为。
在setSystemProcess()和installSystemProviders()都完成之前,AMS 的功能是不完整的。任何提前到达的客户端请求,要么被缓存,要么被拒绝,直到systemReady()真正放行。
实际调试中你会遇到一种现象:系统启动阶段偶发的SERVICE_TIMEOUT或者Provider not found,很多都跟这个准备窗口有关。把时序表列清楚,问题会好定位得多。
4. systemReady():AMS从"创建完成"到"开始掌管全局"的爆发点
4.1 一条回调链的起点
AMS 的systemReady()是启动过程的重头戏。它在SystemServer.startOtherServices()中被调用,但调用方式往往不是直接同步执行,而是通过ActivityTaskManagerInternal、WindowManagerService等服务的准备度判断后才触发。
简单概括时序:
SystemServer.startOtherServices() -> mActivityManagerService.systemReady(...) -> AMS内部调用多个服务的systemRunning(比如wm、input等) -> AMS检查Persistent进程 -> AMS准备启动LaunchersystemReady()内部会创建一个包含所有"持久进程"的启动任务,比如com.android.systemui就是 persistent 进程,需要优先拉起。用户空间看到的就是开机动画结束后,SystemUI 先出现,Launcher 随后才起来。
4.2 回调到ActivityTaskManagerService的细节
Android 10 之后因为ATMS的拆分,AMS.systemReady()有一部分工作委托给了ActivityTaskManagerService。比如恢复任务栈、恢复最近任务列表、启动 Launcher 这些,实际执行者已经是ATMS了。
我这里想说一个重要调试观点:在看启动过程相关的 trace 或日志时,不能只盯ActivityManager和AMS,还要留意ActivityTaskManager相关线程。很多"AMS启动慢"的案例,实际瓶颈在 ATMS 线程里处理恢复任务和窗口容器的部分。系统开机阶段,ActivityManager: systemReady和ActivityTaskManager: systemReady两条日志要结合起来看。
为了区分职责,我把新旧版本的核心差异整理成表格:
| 阶段 | 旧版本(Android 9及以前) | 新版本(Android 10及以后) |
|---|---|---|
| Activity栈管理 | AMS直接负责 | ActivityTaskManagerService单独负责 |
| 启动入口 | AMS内部执行 | AMS委托ATMS执行 |
| 系统就绪回调 | AMS.systemReady | ATMS.systemReady + AMS.systemReady |
| 窗口层级关系 | WindowManagerService与AMS强耦合 | ATMS承担更多容器管理 |
4.3 Launcher是谁启动的
很多文章会说Launcher是由 AMS 启动的,严格讲不完全准确。在AMS.systemReady()的流程里,会调用startHomeActivityLocked()或者经由ActivityTaskManagerInternal发起HOMEIntent 启动,最终真正执行启动的是ActivityStarter。
不过我们顺着ActivityTaskManager的onSystemReady()往深处找,能看到它会调用mRootWindowContainer.ensureVisibilities()、重置窗口容器状态,然后请求启动 Home。所以你要是被问到"Launcher 是 AMS 启动的吗?",答案应该拆开:
- 从调度层面看,是 AMS 发起的。
- 从执行层面看,是
ActivityTaskManagerService通过ActivityStarter完成的。 - 从窗口层面看,真正的窗口落地还得靠
WindowManagerService。
这个"拆分职责"的思路也是 Android 10 架构改革的核心理念:AMS 里那些跟"任务管理、栈管理"关系太深的内容逐步转移到 ATMS,让 AMS 更聚焦于进程、服务、广播等生命周期管理。
5. 实战视角:如何用日志和Trace跟踪AMS启动链路
5.1 必抓的几个日志节点
实战排查时,我一般不靠肉眼读源码,而是靠日志节点快速定位启动到了哪一步。常见的关键日志有这些:
ActivityManager: System server: starting ActivityManagerServiceActivityManager: setSystemProcessActivityManager: systemReadyActivityTaskManager: systemReadyActivityManager: Start proc(SystemUI 等进程启动)
logcat里可以用如下方式过滤:
adb logcat -v time -s ActivityManager:V ActivityTaskManager:V SystemServer:V如果设备启动期间开启了logcatd或者能抓serial日志,可以观察到从boot_progress_start到boot_progress_enable_screen之间的活动,AMS相关日志大多落在这个窗口内。
5.2 Systrace上看启动瓶颈
抓systrace时注意看SurfaceFlinger、SystemServer、app_process等进程在启动阶段的缩放图。AMS 启动中最常见的性能瓶颈有两类:
- 一是持久进程的启动排队时间,比如 SystemUI、Service 较多时
startProcess唤醒过快导致 CPU 抢占。 - 二是
PMS(PackageManagerService)查询包信息耗时,间接拖慢systemReady回调。
如果看到ActivityManager: systemReady之后过了很久才Start proc,多半不是 AMS 的锅,而是上游某个服务systemRunning()卡住了。这种时候优先查WMS、PMS的systemRunning耗时。
5.3 常见ANR和启动时序坑
我见过不少朋友把"开机黑屏"或"开机 Launcher 崩溃"归因于 AMS。这里给一个排查建议:
如果 Launcher 启动后立即退出,先看是不是Launcher的进程在systemReady阶段就被kill了。AMS 在启动阶段会对一些processRecord做状态检查,如果Launcher进程提前被杀,后续startHomeActivityLocked()会再次拉起。这种双次启动的问题,在 logcat 里表现为同样的Start proc出现两次,格外耗时。
同一类的问题还包括开机阶段package扫描未完成就直接尝试启动所有 persistent 进程,导致部分进程反复重启。遇到这种情况,最快的方法是抓 bootchart 和 systrace,看进程启动的时间线是否集中在同一瞬间,这能说明 AMS 的并发启动窗口过窄。
6. 源码阅读的正确姿势与面试高频追问
6.1 锁定版本、抓住主线、延展分支
AMS 启动过程跨版本差异很大,读源码时务必记住三条:
- 主线是
SystemServer.run()到AMS.systemReady()。 - 支线是
ATMS、WMS、PMS与 AMS 的互相调用。 - 每个版本的
startBootstrapServices()函数体都不一样,优先看当前设备版本的源码。
如果你打开源码觉得头大,我建议用一个笨但有效的办法:在AMS.systemReady()打上断点或加一条Log.w,然后从 logcat 的时间戳反推前置调用栈。这在真机调试和模拟器调试中都适用。
有条件的还可以尝试adb shell dumpsys activity activity、adb shell dumpsys activity processes,这些命令会把 AMS 内部的对象状态实时打出来,能直观看到进程记录、任务栈恢复情况。配合源码里的成员名字,理解速度会快很多。
6.2 面试中绕不开的AMS启动问题
看过启动过程之后,很多面试题其实可以串在一起答:
- AMS 启动入口在哪?答:
SystemServer.startBootstrapServices()中通过Lifecycle创建。 - AMS 是单例吗?答:一个进程内一个 AMS 实例,系统全局只有一个
system_server承载它。 systemReady()前为什么不响应业务?答:因为内部服务和所需 Provider、系统配置未就绪。- Android 10 为什么拆出 ATMS?答:为了降低 AMS 复杂度和启动耦合,任务栈管理独立。
还有一类更细节的追问:AMS 构造时传进来的Context到底是什么?答案是mSystemContext,它由ActivityThread.getSystemContext()创建,而不是通过createSystemContext再启动其他 Application。理解了这一点,就理解了为什么system_server不需要真正的Application对象也能拥有资源加载能力。
6.3 最后给新手的一个学习路径建议
如果你是想深入 framework 的新人,建议不要一上来就啃ActivityTaskManagerService或者ContentProvider的源码。先把SystemServer主流程读三遍,把AMS的构造函数中每个成员变量的命名扫一遍,再带着"某某成员在哪个阶段被真正使用"的问题去读。这样比逐行精读高效得多。
学习源码时,顺手积累一张自己的"启动时间线",把Subscribe、systemReady、setSystemProcess、startHomeActivityLocked这些节点都按照版本记录下来。等以后排查开机问题、性能问题时,这张时间线就是你的王牌。我在实际处理一次开机变慢的问题时,凭借的就是时间线上"AMS 比正常情况多等待了 PMS 回调近 800ms"这个细节,最终定位到某个预置应用的包信息解析异常。带着问题读源码、用日志反推时序,比背一百行源码更管用。