2. HIDL基础回顾:HIDL接口定义语言语法、服务注册与发现机制

在深入AIDL化Camera HAL架构之前,必须牢固掌握HIDL(HAL Interface Definition Language)的核心机制。HIDL是Android 8.0(Treble项目)引入的接口定义语言,用于实现Framework与HAL之间的稳定、可独立更新的通信边界。本章将系统回顾HIDL的语法规范、服务注册与发现流程,为后续与AIDL方案的对比奠定基础。

2.1 HIDL接口定义语言语法

HIDL语法设计目标:严格类型安全、跨进程透明、向后兼容。其核心语法元素包括包名、接口、方法、数据类型与回调。

2.1.1 包名与版本管理

每个HIDL接口必须声明唯一的包名,并附带主版本号和次版本号。版本号用于接口演进时的兼容性检查。

// 包名格式:vendor.hardware.模块名@版本
package android.hardware.camera.provider@3.5;
语法元素 说明 示例
包名 反向域名风格,标识接口所属厂商和模块 android.hardware.camera
主版本 不兼容变更时递增 @3
次版本 向后兼容新增时递增 .5
完整声明 package + 版本号 package android.hardware.camera.provider@3.5;

2.1.2 接口定义

HIDL接口使用interface关键字声明,支持单继承。接口内可定义方法、枚举、结构体、联合体等类型。

interface ICameraDevice {
    // 方法定义:返回类型 方法名(参数列表) 生成(回调)
    getResourceCost() generates (CameraResourceCost cost);

    // 单向方法(fire-and-forget)
    oneway flush();

    // 同步方法(默认)
    close() generates (Status status);
};
关键语法规则:
  • generates:用于声明异步回调结果,HIDL中所有返回值都通过generates传递。
  • oneway:标记方法为单向调用,不等待返回,适用于通知类操作。
  • 方法命名:小驼峰风格,动词开头。

2.1.3 数据类型系统

HIDL定义了完整的数据类型体系,确保跨进程传输时数据布局一致。

类别 类型 说明
基本类型 int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double 固定宽度整数和浮点数
字符串 string UTF-8编码,长度可变
数组 T[] 可变长度数组,如 uint8_t[]
结构体 struct 成员按声明顺序内存对齐
联合体 union 共享内存区域,需显式指定判别器
枚举 enum 底层为int32_t,支持位掩码
句柄 handle 跨进程传递的文件描述符或原生句柄
接口引用 interface 指向另一个HIDL接口的Binder引用
// 结构体定义示例
struct CameraMetadata {
    uint32_t tag;
    uint8_t dataType;
    int32_t count;
    uint8_t[] data;
};

// 枚举定义示例
enum Status : int32_t {
    OK = 0,
    ERROR_ILLEGAL_ARGUMENT = -1,
    ERROR_CAMERA_IN_USE = -2,
    ERROR_MAX_CAMERAS_IN_USE = -3,
};

2.1.4 回调与异步通信

HIDL通过回调接口实现异步通知。服务端定义回调接口,客户端实现并注册,服务端在事件发生时调用回调方法。

// 回调接口定义
interface ICameraDeviceCallback {
    onResult(CaptureResult result);
    onError(ErrorCode error);
};

// 主接口中使用回调
interface ICameraDevice {
    open(ICameraDeviceCallback callback) generates (Status status);
};
设计要点:回调接口必须使用oneway或默认同步方式。Camera HAL中,onResult通常为同步调用以保证帧顺序,onError可使用oneway避免阻塞。

2.2 HIDL服务注册与发现机制

HIDL服务使用hwservicemanager作为中心注册表,负责服务的注册、发现和生命周期管理。该机制是Treble架构实现Framework与HAL解耦的关键基础设施。

2.2.1 服务注册流程

HAL服务进程在启动后,通过registerAsService将自身实例注册到hwservicemanager。注册信息包括:服务名称、接口描述符、版本号。

// C++ 服务端注册示例
using android::hardware::camera::provider::V3_5::ICameraProvider;
using android::hardware::defaultServiceManager;

sp<ICameraProvider> service = new CameraProvider();
status_t status = service->registerAsService("default");
// 注册成功后,客户端可通过 "default" 名称发现该服务
HIDL服务注册流程 HAL服务进程 (Camera HAL) hwservicemanager (服务注册中心) 服务注册表 (名称→接口映射) 注册步骤: ① HAL服务创建接口实例 (ICameraProvider) ② 调用 registerAsService("default") ③ hwservicemanager 验证接口描述符与版本 ④ 将服务名称 + Binder引用存入注册表 ⑤ 返回注册结果 (OK/FAIL)

2.2.2 服务发现流程

客户端(如CameraService)通过hwservicemanager查询指定名称和版本的服务,获取Binder引用后即可跨进程调用。

// C++ 客户端发现服务示例
using android::hardware::camera::provider::V3_5::ICameraProvider;

sp<ICameraProvider> service = ICameraProvider::getService("default");
if (service != nullptr) {
    // 成功获取服务引用,开始调用
    service->getCameraIdList([](Status status, const hidl_vec<CameraId>& ids) {
        // 处理回调
    });
} else {
    // 服务不可用,处理错误
}
HIDL服务发现流程 CameraService (客户端) hwservicemanager (查询服务) Camera HAL (服务端) 发现步骤: ① CameraService 调用 getService("default") ② hwservicemanager 查找注册表匹配项 ③ 返回服务Binder引用给客户端 ④ 客户端通过Binder直接调用HAL方法 ⑤ 若服务未注册,返回null,客户端需等待或重试

2.2.3 服务生命周期管理

HIDL服务支持延迟注册和热插拔。Camera HAL中,物理摄像头设备可能动态插入或移除,服务注册机制需配合IServiceNotification实现动态感知。

// 注册服务通知,监听服务上线/下线
using android::hidl::manager::V1_0::IServiceNotification;

class ServiceListener : public IServiceNotification {
    Return<void> onRegistration(
        const hidl_string& fqName,
        const hidl_string& name,
        bool preexisting) override {
        if (fqName == "android.hardware.camera.provider@3.5::ICameraProvider") {
            // 服务已注册,可以开始使用
        }
    }
};
常见陷阱:
  • 版本不匹配:客户端请求的版本与服务端注册的版本必须兼容(主版本相同,次版本≥客户端要求)。
  • 服务死锁:在服务注册回调中直接调用getService可能导致死锁,应使用异步通知。
  • 权限问题:只有system分区或vendor分区的进程才能注册HIDL服务,普通应用无法注册。

2.3 HIDL与Binder驱动的关系

HIDL通信底层依赖Binder驱动,但与Android Framework的AIDL Binder使用不同的域:

特性 HIDL Binder AIDL Binder
Binder域 /dev/hwbinder /dev/binder
服务管理器 hwservicemanager servicemanager
主要用途 Framework ↔ HAL 通信 应用 ↔ Framework 通信
接口定义语言 HIDL (.hal文件) AIDL (.aidl文件)
传输效率 优化大块数据(如Camera帧元数据) 通用场景
理解要点:HIDL使用独立的Binder域(hwbinder)是为了隔离Framework与HAL的Binder线程池,避免相互阻塞。Camera HAL中,大量帧元数据通过HIDL的hidl_memory或FMQ(快速消息队列)传输,减少Binder拷贝开销。

2.4 HIDL接口的编译与生成

HIDL接口文件(.hal)通过hidl-gen工具编译,生成C++或Java的客户端/服务端代码骨架。

# 编译HIDL接口,生成C++代码
hidl-gen -o output_dir -L c++-impl \
    -randroid.hardware:hardware/interfaces \
    android.hardware.camera.provider@3.5

# 生成的文件结构
output_dir/
├── CameraProvider.h          # 接口头文件
├── CameraProvider.cpp        # 接口实现骨架
├── CameraProviderAll.cpp     # 所有接口的合并实现
└── types.h                   # 数据类型定义
生成代码的关键组件:
  • BpCameraProvider:客户端代理类,封装Binder调用。
  • BnCameraProvider:服务端基类,处理Binder请求分发。
  • ICameraProvider:纯虚接口类,定义所有方法。
  • HwBinder:底层传输对象,管理跨进程通信。