
作为常年跟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进程拉起ZygoteZygote完成 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、mServicesActiveServices、mBroadcastQueues、mActivityStarter等成员。有些成员不是直接 new而是通过工厂创建。这也是源码阅读里比较费劲的地方。2. 构造函数里的大興土木AMS内部到底初始化了什么2.1 ActivityThread与系统上下文system_server也有ActivityThreadAMS 构造函数可以说是整个启动流程中工作量最大的一个。它首先要创建一个属于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、绑定进程等。没有这个 ContextAMS 根本无法正常工作。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 自定义线程与Handlersystem_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()系统上下文里的ContentProviderAMS 启动过程中还有一个很容易被忽略的动作加载系统级 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.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 ActivityManagerServiceActivityManager: setSystemProcessActivityManager: systemReadyActivityTaskManager: systemReadyActivityManager: Start procSystemUI 等进程启动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 抢占。二是PMSPackageManagerService查询包信息耗时间接拖慢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这个细节最终定位到某个预置应用的包信息解析异常。带着问题读源码、用日志反推时序比背一百行源码更管用。