☰
AMS启动过程全解析:从system_server到systemReady的完整链路
2026/10/7 3:42:49 网站建设 项目流程

作为常年跟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准备启动Launcher

systemReady()内部会创建一个包含所有"持久进程"的启动任务,比如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.systemReadyATMS.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 ActivityManagerService
  • ActivityManager: setSystemProcess
  • ActivityManager: systemReady
  • ActivityTaskManager: systemReady
  • ActivityManager: 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"这个细节,最终定位到某个预置应用的包信息解析异常。带着问题读源码、用日志反推时序,比背一百行源码更管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询