27、日志与调试:logcat 高级用法、systrace 分析、Bugreport 解读
说实话,做 Android Automotive 开发,最离不开的就是日志和调试工具。车机系统不像手机,出了问题你没法直接拿过去看——用户坐在车里,你总不能趴车窗上盯着 log 吧?所以,掌握 logcat、systrace 和 Bugreport 这三板斧,是每个车载工程师的必修课。
我个人习惯把这三种工具比作「望闻问切」:logcat 是「问」,直接看系统说了什么;systrace 是「切」,摸一摸系统的脉搏;Bugreport 是「望」,把整个系统的状态拍一张全景 X 光片。今天我们就一个一个聊透。
logcat 高级用法:别只会 grep
很多同学用 logcat 就是 adb logcat | grep xxx,然后盯着屏幕看。嗯,这当然能用,但效率太低了。尤其是在 Automotive 这种多进程、多服务的环境下,日志量是普通手机的好几倍。
按优先级和标签过滤
我建议你养成用 -s 参数的习惯。比如我只想看 CarService 的警告以上日志:
adb logcat -s CarService:W
这样输出干净很多。你还可以组合多个标签:
adb logcat -s CarService:W SystemUI:E
缓冲区选择
Android 有多个 log 缓冲区:main、system、crash、events。默认只输出 main 和 system。但有些关键信息藏在 events 里,比如用户操作、窗口切换:
adb logcat -b events
我在项目中遇到过一个问题:车机蓝牙连不上,main 和 system 里什么异常都没有。后来我看了 events 日志,发现是蓝牙服务在启动时抛了一个权限检查的异常,events 里记录得清清楚楚。
时间戳和线程号
调试时序问题时,一定要带上时间戳:
adb logcat -v threadtime
这样每行日志都会显示线程 ID 和精确到毫秒的时间。你想想看,两个服务谁先谁后,一目了然。
-v usec 把时间精度提升到微秒级。虽然大多数场景用不到,但关键时刻能救命。
日志保存与轮转
车机日志量很大,直接输出到终端容易丢。我习惯用 -f 写到文件,配合 -r 做轮转:
adb logcat -f /sdcard/log.txt -r 1024 -n 5
这样每个文件 1MB,最多保留 5 个文件。不会撑爆存储,也不会丢日志。
logcat 可能看不到。你需要用 adb root 或者 adb shell setenforce 0 临时关闭(仅限开发设备)。
systrace 分析:抓住性能瓶颈
logcat 告诉你「发生了什么」,systrace 告诉你「花了多长时间」。说白了,systrace 就是系统的火焰图,能精确到每个函数调用的耗时。
基本用法
我一般这样启动 systrace:
python systrace.py -t 10 -o trace.html gfx input view wm am
-t 10 表示采集 10 秒,-o 指定输出文件。后面的标签是你要跟踪的模块。车载开发中,我建议至少加上 hal 和 rs:
python systrace.py -t 10 -o trace.html gfx input view wm am hal rs
怎么看 systrace
打开生成的 HTML 文件,你会看到一堆彩色的条条。别慌,我教你三步走:
- 看整体负载: 最上面是 CPU 使用率,如果某个核一直 100%,说明有线程在死循环。
- 找长条: 每个彩色条代表一个函数调用,条越长说明越慢。重点关注那些明显比周围长的。
- 看唤醒链: 点击一个条,下面会显示它被谁唤醒的。我曾经靠这个发现一个服务被另一个低优先级的线程频繁打断。
核心经验: 在 Automotive 上,最常见的性能问题是「Binder 调用阻塞」。systrace 里如果看到大量 Binder 线程处于「waiting for work」状态,说明某个服务响应太慢。我曾经排查过一个空调面板卡顿的问题,最后发现是某个 HIDL 服务在等待硬件响应时超时了。
自定义跟踪点
你可以在自己的代码里加跟踪点,这样 systrace 就能看到你的函数耗时:
import android.os.Trace;
Trace.beginSection("updateCarSpeed");
// 你的业务逻辑
Trace.endSection();
嗯,这里要注意:beginSection 和 endSection 必须成对出现,而且不能嵌套错。我见过有人忘记调 endSection,结果整个 trace 都乱了。
Bugreport 解读:系统的全景 X 光片
Bugreport 是 Android 提供的最全面的诊断工具。它把系统当前的状态全部 dump 出来——进程列表、内存使用、网络状态、日志缓冲区、ANR 信息……全在一个 zip 包里。
生成 Bugreport
adb bugreport
执行后会在当前目录生成一个 bugreport-日期.zip 文件。解压后里面有一个 bugreport-设备名-日期.txt,这是主报告文件。
快速定位关键信息
这个文件动辄几十 MB,直接看会疯掉。我教你几个 grep 关键词:
| 关键词 | 作用 |
|---|---|
ANR in |
查找应用无响应记录 |
FATAL EXCEPTION |
查找崩溃堆栈 |
lowmemorykiller |
查看是否因内存不足杀进程 |
ServiceManager |
查看系统服务注册状态 |
DUMP OF SERVICE |
每个服务的详细 dump 信息 |
我曾经排查过一个 CarService 启动失败的问题。Bugreport 里搜 DUMP OF SERVICE car_service,发现它一直在等待一个硬件 HAL 服务注册,而那个 HAL 根本没起来。如果没有 Bugreport,这种跨进程的依赖问题很难定位。
重点关注:dump 中的 Automotive 特有信息
在 Automotive 上,Bugreport 还会包含一些车机特有的 dump:
- CarService dump: 车辆属性、空调状态、车门状态等
- Vehicle HAL dump: 硬件抽象层的当前值
- AudioPolicy dump: 音频焦点、音区分配
- Display dump: 多屏显示配置
你想想看,如果用户说「空调没反应」,你直接看 CarService dump 里空调属性的当前值,就知道是上层没发指令,还是底层没响应。省去了大量复现的时间。
知识体系总览
下面这张图总结了本章的核心内容,你可以把它当作调试时的「作战地图」:
这三样工具,单独用都能解决不少问题,但组合起来威力更大。我的习惯是:先看 Bugreport 了解整体状态,再用 logcat 缩小范围,最后用 systrace 精确定位。这样一套组合拳下来,大部分问题都能在半小时内找到根因。
好了,日志与调试这块就聊到这儿。工具终究是工具,关键还是多动手、多积累。你遇到的每个诡异问题,都会成为你下一次调试的直觉。