2、Bootchart工具详解:Bootchart原理、抓取方法、日志解读与可视化分析
好,咱们进入第二章。Bootchart 这个工具,说白了就是 Android 启动优化的「CT 机」。没有它,你优化启动就像蒙着眼睛走路。我个人习惯,拿到一台新设备,第一件事就是跑一遍 Bootchart,看看它到底在磨蹭什么。
2.1 Bootchart 的工作原理
Bootchart 其实不复杂。它本质上是一个轻量级的性能剖析工具,专门盯着系统启动过程。
它的核心思路是这样的:
- 采样:每隔一小段时间(默认 200 毫秒),拍一张系统状态的快照。
- 记录:拍下 CPU 每个核在干什么、哪些进程在跑、磁盘读写有多忙、进程间上下文切换有多频繁。
- 输出:把这些快照数据写到一个日志文件里,通常是
/data/bootchart/目录下的header、proc_diskstats.log、proc_ps.log、proc_stat.log这几个文件。
嗯,这里要注意。Bootchart 不是自己主动去「分析」问题,它只负责忠实地记录。真正的分析工作,是在我们把日志拉出来之后,用可视化工具去解读。
核心要点:Bootchart 记录的是「系统级」的启动行为,不是某个 App 的启动行为。它关注的是 init 进程、Zygote、SystemServer 这些系统组件的启动时序。
2.2 如何抓取 Bootchart 日志
抓取方法分两种:一种是设备已经 root 了,另一种是没 root。我分别说说。
2.2.1 有 root 权限的设备
这个最简单。你只需要在系统启动完成后,执行以下命令:
# 1. 进入 root 模式
adb root
adb remount
# 2. 启动 Bootchart 记录(其实默认就是开启的)
touch /data/bootchart/enabled
# 3. 重启设备
adb reboot
# 4. 等待设备启动完成,拉取日志
adb shell 'cd /data/bootchart && tar -czf /data/bootchart.tgz *'
adb pull /data/bootchart.tgz
我曾经在一个项目里,发现设备重启后 /data/bootchart/ 目录是空的。查了半天,原来是 enabled 文件没创建成功。所以我的习惯是:重启前先 ls -l /data/bootchart/enabled 确认一下文件存在。
2.2.2 无 root 权限的设备
没 root 怎么办?别急,也有办法。Android 系统其实内置了一个 bootchart 服务,只是默认没开。你可以通过设置系统属性来启用:
# 设置属性,启用 Bootchart
adb shell setprop persist.bootchart.enabled 1
# 设置采样间隔(毫秒),默认 200
adb shell setprop persist.bootchart.interval 200
# 设置采样时长(秒),默认 120
adb shell setprop persist.bootchart.timeout 120
# 重启设备
adb reboot
设备启动后,日志会自动生成在 /data/bootchart/ 目录下。拉取方式跟上面一样。
注意:无 root 设备拉取日志时,如果提示权限不足,可以试试 adb backup 或者用 adb shell cat 逐个文件查看。不过说实话,没 root 的设备抓 Bootchart 确实有点折腾。
2.3 日志文件解读
日志拉下来之后,你会得到一个 bootchart.tgz 压缩包。解压后,里面有几个关键文件。我带你一个一个看。
| 文件名 | 内容说明 |
|---|---|
header |
记录系统基本信息,如内核版本、CPU 型号、内存大小、启动时间戳等 |
proc_stat.log |
CPU 使用率统计,每个采样点记录一次 |
proc_ps.log |
进程列表,包含每个进程的 PID、PPID、CPU 占用、内存占用等 |
proc_diskstats.log |
磁盘 I/O 统计,记录读写次数、读写扇区数等 |
你想想看,这四个文件合在一起,就能还原出系统启动时每一秒发生了什么。CPU 在忙什么?哪个进程在抢资源?磁盘是不是瓶颈?一目了然。
2.4 可视化分析
光看日志文件太累了。咱们得用工具把它变成图表。最常用的工具是 PyBootchart,一个 Python 脚本。
2.4.1 安装 PyBootchart
# 安装依赖
sudo apt-get install python3 python3-pip
pip3 install pybootchartgui
# 或者直接用源码
git clone https://github.com/mmeeks/bootchart.git
cd bootchart/pybootchartgui
python3 pybootchartgui.py /path/to/bootchart.tgz
2.4.2 生成图表
# 生成 PNG 图片
python3 pybootchartgui.py -o bootchart.png /path/to/bootchart.tgz
# 生成 SVG 矢量图(我比较喜欢这个,可以无限放大)
python3 pybootchartgui.py -o bootchart.svg /path/to/bootchart.tgz
2.4.3 图表怎么看?
生成的图表长这样:
- 顶部:CPU 使用率曲线。每个核一条线,颜色不同。如果某个核长时间跑满,说明那里有瓶颈。
- 中间:磁盘 I/O 曲线。读写分开显示。如果 I/O 曲线长时间在高位,说明磁盘是短板。
- 底部:进程时间轴。每个进程一条横线,从它启动到结束。线越长,说明这个进程启动越慢。
我记得有一次,看到一个项目的启动时间有 35 秒。一看图表,发现 surfaceflinger 进程启动花了 8 秒,明显不正常。顺着这个线索查下去,发现是显示驱动初始化时有个死循环。嗯,这种问题,没有 Bootchart 你根本想不到。
我的小技巧:看图表时,先看「进程时间轴」部分。找到那些启动时间特别长的进程,然后去查它为什么慢。通常 80% 的问题都集中在 20% 的进程上。
2.5 常见问题与避坑指南
最后,分享几个我踩过的坑。
- 日志为空:我曾经遇到过
/data/bootchart/目录下只有header文件,其他日志文件都是空的。原因是采样间隔设置得太短,系统来不及写入。建议保持默认的 200 毫秒。 - 图表无法生成:PyBootchart 报错说找不到数据。多半是因为日志文件不完整。检查一下
proc_ps.log文件大小,如果只有几 KB,说明采样时间太短,把timeout设长一点。 - 设备重启后日志丢失:有些设备的
/data分区在启动过程中会被格式化。解决办法是把日志输出到/cache分区,或者用persist.bootchart属性来启用。
好了,Bootchart 的基本用法就这些。下一章,我们会用实际案例,手把手教你分析一张真实的 Bootchart 图表。到时候你会发现,原来启动优化没那么玄乎。