Camera HAL开发从入门到精通 - 第3节

3.1 HAL3 核心接口总览

Android Camera HAL3 接口是连接 Android 框架层(Framework)与底层相机硬件驱动的关键抽象层。HAL3 的设计围绕三个核心结构体展开:camera3_device_t(设备操作接口)、camera3_callback_ops_t(回调通知接口),以及底层的 hw_module_t 和 hw_device_t(HAL 模块与设备基础定义)。

理解这四个结构体的职责与协作关系,是掌握 HAL3 开发的第一步。下图展示了它们在系统架构中的位置与数据流方向:

核心要点:HAL3 接口设计遵循“模块-设备-操作-回调”四层分离原则。Framework 通过 hw_module_t 加载 HAL 模块,通过 hw_device_t 获取设备句柄,再通过 camera3_device_t 下发拍照/预览请求,最后通过 camera3_callback_ops_t 接收结果与事件。
HAL3 核心接口协作关系 Android Framework hw_module_t hw_device_t camera3_device_t (操作接口) camera3_callback_ops_t (回调接口) 说明: Framework 通过 hw_module_t 的 open() 方法获取 hw_device_t,再通过 hw_device_t 的 common 域 获取 camera3_device_t 指针,最终通过该指针下发请求并注册回调。

3.2 HAL 模块定义:hw_module_t

hw_module_t 是所有 Android HAL 模块的通用基类,定义在 hardware/libhardware/include/hardware/hardware.h 中。Camera HAL 模块必须首先实现此结构体,作为 Framework 发现和加载 HAL 的入口。

3.2.1 结构体定义

typedef struct hw_module_t {
    uint32_t tag;              // 必须为 HARDWARE_MODULE_TAG
    uint16_t module_api_version; // 模块 API 版本
    uint16_t hal_api_version;    // HAL API 版本
    const char *id;            // 模块 ID,Camera 为 "camera"
    const char *name;          // 模块名称
    const char *author;        // 作者信息
    struct hw_module_methods_t *methods; // 模块方法表
    void *dso;                 // 动态库句柄
    uint32_t reserved[32-7];   // 保留字段
} hw_module_t;

3.2.2 Camera HAL 模块实例

Camera HAL 模块需要定义一个全局的 HAL_MODULE_INFO_SYM 符号,Framework 通过 dlopen 加载该符号来获取模块句柄。典型实现如下:

static struct hw_module_methods_t camera_module_methods = {
    .open = camera_device_open,  // 打开相机设备
};

struct camera_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag                 = HARDWARE_MODULE_TAG,
        .module_api_version  = CAMERA_MODULE_API_VERSION_3_0,
        .hal_api_version     = HARDWARE_HAL_API_VERSION,
        .id                  = CAMERA_HARDWARE_MODULE_ID,
        .name                = "Camera HAL3 Module",
        .author              = "Your Company",
        .methods             = &camera_module_methods,
        .dso                 = NULL,
        .reserved            = {0},
    },
};
开发提示:模块 ID 必须为 "camera",否则 Framework 无法正确匹配 HAL 模块。module_api_version 应设置为 CAMERA_MODULE_API_VERSION_3_0 或更高版本,以标识 HAL3 接口。

3.3 HAL 设备定义:hw_device_t

hw_device_t 是 HAL 设备的通用基类,代表一个具体的硬件设备实例。当 Framework 调用模块的 open() 方法时,HAL 需要返回一个填充好的 hw_device_t 结构体,其中包含指向具体设备操作接口的指针。

3.3.1 结构体定义

typedef struct hw_device_t {
    uint32_t tag;              // 必须为 HARDWARE_DEVICE_TAG
    uint32_t version;          // 设备版本
    struct hw_module_t *module; // 指向所属模块
    uint32_t reserved[12];     // 保留字段
    int (*close)(struct hw_device_t* device); // 关闭设备
} hw_device_t;

3.3.2 Camera 设备结构体

Camera HAL3 在 hw_device_t 基础上扩展出 camera3_device_t,其第一个成员 common 就是 hw_device_t 类型。这种“继承”关系使得 Framework 可以通过类型转换安全地访问底层设备。

成员 类型 说明
common hw_device_t 基类设备结构体,包含 tag、version、close 等
ops camera3_device_ops_t * 指向设备操作函数表,包含 initialize、configure_streams、process_capture_request 等
priv void * 私有数据指针,HAL 实现可在此存放设备上下文

3.4 设备操作接口:camera3_device_t

camera3_device_t 是 HAL3 中最重要的结构体,它定义了 Framework 与 HAL 之间所有请求/响应交互的接口。每个打开的相机设备对应一个 camera3_device_t 实例。

3.4.1 结构体定义

typedef struct camera3_device {
    hw_device_t common;                    // 基类设备
    camera3_device_ops_t *ops;             // 操作函数表
    void *priv;                            // 私有数据
} camera3_device_t;

3.4.2 核心操作函数表

camera3_device_ops_t 是 HAL3 的核心操作接口,Framework 通过该表下发所有控制指令。下表列出了最关键的几个函数指针:

函数指针 职责 调用时机
initialize 初始化设备,注册回调接口 设备打开后立即调用
configure_streams 配置数据流(分辨率、格式、方向等) 预览/录像/拍照开始前
process_capture_request 下发单次捕获请求 每次拍照或预览帧请求
flush 刷新所有未完成的请求 设备关闭或异常恢复时
dump 导出调试信息 Framework 请求调试时
typedef struct camera3_device_ops {
    int (*initialize)(const struct camera3_device *,
                      const camera3_callback_ops_t *callback_ops);
    int (*configure_streams)(const struct camera3_device *,
                             camera3_stream_configuration_t *config);
    int (*register_stream_buffers)(const struct camera3_device *,
                                   const camera3_stream_buffer_set_t *buffer_set);
    int (*process_capture_request)(const struct camera3_device *,
                                   camera3_capture_request_t *request);
    void (*get_metadata_vendor_tag_ops)(const struct camera3_device *,
                                        vendor_tag_query_ops_t *ops);
    int (*flush)(const struct camera3_device *);
    void (*dump)(const struct camera3_device *, int fd);
    int (*reserved[8])();
} camera3_device_ops_t;
常见错误:在实现 process_capture_request 时,必须确保每个请求都能通过回调返回结果(成功或失败)。如果 HAL 未返回结果就丢弃请求,会导致 Framework 超时并触发 ANR(应用无响应)。

3.5 回调通知接口:camera3_callback_ops_t

camera3_callback_ops_t 是 Framework 提供给 HAL 的回调接口,HAL 通过此接口将捕获结果、事件通知、缓冲区状态等异步信息返回给 Framework。该结构体在 initialize() 调用时由 Framework 传入,HAL 必须保存该指针以便后续使用。

3.5.1 结构体定义

typedef struct camera3_callback_ops {
    void (*process_capture_result)(const struct camera3_callback_ops *,
                                   const camera3_capture_result_t *result);
    void (*notify)(const struct camera3_callback_ops *,
                   const camera3_notify_msg_t *msg);
} camera3_callback_ops_t;

3.5.2 回调函数详解

回调函数 触发时机 传递数据
process_capture_result 捕获请求完成(或部分完成)时 camera3_capture_result_t:包含输出缓冲区、元数据、部分结果标识等
notify 发生异步事件时 camera3_notify_msg_t:包含错误码、快门时间、请求 ID 等

3.5.3 回调使用示例

// HAL 端保存回调指针
static const camera3_callback_ops_t *g_callback_ops = NULL;

int my_camera_initialize(const struct camera3_device *dev,
                         const camera3_callback_ops_t *callback_ops) {
    g_callback_ops = callback_ops;
    // 初始化硬件...
    return 0;
}

// 在捕获完成时调用
void on_capture_done(uint32_t frame_number,
                     const camera3_capture_result_t *result) {
    if (g_callback_ops && g_callback_ops->process_capture_result) {
        g_callback_ops->process_capture_result(g_callback_ops, result);
    }
}

// 在发生错误时调用
void on_error(uint32_t frame_number, int error_code) {
    camera3_notify_msg_t msg;
    memset(&msg, 0, sizeof(msg));
    msg.type = CAMERA3_MSG_ERROR;
    msg.message.error.frame_number = frame_number;
    msg.message.error.error_code = error_code;
    if (g_callback_ops && g_callback_ops->notify) {
        g_callback_ops->notify(g_callback_ops, &msg);
    }
}
关键设计原则:回调函数必须在 HAL 的独立线程中调用,不能阻塞 Framework 的主线程。HAL 应确保回调的线程安全性,避免多个线程同时调用同一个回调导致数据竞争。建议为每个相机设备创建一个专用的回调线程。

3.6 接口初始化流程

从 Framework 打开相机到完成初始化的完整流程如下,展示了四个核心结构体如何串联工作:

  1. 模块加载:Framework 通过 hw_get_module(CAMERA_HARDWARE_MODULE_ID, &module) 加载 HAL 动态库,获取 hw_module_t 指针。
  2. 设备打开:调用 module->methods->open(module, camera_id, &device),HAL 返回填充好的 camera3_device_t(其 common 成员为 hw_device_t)。
  3. 初始化:Framework 调用 device->ops->initialize(device, callback_ops),传入 camera3_callback_ops_t 回调接口。
  4. 流配置:调用 device->ops->configure_streams(device, &stream_config) 配置输出流。
  5. 请求循环:Framework 反复调用 device->ops->process_capture_request(device, request) 下发捕获请求,HAL 通过回调返回结果。
  6. 设备关闭:调用 device->common.close(&device->common) 释放资源。
HAL3 接口初始化与请求处理流程 1. hw_get_module() 2. module->open() 3. ops->initialize() 4. ops->configure_streams() 5. ops->process_capture_request() 6. common->close() 获取 hw_module_t 指针,加载 HAL 动态库 返回 camera3_device_t(含 hw_device_t 基类) HAL 分配设备上下文,初始化硬件资源 返回填充好的 camera3_device_t 指针 Framework 传入 camera3_callback_ops_t HAL 保存回调指针,准备接收请求 配置输出流的分辨率、格式、缓冲区数量 HAL 分配流缓冲区,返回配置结果 循环调用,每次下发一个捕获请求 HAL 通过回调返回结果和事件通知 释放所有硬件资源,关闭设备 Framework 不再持有设备指针

3.7 接口实现注意事项

  • 线程安全:process_capture_request 可能被多个线程并发调用,HAL 实现必须保证内部状态的一致性,建议使用互斥锁保护关键数据结构。
  • 内存管理:HAL 不应在回调中直接释放 Framework 传入的缓冲区,应等待 Framework 通过 return_buffer 机制(或等效方式)通知后再释放。
  • 超时处理:每个捕获请求应在合理时间内(通常 3-5 秒)通过回调返回结果。超时未返回会导致 Framework 触发错误恢复流程。
  • 错误上报:当硬件发生不可恢复错误时,必须通过 notify() 回调上报 CAMERA3_MSG_ERROR 事件,并携带具体的错误码。
  • 版本兼容:HAL3 接口从 Android 5.0 引入,后续版本增加了部分扩展字段。实现时应检查 module_api_version 和 hal_api_version,确保向后兼容。
调试技巧:在开发初期,可以在每个操作函数入口和出口添加日志(ALOGV/ALOGD),打印函数名、关键参数和返回值。这有助于快速定位接口调用顺序错误或参数传递异常。