HAL接口定义演进与Camera HAL3兼容性设计 - 第4节

4.1 HIDL 接口定义文件 (.hal) 语法与结构

HIDL (HAL Interface Definition Language) 是 Android 8.0 引入的接口定义语言,用于实现 Treble 架构中 Framework 与 HAL 之间的进程间通信。.hal 文件是 HIDL 的核心载体,其语法结构直接决定了生成的 C++/Java 代码质量。

核心原则: .hal 文件必须遵循严格的包名、版本号、类型定义和接口声明规范,任何语法错误都会导致代码生成失败。

4.1.1 包名与版本管理策略

HIDL 包名采用反向域名风格,版本号使用主版本.次版本格式。包名与版本号共同构成接口的唯一标识,直接影响生成的代码命名空间和目录结构。

组件 格式 示例 说明
包名前缀 android.hardware.xxx android.hardware.camera 固定前缀,表示硬件抽象层
模块名 小写字母+下划线 provider 具体硬件模块名称
主版本 正整数 3 不兼容变更时递增
次版本 正整数 5 向后兼容扩展时递增
// Camera HAL3 典型包名声明示例
package android.hardware.camera.provider@3.5;

// 完整包名:android.hardware.camera.provider@3.5
// 生成代码目录:android/hardware/camera/provider/3.5/
// C++ namespace:android::hardware::camera::provider::V3_5
// Java package:android.hardware.camera.provider.V3_5
版本管理最佳实践: 主版本变更意味着接口不兼容,需要同时更新所有实现方;次版本变更只增加新方法或类型,旧实现仍可正常工作。Camera HAL3 从 3.0 演进到 3.8,始终保持主版本 3,体现了良好的向后兼容设计。

4.1.2 类型定义与接口声明

.hal 文件支持基本类型、结构体、枚举、联合体、函数指针和接口类型。Camera HAL3 中大量使用结构体描述相机元数据、流配置和缓冲区信息。

// Camera HAL3 核心类型定义示例
package android.hardware.camera.device@3.5;

// 枚举类型:相机状态
enum CameraDeviceStatus : int32_t {
    PRESENT = 0,
    ENUMERATING = 1,
    NOT_PRESENT = 2,
};

// 结构体类型:流配置
struct StreamConfiguration {
    int32_t width;
    int32_t height;
    int32_t format;
    int32_t rotation;
    vec<Stream> streams;
};

// 接口声明:相机设备操作
interface ICameraDevice {
    // 打开相机会话
    open(ICameraDeviceCallback callback) generates (Status status);
    
    // 配置流
    configureStreams(StreamConfiguration config) 
        generates (Status status, StreamConfiguration outConfig);
    
    // 捕获请求
    processCaptureRequest(vec<CaptureRequest> requests, 
                          vec<BufferCache> cachesToRemove)
        generates (Status status, uint32_t frameNumber);
};
注意: HIDL 接口方法必须显式声明返回值方向。使用 generates 关键字表示异步回调返回值,使用 returns 表示同步返回值。Camera HAL3 中大部分操作采用异步模式,以匹配相机 pipeline 的实时性要求。
.hal 文件结构解析 package android.hardware.camera.device@3.5; 类型定义区 enum CameraDeviceStatus { PRESENT, ENUMERATING, NOT_PRESENT } struct StreamConfiguration { int32 width; int32 height; ... } struct CaptureRequest { int32 frameNumber; vec<Stream> streams; ... } 接口声明区 interface ICameraDevice { open(ICameraDeviceCallback cb) generates (Status status); configureStreams(StreamConfiguration cfg) generates (...); processCaptureRequest(vec<CaptureRequest> req) generates (...); }

4.2 代码生成流程与工具链

HIDL 编译器 hidl-gen 负责将 .hal 文件转换为 C++ 和 Java 代码。整个代码生成流程涉及接口定义、编译配置、代码生成和集成验证四个阶段。

4.2.1 hidl-gen 编译器使用

hidl-gen 是 Android 源码中的专用工具,支持多种输出模式。Camera HAL3 的接口定义通常使用 -Lc++-impl 和 -Ljava 选项分别生成 C++ 实现骨架和 Java 客户端代码。

# 生成 C++ 接口头文件
hidl-gen -o output/cpp -Lc++-headers \
    -randroid.hardware:hardware/interfaces \
    android.hardware.camera.device@3.5

# 生成 C++ 实现骨架
hidl-gen -o output/cpp -Lc++-impl \
    -randroid.hardware:hardware/interfaces \
    android.hardware.camera.device@3.5

# 生成 Java 客户端代码
hidl-gen -o output/java -Ljava \
    -randroid.hardware:hardware/interfaces \
    android.hardware.camera.device@3.5
关键参数说明:
  • -o:指定输出目录
  • -L:指定输出语言和模板类型(c++-headers, c++-impl, java, java-constants 等)
  • -r:指定包名到路径的映射关系,格式为 package:path

4.2.2 生成代码目录结构

hidl-gen 严格按照包名和版本号生成目录结构,确保不同版本的接口可以共存。Camera HAL3 的多个版本(3.0~3.8)可以在同一系统中并存,由 Framework 根据设备能力选择加载。

生成文件 路径示例 用途
接口头文件 android/hardware/camera/device/3.5/ICameraDevice.h C++ 接口定义,包含纯虚函数
类型头文件 android/hardware/camera/device/3.5/types.h 结构体、枚举等类型定义
Bp 代理类 android/hardware/camera/device/3.5/BpCameraDevice.h 客户端代理,封装 IPC 调用
Bn 桩类 android/hardware/camera/device/3.5/BnCameraDevice.h 服务端桩类,处理 IPC 请求
Java 接口 android/hardware/camera/device/V3_5/ICameraDevice.java Java 层接口定义
Java 代理 android/hardware/camera/device/V3_5/ICameraDeviceProxy.java Java 客户端代理
HIDL 代码生成流程 .hal 接口文件 hidl-gen 编译器 C++ 头文件 (.h) C++ 实现骨架 Java 接口代码 Bp/Bn 代理桩类 HAL 实现类 Java 代理类

4.3 Camera HAL3 接口实战案例

以 Camera HAL3 的 ICameraDevice 接口为例,展示从 .hal 定义到 C++/Java 代码生成的全过程。Camera HAL3 的核心接口包括设备管理、流配置、捕获请求和结果回调。

4.3.1 定义 Camera HAL3 核心接口

// camera/device/3.5/ICameraDevice.hal
package android.hardware.camera.device@3.5;

import android.hardware.camera.common@3.5::Status;
import android.hardware.camera.common@3.5::Stream;
import android.hardware.camera.common@3.5::CaptureRequest;
import android.hardware.camera.common@3.5::CaptureResult;

interface ICameraDevice {
    // 打开相机设备
    open(ICameraDeviceCallback callback) 
        generates (Status status);
    
    // 关闭相机设备
    close() 
        generates (Status status);
    
    // 初始化配置
    initialize(ICameraDeviceSession session) 
        generates (Status status);
    
    // 获取相机元数据
    getCameraCharacteristics() 
        generates (Status status, CameraCharacteristics characteristics);
    
    // 设置流配置
    configureStreams(StreamConfiguration config) 
        generates (Status status, StreamConfiguration outConfig);
    
    // 处理捕获请求
    processCaptureRequest(vec<CaptureRequest> requests, 
                          vec<BufferCache> cachesToRemove)
        generates (Status status, uint32_t frameNumber);
    
    // 刷新待处理请求
    flush() 
        generates (Status status);
};

// 回调接口
interface ICameraDeviceCallback {
    // 通知捕获结果
    processCaptureResult(vec<CaptureResult> results);
    
    // 通知错误
    notify(vec<NotifyMsg> msgs);
};

4.3.2 生成的 C++ 代码结构

hidl-gen 为上述接口生成以下 C++ 代码文件,开发者只需继承 ICameraDevice 并实现纯虚函数。

// 生成的 C++ 接口头文件 (ICameraDevice.h)
namespace android {
namespace hardware {
namespace camera {
namespace device {
namespace V3_5 {

struct StreamConfiguration {
    int32_t width;
    int32_t height;
    int32_t format;
    int32_t rotation;
    ::android::hardware::hidl_vec<Stream> streams;
};

struct CameraCharacteristics {
    int32_t deviceVersion;
    int32_t supportedHardwareLevel;
    // ... 其他元数据字段
};

struct ICameraDevice : public ::android::hardware::IInterface {
    using Status = ::android::hardware::camera::common::V3_5::Status;
    
    virtual Status open(
        const ::android::sp<ICameraDeviceCallback>& callback) = 0;
    
    virtual Status close() = 0;
    
    virtual Status configureStreams(
        const StreamConfiguration& config,
        StreamConfiguration* outConfig) = 0;
    
    virtual Status processCaptureRequest(
        const ::android::hardware::hidl_vec<CaptureRequest>& requests,
        const ::android::hardware::hidl_vec<BufferCache>& cachesToRemove,
        uint32_t* frameNumber) = 0;
    
    // ... 其他纯虚函数
};

}  // namespace V3_5
}  // namespace device
}  // namespace camera
}  // namespace hardware
}  // namespace android

4.3.3 生成的 Java 代码结构

Java 层代码同样遵循包名和版本号规则,Framework 通过 Java 代理类与 HAL 服务通信。

// 生成的 Java 接口 (ICameraDevice.java)
package android.hardware.camera.device.V3_5;

public interface ICameraDevice extends android.os.IInterface {
    // 状态码
    public static final int STATUS_OK = 0;
    public static final int STATUS_ERROR = 1;
    public static final int STATUS_INVALID_OPERATION = 2;
    
    // 打开相机设备
    public int open(ICameraDeviceCallback callback) 
        throws android.os.RemoteException;
    
    // 关闭相机设备
    public int close() 
        throws android.os.RemoteException;
    
    // 配置流
    public int configureStreams(StreamConfiguration config, 
                                StreamConfiguration outConfig) 
        throws android.os.RemoteException;
    
    // 处理捕获请求
    public int processCaptureRequest(CaptureRequest[] requests, 
                                     BufferCache[] cachesToRemove) 
        throws android.os.RemoteException;
    
    // 抽象类,提供默认实现
    public abstract static class Stub extends android.os.Binder 
        implements ICameraDevice {
        // Binder 通信逻辑自动生成
    }
}
版本兼容性设计: Camera HAL3 从 3.0 到 3.8 的演进过程中,新增的方法都放在接口末尾,并使用 @V3_2::ICameraDevice、@V3_3::ICameraDevice 等子接口继承。Framework 通过 getInterfaceVersion() 方法检测 HAL 支持的版本,动态选择调用路径。

4.4 包名与版本管理最佳实践

在大型项目中,多个 HAL 版本共存是常态。合理的包名和版本管理策略可以避免命名冲突,降低维护成本。

4.4.1 版本演进策略

场景 版本变更 示例 兼容性
新增方法 次版本+1 3.4 → 3.5 向后兼容
新增类型 次版本+1 3.5 → 3.6 向后兼容
修改方法签名 主版本+1 3.6 → 4.0 不兼容
删除方法 主版本+1 3.7 → 4.0 不兼容
修改类型定义 主版本+1 3.8 → 4.0 不兼容

4.4.2 多版本共存方案

Android Treble 架构支持同一 HAL 接口的多个版本同时注册到 hwservicemanager。Camera HAL3 实现可以通过 @3.4::ICameraDevice 和 @3.5::ICameraDevice 两个服务名分别注册,Framework 根据设备能力选择连接。

// 服务注册示例 (C++ 实现)
// 注册 3.4 版本服务
android::sp<ICameraDevice> device34 = new CameraDeviceImpl34();
device34->registerAsService("camera_device@3.4");

// 注册 3.5 版本服务
android::sp<ICameraDevice> device35 = new CameraDeviceImpl35();
device35->registerAsService("camera_device@3.5");

// Framework 端获取服务
// 优先尝试 3.5 版本
sp<ICameraDevice> device = ICameraDevice::getService("camera_device@3.5");
if (device == nullptr) {
    // 降级到 3.4 版本
    device = ICameraDevice::getService("camera_device@3.4");
}
Camera HAL3 多版本共存架构 Android Framework (CameraService) 版本协商选择器 HAL 3.4 实现 camera_device@3.4 HAL 3.5 实现 camera_device@3.5 HAL 3.6 实现 camera_device@3.6 hwservicemanager 服务注册表
常见陷阱: 在 .hal 文件中修改已有结构体字段顺序或类型,即使不改变版本号,也会导致二进制不兼容。正确的做法是新增字段到结构体末尾,或者创建新的结构体类型。Camera HAL3 在演进过程中严格遵循这一原则,确保旧版本实现可以安全加载新版本接口。

4.5 本章小结

HIDL 接口定义是 Camera HAL3 开发的基石。通过本章学习,应掌握以下核心技能:

  • .hal 文件语法: 包名声明、类型定义、接口声明、方法签名和回调机制
  • 版本管理策略: 主版本/次版本的含义、变更规则和多版本共存方案
  • 代码生成流程: hidl-gen 工具使用、输出目录结构和 C++/Java 代码对应关系
  • Camera HAL3 实战: 核心接口定义、回调接口设计和版本兼容性实现

在实际项目中,建议将 .hal 文件纳入版本控制,每次接口变更都同步更新版本号,并使用自动化脚本验证生成的代码与 .hal 定义的一致性。