做Android开发这些年天天跟四大组件打交道最后都会绕到一个叫ActivityManagerServiceAMS的地方。startActivity、startService、registerReceiver看起来是各自为战实际全归它管。谁该启动、谁该暂停、内存吃紧先杀谁、任务栈怎么恢复都是它说了算。我真正下决心啃AMS的启动过程是因为遇到一台开机黑屏的设备顺着system_server日志一路追到AMS才明白整个开机链路里这一环有多关键。这篇东西就按我当时的排查思路把AMS从无到有的启动过程完整拆开讲清楚它什么时候创建、创建时做了什么、怎么一步步进入ready状态顺便把踩过的坑和排查心得一起放出来给正在啃framework的朋友做个参考。1. AMS到底是什么它凭什么这么重要1.1 Android系统里的“大内总管”如果把Android框架比作一家餐厅AMS就是那个大内总管。Activity是包厢里的客人Service是后厨的团队ContentProvider是仓库管理员BroadcastReceiver是传菜员。表面上各干各的但谁进哪个包厢、后厨团队要不要扩编、仓库数据怎么分发、传菜员什么时候待命全部由AMS统一调度。具体来说AMS至少管这几摊事组件调度所有Activity和Service的启动、停止、绑定都由它分配进程管理每个App进程的优先级adj由它打分低分进程在内存不足时最先被回收任务栈管理记录最近任务、返回栈、Activity启动模式这决定了你的返回键到底回到了哪一页系统级权限检查和多用户管理虽然细节拆给了别的模块但入口基本都在AMS。1.2 弄懂AMS启动过程能解决什么实际问题很多人觉得“AMS启动过程”是面试题背背流程就够了。但我在实际调试中发现不搞懂这一块遇到下面这些问题基本抓瞎开机黑屏停在logo桌面进程一直起不来你只知道“系统没起来”说不清是AMS没ready还是launcher被卡在pid 0system_server反复崩溃软重启日志里只有一堆“System is rebooting”不知道是AMS初始化失败还是后面某个服务把主线程弄死了设备从开机到可用要两分钟但不确定是哪一项服务拖了后腿权限异常导致某些系统应用闪退你可能压根没想到是AMS携带的权限数据在启动阶段就没配好。这些问题的共同点是现象在应用层根因全在SystemServer那几十个服务的启动时序。AMS又是其中最核心的一个所以把它的启动链路搞明白排错能力会直接上一个台阶。1.3 启动链路一句话时间线先把AMS在整个系统启动里的位置用一张表记住后面所有内容都是围绕这张表展开的阶段干了什么AMS在哪出现BootROM/BootLoader加载引导程序初始化基础硬件还不存在Kernel初始化驱动、内存、调度器还不存在init进程解析init.rc启动属性服务、Zygote不存在Zygote预加载Java框架类fork出SystemServerZygote内存中已有framework但AMS未实例化SystemServer.main启动系统服务按序构建AMS、PMS、WMS等AMS在此阶段创建并注册AMS.systemReady启动持久进程、恢复任务栈、发BOOT_COMPLETEDAMS正式进入“可用”状态这张表也解释了为什么AMS启动过程值得单独研究它不是一个“启动一下就完事”的服务而是分阶段从实例化走到ready链路很长任何一步出问题都会以各种诡异现象暴露在开机过程中。2. 从按下电源键到AMS准备就绪完整启动链路2.1 init、Zygote与SystemServer一次接力赛开机流程本质是一场接力赛。内核跑起来之后用户空间的第一个进程是initPID 1它负责解析init.rc配置文件把分区挂载好启动关键的native服务然后再把Zygote拉起来。Zygote是Android Java世界的“母进程”它的工作方式很巧妙进程启动前先fork自己子进程里再走Java层初始化。由于fork会完整复制父进程的内存Zygote在启动时提前把常用Java类和资源加载进内存这样后续每个App进程fork时就不用重新加载framework的类了启动速度和内存开销都好看很多。SystemServer就是Zygote fork出来的第一个进程也是整个framework服务的“家”。它内部会创建SystemServiceManager然后通过这个管理器逐个启动几十个系统服务。AMS就住在SystemServer里跟着它一起出生。2.2 Zygote如何“生”出SystemServer在AOSP源码里ZygoteInit的main方法会判断一个startSystemServer参数如果为true就调用forkSystemServer子进程拿到一个Runnable跑起来最终进入SystemServer.main。这里有个容易忽略的细节Zygote forkSystemServer时传进去的类名是com.android.server.SystemServer参数里还带着“--zygote”这样的标记目的是让SystemServer初始化时知道自己不是普通App。SystemServer.main做的事情很简单new一个SystemServer对象然后调用run()。真正的工作全在run()里面public static void main(String[] args) { new SystemServer().run(); } private void run() { // 创建系统上下文 createSystemContext(); // 创建SystemServiceManager mSystemServiceManager new SystemServiceManager(mSystemContext); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // 按批次启动服务 startBootstrapServices(); startCoreServices(); startOtherServices(); }这种三段式启动顺序是刻意设计的。startBootstrapServices是“引导批”只启动那些系统运行必需、且后续服务依赖的服务startCoreServices是“核心批”启动一些独立性强的基础服务startOtherServices是“其他批”把剩下的服务全部拉起来并在最后统一做“systemReady”的通知。2.3 AMS在SystemServer中的出场顺序AMS属于“引导批”里第二顺位的服务第一顺位是Installer服务它负责安装和删除应用时的native层操作必须先就位。紧接着就是AMS。为什么AMS要这么早启动因为后面很多服务比如PackageManagerServicePMS、WindowManagerServiceWMS都需要AMS帮忙处理进程、任务、权限相关的事情。PMS扫描完应用后要通知AMS更新权限和包信息WMS也要和AMS协同管理Activity窗口。如果AMS放在最后才启动整条链路会被卡住。但这里有个先后关系的细节AMS先构造PMS后构造两者之间还要交换数据。所以AMS的setSystemProcess阶段不会依赖PMS而是等PMS在startBootstrapServices里跑完扫描后再通过AMS的回调接口把权限信息补齐。这种“先建对象后补依赖”的设计在framework里非常常见目的就是尽量缩短启动串行时间。3. 源码视角AMS启动的核心代码路径3.1 构造阶段new ActivityManagerService里搭班子在startBootstrapServices里看到的第一句关键代码大概是这样的mActivityManagerService mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemProcess();AMS的构造过程有不少门道。它不是一个空壳对象而是会创建一条属于自己的消息线程mHandlerThread前台优先级允许IO因为AMS要处理大量binder调用和调度消息如果都堆在system_server主线程上主线程一旦被某个慢操作卡住整个系统就跟着卡死。独立线程让AMS既能保持响应又不会拖累主线程处理DisplayManager、WMS这些同样高优先级的服务。构造函数里还会初始化一堆内部组件ProcessList负责进程列表和adj值更新ActiveServices负责Service生命周期BroadcastQueue负责广播排队ActivityTaskManagerService负责Activity栈管理新版Android把Activity栈逻辑基本拆到了这个模块AMS作为入口统一调度ActivityManagerConstants则用来读系统配置比如最近任务数量上限、App启动超时时间等。用生活化的说法构造阶段就是“开张前先把店面、员工、账本、存货都准备好”这一步没做扎实后面的一切都是空中楼阁。3.2 从Lifecycle到onStartSystemServiceManager的启动机制SystemServiceManager.startService的入参是一个Class对象框架会通过反射创建实例然后把服务加入内部列表再调用onStart方法。AMS内部默认实现了Lifecycle类来做适配public static final 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; } }这段代码最大的价值是“早期化”真正的AMS实例在Lifecycle构造期间就已经创建完成而不是等onStart才创建。这样后续服务在startService返回后就能立刻拿到AMS对象不用等什么异步回调。start()里面做的事情主要是确认系统上下文、注册一些本地服务并启动AMS内部的消息处理线程为后续setSystemProcess和systemReady打基础。3.3 setSystemProcess与installSystemProviders注册与备料setSystemProcess这个方法是AMS启动里“对外亮相”的一步核心动作是把自己注册成系统级binder服务ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated */ false, DUMP_FLAG_PRIORITY_CRITICAL);这一步之后任何App进程都可以通过ServiceManager查询到“activity”服务再通过binder IPC调用到AMS。同时setSystemProcess还会做几件容易被忽略的事加载系统权限数据判断哪些权限是系统级预授权把system_server这个进程本身录入进程管理列表让它持有SYSTEM_ADJ的高优先级把AMS内部的一些实现接口注册进LocalServices方便系统内部模块没必要走binder就去直接调用。installSystemProviders是紧接着的“备料”工作。AMS所在的system_server进程要先安装好系统级的ContentProvider比如SettingsProvider后面系统和应用才能通过Settings读取各种配置。AMS会调用mSystemThread.installSystemProviders把系统包扫描出来的Provider列表逐个装好。这一步如果失败往往表现为开机后设置无法读取、各种系统服务初始化拿不到配置值异常日志又五花八门很容易让人误判成数据库问题。3.4 systemReady万事俱备的信号AMS从构造到setSystemProcess只是把服务本身拉起来了真正进入“系统可用”状态还要等systemReady。这个方法的调用发生在startOtherServices的末尾它接收一个Runnable回调回调内部会执行一系列“所有服务都准备好了才开始”的操作。核心逻辑可以概括成四件事恢复持久化数据和最近任务启动persistent进程——也就是常驻系统进程比如SystemUI、Telephony等发送LOCKED_BOOT_COMPLETED和BOOT_COMPLETED广播通知系统应用和普通应用开机完成启动桌面应用Launcher让用户看到可以操作的界面通知WindowManagerService做暂停/恢复窗口的整理结束开机动画。我建议你在阅读时重点盯一下systemReady里“goingCallback.run()”的位置它保证所有服务都处于可工作状态后才触发开机广播。这也是为什么有时候logcat里已经能看到BOOT_COMPLETED桌面还是黑屏——因为Launcher的启动请求是在AMS内部另一个线程里分发的回调顺序稍有异常就会出现“系统广播已发出但UI还没起来”的中间态。4. 启动过程容易被坑的地方与排查技巧4.1 开机黑屏先分清楚死在“哪一层”开机黑屏是我见过最多、也最容易误判的问题。同样一个黑屏可能是屏驱动没起来可能是SurfaceFlinger没起来可能是SystemServer没起来也可能是桌面进程没起来。层与层之间表现很像但排查路径完全不同。我的第一板斧永远是看logcat里的SystemServer、ActivityManager、SystemUI这几个tag。如果开机动画正常播放完才黑屏那屏幕驱动和SurfaceFlinger基本没问题重点看AMS有没有完成systemReady以及Launcher进程有没有被正常创建和attach。如果logcat里能看到Launcher的pid和adj但窗口一直没绘制就要再往ActivityTaskManager和WMS方向查。有个容易被坑的点开机黑屏时不一定是“异常”合理范围内的黑屏时间不等于故障。所以排查前先抓正常设备的基线对比AMS从构造到systemReady的耗时再判断是不是真的回退了。4.2 AMS启动变慢用日志时间戳锁定位点系统开机慢很多人上来就怀疑AMS里某个操作太慢但慢在哪里完全靠猜。其实可以用日志时间戳做一次粗定位。先用过滤命令把关键日志抓下来adb logcat -b all -s SystemServer ActivityManager ActivityTaskManager BootAnimation重点观察几个标志性时间点SystemServer.run()开始时间、AMS构造完成时间、systemReady调用时间、BOOT_COMPLETED发出时间。每个时间点之间如果有明显的等待间隙再用adb shell dumpsys activity查看AMS内部消息队列的情况看看是不是有长任务卡住了主线程。我遇到过一种情况AMS构造完成后setSystemProcess阶段要等PMS扫描完整个/vendor/app目录结果某个预装应用安装包损坏解析APK时反复抛异常导致AMS的systemReady迟迟没被调用。这类问题只看AMS本身的代码是看不出名堂的必须把PMS和AMS的日志对照起来看明白“AMS先构造、PMS后扫描、再通过回调补齐权限”的时序才能快速定位到“等PMS”这个节点上。4.3 权限与配置问题导致AMS异常AMS启动阶段对权限非常敏感。setSystemProcess时它会加载系统中的权限数据如果某个权限文件损坏或者内核SELinux策略没放行AMS可能直接抛出SecurityException导致system_server崩溃。还有一个容易被忽略的配置项平台签名。系统应用签名不对AMS在扫描时会对某些系统组件做权限校验签名不一致会直接拒绝加载表现是开机后部分系统应用一直“未安装”或者闪退。这种问题在自编译固件里很常见排查时用adb shell settings get global看设备标识和签名状态再对比构建时使用的platform密钥基本能锁定方向。另外内存配置也要提一下。AMS启动时会读取框架的low memory相关常量如果设备内存很小但系统配置里还是采用了高内存阈值的参数进程管理就会激进导致开机后桌面被误杀循环重启开不进去。4.4 三板斧排查dumpsys、ps与ANR trace真到排查现场我一般固定用三招按顺序来。第一招是adb shell dumpsys activity看AMS全局状态。注意这里有大量输出优先看Processes部分确认system_server和桌面进程是否存在、adj多少、是否处于“cached”或“receiving”等状态。如果桌面进程没有出现在列表里说明Launcher没被启动如果出现了但处于低优先级说明是被进程管理清掉了。第二招是adb shell ps -A | grep system_server确认system_server还活着、CPU占用是否异常。如果一个设备的system_server反复重启ps会看到pid在跳动这时再看logcat里有没有“System server died”之类的信息。第三招是抓ANR或重启前的trace。在userdebug或root设备上执行adb shell kill -SIGQUIT pid让system_server在/data/anr目录下输出当前线程栈重点看主线程和AMS消息线程在等哪把锁。很多时候AMS卡住不是AMS自身的问题而是其他服务持有锁一直不释放通过栈回溯能直接看到等待链。这三招看完大部分AMS启动相关的问题都能缩小到某个具体模块而不是在应用层瞎猜。5. 一点实操心得把AMS吃透的建议5.1 源码阅读顺序推荐如果准备从源码层面把AMS启动啃下来我的路径建议是这样的从SystemServer.java的run()入口开始先明白服务启动的批次划分接着读SystemServiceManager.startService理解Lifecycle的创建机制再进入ActivityManagerService的构造函数、start()、setSystemProcess()、installSystemProviders()、systemReady()按这个顺序读思路最顺。遇到Activity栈相关逻辑不用死磕细节Android 10以后Activity栈管理已经拆到ActivityTaskManagerService里先把AMS的主干搞清楚再按需要补ActivityTaskManager和ProcessList的专项知识即可。源码版本的选择上我建议从Android 10到Android 13之间选一个你手头设备能跑起来的版本不要单纯追求最新。新版代码里新增了很多可配置开关和模块化拆解主干逻辑虽然没变但细节量对于新手来说容易淹没主线。5.2 调试工具与设备准备准备一台能root或者userdebug的测试设备非常重要。没有root权限开机黑屏这种问题你很难从system_server进程层面入手。模拟器也可以但模拟器的内核、驱动和真机差异较大遇到SELinux策略或vendor相关的问题模拟器上复现不了。AOSP源码加Android Studio这个组合是我用的比较多的方案。源码可以方便地本地检索、断点调试Android Studio用来查看模块结构和单步跟踪Java层代码。搭建环境的过程确实比较折腾但如果你的目标是深入framework这一步省不掉。平时我会把这几条命令记在手机里adb logcat -b all -s SystemServer ActivityManager ActivityTaskManageradb shell dumpsys activity processesadb shell ps -A | grep system_server。排查的时候直接能用比现查快很多。5.3 记录“启动时间线”基线的好习惯最后分享一个帮过我好几次的习惯每次调试系统启动相关问题之前先抓一台正常设备的完整启动日志按我前面说的时间节点整理成基线数据。比如从SystemServer.run()到AMS构造完成是1.2秒从AMS构造完成到systemReady是3.8秒从systemReady到BOOT_COMPLETED是0.6秒。之后改动任何系统服务、预装应用或权限配置都拿这套基线做对比。有一次设备开机从15秒回退到25秒所有人都怀疑是某个自定义服务的问题我对了一下基线发现卡点根本不在自定义服务里而是PMS扫描阶段多耗了8秒最后查出来是某个预装APK没有对齐导致解析超时。没有基线数据这个问题可能要浪费一个下午去猜。启动过程这种长链路时间戳对比是最直接有效的排查手段希望你也养成这个习惯。