4. Camera HAL 源码结构:AOSP 目录布局与核心文件

Camera HAL 在 AOSP 中并非一个独立仓库,而是作为 hardware/libhardware 与 frameworks/av 的交叉模块存在。理解其目录结构与核心文件,是搭建开发环境、进行模块裁剪与编译集成的第一步。本章将拆解 Camera HAL 在 AOSP 中的物理布局、关键文件职责以及模块划分方式。

4.1 AOSP 中的目录结构

Camera HAL 源码主要分布在以下三个核心目录中,每个目录承担不同的抽象层级:

目录路径 职责说明 关键子目录/文件
hardware/libhardware/include/hardware/ 定义 Camera HAL 标准接口头文件(HAL 层契约) camera.h, camera_common.h
hardware/libhardware/modules/camera/ Google 提供的参考实现(Reference HAL) CameraHAL.cpp, CameraHAL.h, VendorTags.cpp
frameworks/av/camera/ CameraService 与 HAL 之间的桥梁(CameraService 端) CameraService.cpp, Camera2Client.cpp
device///camera/ OEM/ODM 厂商实际实现的 Camera HAL 库 Android.mk, CameraWrapper.cpp, HAL3Module.cpp
开发提示: 在 AOSP 源码中,hardware/libhardware/modules/camera/ 下的参考实现通常只用于快速原型验证。实际产品开发应在 device/ 目录下创建厂商专属 HAL 模块,避免与 AOSP 原生代码冲突。

4.2 核心文件说明:CameraHAL.cpp 与 CameraHAL.h

在 Google 参考实现中,CameraHAL.cpp 与 CameraHAL.h 是 HAL 模块的入口文件。它们共同实现了 hw_module_t 与 camera_module_t 结构体,并负责初始化、设备枚举与回调注册。

4.2.1 CameraHAL.h — 模块声明与数据结构

该头文件定义了 HAL 模块的顶层结构体与导出符号:

// CameraHAL.h — 核心结构体定义
typedef struct camera_module {
    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
    int (*set_callbacks)(const camera_module_callbacks_t *callbacks);
    void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
    int (*open_legacy)(const struct hw_module_t* module, const char* id,
                       uint32_t halVersion, struct hw_device_t** device);
    int (*set_torch_mode)(const char* camera_id, bool enabled);
    int (*init)(void);
} camera_module_t;

关键字段说明:

  • common:继承自 hw_module_t,包含模块版本、作者、方法表指针。
  • get_number_of_cameras:返回设备上物理 Camera 的数量。
  • get_camera_info:填充 camera_info 结构体,包含朝向、旋转角度、是否支持闪光灯等静态信息。
  • set_callbacks:注册 HAL 回调(如热插拔通知、Torch 状态变化)。
  • open_legacy:用于兼容 HAL1 与 HAL3 的 legacy 模式打开。

4.2.2 CameraHAL.cpp — 模块实现与设备管理

该文件是 HAL 模块的实体实现,主要完成以下工作:

  1. 模块定义:声明 HAL_MODULE_INFO_SYM 符号,填充 camera_module_t 实例。
  2. Camera 设备枚举:通过 get_number_of_cameras() 返回静态数组长度。
  3. 设备打开/关闭:实现 camera_device_open() 与 camera_device_close()。
  4. 回调注册:保存 CameraService 传入的回调函数指针。
// CameraHAL.cpp — 模块入口符号定义
static struct hw_module_methods_t camera_module_methods = {
    .open = camera_device_open,
};

camera_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = CAMERA_MODULE_API_VERSION_3_4,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = CAMERA_HARDWARE_MODULE_ID,
        .name = "Camera Reference HAL",
        .author = "The Android Open Source Project",
        .methods = &camera_module_methods,
        .dso = NULL,
        .reserved = {0},
    },
    .get_number_of_cameras = get_number_of_cameras,
    .get_camera_info = get_camera_info,
    .set_callbacks = set_callbacks,
    .get_vendor_tag_ops = get_vendor_tag_ops,
    .open_legacy = NULL,
    .set_torch_mode = set_torch_mode,
    .init = NULL,
};
常见陷阱: HAL_MODULE_INFO_SYM 的变量名必须严格遵循此命名,否则 HAL 加载器无法找到模块入口。此外,module_api_version 必须与 CameraService 期望的版本匹配,否则 hw_get_module() 会返回 -ENOENT。

4.3 模块划分:从 HAL1 到 HAL3 的演进

Camera HAL 在 AOSP 中按 API 版本划分为三个主要模块层级。当前主流开发基于 HAL3,但 HAL1 仍在 legacy 设备中存在。

模块版本 接口文件 核心特点 适用场景
HAL1 camera.h (legacy) 同步操作、单一预览/拍照流、Callback 模式 Android 4.x 以下设备、低端平台
HAL3 camera3.h Pipeline 模型、Capture Request/Result、多流并发 Android 5.0+ 主流设备、Camera2 API
HAL3 + Vendor Ext camera3.h + 厂商扩展 在 HAL3 基础上增加 Vendor Tag、自定义 Pipeline OEM 差异化功能(如夜景、HDR+)

4.4 模块划分架构图

下图展示了 Camera HAL 在 AOSP 中的模块划分与数据流向:

Camera HAL 模块划分与数据流向 Camera HAL 模块划分与数据流向 CameraService camera_module_t HAL1 模块 camera_device_t HAL3 模块 camera3_device_t Vendor 扩展模块 Vendor Tag + Pipeline 硬件抽象层(Sensor / ISP / Flash) 说明: HAL 模块通过 hw_module_methods.open 分发到不同版本的设备接口。HAL3 是当前主流,Vendor 扩展模块在 HAL3 基础上增加私有 Tag 与自定义处理 Pipeline。

4.5 模块划分的工程意义

在开发环境中,理解模块划分直接影响以下决策:

  • 编译目标选择:HAL1 与 HAL3 的编译宏不同,Android.mk 中需通过 LOCAL_MODULE_TAGS 区分。
  • 接口兼容性:若平台同时支持 HAL1 和 HAL3,需在 camera_module_t 中实现 open_legacy 方法。
  • 调试入口:HAL3 的 process_capture_request 是性能调优的核心断点位置。
工程实践要点: 在 device/ 目录下创建厂商 HAL 时,建议直接基于 HAL3 接口实现,并利用 vendor_tag_ops 扩展私有功能。避免同时维护 HAL1 与 HAL3 两套代码,除非有明确的 legacy 兼容需求。

4.6 核心文件调用关系图

下图展示了 CameraHAL.cpp 与 CameraHAL.h 在 HAL 模块启动过程中的调用关系:

CameraHAL 核心文件调用关系 CameraHAL 核心文件调用关系 CameraHAL.h CameraHAL.cpp camera.h / camera3.h hw_module_t / hw_device_t 结构体实例化 camera_device_open() → 返回设备句柄 调用顺序: CameraHAL.h 定义结构体 → CameraHAL.cpp 实现并实例化 → 引用 camera.h 标准接口 → 最终通过 hw_module_methods.open 暴露给 CameraService。

4.7 模块划分与编译集成的关系

在后续章节的编译集成中,模块划分直接影响 Android.mk 或 Android.bp 的编写方式:

  • HAL1 模块:LOCAL_MODULE := camera.$(TARGET_BOARD_PLATFORM).legacy
  • HAL3 模块:LOCAL_MODULE := camera.$(TARGET_BOARD_PLATFORM)
  • Vendor 扩展:通过 LOCAL_HEADER_LIBRARIES 引入私有头文件,并注册 Vendor Tag 到 vendor_tag_ops。

掌握源码结构后,下一步即可进入编译环境的搭建与模块的首次编译验证。