1. AMS简介与Android启动流程

先聊聊AMS是什么。ActivityManagerService,简称AMS,是Android系统里最核心的服务之一。

我刚开始接触Android源码时,觉得AMS就是个“管家婆”——Activity、Service、Broadcast、ContentProvider,它全都要管。其实说白了,它就是整个Android应用层的大脑。所有App的启动、切换、生命周期管理,最后都要走到AMS这里来裁决。

1.1 AMS在系统中的地位

你可以把Android系统想象成一个大公司。Linux Kernel是基础设施(水电、安保),Zygote是人力资源部(负责生成进程),而AMS就是CEO办公室——它不直接干活,但所有重要决策都得经过它。

核心职责:

  • 管理Activity栈(谁在前台、谁要销毁)
  • 调度Service生命周期
  • 广播(Broadcast)分发与权限检查
  • ContentProvider的存活控制
  • 进程优先级与OOM调整

我记得有一次线上问题:某个App频繁ANR,查了一圈发现是AMS的广播队列卡住了。你能想象吗?一个广播卡住,全系统App都跟着遭殃。说白了,AMS一旦出问题,整个系统都会“感冒”。

1.2 Android启动阶段划分

Android从按下电源键到Launcher弹出来,中间经历了什么?我把它分为6个关键阶段。你想想看,这一套流程其实非常像组装一台电脑:先通电,再加载BIOS,然后操作系统内核起来,最后启动桌面。

阶段 说明 关键进程
1. Bootloader加载引导程序,校验分区bootloader.img
2. Kernel初始化硬件、驱动、内存管理kernel
3. Init解析init.rc,启动关键守护进程/init
4. Zygote创建虚拟机,预加载核心类zygote
5. System Server启动AMS、WMS、PMS等核心服务system_server
6. Launcher桌面启动,用户可见launcher

这里我想强调一下:AMS是在第5阶段“System Server”中诞生的。它不是一个单独进程,而是system_server进程里的一个线程。嗯,这里要注意,AMS虽然是“服务”,但它跑在system_server的Binder线程池里,所以AMS卡死就等于system_server卡死——整个系统都动不了了。

1.3 冷启动与热启动概念

这个大家平时用手机应该都有感受。我举个例子:你杀掉一个App后再点开,那叫冷启动;你按Home键回到桌面再切回来,那是热启动。

从技术角度说,冷启动指的是进程还没创建,AMS需要先fork一个进程出来,然后加载Application、创建Activity。热启动则是进程还在,只是Activity被销毁了,AMS直接重建Activity实例就好。

我的经验:很多开发者只关心代码性能,忽略了冷启动中AMS埋点的价值。其实冷启动阶段,AMS会打印大量日志(如 Displayed com.example/.MainActivity),这些日志就是我们做启动耗时埋点的核心数据源。

我曾经踩过一个坑:以为热启动速度一定比冷启动快。结果发现如果App的onCreate里做了大量网络请求或数据库操作,热启动重建Activity时照样慢得离谱。你看,埋点数据才是最诚实的。

再补充一个概念:温启动。进程存活但Activity被系统回收了,这种情况介于冷热之间。AMS埋点里通常把它们合并到冷启动一起统计,因为主要耗时还是发生在Application初始化阶段。

避坑指南:我曾经在某个ROM开发中,发现AMS埋点的启动耗时数据忽高忽低。查了半天,原来是系统服务启动阶段的锁竞争导致的。所以如果你的埋点数据出现异常峰值,先排查AMS是否在后台处理其他广播或Service绑定——这些都会影响启动速度。

Android 启动流程关键阶段 Bootloader Kernel Init Zygote System Server (包含AMS) Launcher fork system_server 💡 关键理解 • AMS在System Server阶段启动,不单独创建进程 • 冷启动 = 从Zygote fork新进程开始;热启动 = 进程存活,仅重建Activity • 启动耗时埋点主要采集“Displayed”时间戳与Application创建时间

1.4 埋点视角下的启动流程

好了,前两部分是理论地基。现在我们站在AMS的角度看看,埋点到底应该打在哪儿?

我个人习惯把AMS启动埋点分为三个时间窗口:

  1. 进程创建阶段:Zygote fork出App进程,AMS会记录 process start time。
  2. Application初始化阶段:AMS调用 attachApplication,App端执行 onCreate。这里最容易丢埋点——很多开发者把这个阶段漏掉了。
  3. Activity显示阶段:AMS收到 IApplicationThread.scheduleLaunchActivity 一直到 WindowManager.addView。最终用户看到首帧。

实战建议:如果你想做好AMS启动阶段埋点,第一步先在 ActivityManagerService.java 里找到 processStartTimeline 这个变量。它记录了进程创建的开始、结束时间,是冷启动的黄金起点。

这里有个坑——我记得某次项目里,团队发现埋点数据中“启动耗时”一直为0。查了半天,原来是埋点代码写在了 attachApplication 之后,但AMS日志居然没打印。嗯,后来发现是系统裁剪了一个log tag。所以说,埋点代码要放在AMS处理流程的“必经之路”上,别放在条件分支里。

最后简单列一下相关源码入口,方便你后续查阅:

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

// 进程创建时间记录
void startProcessLocked(String processName, ...) {
    ProcessStartTimeline tim = new ProcessStartTimeline();
    tim.startUptime = SystemClock.uptimeMillis();
    // ... AMS埋点打印
}

// 应用attach完成
final boolean attachApplicationLocked(IApplicationThread thread, ...) {
    // 在这里可以打上 Application onCreate 开始标记
    // 我通常在这里插入一个 Trace.beginSection()
}

好了,这一节就到这里。记住:AMS是启动流程的“总导演”,埋点就是他的场记板——打好每一板,后面分析才不慌。