35、Treble架构调试:HAL接口、hidl服务、VINTF、兼容性测试

Treble架构,说白了就是Google在Android 8.0搞的一次大手术。把原来铁板一块的Framework和厂商底层实现,硬生生切成了两半。为什么要这么干?你想想看,以前每次Android大版本升级,芯片厂商都得重新适配一遍,累死累活。Treble之后,Framework和vendor分家,升级就快多了。

但分家也有分家的烦恼。接口多了,调试起来就复杂了。我这些年跟Treble打交道,踩过的坑真不少。今天咱们就聊聊,怎么在Treble架构下做调试。

HAL接口:从传统到Binder化

传统HAL是so库,直接dlopen加载。Treble之后,HAL变成了HIDL服务,跑在独立进程里。这变化,调试方式完全不同了。

传统HAL出问题,我一般直接看logcat,搜“HAL”关键字。但HIDL服务出问题,你得先确认服务有没有起来。

核心命令:

# 查看所有注册的HIDL服务
adb shell lshal

# 查看特定服务是否存活
adb shell lshal | grep camera

# 查看服务进程
adb shell ps -A | grep hwservicemanager

我记得有一次,camera HAL死活打不开。我查了半天log,发现服务根本没注册。后来用lshal一看,果然没有camera provider。最后定位到是selinux权限问题,服务进程被杀了。

我的习惯:调试HAL之前,先跑一遍lshal,确认所有服务都在。这一步能省掉你一半的排查时间。

HIDL服务:调试三板斧

HIDL服务跑在独立进程里,调试起来比传统HAL麻烦。我总结了三板斧:

  1. 看log:HIDL服务的log默认打到logcat里,但有些厂商会重定向。我建议直接看/dev/log或者logcat -b all
  2. 查状态:用dumpsys或者lshal --debug,能拿到服务的内部状态。
  3. 抓调用:用systrace或者perfetto,能看到HIDL调用的耗时。

举个例子,我曾经遇到一个audio HAL的问题,声音断断续续。我打开systrace,发现每次音频播放时,HIDL调用耗时都在100ms以上。这明显不正常。后来定位到是底层驱动锁竞争,改了调度策略就好了。

注意:HIDL服务如果crash了,hwservicemanager会自动重启它。但重启过程中,所有依赖这个服务的客户端都会收到死亡通知。如果你的app突然卡死,先看看是不是HAL服务重启了。

VINTF:兼容性检查的命门

VINTF(Vendor Interface)是Treble的“契约”。它定义了vendor和Framework之间的接口约定。说白了,就是一份清单,告诉系统:我支持哪些HAL,版本是多少。

VINTF文件在/vendor/etc/vintf/目录下,主要有两个:

  • manifest.xml:厂商声明自己实现了哪些HAL
  • compatibility_matrix.xml:Framework声明自己需要哪些HAL

系统启动时,会比对这两份文件。如果对不上,系统会报错,甚至直接不进系统。

调试VINTF问题:

# 检查VINTF是否匹配
adb shell vintf --check

# 查看当前系统的VINTF信息
adb shell dumpsys vintf

# 查看manifest
adb shell cat /vendor/etc/vintf/manifest.xml

我曾经遇到一个坑:升级了HAL版本,但忘了更新manifest.xml。结果系统启动时,Framework发现版本不匹配,直接拒绝加载。查了半天log,才看到vintf --check报的错。嗯,从那以后,我每次改HAL接口,第一件事就是更新manifest。

兼容性测试:CTS/VTS

Treble架构下,兼容性测试分两套:

  • CTS(Compatibility Test Suite):测Framework和app的兼容性
  • VTS(Vendor Test Suite):测vendor实现的兼容性

VTS是Treble特有的。它直接测试HIDL接口,确保厂商的实现符合规范。

跑VTS的命令:

# 跑所有VTS测试
adb shell vts-tradefed run vts

# 跑特定模块的测试
adb shell vts-tradefed run vts -m VtsHalCameraProviderV2_4TargetTest

我建议你重点关注VTS的测试结果。如果VTS没过,说明你的HAL实现有问题。别想着绕过,CTS也会卡你。

我的经验:VTS测试失败,90%的原因是接口实现不完整。比如某个方法返回了UNKNOWN_ERROR,或者参数校验没做。仔细看测试log,一般都能找到线索。

实战:调试一个HIDL服务crash

咱们来走一遍完整的调试流程。假设camera HAL服务crash了。

  1. 确认服务状态lshal | grep camera,发现没有输出。
  2. 看loglogcat -b all | grep -i camera,看到FATAL EXCEPTION
  3. 抓tombstoneadb pull /data/tombstones/,分析crash堆栈。
  4. 查VINTFvintf --check,确认manifest没问题。
  5. 复现并抓traceperfetto -t 10s -o /data/misc/perfetto/trace,分析调用链路。

我记得有一次,crash堆栈指向了内存越界。我查了半天,发现是HIDL接口传了一个空指针,服务端没做判空。嗯,这种问题,加个if (ptr == nullptr) return error;就解决了。

SVG:Treble调试知识体系

Treble架构调试知识体系 Treble调试 HAL接口调试 HIDL服务调试 VINTF检查 CTS/VTS测试 lshal logcat dumpsys systrace manifest.xml compat_matrix CTS VTS 核心:接口契约 + 服务状态 + 兼容性验证

总结

Treble调试,核心就三件事:

  • 接口契约:VINTF文件必须对得上,否则系统不认
  • 服务状态:HIDL服务必须活着,否则功能不可用
  • 兼容性验证:VTS必须过,否则CTS也过不了

我个人习惯,每次改完HAL接口,先跑一遍vintf --check,再跑一遍VTS。这两步过了,基本就没大问题了。如果还有问题,那就老老实实看log,抓trace,一步步排查。

嗯,Treble调试其实没那么玄乎。把基础工具用好,把流程走顺,大部分问题都能搞定。


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