
在Android系统里如果你只挑一个最值得啃的类我大概率会推荐ActivityManagerService。这哥们儿的简称就叫AMS从应用进程的出生、审批、分配内存到Activity栈的调度、运行时的生命周期管理几乎都绕不开它。更关键的是整个Android Framework是在system_server进程里拉起的一堆服务而AMS就是这一堆服务里最早启动、也最牵动全局的一个。我最初啃它的时候光是找入口就翻了半天源码对着SystemServer里的启动顺序一脸懵。这篇东西想把AMS的启动过程讲清楚它从哪里来、在哪里被实例化、启动时做了什么、你怎么从日志和dumpsys里判断它干没干好活。如果你正跟着教程学Framework或者准备自己改系统服务这条主线值得先理顺。我会尽量用大白话拆解但该给的源码路径和关键类名一个也不省这样你回头翻AOSP时能对上号。1. 先看懂AMS在系统里的角色1.1 为什么AMS是系统大管家很多人第一眼看到AMS的类名会以为它只管Activity。实际上它在现代Android版本里管的事情远不止Activity栈。它负责四大块应用进程的创建与销毁、组件生命周期调度Activity、Service、BroadcastReceiver、任务的栈管理、以及和系统内存压力相关的进程优先级OomAdj计算。Activity栈这部分的实现在Android 10之后被拆分到了ActivityTaskManagerServiceATMS但对外老接口和大部分决策逻辑仍然在AMS这边统一协调。不理解它的角色直接去看启动代码会非常难受。你会在ActivityManagerService构造函数里看到一堆new出来的对象比如mProcessList、mServices、mBroadcastQueues如果脑子里没有“这分别是管进程的、管服务的、管广播的”这个映射这些字段对你来说就是一堆字母。反过来只要你心里有“AMS是系统大管家”这个概念再去看它的构造函数就有种“哦这是在搭班子”的感觉。启动过程本质上不是把AMS这个对象new出来就算完而是要把这个班子搭好并且让它能够接受外部指令。1.2 AMS启动前的世界Zygote和SystemServer的接力很多人以为AMS是开机后“第一个被new出来的东西”实际上它在Android世界里出生得很晚。系统从bootloader到kernel起来后init进程会解析init.rc启动一个叫Zygote的进程。Zygote是个Java进程它的特殊能力是fork也就是把自己复制一份变成新的进程。Android上所有应用进程包括system_server几乎都是Zygote fork出来的。这样设计的重要原因是可以共享Zygote进程里预加载的Java类库和资源省得每个应用启动时都要重新加载一遍基础类速度会快很多。Zygote在启动完自己之后会通过forkSystemServer()专门生出一个子进程这个子进程最终会运行SystemServer类的main()方法成为常说的system_server进程。AMS就在这个SystemServer进程里被创建它和Zygote的关系是Zygote给了它生命但它负责管理Zygote后面孵化出来的所有普通应用进程。所以你要是把“AMS启动过程”理解成“从开机第一行代码就开始”方向就偏了。准确说法是AMS的启动是system_server进程内部的一次服务初始化。它前面已经有很多基础环境就绪了比如内核、init、Zygote、SELinux、Binder驱动。AMS启动之后才轮到它去管理那些由Zygote孵化的第三方App。1.3 启动流程全景概览文字版整个流程可以用一句话总结SystemServer.main()进入后创建SystemServiceManager然后按阶段启动一系列系统服务其中AMS在一个很早的阶段被实例化随后注册进Binder、安装系统Provider再跟着系统启动阶段一步步走到systemReady()此时系统才会去启动桌面Home和允许第三方应用运行。我建议你在读源码之前先在脑子里刻下这条主干道SystemServer.main()Java层system_server入口创建SystemServer对象。SystemServer.run()准备Looper、加载native库、创建SystemServiceManager。startBootstrapServices()启动引导服务AMS在这个阶段通过ActivityManagerService.Lifecycle包装类创建。startCoreServices()和startOtherServices()启动其它依赖服务AMS会等待它们就绪。各种onBootPhase()回调服务们按启动阶段递进AMS的systemReady()是最后一个关键标志。Android 10/11/13/14这些版本里具体服务的启动顺序有细微差别比如Android 13把ActivityTaskManagerService放在AMS之后立刻启动但整体思路不变。你要抓的是“先有SystemServiceManager然后AMS被Lifecycle创建再逐步就绪”这条线而不是死记某个常量值。2. 从入口到实例化SystemServer里的AMS诞生记2.1 main()方法里的启动顺序SystemServer的入口方法非常朴素就是Java标准的main()。它做了两件事清一下环境然后new一个SystemServer并调用run()。run()里面的逻辑才是关键顺序大概是// 最终会设置系统属性、初始化Looper、加载libandroid_servers.so Looper.prepareMainLooper(); // 创建SystemServiceManager它是所有系统服务生命周期的统一管理者 mSystemServiceManager new SystemServiceManager(mSystemContext); mSystemServiceManager.setStartInfo(...); // 依次执行三个阶段的服务启动 startBootstrapServices(); startCoreServices(); startOtherServices(); // 让system_server的主Looper转起来处理Binder消息和Handler消息 Looper.loop();这里有个很容易忽略的点main()之后system_server进程并不像普通应用那样去onCreate而是直接在一个Java函数里做所有初始化最后进入自己的Looper循环。AMS的构造代码其实是在这个“初始化”阶段里执行的而不是运行在Android应用的四大组件生命周期里。理解了这个你就能明白为什么system_server不像App一样有ApplicationContext但它有整个系统级别的systemContext。2.2 关键代码路径逐行拆解现在我们缩小范围看startBootstrapServices()里的AMS相关代码。在AOSP里你会在SystemServer.java中看到类似这样的片段不同版本略有差异Android 13比较接近// 通过SystemServiceManager启动ActivityManagerService的Lifecycle mActivityManagerService mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); // 将AMS注册到系统进程同时进行权限和系统Provider的初始化 mActivityManagerService.setSystemProcess(); // 安装系统Provider比如SettingsProvider、MemoryProvider等 mActivityManagerService.installSystemProviders();ActivityManagerService.Lifecycle这个类非常典型它继承了SystemService内部创建了ActivityManagerService实例并暴露getService()静态方法。为什么用Lifecycle包装而不直接在SystemServer里new ActivityManagerService()原因在于SystemServiceManager能够统一管理服务生命周期提供启动、异常捕获和Boot Phase回调。这样SystemServer就只管按阶段叫服务而每个服务自己知道何时该做什么。setSystemProcess()这名字听起来抽象其实就是把AMS注册到ServiceManager里让其他进程可以通过Binder拿到IActivityManager代理。同时它还会向PackageManager注册权限、设置系统进程的package相关信息。这一步做完AMS才算对外“可见”了。installSystemProviders()则是把一些系统级别Provider放进系统里最常见的是SettingsProvider因为很多组件启动时需要读系统设置。这一步要是晚于开机广播很多服务读取设置就会返回空值所以必须前移。2.3 线程、Handler、Looper的初始化看AMS构造函数时第一个吸引眼球的是线程创建mHandlerThread new ServiceThread(ActivityManager, Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); mHandler new MainHandler(mHandlerThread.getLooper());AMS把大量主流程消息放到这个名为“ActivityManager”的线程里处理而不是直接跑到system_server的main线程。为什么因为AMS的Binder调用量非常大如果都在main线程上执行任何一个耗时逻辑都会把整个系统服务卡死。独立工作线程让AMS能更从容地处理进程启动、广播分发、Service调度这些脏活累活。理解这一点对看启动代码特别有用。你经常会看到类似mHandler.post(...)或者obtainMessage(...).sendToTarget()要知道这不是随便玩线程而是为了把任务投递到一个带顺序保证的消息队列里。AMS里还有mUiHandler负责一些需要主线程才能做的UI相关操作mProcStartHandler专门处理进程启动的排队逻辑。不同Handler负责不同职责拆得很细这也是后期AMS代码越来越难读的原因之一。有个特别容易踩的坑AMS构造函数里很多成员变量都是直接new出来的比如mProcessList、mServices、mBroadcastQueues但它们内部去拿其它系统服务时可能会发生跨Binder调用。如果那个被调的服务还没启动就可能返回空引用或者抛异常后导致system_server崩掉。所以源码里往往会有大量防御性判断和延迟初始化这也是为什么AMS不是一口气把所有东西都初始化完而是按Boot Phase分批做。2.4 从启动到“准备就绪”Boot Phase的递进SystemServiceManager在提供服务启动时除了调用onStart()之外还会在系统进入某个阶段后调用onBootPhase(int phase)。AMS参与的阶段通常有这几个Boot Phase大概含义AMS在这阶段做什么PHASE_WAIT_FOR_DEFAULT_DISPLAY等待默认显示设备确认屏幕可用为窗口动画和Home做准备PHASE_SYSTEM_SERVICES_READY核心服务已就绪执行systemReady()前的准备工作PHASE_ACTIVITY_MANAGER_READYAMS自身就绪恢复前次任务、启动开机广播PHASE_THIRD_PARTY_APPS_CAN_START第三方应用可启动允许普通App进程创建启动桌面你可能会在日志里看到Starting phase 500...或Boot phase 600...之类的字样这分别对应上面的常量。理解阶段递进最大的价值是排查问题时能分清“AMS到底卡在哪一步”。比如系统一直没启动Home可能是PHASE_SYSTEM_SERVICES_READY之后某个依赖服务没回复也可能AMS的systemReady()没有拿到正确的首屏Intent。这个我们到后面的实战部分会展开。3. AMS启动过程中那些看不见的底层机制3.1 BinderAMS与其他进程对话的门牌AMS本身是个Java对象但要让别的进程能调用它必须通过Binder跨进程通信。setSystemProcess()里会调用ServiceManager.addService(activity, ams)这里的ams其实是通过ActivityManagerService内部类LocalService往外暴露的Binder实体。客户端进程通过ActivityManager.getService()拿到的是IActivityManager的代理调用方法时数据会经Binder驱动转发到system_server进程里。启动AMS时core framework会先确保Binder驱动是正常的否则addService都加不上。你在SystemServer里还经常看到类似Binder.setThreadPoolMaxSize之类的调用这是在给system_server进程的Binder线程池调参。线程池不够用会导致跨进程调用排队系统启动时会表现为“某些服务响应慢”。如果你在改AMS碰到“其他进程调不到我”的诡异问题第一反应应该是查servicemanager是否成功注册而不是怀疑逻辑不对。用adb shell service list能看到ams是否在列表里这是很直接的验证。3.2 Context、SystemServiceManager与权限检查的早期建立SystemServer在创建各种服务之前会先用自己的ActivityThread创建好一个系统Context。传统App的Context由ActivityThread创建但system_server也是一个Java进程它照样有自己的ActivityThread实例。AMS构造时拿到的systemContext一般就是这个系统级Context它没有Application的概念但持有系统资源的Resources、PackageManager、Theme等。这里有个很容易误解的地方SystemServiceManager并不只是“能帮忙new服务”它还会对服务的类进行反射实例化、记录启动时序、统一设置looper并且像保姆一样捕获异常。如果某个服务启动时抛异常SystemServiceManager可能会直接让system_server进程退出以保证系统不会带着半残废的服务运行。这在调试AMS时很有用你看到一个服务没起来就去找SystemServiceManager的日志它一般会告诉你“failed to start service X”。权限检查在AMS启动里也很核心。AMS要做很多系统级操作比如杀进程、改adj、检查权限它必须先取得自己的IPermissionManager。在setSystemProcess()阶段AMS会把自己注册进PackageManager表示“我是系统进程我拥有大量运行时权限”。一旦这一步出错后面AMS无论做什么系统权限操作都会失败表现为杀应用也杀不了、设置进程状态也设置失败。3.3 与Zygote的Socket通信和进程孵化通道AMS启动后最重要的能力之一是能“生进程”。这个能力来自一个叫ZygoteProcess的类AMS在进程中通过mProcessList间接持有它。ZygoteProcess封装了与Zygote进程之间的Socket协议默认连接/dev/socket/zygote。当AMS要启动一个App时它会将应用入口、uid、gid、附加参数、SELinux信息等打包通过Socket发给ZygoteZygote收到后fork出一个新的进程然后在新进程里执行RuntimeInit和应用入口。这个通道在AMS启动时其实早就通了因为system_server本身就是Zygote fork出来的继承的文件描述符里可能已经存在Zygote socket相关的东西。也因此“鸡生蛋、蛋生鸡”的问题被拆解得很干净Zygote先启动SystemServerSystemServer再启动AMSAMS再反向通过Zygote启动别人。你读源码时如果看到ProcessList里一堆ProcessRecord、ProcessState不要慌它们都是AMS通过这个通道孵化出的进程的记录。调试时有个小技巧当你怀疑AMS启动进程的速度有问题可以用adb shell cat /dev/socket/zygote确认socket权限是否正常或者用adb shell ps -A | grep zygote看Zygote进程是否活着。如果Zygote都挂了AMS再怎么调也不会成功。3.4 启动早期最容易被忽略的Uid和SELinux决策SystemServer进程本身是以system用户uid1000运行的SELinux策略里给它分配了system_serverdomain。AMS启动过程中几乎每一步都会跟SELinux打交道。比如创建一些目录、写统计数据、访问网络状态、读取配置文件都必须符合SELinux规则。一旦规则不对你在logcat里会看到大量的avc: denied记录。我见过不少初学者改AMS启动逻辑添加了一个简单的文件写入操作结果系统直接起不来logcat里全是权限拒绝。这种问题不是Java代码逻辑错误而是SELinux策略没有允许system_serverdomain去写那个文件路径。解决办法是在合适的.te规则里增加allow语句或者避开特殊路径。这部分内容平时大伙儿讲得不多但实际做系统裁剪、定制ROM时特别常见建议在学AMS启动时顺带扫一眼system_server.te文件。4. 实战验证如何用日志和工具确认AMS走了正确的路4.1 logcat里的启动轨迹代码看再多不如在真机或模拟器上亲眼看到AMS的生命轨迹。开机后抓logcat我会习惯性用这个命令adb logcat -b all -s SystemServer:* ActivityManager:* ActivityTaskManager:*这里-b all表示抓main、system、crash、events几个缓冲区单独的SystemServertag会打印服务启动阶段的很多关键点。你会在日志里看到类似SystemServerTiming的条目记录每个服务启动耗时还有SysServiceStart这类结构化事件。如果AMS启动阶段出了问题通常在这个tag下会直接看到异常栈。AMS真正开始“干活”的标志是你看到日志里有ActivityManager: Start proc ...这样的输出说明它已经在尝试孵化应用进程了。再往后会看到ActivityManager: Start proc 1000 for activity com.android.launcher3/.Launcher之类的语句这代表桌面已经启动。如果你一直看不到这一行说明AMS还没走到systemReady()。4.2 通过dumpsys activity查看AMS状态adb shell dumpsys activity是了解AMS运行时状态最直接的命令。它可以拆成很多子命令比如dumpsys activity processes打印当前所有进程、uid、pid、进程优先级和最近状态。dumpsys activity activities打印Activity栈详情、焦点窗口等。dumpsys activity services打印正在运行的Service和绑定关系。dumpsys activity broadcasts打印广播队列信息。在启动刚完成时用dumpsys activity processes能看到system_server自身和已启动的系统进程。重点看每一行里的“adj”字段它对应AMS计算出的进程优先级。如果某个应用进程的adj反复闪烁说明AMS的内存回收策略正忙。你还可以通过dumpsys activity来确认AMS到底处于哪个阶段但官方没有提供一个直接的mBootPhase字段所以更多是靠日志和进程列表来推断。4.3 排查AMS启动异常的常规手段如果AMS在启动过程中出了问题通常不是“crash一下”那么简单而是整个system_server进程反复重启或者开机卡在动画上。我的排查顺序一般是先用adb logcat -b crash看有没有Java崩溃。AMS的主体跑在system_server进程里要是它自己崩了crash buffer会留下Process: system_server的异常日志。如果只看到“Fatal signal”之类的native崩溃那还要带上adb shell debuggerd -b去看native栈。然后看/data/anr/和/data/system/dropbox里有没有最近生成的异常文件。AMS启动慢导致系统关键服务超时经常会在这里留下痕迹。接着用kill -3 pidof system_server让system_server打印一份Java线程栈到/data/anr/能看到AMS卡在哪一段代码上。如果是死锁栈里通常会有“held by”这样的提示词。如果系统进入了“反复重启”的循环最大的嫌疑是Watchdog。Android里有一个Watchdog机制它会监控system_server里几个核心线程的响应时间如果超过一定时间没有得救就会杀掉system_server重新启动。这种情况下logcat里能看到WATCHDOG KILLING SYSTEM PROCESS后面往往跟着一堆线程栈。不要一上来就怀疑AMS先看是哪个线程被卡住再顺着栈去查它等什么。4.4 常见问题与排查技巧实录这里整理几个我在调试中遇到过的问题不一定都只出现在“启动过程”但很多都和系统服务生命周期有关。现象可能原因排查路径开机动画出现后卡住桌面迟迟不显示AMS的systemReady()没有完成或Launcher没有被拉起抓ActivityManager日志看是否有Start proc ... Launchersystem_server反复重启每次启到一半就退AMS构造或某个Boot Phase抛异常logcat -b crash定位异常栈优先怀疑新改的代码第三方应用一直显示“Waiting to debug/Force close”进程孵化通道异常或Zygote被阻塞检查zygote进程状态确认socket可连接logcat出现大量avc deniedSELinux策略不允许system_server做某个操作抓取denied字段去. te规则增加allowAMS启动非常慢导致开机超时某个依赖服务启动慢如PackageManager看SystemServerTiming找出耗时最长的服务重点提醒一句AMS启动期间的日志往往不像普通应用那么好抓因为system_server有时会在早期阶段崩溃logcat缓冲区也会被刷掉。遇到这种情况建议用adb reboot后用adb logcat -b all -c adb reboot提前清空缓冲再开机时完整抓取。如果手头有串口或内核日志那更是排查神器。5. 避坑指南与个人经验5.1 我踩过的三个坑第一次在AMS启动流程里加代码我犯了一个经典错误在构造函数里直接调Binder方法想获取另一个还没有启动的服务。结果可想而知system_server抛了空指针然后开始无限重启。那次我花了一个多小时才意识到问题根本不在代码逻辑而在启动顺序上。后来养成了习惯凡是跨服务调用先确认目标服务是否已经加入ServiceManager或者在调用四周包一层“如果拿不到就稍后重试”的处理。第二个坑是误以为AMS只在SystemServer.java里被启动。实际上很多逻辑藏在了ActivityManagerService的onStart()和onBootPhase()里。你如果只在SystemServer.java里打断点会发现AMS构造正常但后续一堆系统行为根本没按预期走因为那些都在Boot Phase回调里。我后来把所有Boot Phase的入口都打上日志才真正看懂启动过程的全貌。第三个坑和代码无关是测试环境。改AMS这种系统级代码在真机上反复刷机特别费时间还容易变砖。我后来都是先在带有可调试userdebug版本的模拟器上操作先验证核心链路再跑真机。模拟器虽然启动慢但可以随时拉日志、重启system_server效率反而高很多。5.2 给Framework初学者的三个建议第一不要一上来就追着AMS源码逐行走很容易迷路。建议先读SystemServer.java的启动顺序再读SystemServiceManager.java理解生命周期最后才打开ActivityManagerService看关键方法。顺序反了你的脑袋会被字段名塞满。第二把“打日志”当成第一工具。启动过程涉及线程切换和Binder回调单靠读代码很难建立时序感。你可以在关键方法入口加一条Log.i(zhouchen, AMS start: xxx)然后跑一遍抓logcat让日志引导你去看逻辑而不是靠猜。第三保持版本意识。AOSP不同大版本之间AMS启动相关代码变动相当频繁。网上很多老文章用的是Android 7/8的路径放到Android 13上已经找不到入口了。我建议你看源码时锁定一个具体版本比如Android 13或14最好用android.googlesource.com和本地的repo镜像对照着看。5.3 从AMS启动过程延伸出去的知识点AMS启动如果看透了你已经比很多人强了。接下来可以顺着这条线往四个方向延伸一是ActivityTaskManagerService看它如何接管任务栈二是进程管理里的OomAdj和ProcessList了解AMS如何决定哪个进程先被杀三是Broadcast和Service的内部队列机制毕竟启动时有很多系统广播正是AMS分发的四是Watchdog的实现这能帮你快速排查系统服务卡死问题。这四个方向都建立在启动过程之上有了主干再填枝叶会扎实得多。最后再说个实用小技巧如果你在改AMS启动相关代码建议在SystemServer.java的startOtherServices阶段加一段System.nanoTime()计时代码或者直接用logcat自带的SystemServerTiming很快能对比出AMS在哪个环节最耗时。别小看这个定位启动慢问题的时候比你在代码里瞎猜要省事一个数量级。