2. HAL 接口定义语言(AIDL/HIDL):HIDL 与 AIDL 的对比、选择策略、接口文件基本结构

在 Treble 架构中,HAL 接口定义语言是连接 Framework(系统框架)与 Vendor(供应商)实现的契约。Android 先后引入了 HIDL(HAL Interface Definition Language)和 AIDL(Android Interface Definition Language)作为接口定义工具。理解两者的差异、适用场景以及文件结构,是编写可测试、可维护 HAL 接口的前提。

2.1 HIDL 与 AIDL 的核心对比

HIDL 是 Android 8.0(Treble 首发版本)引入的专用 HAL 接口语言,旨在严格分离 Framework 和 Vendor 实现。AIDL 则是 Android 传统的跨进程通信(IPC)接口语言,从 Android 11 开始被官方推荐用于 HAL 开发。下表从多个维度对比两者的关键差异:

对比维度 HIDL AIDL(HAL 模式)
引入版本 Android 8.0(Treble 首发) Android 11(HAL 场景推荐)
设计目标 严格分离 system.img 与 vendor.img 统一 Framework 与 HAL 的 IPC 语言
接口稳定性 通过 .hal 文件版本号(如 1.0、2.0)保证 通过 @VintfStability 注解和版本化包名保证
后端实现 生成 C++(passthrough/binderized) 生成 Java / C++ / NDK(native)
数据类型 HIDL 原生类型 + struct/enum/union/vec Parcelable + 原生类型 + 泛型 + 接口回调
错误处理 Return<T> + 异常状态码 异常(Java)/ Status(C++)
工具链 hidl-gen、hidl2aidl 转换工具 aidl(支持 --lang=cpp/ndk/java)
测试友好度 需额外编写 VTS 测试用例 原生支持单元测试 + 模拟桩(Mock)
关键认知:HIDL 是 Treble 架构的“原配”语言,但 AIDL 从 Android 11 起成为 Google 推荐的统一接口语言。新项目优先选择 AIDL(HAL 模式),存量 HIDL 接口可通过 hidl2aidl 工具迁移。

2.2 选择策略:何时用 HIDL,何时用 AIDL?

选择接口定义语言需要综合考虑项目阶段、兼容性要求和团队技术栈。以下决策流程可以帮助你做出合理选择:

  1. 项目启动时间:若项目基于 Android 11+,优先选择 AIDL(HAL 模式)。
  2. 存量接口:已有 HIDL 接口且无重构计划,继续使用 HIDL;若需统一技术栈,使用 hidl2aidl 迁移。
  3. 跨进程性能:两者性能接近,但 AIDL 的 NDK 后端在零拷贝场景下略优。
  4. 测试需求:AIDL 原生支持 Mock 和单元测试,适合测试驱动开发(TDD)。
  5. 生态兼容:HIDL 在 Android 8-10 设备上更成熟,AIDL 在 Android 11+ 上更受官方支持。
推荐策略:新 HAL 模块(Android 11+)使用 AIDL + @VintfStability;存量 HIDL 模块保持 HIDL 直至迁移窗口;混合场景可通过 hidl2aidl 桥接。

下图展示了两种语言在 Treble 架构中的位置与选择路径:

HIDL vs AIDL 选择策略流程图 选择接口语言 项目基线 Android 11+? 选择 AIDL(HAL 模式) 选择 HIDL(存量兼容) 测试策略:AIDL → 单元测试 + Mock HIDL → VTS 兼容性测试 + 手动桩 注意:AIDL 需添加 @VintfStability HIDL 需严格遵循版本号规则

2.3 HIDL 接口文件基本结构

HIDL 接口文件以 .hal 为扩展名,遵循严格的包名和版本号规则。一个典型的 HIDL 接口文件包含以下要素:

  • 包名声明:格式为 package vendor.xxx.hardware.xxx@1.0;
  • 接口定义:使用 interface IMyHAL { ... }; 包裹方法声明
  • 数据类型:支持 struct、enum、union、vec<T> 等
  • 方法签名:返回类型为 Return<T>,参数支持 in/out 方向

以下是一个完整的 HIDL 接口文件示例:

// IMySensor.hal
package vendor.example.hardware.sensor@1.0;

interface IMySensor {
    // 枚举定义
    enum Status : int32_t {
        OK = 0,
        ERROR = 1,
        TIMEOUT = 2
    };

    // 结构体定义
    struct SensorData {
        int32_t x;
        int32_t y;
        int32_t z;
        int64_t timestamp;
    };

    // 接口方法
    Return<Status> getSensorData(out SensorData data);
    Return<void> setSamplingRate(int32_t rateHz);
    Return<vec<SensorData>> getBatchData(int32_t count);
};
HIDL 文件注意事项:
  • 版本号必须与目录结构一致(如 1.0 对应 sensor/1.0/)
  • 接口名必须以 I 开头(如 IMySensor)
  • 方法返回类型必须使用 Return<> 包装
  • 不支持方法重载(overload)

2.4 AIDL 接口文件基本结构(HAL 模式)

从 Android 11 开始,AIDL 支持 @VintfStability 注解,使其能够用于定义稳定的 HAL 接口。AIDL 文件以 .aidl 为扩展名,结构更接近 Java 接口风格:

  • 包名声明:与 Java 包名一致,如 package vendor.example.hardware.sensor;
  • 稳定性注解:在接口前添加 @VintfStability
  • 接口定义:使用 interface IMySensor { ... }
  • 数据类型:支持 Parcelable、List、Map、接口回调等
  • 方法签名:支持异常抛出,参数支持 in/out/inout 方向

以下是一个 AIDL(HAL 模式)接口文件示例:

// IMySensor.aidl
package vendor.example.hardware.sensor;

@VintfStability
interface IMySensor {
    // 枚举定义(AIDL 使用 @IntDef 或直接 int 常量)
    const int STATUS_OK = 0;
    const int STATUS_ERROR = 1;
    const int STATUS_TIMEOUT = 2;

    // 自定义 Parcelable 类型(需单独定义 .aidl 文件)
    // 此处使用 in/out 参数传递

    /**
     * 获取传感器数据
     * @param data 输出参数,填充传感器数据
     * @return 状态码
     */
    int getSensorData(out SensorData data);

    /**
     * 设置采样率
     * @param rateHz 采样率(Hz)
     */
    void setSamplingRate(int rateHz);

    /**
     * 批量获取数据
     * @param count 请求数量
     * @return 传感器数据列表
     */
    List<SensorData> getBatchData(int count);
}

对应的 SensorData.aidl 文件:

// SensorData.aidl
package vendor.example.hardware.sensor;

@VintfStability
parcelable SensorData {
    int x;
    int y;
    int z;
    long timestamp;
}
AIDL 优势:支持 in/out/inout 方向参数,支持异常抛出,支持接口回调(oneway),且与 Android Framework 的 IPC 机制完全统一,测试时可直接使用 Mockito 或 aidl-mock 工具。

2.5 接口文件结构对比图

下图直观对比 HIDL 与 AIDL 接口文件的结构差异:

HIDL 与 AIDL 接口文件结构对比 HIDL 文件结构 package vendor.xxx.hardware.xxx@1.0; interface IMyHAL { enum Status : int32_t { ... } struct SensorData { ... } Return<Status> getData(out Data d); Return<void> setRate(int32_t rate); }; // 结束接口 扩展名:.hal | 版本号嵌入包名 AIDL 文件结构 package vendor.xxx.hardware.xxx; @VintfStability interface IMyHAL { const int STATUS_OK = 0; int getData(out SensorData d); void setRate(int rate); } // 结束接口 扩展名:.aidl | 注解驱动稳定性 vs

2.6 测试验证视角的关键差异

从测试验证角度,HIDL 和 AIDL 对测试策略的影响显著:

测试维度 HIDL AIDL
单元测试 需手动编写 Mock 桩(C++) 原生支持 Mock(Java Mockito / C++ GMock)
集成测试 依赖 VTS 框架 + 测试用例 可直接使用 Android Test 框架
接口变更检测 版本号 + hidl-gen 编译检查 @VintfStability + aidl 编译检查
跨语言测试 C++ 为主,Java 需 JNI 桥接 Java / C++ / NDK 原生支持
自动化生成 hidl-gen 生成测试桩 aidl --gen-test 生成测试框架
测试建议:若团队以 Java/Kotlin 为主,优先选择 AIDL 以降低测试门槛;若团队以 C++ 为主且项目基于 Android 10 以下,HIDL 仍是稳妥选择。无论选择哪种语言,接口定义阶段就应同步编写测试用例,实现“测试先行”。