16、启动时间测量方法:bootchart工具使用,ftrace与systrace在启动分析中的应用,自定义启动时间打点
启动优化这件事,说白了就是「先得知道时间花在哪了」。你连瓶颈在哪都不知道,怎么优化?
我在项目里见过不少同学,一上来就闷头改代码,改完发现启动时间反而更长了。嗯,这就是典型的「没有测量就没有优化」。今天我们就来聊聊,Android 启动时间到底怎么测,用什么工具测,以及如何自己埋点。
16.1 启动时间测量的整体思路
先看一张图,帮你快速建立知识框架:
从图上你能看到,三个工具各有侧重。bootchart 适合看「谁先谁后」,ftrace 适合深挖内核,systrace 适合看整体流程。而自定义打点,则是你手里的「万能补丁」。
16.2 bootchart:最省事的启动分析工具
bootchart 是我个人最喜欢的工具。为什么?因为它不需要你改任何代码,开箱即用。
16.2.1 如何开启 bootchart
在 Android 10 之后,bootchart 默认是关闭的。你需要手动触发:
# 在 adb shell 中执行
touch /data/bootchart/enabled
reboot
重启后,系统会在 /data/bootchart/ 目录下生成数据文件。用 adb pull 拉下来,然后用 bootchart 工具解析:
# 拉取数据
adb pull /data/bootchart/ ./bootchart_data
# 解析生成 SVG 图
bootchart -f svg ./bootchart_data
system/core/init/bootchart.cpp,编译出来就能用。
16.2.2 怎么看 bootchart 图
生成的 SVG 图里,横轴是时间,纵轴是进程。你会看到:
- CPU 使用率曲线:顶部那条,如果一直跑不满,说明瓶颈在 IO 或锁。
- 进程启动时间线:每个进程从创建到就绪的时间。
- 磁盘读写:底部区域,看有没有大量读操作拖慢启动。
我曾经在一个项目里,发现 system_server 启动后等了 2 秒才开始启动 Launcher。一看 bootchart 图,发现有个第三方服务在 init.rc 里写了 class late_start,结果它占着 CPU 不放。嗯,改完就快了 1.5 秒。
16.3 ftrace:内核级别的「显微镜」
ftrace 是 Linux 内核自带的追踪工具。说白了,它能告诉你内核里每个函数被调用的时间。
16.3.1 基本用法
ftrace 通过 /sys/kernel/tracing/ 下的文件来控制。我常用的步骤:
# 进入 trace 目录
cd /sys/kernel/tracing
# 选择追踪器
echo function_graph > current_tracer
# 设置要追踪的函数(比如你想看 init 进程)
echo do_execve > set_ftrace_filter
# 开始追踪
echo 1 > tracing_on
# 跑你的测试(比如重启)
# ...
# 停止追踪
echo 0 > tracing_on
# 查看结果
cat trace
输出会是一长串函数调用树,像这样:
1) | do_execve() {
1) 0.123 us | getname();
1) 0.456 us | count();
1) 0.789 us | prepare_bprm_creds();
1) | exec_binprm() {
1) 1.234 us | load_elf_binary();
1) 0.567 us | flush_old_exec();
1) 2.345 us | }
1) 5.678 us | }
你看,每个函数的耗时一目了然。我在调优内核驱动时,就靠这个找到了一个 SPI 驱动初始化时多等了 200ms 的原因——它读了一个不存在的寄存器。
16.3.2 启动阶段用 ftrace 抓什么
我个人建议重点关注这几个点:
- init 进程的 do_execve:看 init 启动花了多久。
- 文件系统挂载:比如 mount、do_mount 相关函数。
- 驱动 probe:比如 platform_drv_probe,看哪个驱动慢。
set_ftrace_pid 只追踪特定进程,避免被其他进程的输出淹没。比如只追踪 init 进程:echo 1 > set_ftrace_pid(1 是 init 的 PID)。
16.4 systrace:用户态 + 内核态的统一视图
systrace 是 Google 官方推荐的性能分析工具。它把用户态的 Trace 和内核态的 ftrace 数据合并在一起,生成一个 HTML 文件,用 Chrome 打开就能看。
16.4.1 抓取启动阶段的 systrace
启动阶段的 systrace 需要在开机过程中抓取。我常用的命令:
# 在 adb shell 中执行
echo 1 > /sys/kernel/tracing/tracing_on
# 然后重启设备(保持 adb 连接)
adb reboot
# 等设备启动后,拉取 trace
adb shell cat /sys/kernel/tracing/trace > boot_trace.txt
# 或者用 atrace 直接抓
adb shell atrace --async_start -b 4096 am wm view
# 重启后
adb shell atrace --async_dump > boot_trace.html
adb shell perfetto 来抓,功能更强大。perfetto 是 systrace 的下一代工具。
16.4.2 怎么看 systrace 图
打开生成的 HTML 文件,你会看到:
- CPU 调度:每个 CPU 核心在跑什么进程。
- 进程状态:Running、Runnable、Sleeping 等。
- 自定义 Trace 段:如果你在代码里打了点,这里会显示。
我曾经遇到一个 case:Launcher 启动后白屏了 3 秒。用 systrace 一看,发现 Launcher 的主线程在等一个 Binder 调用,而那个 Binder 服务在 system_server 里,system_server 又在等一个 IO 操作。这一串依赖链,在 systrace 里看得清清楚楚。
16.5 自定义启动时间打点
工具再好,也有覆盖不到的地方。比如你想精确测量「从开机到 Launcher 绘制第一帧」的时间,bootchart 和 systrace 都做不到。这时候就需要自己埋点。
16.5.1 在 Java 层打点
Android 提供了 Trace 类,用法很简单:
import android.os.Trace;
public class MyApp {
public void onCreate() {
Trace.beginSection("MyApp.onCreate");
// 你的初始化代码
Trace.endSection();
}
}
这样在 systrace 里就能看到 MyApp.onCreate 这个段了。
16.5.2 在 Native 层打点
Native 代码用 ATrace:
#include <cutils/trace.h>
void my_init() {
ATRACE_BEGIN("my_init");
// 你的初始化代码
ATRACE_END();
}
16.5.3 在 init.rc 里打点
这个可能很多人不知道。init.rc 里也能打点:
on boot
# 开始一个 trace 段
write /sys/kernel/tracing/trace_marker "C|1|boot_start|0"
# 你的启动命令
start core
# 结束 trace 段
write /sys/kernel/tracing/trace_marker "C|1|boot_start|1"
ATRACE 宏,它会自动处理权限问题。
16.5.4 实战:测量「开机到 Launcher 第一帧」
我在一个项目中,需要精确测量这个时间。做法是:
- 在 Launcher 的
onFirstFrame回调里打点。 - 在 init 进程启动时打一个起始点。
- 用 systrace 抓取,然后看两个点之间的时间差。
代码大概这样:
// 在 Launcher 中
public class Launcher extends Activity {
@Override
public void onFirstFrame() {
Trace.beginSection("Launcher.firstFrame");
Trace.endSection();
}
}
然后在 systrace 里搜索 Launcher.firstFrame,看它离 init 的起始点有多远。这个时间就是「真正的启动时间」。
16.6 总结与避坑
好了,我们来快速回顾一下:
- bootchart:适合快速看进程启动顺序,不需要改代码。
- ftrace:适合深挖内核函数,精度高。
- systrace:适合看整体流程,结合用户态和内核态。
- 自定义打点:适合精确测量特定阶段的时间。
我曾经踩过一个坑:用 bootchart 分析时,发现某个服务启动很慢,以为是它的问题。结果用 ftrace 一查,发现是内核的 IO 调度器在搞鬼——它把读请求排在了写请求后面。嗯,这就是「工具选对了,问题就解决了一半」。
最后送你一句话:没有测量就没有优化,但测量本身也要选对工具。
公众号:蓝海资料掘金营,微信deep3321