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 和精确到毫秒的时间。你想想看,两个服务谁先谁后,一目了然。

小技巧: 如果你在分析 ANR 或卡顿,可以用 -v usec 把时间精度提升到微秒级。虽然大多数场景用不到,但关键时刻能救命。

日志保存与轮转

车机日志量很大,直接输出到终端容易丢。我习惯用 -f 写到文件,配合 -r 做轮转:

adb logcat -f /sdcard/log.txt -r 1024 -n 5

这样每个文件 1MB,最多保留 5 个文件。不会撑爆存储,也不会丢日志。

注意: 在 Automotive 上,有些日志受 SELinux 策略保护,普通 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 指定输出文件。后面的标签是你要跟踪的模块。车载开发中,我建议至少加上 halrs

python systrace.py -t 10 -o trace.html gfx input view wm am hal rs

怎么看 systrace

打开生成的 HTML 文件,你会看到一堆彩色的条条。别慌,我教你三步走:

  1. 看整体负载: 最上面是 CPU 使用率,如果某个核一直 100%,说明有线程在死循环。
  2. 找长条: 每个彩色条代表一个函数调用,条越长说明越慢。重点关注那些明显比周围长的。
  3. 看唤醒链: 点击一个条,下面会显示它被谁唤醒的。我曾经靠这个发现一个服务被另一个低优先级的线程频繁打断。

核心经验: 在 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 里看到一个诡异的现象——某个车辆属性值在 0 和 1 之间来回跳。后来发现是 HAL 层的一个竞态条件,两个线程同时写同一个属性。Bugreport 的 dump 是「瞬间快照」,如果看到矛盾的值,基本可以断定有并发问题。

知识体系总览

下面这张图总结了本章的核心内容,你可以把它当作调试时的「作战地图」:

Android Automotive 日志与调试三板斧 logcat 「问」——系统说了什么 • 按标签/优先级过滤 • 多缓冲区选择 • 时间戳与线程号 • 日志保存与轮转 • SELinux 权限注意 systrace 「切」——系统花了多久 • 采集命令与标签 • 三步分析法 • 看负载/找长条/看唤醒 • Binder 阻塞排查 • 自定义跟踪点 Bugreport 「望」——系统全景快照 • 生成与解压 • 关键 grep 关键词 • ANR/崩溃/内存 • 服务注册状态 • Automotive 特有 dump 三者配合:logcat 定位现象 → systrace 分析耗时 → Bugreport 获取全景

这三样工具,单独用都能解决不少问题,但组合起来威力更大。我的习惯是:先看 Bugreport 了解整体状态,再用 logcat 缩小范围,最后用 systrace 精确定位。这样一套组合拳下来,大部分问题都能在半小时内找到根因。

好了,日志与调试这块就聊到这儿。工具终究是工具,关键还是多动手、多积累。你遇到的每个诡异问题,都会成为你下一次调试的直觉。

公众号:蓝海资料掘金营,微信deep3321