1、前言 - Project Treble
Android 目前有一个比较明显的缺点是设备升级到新版本系统所要花费的时间太长(比如从 Android 6.0 升级到 Android 7.0)。通常在由 Google 发布新版本的 AOSP 之后,还需要 SoC 厂商对 HAL 进行升级,以及 OEM 厂商对 HAL 和 Framework 进行升级后,用户才能在设备上收到 OTA 升级包的推送。低端一点的产品甚至在出厂后就不会再进行系统升级了。用户对此抱怨良多。反观竞争对手 iOS 在这方面就做得比较好(但这不代表我支持 iOS)。
为了解决这个问题,于是 Google 发起了 Project Treble 项目。2017 年 5 月 12 日,官方在”Developers Blog”上向公众介绍了这一项目并宣布 Android 8.0 中将引入它,但从目前我拿到的描述 Project Treble 的相关文档的修订记录来看,这些文档最早的起草时间可以追溯到 2015 年 10 月 30 日。 而 Project Treble 中最重要的就是新增了 Vendor Interface 这一概念,以及相应的 Vendor Test Suite (VTS) 测试。
2、VTS 的概念及作用
VTS 全称是 Vendor Test Suite,官方在介绍它时将其与 CTS 进行了类比,原文是:
Project Treble aims to do what CTS did for apps, for the Android OS framework. The core concept is to separate the vendor implementation — the device-specific, lower-level software written in large part by the silicon manufacturers — from the Android OS Framework.
This is achieved by the introduction of a new vendor interface between the Android OS framework and the vendor implementation. The new vendor interface is validated by a Vendor Test Suite (VTS), analogous to the CTS, to ensure forward compatibility of the vendor implementation.
意思是 Project Treble 中引入 Vendor Interface 的目的是将 Android Framework 与 HAL 分开,并通过 VTS 测试来对这些 Vendor Interface 进行测试以确保 HAL 的向前兼容。
只看这一段可能还是描述得不太清楚。我们知道仅管 APP 层与 Framework 层在设计上是分开的, 但通过 CTS 测试,确保了 APP 与 Android Framework 之间有一致的调用接口(API),这使得 APP 开发者编写的同一款程序可以运行在不同系统版本(向前兼容)、不同硬件平台、不同厂商制造的不同设备上。 VTS 类似 CTS,通过对 Vendor Interface 进行测试,确保同一个版本的 Android Framework 可以运行在不同 HAL 上,或不同 Android Framework 可以运行在 同一个 HAL 上。 通过这样的 Framework / HAL 分离设计和接口一致性保证,也使得 8.0 版本之后的 Android 系统在进行升级时,可以直接对 Framework 进行升级而不用考虑 HAL 层的改动,从而缩短了用户手上设备得到系统升级 OTA 推送的时间。
下面的图描述了这种新的架构:
采用新架构之后的 Android 系统升级过程则是直接对 Framework 进行替换,如下图:
3、对工程师的影响
这样的架构变动对于 Android 设备用户的影响是他们今后可以得到更及时的升级服务,对于我们 Android BSP 工程师来说就是要为实现这样的服务铺设好平台基础,主要是以下几方面工作:
1)将现有 Android Framework 中耦合的 HAL 代码剥离出来
2)使用 HIDL 描述的 HAL (.hal文件)替换旧的头文件描述的 HAL
3)根据接口描述实现各模块 HAL。
4)在 makefile 中为 .hal 文件添加声明
5)添加相应的 SEpolicy 配置
根据文档《HIDLHALVersioningandExtensions.pdf》的描述,Android 8.0 及之后版本的系统仅支持经过 binder 化(binderized)的 HAL,因此老版本的 HAL 必须被全部替换掉。原文如下:
The most relevant aspect of this change is the binderization of the HAL:
Binderized HALs replace older versions of the HALs, and all devices running Android O must support binderized HALs only.
庆幸的是,我们可以使用 c2hal 工具将那些在头文件中定义的老的 HAL 接口转换为使用 HIDL 描述的 .hal 文件,这会大大减少我们手动进行添加的工作量,甚至有时我们会发现这些基本工作有的已经由 Google 的工程师帮我们完成了,我们只需要根据这些 .hal 文件中的 Vendor Interface 接口定义和数据声明来实现这些接口就好。
要使用 c2hal 工具,我们需要先执行下面的命令来生成她:
$ make c2hal
然后就可以使用这个工具进行自动转换了。比如我们要为 NFC HAL 生成相应的 .hal 文件,那么可以执行下方的命令:
$ c2hal -r android.hardware:hardware/interfaces -r android.
hidl:system/libhidl/transport -p android.hardware.nfc@1.0 hardware/libhardware/include/hardware/nfc.h
关于 HIDL 的介绍可以参考我之前写的《Android HIDL 简介》这篇文章。
除了为模块编写 .hal 文件,我们还应该确保相应的.rc脚本也已经添加到源码目录中了,脚本的名字一般是 android.hardware.<moduleName>@<version>-service.rc,位于 hardware/interfaces/<moduleName>/<versionNumber>/default/ 目录下。比如音频模块的脚本名称就是 android.hardware.audio@2.0-service.rc。如下图:
然后在 makefile 中添加相应的声明:
再在 sepolicy 中添加相应的权限声明:在 device/<companyName>/commom/sepolicy/ 目录下新建 .te 文件,比如我负责 Audio 模块,那么就在该目录下新建了 hal_audio_default.te 文件,然后在文件中添加需要的规则。如下:
也可以最后再添加这些 sepolicy 规则。在没有编写相应 .te 文件的情况下,直接把 setenforce 环境变量的值设置为 permissive 进行测试也不会提示权限问题。
最后编译系统镜像并烧写到设备,设备上电运行起来后就可以使用 ps -A 命令看到android.hardware.audio@2.0-service进程已经随系统启动而执行起来了。
4、怎么进行 VTS 测试
要进行 VTS 测试,首先需要搭建测试环境,我们需要以下这些组件:
+ 64-bit Ubuntu Linux
+ Java 8
+ Python 2.7
+ ADB 1.0.39
具体的搭建步骤是:
1) 安装 python 开发包
$ sudo apt-get install python-dev
2) 安装 Protocol Buffer 工具
$ sudo apt-get install python-protobuf
$ sudo apt-get install protobuf-compiler
3) 安装 Python 虚拟环境相关工具
$ sudo apt-get install python-virtualenv
$ sudo apt-get install python-pip
4) 在设备上启用开发者模式并打开 USB 调试功能
5) 检查设备是否能被 ADB 探测到
$ adb devices
6) 使用 ADB 登录设备
$ adb shell
如果以上步骤你都执行成功了,那么 VTS 测试环境就搭建好了。 然后我们还需要先编译 VTS 测试工具。在 Android 源码根目录下执行以下命令可以生成测试工具:
$ source build/envsetup.sh
$ lunch <productName>
$ make vts -j20
其中 < product > 的值需要根据你想要进行测试的产品来给定。
编译完成后,我们可以在out/host/linux-x86/vts/android-vts.zip目录下找到 VTS 测试包,解压之后,进入android-vts/tools/目录,执行以下命令即可进行默认的全局 VTS 测试:
$ vts-tradefed
> run vts
也可以只对某个模块进行测试:
$ vts-tradefed
> run vts -m VtsHalAudioV2_0Target
还可以只对某个模块中的某一项用例进行测试:
$ vts-tradefed
> run vts -m VtsHalAudioV2_0Target -t RecommendedOutputStreamConfigSupport
剩下的就是耐心等待。测试完成后我们可以在android-vts/results/目录下找到测试报告,可以在android-vts/logs/目录下看到测试日志。
5、如何解决 VTS Fail 项 / VTS 测试失败的可能原因
目前我根据文档总结出了以下几种可能导致 VTS 测试失败的原因:
1) 没有使用经过 binderized 的 HAL
2) HAL 中存在与接口规范不符的实现
3) Kernel 接口问题
4) 没有添加相应的 SEpolicy 配置