3. 启动性能核心指标
在 Android 启动性能优化中,最容易出现的沟通障碍不是技术方案,而是“指标口径不一致”。产品说“启动太慢”,测试说“冷启动 1.8 秒”,系统工程师说“开机时间 32 秒”,应用工程师说“首帧 900 毫秒”——这些数字往往测的不是同一件事。因此,本章先把启动性能的核心指标拆开定义,明确每个指标的边界、测量起点、测量终点和常见采集方式,为后续优化建立统一语言。
一、核心原理:启动指标由“进程状态 + 测量区间”共同决定
Android 启动指标可以抽象成两个维度:第一是进程与组件的初始状态,第二是测量区间的起止点。进程状态决定了系统需要做多少工作,测量区间决定了这些工作是否被计入。冷启动、温启动、热启动的本质区别,就是进程、Application、Activity、页面数据是否已经存在。
- 冷启动:应用进程不存在,系统需要创建进程、初始化 Application、加载 Activity、完成首帧绘制。它是最完整、最慢、也最值得优化的路径。
- 温启动:进程可能仍存在,但 Activity 已销毁或需要重建,Application 通常已初始化。它介于冷启动和热启动之间,耗时主要落在 Activity 创建、资源加载和页面恢复。
- 热启动:进程和 Activity 都还在后台,系统只需把已有任务切到前台并恢复可见。它通常最快,主要受调度、内存压力和渲染恢复影响。
- 首次开机:设备第一次启动,涉及数据分区初始化、预置应用扫描、系统服务首次启动、DEX 优化等一次性工作,耗时显著高于后续开机。
- 二次开机:设备已经完成首次初始化后的正常重启,系统可复用已有缓存和优化产物,是评估“日常开机体验”的主要口径。
- 开机时间:从内核启动到系统可交互的端到端时间,通常细分为 Bootloader、Kernel、Init、Zygote、SystemServer、Launcher 等阶段。
- 应用启动耗时:从用户点击图标或系统发出启动 Intent,到应用首帧可见或可交互的时间,常用 TTID、TTFD 等指标表达。
关键结论:讨论启动性能时,必须先声明“测的是哪个指标、起点在哪里、终点在哪里、设备处于什么状态”。否则“1.5 秒”和“3 秒”可能都正确,只是口径不同。
二、测量口径:起点、终点与常用采集方式
不同指标的测量口径差异很大。应用启动耗时通常以用户点击图标或系统调用 startActivity 为起点,以首帧上屏为终点;开机时间则以 Bootloader 或 Kernel 起点为起点,以 Launcher 可交互为终点。工程上必须把口径写进测试用例,避免“同一指标、不同测法”。
| 指标 | 典型起点 | 典型终点 | 常用采集方式 |
|---|---|---|---|
| 冷启动 | 点击图标 / startActivity | 首帧可见或可交互 | Logcat、Perfetto、adb shell am start -W |
| 温启动 | 点击图标 / 任务恢复 | Activity 重建并首帧可见 | Perfetto、ActivityTaskManager 日志 |
| 热启动 | 任务切前台 | 已有 Activity 恢复可见 | Perfetto、系统调度日志 |
| 首次开机 | Bootloader / Kernel | Launcher 可交互 | bootchart、dmesg、logcat、Perfetto |
| 二次开机 | Bootloader / Kernel | Launcher 可交互 | 同上,需区分首次与二次 |
| 应用启动耗时 | 点击图标 / Intent | 首帧或可交互 | TTID、TTFD、Perfetto、Macrobenchmark |
在命令行中,常用 am start -W 获取应用启动耗时,它输出 TotalTime、WaitTime 等字段。需要注意,TotalTime 通常表示从 Activity 启动到首帧绘制完成的时间,而 WaitTime 还包含系统调度和 Activity 切换开销,两者不能混用。
adb shell am start -W -n com.example.app/.MainActivity
Starting: Intent { cmp=com.example.app/.MainActivity }
Status: ok
Activity: com.example.app/.MainActivity
ThisTime: 428
TotalTime: 428
WaitTime: 512
Complete
对于系统开机时间,常用 dmesg 查看内核阶段,用 logcat -b events 查看 boot_progress 事件,例如 boot_progress_start、boot_progress_preload_start、boot_progress_system_run、boot_progress_enable_screen 等。这些事件把开机过程切成可观测阶段,是定位“开机慢在哪一段”的基础。
三、场景案例:同一台设备,三种启动口径的差异
假设某应用在测试机上表现如下:冷启动 TotalTime 为 1280 ms,温启动为 620 ms,热启动为 180 ms;设备首次开机为 48 s,二次开机为 26 s。若产品只看到“启动 1.28 秒”,可能会认为优化空间不大;但拆开看,冷启动中 Application 初始化占 420 ms,Activity 创建占 310 ms,首帧渲染占 550 ms,优化重点就非常明确。
系统侧同样如此。首次开机 48 s 中,可能包含 12 s 的 DEX 优化、8 s 的预置应用扫描、6 s 的 SystemServer 初始化;二次开机 26 s 中,这些一次性工作大部分消失,剩余时间主要落在 Kernel、Zygote、SystemServer 和 Launcher。若把首次开机指标直接用于评估日常体验,就会误判优化收益。
建议:在性能看板中同时展示“冷启动 / 温启动 / 热启动”和“首次开机 / 二次开机”两组指标,并标注设备型号、系统版本、是否首次安装、是否清空缓存等前置条件。
四、误区与复盘:常见口径错误
- 把 WaitTime 当 TotalTime:WaitTime 包含系统调度和切换开销,通常大于 TotalTime,直接比较会放大应用耗时。
- 冷启动测试前未杀进程:进程仍在后台时测到的是温启动或热启动,数据会明显偏小。
- 首次开机与二次开机混测:首次开机包含一次性初始化,不能与二次开机直接对比。
- 只测首帧,不测可交互:首帧可见不等于用户可操作,TTID 与 TTFD 要区分。
- 忽略设备状态:低电量、温控降频、后台压力都会显著影响启动耗时,测试需固定条件。
复盘时建议把每次测试的“指标定义、起点、终点、设备状态、采集命令、样本数量”记录成固定模板。只有口径稳定,优化前后的数据才具有可比性,后续的瓶颈定位和收益验证才有意义。
掌握这些指标定义与测量口径后,后续无论是做应用冷启动优化、系统开机裁剪,还是建立性能看板,都可以在同一套语言下讨论问题。指标不是越多越好,而是每个指标都要有明确的起点、终点和适用场景,才能真正指导优化决策。