第二十一章:稳定性与测试:CTS/VTS 测试、Monkey 测试、稳定性问题定位
各位同学,今天我们来聊聊车载系统里最“磨人”但又最绕不开的话题——稳定性与测试。
说实话,我在这个领域摸爬滚打这么多年,见过太多“功能跑得飞起,一上路就崩”的项目。你想想看,手机死机了重启一下就行,车载系统要是死机,那可是要出大事的。所以,稳定性测试在 Automotive 开发中,地位比功能开发还要高。
这一章,我会把 CTS/VTS、Monkey 测试,还有 Tombstone 和 Logcat 的定位技巧,掰开了揉碎了讲给你听。
21.1 CTS/VTS 测试:Google 的“入场券”
CTS(Compatibility Test Suite)和 VTS(Vendor Test Suite),说白了就是 Google 给你发的“入场券”。你的车机系统要想通过认证,这两项测试必须过。
CTS 测什么?
CTS 主要测 Android Framework 层的兼容性。比如你的系统能不能正确响应 Intent?App 能不能正常调用 Camera?这些都是 CTS 的覆盖范围。
VTS 测什么?
VTS 则更底层,它测的是 HAL(硬件抽象层)和内核的接口。比如你的 GPS HAL 是否实现了所有必须的函数?你的音频 HAL 延迟是否达标?
我个人习惯,在项目早期就把 CTS/VTS 的测试环境搭好。别等到最后才跑,那时候发现问题,改起来成本太高了。
- CTS 失败 → 通常是 Framework 或 App 层的问题
- VTS 失败 → 通常是 HAL 或 Kernel 驱动的问题
- 两者都失败 → 检查基础系统镜像是否完整
21.2 Monkey 测试:暴力测试的艺术
Monkey 测试,名字听着挺可爱,但干的事一点都不温柔。它就像一个“熊孩子”,在你的系统上随机乱点、乱滑、乱按。
为什么要做 Monkey 测试?因为用户的行为是不可预测的。你永远不知道用户会在导航的时候同时打开音乐,又在倒车影像弹出来的时候去点设置。
我曾经在一个项目中,Monkey 跑了 3 个小时都没问题,结果第 4 个小时突然崩了。查了半天,发现是一个极其罕见的竞态条件——两个线程同时访问了同一个未加锁的 HashMap。
跑 Monkey 测试时,我建议你注意以下几点:
- 指定包名:用
-p参数限定测试范围,避免点到系统设置里的危险选项 - 控制事件间隔:用
--throttle参数,别让事件太快,否则容易触发系统 ANR - 记录日志:一定要把 Monkey 的日志和系统 Logcat 一起保存,方便事后分析
# 一个典型的 Monkey 测试命令
adb shell monkey -p com.android.car --throttle 200 -s 12345 -v -v 10000
这个命令的意思是:在车载系统的主应用上,每隔 200 毫秒发送一个随机事件,总共发送 10000 个事件,种子是 12345(方便复现)。
21.3 稳定性问题定位:Tombstone 与 Logcat
系统崩了,怎么办?别慌,先找“尸体”——Tombstone 文件。
Tombstone 是什么?
Tombstone 是 Android 系统在 Native 层程序崩溃时生成的“死亡报告”。它记录了崩溃时的寄存器状态、堆栈信息、内存映射等。说白了,就是系统给你留的“遗书”。
我一般会这样定位问题:
- 先看 Logcat:Logcat 里通常会有明显的错误日志,比如
FATAL EXCEPTION或CRASH字样 - 再找 Tombstone:Tombstone 文件通常位于
/data/tombstones/目录下,文件名是tombstone_XX - 解析堆栈:用
addr2line或ndk-stack工具,把堆栈地址翻译成具体的代码行号
如果 Tombstone 里的堆栈信息不全,可以试试用 debuggerd 手动触发一次 dump。命令是:adb shell debuggerd -b [PID]。这样能拿到更详细的线程信息。
Logcat 怎么看?
Logcat 里的信息很杂,我一般会先用 grep 过滤关键词。比如:
# 只看错误级别的日志
adb logcat *:E
# 过滤特定进程的日志
adb logcat --pid=1234
# 保存到文件,方便慢慢看
adb logcat -d > crash_log.txt
嗯,这里要注意一点:Logcat 的缓冲区是有限的。如果系统反复崩溃,旧的日志会被覆盖。所以,一旦发现崩溃,第一时间把 Logcat 导出来。
21.4 实战:一次典型的稳定性问题排查
我拿一个真实案例来说吧。有一次,我们的车载系统在跑 Monkey 测试时,大概跑到 5000 个事件左右,系统突然黑屏重启了。
排查步骤是这样的:
- 查看 Logcat:发现最后一条日志是
SurfaceFlinger: Failed to allocate buffer - 检查 Tombstone:在
/data/tombstones/下找到了一个tombstone_00文件,指向了libgui.so里的一个函数 - 解析堆栈:用
addr2line翻译后,定位到BufferQueueProducer.cpp的第 342 行 - 分析代码:发现是 BufferQueue 在 dequeueBuffer 时,没有正确处理内存不足的情况,导致了一个空指针异常
你看,整个流程其实不复杂。关键是要有耐心,一步一步来。
我曾经遇到过一个问题:Tombstone 文件生成了,但堆栈信息全是问号。后来发现是编译时 strip 掉了符号表。所以,调试版本一定要保留符号信息,用 LOCAL_STRIP_MODULE := false 来控制。
21.5 知识体系总览
为了让你更直观地理解这一章的内容,我画了一张图。它把稳定性测试的三大块——CTS/VTS、Monkey、问题定位——串在了一起。
这张图把 CTS/VTS、Monkey 测试和问题定位串联了起来。你可以看到,这三者不是孤立的——CTS/VTS 保证基础兼容性,Monkey 测试暴露隐藏问题,而 Tombstone 和 Logcat 则是我们解决问题的“手术刀”。
好了,这一章的内容就到这里。稳定性测试没有捷径,就是一遍遍地跑、一遍遍地看日志、一遍遍地修。但只要你掌握了这些工具和方法,再难的问题也能找到根因。