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/ |
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 模块的实体实现,主要完成以下工作:
- 模块定义:声明
HAL_MODULE_INFO_SYM符号,填充camera_module_t实例。 - Camera 设备枚举:通过
get_number_of_cameras()返回静态数组长度。 - 设备打开/关闭:实现
camera_device_open()与camera_device_close()。 - 回调注册:保存 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 中的模块划分与数据流向:
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 模块启动过程中的调用关系:
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。
掌握源码结构后,下一步即可进入编译环境的搭建与模块的首次编译验证。