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接口?

避坑指南:我曾经在一个项目里混用了HIDL和AIDL的服务,结果发现HIDL服务注册到hwservicemanager,AIDL服务注册到servicemanager,两个manager互不通信。调试时服务死活找不到,排查了整整一天。所以,同一个HAL服务,要么全用HIDL,要么全用AIDL,别混着来

7.3 HAL Service注册与启动

接口定义好了,代码也实现了,接下来就是让这个HAL Service跑起来。这个过程我把它拆成三步:

  1. 实现服务端:写一个继承自接口stub的类,实现所有方法。
  2. 注册服务:把服务实例注册到系统服务管理器中。
  3. 配置启动:通过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测试最好在真实硬件上跑,模拟器上很多属性读出来都是默认值,测不出问题。

核心要点:VTS保证你的HAL接口“长得对”,VHAL保证你的HAL接口“用得好”。两者缺一不可。

知识体系总览

为了让你更直观地理解这一章的内容,我画了一张图,把HAL驱动开发的整体流程串起来:

Android Automotive HAL驱动开发流程 1. 接口定义 数据结构 + 函数声明 2. 接口描述语言 HIDL 或 AIDL for HAL 3. 服务实现与注册 Stub实现 + init.rc + manifest 4. 测试验证 VTS + VHAL 测试 底层硬件驱动 I2C/SPI/UART 操作 上层应用/服务 CarService / 车载App HAL层是连接底层硬件与上层应用的桥梁,接口定义、描述语言、服务注册、测试验证缺一不可

从这张图可以看得很清楚:HAL开发不是孤立的,它一头连着底层硬件驱动,另一头连着上层应用服务。接口定义是起点,描述语言是工具,服务注册是落地,测试验证是保障。每一步都踩实了,你的HAL才能稳定可靠。

好了,这一章的内容就到这里。记住我强调的那句话:接口定义要简洁,描述语言要统一,服务注册要仔细,测试验证要全面。做到这四点,车载HAL开发就不会出大问题。


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