3、Project Treble实战:使用Treble Test Suite验证设备兼容性,常见失败案例分析。
好,咱们直接进入正题。上一章我们把 Treble 的架构讲清楚了,这一章就来点实际的——怎么用 Treble Test Suite(简称 TTS)去验证你的设备到底兼容不兼容。
说实话,我见过太多团队,代码改得飞起,一跑 TTS 就崩。为什么?因为大家总觉得「不就是跑个测试吗」。嗯,这里要注意,TTS 不是普通的单元测试,它是 Google 用来卡你脖子的一道硬门槛。
3.1 TTS 是什么?为什么它这么重要?
TTS,全称 Treble Test Suite,是 Google 为 Project Treble 专门设计的一套兼容性测试工具。说白了,它就是一把尺子,量你的设备到底有没有按 Treble 的规矩来。
我个人习惯,在每次系统大版本升级前,先跑一遍 TTS。不是为了应付认证,而是为了提前发现那些藏在角落里的坑。你想想看,如果等 CTS(Compatibility Test Suite)跑完才发现问题,那返工的成本可就高了去了。
核心要点:TTS 主要验证的是 Vendor 和 System 之间的接口是否合规。它不关心你的 UI 好不好看,也不管你的性能优不优化,它只盯着一件事——你的 HAL 实现有没有按 HIDL 的契约来。
3.2 TTS 的测试框架与执行流程
TTS 基于 Trade Federation(简称 Tradefed)测试框架。这个框架你可能不熟,但它的兄弟 VTS(Vendor Test Suite)你应该听过。TTS 和 VTS 的关系,我简单说一下:
| 对比项 | TTS | VTS |
|---|---|---|
| 测试范围 | Treble 接口兼容性 | Vendor 实现正确性 |
| 测试对象 | System 与 Vendor 的边界 | Vendor 内部实现 |
| 失败影响 | 直接导致认证失败 | 可能导致功能异常 |
| 执行频率 | 每次系统升级前必跑 | 每次 HAL 修改后必跑 |
执行 TTS 其实不复杂,一条命令搞定:
# 在源码根目录执行
source build/envsetup.sh
lunch your_device-userdebug
make -j32
# 运行 TTS
./test/vts/script/run_vts.sh -m TtsTest
等等,这里有个坑。我刚开始跑的时候,直接 make 完就开跑,结果报了一堆依赖缺失。后来才发现,你得先确认你的编译产物里包含了 TTS 的测试用例。建议在 lunch 之后先跑一下:
make vts -j32
这样能确保所有测试模块都编译进去了。
3.3 常见失败案例分析
好,接下来是重头戏。我这些年踩过的坑,一个一个说给你听。
案例一:HAL 接口版本不匹配
这是最常见的失败原因,没有之一。我记得有一次,一个合作厂商的工程师跑过来问我:「为什么我的 TTS 一直报 IBase::interfaceChain 失败?」
我一看他的代码,好家伙,他实现的 android.hardware.camera.provider@2.4 接口,但 TTS 期望的是 @2.5。版本号差了一个小版本,整个接口链就断了。
避坑指南:我曾经在升级 Android 11 到 12 时,就因为没仔细看 HAL 版本变更,导致 TTS 跑了三天全红。后来我养成了一个习惯——每次升级前,先去 hardware/interfaces 目录下 diff 一下版本变更日志。
检查方法很简单:
# 查看当前设备支持的 HAL 版本
adb shell lshal | grep "android.hardware.camera.provider"
# 对比 TTS 期望的版本
grep -r "android.hardware.camera.provider" test/vts/testcases/
案例二:VNDK 库缺失或版本错误
VNDK(Vendor Native Development Kit)是 Treble 的另一个核心概念。说白了,Vendor 分区不能随便用 System 分区的库,得用 VNDK 里规定的那些。
我遇到过最离谱的一次,是某个厂商把 libcutils 直接链接到了 Vendor 的二进制里。TTS 一跑,直接报 VNDK library not allowed。为什么?因为 libcutils 不在 VNDK 的允许列表里。
警告:千万不要为了省事,直接把 System 的库拷贝到 Vendor 分区。TTS 会检查每个 Vendor 进程的 /proc/pid/maps,一旦发现非法库引用,直接判失败。
正确的做法是:
- 确认你的 Vendor 进程只链接了 VNDK 允许的库
- 如果确实需要某个库,先检查它是否在
vndkcore.libraries.txt或vndksp.libraries.txt中 - 如果不在,考虑用
libvndk的扩展机制
案例三:SELinux 策略导致测试失败
这个坑我踩得最深。有一次 TTS 跑了一整天,最后在 VtsHalCameraProviderV2_4TargetTest 上挂了。日志里只写了 Permission denied,但具体哪个权限?不知道。
我排查了整整两天,最后用 adb logcat -b events 才找到线索——原来是 HAL 进程没有访问 /data/vendor/camera 的权限。但问题是,这个目录在之前的版本里是允许的,Android 12 收紧了一部分 SELinux 规则。
嗯,这里要注意,每次 Android 大版本升级,Google 都会调整 SELinux 策略。我的建议是:
- 先跑一遍 TTS,收集所有失败用例
- 针对每个失败,用
audit2allow工具生成建议的策略 - 但不要直接照搬,要人工审核一遍
# 从设备上抓取 SELinux 拒绝日志
adb shell "cat /proc/kmsg | grep avc" > avc_denials.txt
# 生成建议策略
audit2allow -i avc_denials.txt -p policy.conf
3.4 TTS 测试结果解读与调试技巧
TTS 跑完之后,会生成一个 XML 格式的报告。很多人看到这个报告就头大,其实没那么复杂。我教你一个快速定位问题的方法:
- 先看
<Summary>标签,确认总失败数 - 然后看
<Failed>列表,找到失败的测试用例名 - 最后看
<Failure>里的<StackTrace>,那里有具体的错误信息
我个人习惯,会把失败的用例名复制出来,然后去源码里搜对应的测试逻辑。比如:
grep -r "VtsHalCameraProviderV2_4TargetTest" test/vts/testcases/
这样你能看到测试到底在测什么,是哪个接口、哪个参数、哪个返回值出了问题。
调试小技巧:如果某个测试反复失败,但你又看不出原因,试试用 --retry 0 --skip-all-system-status-check 参数跑单用例。这样能排除其他测试的干扰,专注分析这一个失败。
3.5 知识体系总览
为了让你对本章内容有个整体把握,我画了一张图:
这张图把 TTS 的核心脉络理清楚了。你从中心节点出发,左边是框架,中间是验证内容,右边是常见失败。三者环环相扣,缺一不可。
好了,这一章的内容就到这里。TTS 的实战经验,说白了就是「多跑、多看、多分析」。别怕失败,每个失败都是你积累经验的机会。我当年也是从一片红海走过来的,慢慢你就会发现,TTS 其实是你最好的老师。
最后提醒一句:如果你在跑 TTS 时遇到任何奇怪的问题,先检查你的编译环境。我遇到过太多次「测试失败」最后发现是编译选项没开对。先把基础打牢,再谈优化。