Android HAL层驱动开发入门 - 第4节

4.1 HIDL 的作用:硬件服务化的桥梁

HIDL(HAL Interface Definition Language)是 Android 8.0(Treble 项目)引入的接口定义语言,用于在 Android 框架(Framework) 与 HAL 实现(Vendor HAL) 之间建立稳定、可独立更新的通信契约。其核心作用可归纳为三点:

  • 解耦框架与供应商实现:Framework 不再直接链接 HAL 共享库,而是通过 HIDL 定义的接口进行进程间通信(IPC),使得系统更新(OTA)无需重新编译 HAL 代码。
  • 标准化硬件抽象层:为摄像头、音频、传感器、图形等硬件模块提供统一的接口规范,确保不同供应商的 HAL 实现可以无缝替换。
  • 支持多进程与跨边界通信:HIDL 自动生成客户端(Client)与服务端(Server)的 Binder 通信代码,开发者只需关注业务逻辑。
关键概念: HIDL 接口运行在 hwbinder 域中,与传统的 binder 域隔离,确保系统服务与供应商服务互不干扰。
HIDL 在 Android 架构中的位置 Android Framework (Java/Native) HIDL 接口定义(.hal 文件) Vendor HAL 实现 Linux Kernel + 驱动 HIDL 接口是 Framework 与 Vendor HAL 之间的唯一契约,双方独立演进

4.2 HIDL 与 AIDL 的区别:两大接口定义语言对比

Android 系统存在两种接口定义语言:AIDL(Android Interface Definition Language) 用于应用层与系统服务之间的 Binder 通信;HIDL 专用于 Framework 与 HAL 之间的 hwbinder 通信。下表从多个维度进行对比:

对比维度 AIDL HIDL
通信域 binder 域(应用层) hwbinder 域(供应商层)
主要用途 应用与服务、服务与服务之间 Framework 与 HAL 实现之间
稳定性要求 可随系统版本变化 必须保持向后兼容(稳定接口)
版本管理 无强制版本机制 通过 @version 注解管理接口版本
数据类型 支持 Java 基本类型、Parcelable 支持 HIDL 原生类型、struct、enum、union
生成代码 生成 Java/C++ 桩代码 生成 C++ 客户端/服务端代码
接口文件后缀 .aidl .hal
实践建议: 如果你正在开发一个新的硬件 HAL 模块(如指纹、传感器),请使用 HIDL;如果你在修改系统服务接口(如 ActivityManager),请使用 AIDL。两者不可混用。

4.3 HIDL 文件基本语法:从结构到关键字

一个标准的 .hal 文件由 包声明(package)、导入(import)、类型定义 和 接口定义(interface) 四部分组成。以下是一个典型的 HIDL 文件结构:

// 1. 包声明:定义接口的命名空间和版本
package vendor.example.hardware.led@1.0;

// 2. 导入其他 HIDL 类型
import android.hidl.base@1.0::IBase;

// 3. 枚举类型定义
enum LedColor : uint32_t {
    RED = 0,
    GREEN = 1,
    BLUE = 2,
    RGB = 3
};

// 4. 结构体定义
struct LedConfig {
    uint32_t brightness;
    LedColor color;
    bool     enable;
};

// 5. 接口定义:包含方法声明
interface ILed extends IBase {
    // 同步方法:设置 LED 状态
    setConfig(LedConfig config) generates (Result result);

    // 同步方法:获取当前配置
    getConfig() generates (Result result, LedConfig config);

    // 单向方法(fire-and-forget):触发闪烁
    oneway blink(uint32_t intervalMs);
};

语法要点详解

  • 包声明:格式为 package <vendor>.<subsystem>.<module>@<major>.<minor>,版本号必须与接口文件所在目录一致。
  • 导入语句:使用 import 关键字引入其他 .hal 文件中定义的类型或接口。
  • 枚举与结构体:枚举必须指定底层整数类型(如 uint32_t);结构体成员支持基本类型、其他结构体、枚举和 vec<T> 等容器。
  • 方法声明:同步方法使用 generates 关键字指定返回值;单向方法使用 oneway 修饰,不阻塞调用方。
  • 接口继承:所有 HIDL 接口必须显式继承 IBase(或间接继承),IBase 提供了生命周期管理基础方法。
常见错误: 忘记在接口声明中 extends IBase 会导致编译失败;方法参数中不能使用 C++ 指针或引用,必须使用 HIDL 原生类型或 vec<T>。
HIDL 文件语法结构树 .hal 文件 package 声明 import 导入 类型定义 interface 定义 vendor.sub@1.0 IBase enum/struct 方法声明 oneway

4.4 .hal 文件结构:目录布局与编译规则

HIDL 接口文件不仅包含语法内容,还遵循严格的 目录结构 和 编译配置。一个完整的 HIDL 模块在源码树中的布局如下:

hardware/interfaces/
└── vendor/
    └── example/
        └── led/
            ├── 1.0/
            │   ├── default/
            │   │   ├── Android.bp          # HAL 实现编译配置
            │   │   ├── Led.cpp             # HAL 实现代码
            │   │   ├── Led.h
            │   │   └── service.cpp         # 服务注册入口
            │   ├── ILed.hal                # HIDL 接口定义
            │   └── types.hal               # 类型定义(可选)
            └── Android.bp                  # 接口编译配置

关键文件说明

文件/目录 作用 是否必须
ILed.hal 接口定义文件,包含 interface ILed 声明 是
types.hal 集中定义枚举、结构体等共享类型 推荐
Android.bp(接口层) 使用 hidl_interface 模块编译 .hal 文件,生成 C++ 桩代码 是
default/ 目录 存放 HAL 实现代码,包含 hidl_passthrough 或 hidl_service 编译模块 是
service.cpp 将 HAL 服务注册到 hwbinder 域,供 Framework 发现和调用 是

接口层 Android.bp 示例

// hardware/interfaces/vendor/example/led/Android.bp
hidl_interface {
    name: "vendor.example.hardware.led@1.0",
    root: "vendor.example.hardware",
    srcs: [
        "ILed.hal",
        "types.hal",
    ],
    interfaces: [
        "android.hidl.base@1.0",
    ],
    gen_java: false,
    gen_hal: true,
};

实现层 Android.bp 示例

// hardware/interfaces/vendor/example/led/1.0/default/Android.bp
cc_binary {
    name: "vendor.example.hardware.led@1.0-service",
    relative_install_path: "hw",
    srcs: [
        "Led.cpp",
        "service.cpp",
    ],
    shared_libs: [
        "libhidlbase",
        "libhidltransport",
        "libutils",
        "vendor.example.hardware.led@1.0",
    ],
    init_rc: ["vendor.example.hardware.led@1.0-service.rc"],
};
开发流程提示: 先编写 .hal 文件并编译通过,生成 C++ 桩代码;然后实现桩代码中的 ILed 接口方法;最后通过 service.cpp 注册服务,并使用 lshal 命令验证服务是否成功注册。
HIDL 模块编译与运行流程 编写 .hal 文件 定义接口与类型 编译 hidl_interface 生成 C++ 桩代码 实现 HAL 方法 填充业务逻辑 注册服务 启动并验证 关键编译产物 • 桩代码头文件:out/soong/.interfaces/vendor/example/hardware/led/1.0/ • 服务端二进制:vendor.example.hardware.led@1.0-service • 验证命令:adb shell lshal | grep vendor.example.hardware.led