7、Android Automotive HAL驱动开发:HAL接口定义与实现、HIDL与AIDL在车载中的应用、HAL Service注册与启动、VTS/VHAL测试
好,咱们进入第七章。这一章是车载系统驱动开发的核心地带——HAL层。说白了,HAL就是Android系统与硬件之间的那个“翻译官”。系统上层要控制硬件,不能直接操作寄存器,得通过HAL这个标准接口来沟通。
我个人习惯把HAL开发分成四块:接口怎么定义、用什么语言描述(HIDL还是AIDL)、服务怎么跑起来、最后怎么验证。咱们一个一个来拆解。
7.1 HAL接口定义与实现
在Android Automotive里,HAL接口的定义直接决定了上层应用能做什么。比如你要控制空调温度、车窗升降、座椅调节,这些都得先定义好接口。
接口定义通常包含两部分:功能声明和数据结构。功能声明告诉系统“我能做什么”,数据结构告诉系统“我需要什么参数”。
举个例子,一个简单的空调控制HAL接口,可能会这样定义:
// 定义空调控制接口
typedef struct {
int32_t temperature; // 目标温度,单位0.1°C
int32_t fanSpeed; // 风速等级 0-7
bool acOn; // 空调开关
int32_t zoneId; // 分区ID,0=驾驶位,1=副驾...
} AcControlRequest;
// 接口函数声明
int32_t ac_setControl(const AcControlRequest* request);
int32_t ac_getStatus(AcControlRequest* status);
嗯,这里要注意:接口定义要尽量简洁,参数类型用标准化的。我在项目中遇到过有人把温度定义成float,结果上层和底层解析不一致,折腾了两天。后来统一用int32_t乘以10的方式,再也没出过问题。
7.2 HIDL与AIDL在车载中的应用
说到接口描述语言,Android提供了两套方案:HIDL和AIDL。HIDL是Android 8时代推出的,专门给HAL层用。AIDL更老,原本用于应用层IPC。到了Android 10以后,Google开始推AIDL for HAL,说白了就是让AIDL也能干HIDL的活。
那在车载场景下,到底选哪个?我个人的判断标准很简单:
- HIDL:如果你的项目基于Android 9或更早,或者你维护的是老平台,用HIDL更稳妥。它成熟、稳定,社区资料多。
- AIDL for HAL:如果你是新项目,Android 10以上,我建议直接用AIDL。它语法更简洁,而且能和上层服务共用接口定义,减少重复代码。
来看一个对比。HIDL定义空调接口大概是这样:
package vendor.automotive.ac@1.0;
interface IAcControl {
setControl(AcControlRequest request) generates (Result result);
getStatus() generates (AcControlRequest status);
};
而AIDL版本就清爽多了:
package vendor.automotive.ac;
interface IAcControl {
int setControl(in AcControlRequest request);
AcControlRequest getStatus();
}
你想想看,AIDL少了那些@版本号、generates关键字,读起来是不是更像普通Java接口?
7.3 HAL Service注册与启动
接口定义好了,代码也实现了,接下来就是让这个HAL Service跑起来。这个过程我把它拆成三步:
- 实现服务端:写一个继承自接口stub的类,实现所有方法。
- 注册服务:把服务实例注册到系统服务管理器中。
- 配置启动:通过init.rc或manifest文件让系统在启动时自动加载。
以AIDL为例,服务端实现的核心代码大概长这样:
public class AcControlService extends IAcControl.Stub {
@Override
public int setControl(AcControlRequest request) {
// 这里调用底层驱动,设置空调参数
native_setAcControl(request.temperature,
request.fanSpeed,
request.acOn,
request.zoneId);
return 0; // 成功返回0
}
@Override
public AcControlRequest getStatus() {
AcControlRequest status = new AcControlRequest();
native_getAcStatus(status);
return status;
}
}
注册服务时,我习惯在系统启动脚本里加一行:
service vendor.ac-hal /vendor/bin/hw/vendor.automotive.ac@1.0-service
class hal
user system
group system
然后在manifest.xml里声明:
<hal format="aidl">
<name>vendor.automotive.ac</name>
<version>1</version>
<interface>
<name>IAcControl</name>
<instance>default</instance>
</interface>
</hal>
这里有个细节:manifest里的instance名字要和代码里注册时的一致。我见过有人manifest写的是default,代码里注册的是ac_instance,结果服务永远找不到。
7.4 VTS/VHAL测试
代码写完了,怎么证明它是对的?靠VTS和VHAL测试。
VTS(Vendor Test Suite)是Google提供的通用测试框架,用来验证HAL接口是否符合Android兼容性定义。说白了,就是检查你的接口有没有少方法、参数类型对不对、返回值是否规范。
VHAL(Vehicle HAL)是车载特有的测试工具,专门针对车辆属性(如车速、车门状态、空调设置)进行读写测试。
跑VTS测试很简单,在源码根目录执行:
make vts
vts-tradefed run vts -m VtsHalVehicleTargetTest
它会自动发现你注册的HAL服务,然后调用所有接口方法,检查返回值。如果某个接口返回了-1或者超时,测试就会报红。
VHAL测试更贴近实际场景。比如你要测试空调控制,可以写一个测试用例:
@Test
public void testSetAcTemperature() {
AcControlRequest req = new AcControlRequest();
req.temperature = 250; // 25.0°C
req.fanSpeed = 3;
req.acOn = true;
req.zoneId = 0;
int result = mService.setControl(req);
assertEquals(0, result);
// 读取状态,验证是否设置成功
AcControlRequest status = mService.getStatus();
assertEquals(250, status.temperature);
}
嗯,这里要注意:VHAL测试最好在真实硬件上跑,模拟器上很多属性读出来都是默认值,测不出问题。
知识体系总览
为了让你更直观地理解这一章的内容,我画了一张图,把HAL驱动开发的整体流程串起来:
从这张图可以看得很清楚:HAL开发不是孤立的,它一头连着底层硬件驱动,另一头连着上层应用服务。接口定义是起点,描述语言是工具,服务注册是落地,测试验证是保障。每一步都踩实了,你的HAL才能稳定可靠。
好了,这一章的内容就到这里。记住我强调的那句话:接口定义要简洁,描述语言要统一,服务注册要仔细,测试验证要全面。做到这四点,车载HAL开发就不会出大问题。