【全栈第7课】Treble 架构 + VINTF(进入 HAL 阶段)
Android 全栈工程师进阶教程 第07课。Treble 架构 + VINTF(进入 HAL 阶段)。基于公开 AOSP 知识整理,含原理、可编译示例、常见问题定位。
> 本文是《Android 全栈工程师进阶教程》系列第 07 课。完整 26 课见 GitHub 仓库。
【全栈第7课】Treble 架构 + VINTF(进入 HAL 阶段)
0. 这节课你将做出什么
看懂 某真实机型 里真实的 VINTF 文件(vendor manifest + framework matrix),并写一个 vendor manifest 示例(为 L9 写 HAL 预声明)。 学完你能回答:为什么 Android 把系统拆成 system/vendor 两半?它们靠什么约定接口、保证升级不出事?HAL 是怎么"被系统发现"的? 这是从"框架工程师"跨到"BSP 工程师"的认知分水岭。
1. 背景:为什么要 Treble
Android 8 之前,每个厂商把内核/驱动/HAL 和 Android 框架编译在一起,改动深度耦合。结果:Google 发了新版本 Android,厂商要花几个月重新适配自己的魔改,碎片化严重、升级极慢。
Android 8 引入 Treble,把 OS 物理拆成两个分区:
- system 分区:Google/AOSP 的框架,所有设备统一
- vendor 分区:芯片厂/OEM 的 HAL、驱动适配,各设备不同
好处:升级 Android 大版本时,只换 system 分区,vendor 不动 → 升级快。 代价:两边是不同团队、不同节奏开发的,必须有一套接口契约保证它们能配合——这就是 VINTF。
2. 全局图:Treble 两分区 + VINTF 两契约
┌───────────── system 分区(AOSP,统一)──────────────┐
│ Framework / system_server │
│ 要求:"本设备必须提供这些 HAL" │
│ → framework compatibility_matrix.xml (type=framework) │
└───────────────────────┬─────────────────────────────┘
│ 开机时 VINTF 校验:matrix(要求) 对得上 manifest(提供) 吗?
┌───────────────────────┴─────────────────────────────┐
│ vendor 分区(芯片厂/OEM) │
│ 声明:"我提供这些 HAL" │
│ → vendor manifest.xml (type=device) │
│ HAL 进程(vibrator/nfc/...) │
└──────────────────────────────────────────────────────┘
VINTF 两份契约:
| 文件 | 谁写 | 说什么 |
|---|---|---|
| vendor manifest(type=device) | vendor | 我提供哪些 HAL |
| framework compatibility_matrix(type=framework) | AOSP | framework 要求哪些 HAL |
开机时校验:manifest 提供的必须满足 matrix 要求的,否则开不了机。这保证了 system 升级后,只要 matrix 没变,老 vendor 还能配合。
3. 某真实机型 真实源码印证
vendor manifest 实物 device/xiaomi/popsicle/odm/nfc/vintf/manifest_nxp_nfc.xml:
<manifest version="1.0" type="device" target-level="202404">
<hal format="aidl">
<name>vendor.nxp.nxpnfc_aidl</name> <!-- HAL 接口包名 -->
<version>1</version>
<fqname>INxpNfc/default</fqname> <!-- 接口名/实例名 -->
</hal>
</manifest>
type="device"= 这是 vendor/设备侧 manifesttarget-level="202404"= 兼容的 FCM(Framework Compatibility Matrix)版本format="aidl"= 用 AIDL HAL(对比老的 hidl)
framework matrix 实物 hardware/interfaces/compatibility_matrices/:
compatibility_matrix.202604.xml ← 新季度版本 的矩阵
compatibility_matrix.<新版本>.xml ← Android 新版本 矩阵
4. 前置准备
- 依赖 L1(AIDL/Binder 基础)。
- 本课只写一个 xml 示例 + 一份分析文档,为 L9 写真 HAL 铺路。
5. 动手:写一个 vendor manifest 示例
为 L9 要写的 hello HAL 预声明 manifest_hello_hal.xml:
<!-- vendor manifest:vendor 侧声明"我提供 hello HAL" -->
<manifest version="1.0" type="device" target-level="202604">
<hal format="aidl">
<name>vendor.example.demo</name> <!-- HAL 接口包名,和 L9 的 aidl 包一致 -->
<version>1</version>
<fqname>IHelloHal/default</fqname> <!-- 接口名/实例名,L9 注册时也用这个 -->
</hal>
</manifest>
逐行讲:
type="device":vendor 侧(L9 里这个 xml 作为vintf_fragment随 HAL 一起装进 vendor 分区)。target-level="202604":声明兼容 新季度版本(新版本)的 FCM 版本。<name>+<fqname>:这俩组合起来 = 这个 HAL 在系统里的"身份证"。L9 的 HAL 用AServiceManager_addService注册时,服务名就是vendor.example.demo.IHelloHal/default,和这里对应。
6. 看底层:开机 VINTF 校验干了什么
开机时 vintf 框架会:
- 读 vendor manifest(所有 vendor 提供的 HAL 清单)
- 读 framework compatibility_matrix(framework 要求的 HAL 清单 + 版本范围)
- 逐条比对:matrix 里标
optional="false"(必须)的 HAL,manifest 里有没有、版本对不对? - 不满足 →
init阶段报错,开不了机(或进 recovery)。
所以你加一个新 HAL,光写实现不够,还得在 manifest 里声明它(L9/L11 会做),否则系统"不知道"它存在。
7. 编译 & 运行(验证状态如实)
# 看设备实际生效的 VINTF
adb shell cat /vendor/etc/vintf/manifest.xml # vendor 提供的
adb shell cat /system/etc/vintf/compatibility_matrix.device.xml # framework 要求的
adb shell vintf # 有的设备有 vintf 命令直接查
# 校验是否兼容
adb shell cmd android.hardware.vintf ... # 或看开机 init 日志
> 验证状态(诚实):本课为概念课,xml 示例是真实 VINTF 格式(对照 某真实机型 NFC manifest 写);真正生效在 L9(随 HAL vintf_fragment 装入)。
8. 踩坑提醒
- manifest 声明了但 HAL 没真起:开机 VINTF 校验只看声明,不保证 HAL 进程真跑起来;HAL 起不来另查(L11)。
- target-level 不匹配:vendor manifest 的 target-level 和实际 framework FCM 版本对不上,校验失败。
- fqname 写错:
IHelloHal/default里实例名default要和 HAL 注册时的实例名一致,否则 framework 找不到。 - format 写错:aidl HAL 写成
format="hidl",或反之 → 校验/查找失败。 - vintf_fragment 没打进 vendor 分区:Android.bp 里没配
vintf_fragments,manifest 不生效(L9 会配)。
9. 常见问题分析与定位(Treble/VINTF 实战)
9.1 常见问题清单
- 开机失败 / 卡 logo,日志有 VINTF incompatible
- framework 找不到 HAL(getService 返回 null)
- 升级后 vendor HAL 失效
- CTS/VTS VINTF 相关 fail
- 新加的 HAL 系统"看不见"
9.2 分析与定位
① 开机 VINTF incompatible
- 现象:卡 logo,
adb logcat/init 日志有device manifest ... incompatible with framework compatibility matrix。 - 定位:
adb shell dmesg | grep -i vintf
# 比对:vendor manifest 提供的 vs matrix 要求的,哪条对不上
adb shell cat /vendor/etc/vintf/manifest.xml
adb shell cat /system/etc/vintf/compatibility_matrix.*.xml
- 修复:补上 matrix 要求但 manifest 缺的 HAL,或修正版本/target-level。
② getService 找不到 HAL
- 原因:HAL 没在 manifest 声明 / fqname 不一致 / HAL 进程没起。
- 定位:
adb shell lshal | grep hello # lshal 列出所有 HAL,看你的在不在、状态
adb shell lshal list # 看哪些声明了但没起(N/A)
lshal是查 HAL 的神器:声明了没起 = manifest 有但进程问题(查 .rc/sepolicy,L11);压根没列出 = manifest 没声明。
③ 升级后 vendor HAL 失效
- 原因:升级动了 framework matrix,要求变了,老 vendor manifest 不满足。
- 定位:对比新旧 matrix 差异;看 新版本 新增的强制 HAL(见 新版本 总结)。
④ VTS/CTS VINTF fail
- 原因:声明的 HAL 版本/接口和实际不符,或缺必需 HAL。
- 定位:看 VTS 报告具体哪条 VINTF assertion 失败,对照 manifest 修。
9.3 定位决策树
Treble/VINTF 出问题
├─ 开机 incompatible → dmesg vintf + 比对 manifest vs matrix → 补缺的 HAL/修版本
├─ 找不到 HAL → lshal | grep → 没列出=manifest 没声明;列出 N/A=进程没起(L11)
├─ 升级后失效 → 对比新旧 matrix → 补 新版本 新增强制 HAL
└─ VTS/CTS fail → 看具体 assertion → 对照 manifest 修版本/接口
10. 小结
- Treble = system/vendor 物理分区:升级只换 system,vendor 不动 → 升级快。
- VINTF 两契约:vendor manifest(提供)+ framework matrix(要求),开机校验兼容性。
- HAL 的"身份证" =
<name>包名 +<fqname>接口/实例名,注册和查找都用它。 - lshal 是查 HAL 的神器:声明了没起 vs 压根没声明,一眼看出。
- 排查口诀:开机挂比对 manifest/matrix;找不到 HAL 用 lshal;升级失效查 matrix 差异。
下节预告
L8:HIDL 老式 HAL —— 在写 AIDL HAL(L9)前,先看一眼被淘汰的 HIDL 长什么样,理解为什么 新版本 强制转 AIDL。