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绑定——这些都会影响启动速度。
1.4 埋点视角下的启动流程
好了,前两部分是理论地基。现在我们站在AMS的角度看看,埋点到底应该打在哪儿?
我个人习惯把AMS启动埋点分为三个时间窗口:
- 进程创建阶段:Zygote fork出App进程,AMS会记录 process start time。
- Application初始化阶段:AMS调用
attachApplication,App端执行onCreate。这里最容易丢埋点——很多开发者把这个阶段漏掉了。 - 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是启动流程的“总导演”,埋点就是他的场记板——打好每一板,后面分析才不慌。