2、Bootchart工具详解:Bootchart原理、抓取方法、日志解读与可视化分析

好,咱们进入第二章。Bootchart 这个工具,说白了就是 Android 启动优化的「CT 机」。没有它,你优化启动就像蒙着眼睛走路。我个人习惯,拿到一台新设备,第一件事就是跑一遍 Bootchart,看看它到底在磨蹭什么。

2.1 Bootchart 的工作原理

Bootchart 其实不复杂。它本质上是一个轻量级的性能剖析工具,专门盯着系统启动过程。

它的核心思路是这样的:

  • 采样:每隔一小段时间(默认 200 毫秒),拍一张系统状态的快照。
  • 记录:拍下 CPU 每个核在干什么、哪些进程在跑、磁盘读写有多忙、进程间上下文切换有多频繁。
  • 输出:把这些快照数据写到一个日志文件里,通常是 /data/bootchart/ 目录下的 headerproc_diskstats.logproc_ps.logproc_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 图表。到时候你会发现,原来启动优化没那么玄乎。