Camera HAL开发入门:从HIDL接口到驱动交互 - 第3节

3.1 HIDL 的定义与设计目标

HIDL(HAL Interface Definition Language)是 Android Treble 架构中用于定义 HAL 接口的跨进程通信语言。它的核心目标是将 Android 框架(Framework)与硬件供应商实现(Vendor HAL)之间的编译时依赖,转变为运行时稳定的二进制接口(ABI)。

关键定义: HIDL 是一种接口定义语言,用于描述 HAL 服务端与客户端之间的契约。它生成的语言绑定(C++/Java)确保接口的二进制兼容性,使得 Framework 和 Vendor 分区可以独立更新。

3.1.1 HIDL 的核心设计原则

  • 二进制稳定性: 接口一旦发布,其 ABI 在后续版本中必须保持向后兼容。
  • 强类型化: 所有参数、返回值、回调函数都必须显式声明类型,消除运行时类型歧义。
  • 单向/双向通信: 支持同步调用(blocking)和异步回调(oneway)。
  • 版本化管理: 每个接口通过 @version 注解标识,支持接口演进。

3.2 HIDL 与 AIDL 的区别

在 Android 系统中,AIDL(Android Interface Definition Language)主要用于应用层(App <-> Service)的 Binder 通信,而 HIDL 专为 HAL 层设计。两者虽然都基于 Binder 驱动,但在设计哲学和使用场景上有本质区别。

对比维度 HIDL AIDL
目标层级 Framework <-> Vendor HAL App <-> System Service
稳定性要求 严格 ABI 稳定,跨分区独立更新 无强制 ABI 要求,依赖 SDK 版本
接口定义文件 .hal 文件 .aidl 文件
支持的数据类型 HIDL 原生类型 + struct/union/enum Java 原生类型 + Parcelable
服务注册方式 hwservicemanager servicemanager
传输层 Binder(直通模式)/ HwBinder Binder
版本管理 显式 @version,支持 minor/major 隐式,依赖包名
开发提示: 在 Camera HAL 开发中,你几乎只与 HIDL 打交道。AIDL 主要用于 CameraService 与上层 App 的交互,而 Camera HAL 接口(如 ICameraDevice、ICameraProvider)全部使用 HIDL 定义。

3.3 HIDL 在 Treble 架构中的角色

Treble 架构是 Android 8.0 引入的重大重构,其核心目标是将 Framework 与 Vendor 实现解耦。HIDL 在这一架构中扮演着“契约层”的角色,位于 Framework 和 HAL 实现之间。

Treble 架构中 HIDL 的角色定位 Android Framework CameraService SurfaceFlinger MediaServer HIDL 接口契约层(.hal 定义) ICameraProvider / ICameraDevice / ICameraDeviceSession Vendor HAL 实现 Camera HAL 3.x Sensor HAL ISP 驱动封装 HIDL 的核心作用 • 定义稳定的二进制接口 • 允许 Framework 独立 OTA 升级 • 供应商无需修改 Framework 代码 • 接口版本化保证向后兼容 HIDL 接口层是 Framework 与 Vendor 之间的唯一通信桥梁
架构要点: 在 Treble 架构中,Framework 分区(system.img)和 Vendor 分区(vendor.img)通过 HIDL 接口进行通信。CameraService 通过 HIDL 调用 Camera HAL 实现,而无需关心底层驱动细节。这种解耦使得 Google 可以独立推送 Framework 更新,而 OEM 只需维护 Vendor 分区的 HAL 实现。

3.4 .hal 文件的基本语法结构

.hal 文件是 HIDL 接口的载体,采用类似 C++ 的语法风格。一个完整的 .hal 文件包含包声明、导入语句、接口定义、数据类型定义等部分。

3.4.1 文件基本骨架

// 包声明:定义接口的命名空间和版本
package android.hardware.camera.provider@3.5;

// 导入其他 HIDL 接口
import android.hardware.camera.common@3.5::types;
import android.hardware.camera.device@3.5::ICameraDevice;

// 接口定义
interface ICameraProvider {
    // 方法声明
    getCameraIdList() generates (Status status, vec<string> cameraIds);
    
    // 带回调的方法
    getCameraDeviceInterface(
        string cameraId
    ) generates (Status status, ICameraDevice device);
    
    // oneway 异步回调
    oneway notifyDeviceStateChange(
        int64_t deviceState
    );
};

3.4.2 核心语法元素

语法元素 说明 示例
package 声明接口所属的包名和版本号 package android.hardware.camera@3.5;
import 导入其他 .hal 文件中的类型或接口 import android.hardware.camera.common@3.5::types;
interface 定义 HAL 接口,包含方法声明 interface ICameraProvider { ... };
generates 指定方法的返回类型(可返回多个值) generates (Status status, vec<string> list);
oneway 标记异步调用,不阻塞客户端 oneway notify();
struct 定义复合数据类型 struct CameraInfo { ... };
enum 定义枚举类型 enum Status : int32_t { OK, ERROR };
@version 注解,标记接口或类型的版本 @version 3.5

3.4.3 数据类型定义示例

package android.hardware.camera.common@3.5;

// 枚举定义
enum Status : int32_t {
    OK = 0,
    ERROR_ILLEGAL_ARGUMENT = -1,
    ERROR_INVALID_OPERATION = -2,
    ERROR_DEVICE_UNAVAILABLE = -3,
};

// 结构体定义
struct CameraMetadata {
    int32_t tag;
    int32_t dataType;
    vec<uint8_t> data;
};

// 联合体定义(使用 safe_union)
safe_union CameraMetadataValue {
    int32_t int32Value;
    int64_t int64Value;
    float floatValue;
    vec<uint8_t> bytesValue;
};

3.4.4 接口继承与回调

HIDL 支持接口继承,允许子接口扩展父接口的功能。Camera HAL 中大量使用这种模式:

package android.hardware.camera.device@3.5;

// 基础接口
interface ICameraDevice {
    // 打开相机设备,返回会话接口
    open() generates (Status status, ICameraDeviceSession session);
    
    // 获取相机特性元数据
    getCameraCharacteristics() generates (Status status, CameraMetadata chars);
};

// 子接口继承
interface ICameraDeviceSession extends ICameraDevice {
    // 配置输出流
    configureStreams(
        StreamConfiguration config
    ) generates (Status status, HalStreamConfiguration halConfig);
    
    // 处理捕获请求
    processCaptureRequest(
        vec<CaptureRequest> requests,
        vec<BufferCache> cachesToRemove
    ) generates (Status status, uint32_t numRequestProcessed);
    
    // 回调接口:通知框架捕获结果
    oneway notify(
        vec<NotifyMsg> msgs
    );
};
常见陷阱:
  • HIDL 不支持方法重载(overload),每个方法名必须唯一。
  • 所有方法必须显式声明返回类型,即使没有返回值也要使用 generates ()。
  • 接口版本号必须与包声明中的版本一致,否则编译会报错。
  • oneway 方法不能有返回值,且不能保证送达顺序。

3.5 HIDL 接口的版本管理

HIDL 的版本管理采用 major.minor 格式。major 版本变更表示不兼容的 ABI 改动,minor 版本变更表示向后兼容的扩展。

HIDL 版本管理策略 @3.0 初始版本 @3.1 新增方法(兼容) @3.2 新增类型(兼容) @4.0 不兼容 版本管理规则 • Minor 版本升级:只能添加新方法/类型,不能修改或删除已有接口 • Major 版本升级:允许任意修改,但需要同时维护旧版本的实现 • 客户端和服务端可以协商使用双方都支持的版本
实践建议: 在 Camera HAL 开发中,通常使用 @3.x 版本系列。如果你需要扩展接口,优先考虑 minor 版本升级(如从 3.4 到 3.5),而不是创建新的 major 版本。这样可以保持与旧版本 Framework 的兼容性。

3.6 HIDL 接口的编译与生成

.hal 文件不能直接使用,需要通过 hidl-gen 工具编译生成 C++ 或 Java 的源代码。生成的代码包括客户端代理(Proxy)和服务端桩(Stub)。

3.6.1 编译流程

# 1. 生成 C++ 头文件和实现
hidl-gen -o output_dir -L c++-impl \
    -r android.hardware:hardware/interfaces \
    android.hardware.camera.provider@3.5

# 2. 生成 Android.bp 构建文件
hidl-gen -o output_dir -L androidbp \
    -r android.hardware:hardware/interfaces \
    android.hardware.camera.provider@3.5

# 3. 生成 Java 文件(用于 Framework 端)
hidl-gen -o output_dir -L java \
    -r android.hardware:hardware/interfaces \
    android.hardware.camera.provider@3.5

3.6.2 生成的文件结构

生成文件 用途
ICameraProvider.h 接口定义头文件,包含纯虚函数
ICameraProvider.cpp 接口实现基类,包含 Binder 序列化代码
BnCameraProvider.h 服务端桩类,处理 Binder 请求分发
BpCameraProvider.h 客户端代理类,封装 Binder 调用
types.h 所有自定义类型的 C++ 定义
Android.bp 构建配置,包含依赖和编译选项
关键理解: 作为 Camera HAL 开发者,你主要关注的是 服务端实现。你需要继承 BnCameraProvider 或 ICameraProvider 基类,并实现其中的纯虚函数。客户端代理(Bp)由 Framework 的 CameraService 使用,你通常不需要关心。

3.7 本章小结

  • HIDL 是 Treble 架构中 Framework 与 Vendor 之间的契约语言,保证二进制接口稳定性。
  • 与 AIDL 的区别 主要体现在目标层级、稳定性要求和版本管理策略上。
  • 在 Treble 架构中,HIDL 位于 Framework 和 HAL 实现之间,是解耦的关键层。
  • .hal 文件 使用 package、import、interface、generates、oneway 等关键字定义接口契约。
  • 版本管理 采用 major.minor 格式,minor 升级必须保持向后兼容。
  • 编译工具 hidl-gen 将 .hal 文件转换为 C++/Java 代码,生成客户端代理和服务端桩。