常见问题实战:Camera HAL工程排查与案例解析 - 第1节
1.1 Camera HAL 在 Android 系统中的位置与作用
Camera HAL(Hardware Abstraction Layer)是 Android 相机子系统中连接 Framework 与底层硬件驱动的关键中间层。它定义了上层相机服务(CameraService)与硬件实现之间的标准接口,使得同一套 Android 系统能够适配不同厂商的摄像头硬件。
1.1.1 系统层级关系
从 Android 相机软件栈的纵向分层来看,Camera HAL 处于承上启下的关键位置:
- 应用层(App):调用 Camera2 API 或 Camera1 API 发起拍照/录像请求。
- Framework 层:CameraService 管理客户端连接、权限校验、流配置与数据分发。
- HAL 层:实现
camera_module_t、camera3_device_t等接口,负责将 Framework 的请求转换为硬件指令。 - Kernel 层:V4L2、CSI、I2C 等驱动与传感器、ISP 硬件交互。
1.1.2 作用总结
| 作用维度 | 具体说明 |
|---|---|
| 接口标准化 | 定义统一的 HAL 接口,屏蔽不同 SoC 平台(Qualcomm、MTK、Rockchip)的硬件差异 |
| 数据流管理 | 管理从传感器到输出 buffer 的完整图像流水线,包括请求排队、帧回调、buffer 复用 |
| 参数控制 | 将 Framework 的 AE/AWB/AF 控制参数转换为硬件寄存器配置,并返回实际生效的元数据 |
| 性能隔离 | 通过 buffer 管理、流超时检测、异常恢复机制,隔离硬件故障对上层的影响 |
1.2 HAL3 与 HAL1 架构对比
Android 相机 HAL 经历了从 HAL1 到 HAL3 的重大架构演进。HAL3(即 Camera3 HAL)是当前主流架构,HAL1 仅用于兼容老旧设备或特定低端场景。理解两者的差异是排查 HAL 问题的前提。
1.2.1 架构设计对比
| 对比维度 | HAL1 | HAL3 |
|---|---|---|
| 设计理念 | 基于固定流水线,操作模式固化 | 基于请求-响应模型,灵活配置流 |
| 数据流模型 | 单路输出,预览/拍照/录像切换需重新配置 | 多路并行输出,支持同时预览+拍照+录像 |
| 控制粒度 | 粗粒度,全局参数一次性设置 | 逐帧控制,每帧可独立指定 AE/AWB/AF 参数 |
| Buffer 管理 | HAL 内部管理 buffer,Framework 被动接收 | Framework 提供 buffer,HAL 填充后回调 |
| 元数据传递 | 通过固定结构体传递少量参数 | 使用 camera_metadata_t 传递数百个控制项与结果项 |
| 多摄像头支持 | 逻辑摄像头支持困难 | 原生支持物理摄像头与逻辑摄像头组合 |
1.2.2 HAL3 请求-响应模型
HAL3 的核心是 Capture Request / Capture Result 模型。每一帧的采集都由一个独立的请求驱动,HAL 处理完成后返回结果。这种设计使得每一帧的控制参数、输出流、元数据都可以独立配置。
// HAL3 核心接口:process_capture_request
int process_capture_request(const camera3_capture_request_t *request);
// 请求结构体关键字段
typedef struct camera3_capture_request {
uint32_t frame_number; // 帧序号,单调递增
const camera3_stream_t **output_buffers; // 输出 buffer 数组
size_t num_output_buffers; // 输出 buffer 数量
const camera_metadata_t *settings; // 帧控制元数据
// ...
} camera3_capture_request_t;
flush() 接口,用于在异常时快速中止所有待处理请求。如果 HAL 未正确实现 flush(),在应用退出或切换摄像头时可能导致 dumpsys 中残留大量未完成的请求,进而引发 buffer 泄漏或死锁。
1.3 HAL 接口定义与核心数据结构
Camera HAL 的接口定义集中在 hardware/libhardware/include/hardware/camera3.h 和 camera_common.h 中。理解这些接口和数据结构是进行 HAL 层问题定位的基础。
1.3.1 模块级接口:camera_module_t
HAL 模块的入口点,Framework 通过 hw_get_module() 加载并获取该结构体。
typedef struct camera_module {
hw_module_t common; // 继承自 hw_module_t
int (*get_number_of_cameras)(void); // 获取摄像头数量
int (*get_camera_info)(int id, struct camera_info *info); // 获取摄像头信息
int (*set_callbacks)(const camera_module_callbacks_t *callbacks); // 注册回调
void (*get_vendor_tag_ops)(vendor_tag_ops_t *ops); // 获取厂商自定义 tag
int (*open_legacy)(const struct hw_module_t *module, const char *id,
uint32_t halVersion, struct hw_device_t **device); // 打开旧版 HAL
// ...
} camera_module_t;
1.3.2 设备级接口:camera3_device_t
每个摄像头设备对应一个 camera3_device_t 实例,Framework 通过 open() 获取。
typedef struct camera3_device {
hw_device_t common; // 继承自 hw_device_t
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); // 注册 buffer
const camera_metadata_t *(*construct_default_request_settings)(
const struct camera3_device *, int type); // 构造默认请求设置
int (*process_capture_request)(const struct camera3_device *,
camera3_capture_request_t *request); // 处理捕获请求
void (*dump)(const struct camera3_device *, int fd); // 导出调试信息
int (*flush)(const struct camera3_device *); // 刷新所有待处理请求
// ...
} camera3_device_t;
1.3.3 核心数据结构
| 数据结构 | 用途 | 关键字段 |
|---|---|---|
camera3_stream_t |
描述一个输出流(预览、拍照、录像等) | stream_type、width、height、format、usage、max_buffers |
camera3_stream_configuration_t |
描述一次流配置操作的所有流信息 | num_streams、streams、operation_mode、session_parameters |
camera3_capture_request_t |
描述一次捕获请求的所有参数 | frame_number、settings、output_buffers、input_buffer |
camera3_capture_result_t |
描述一次捕获请求的处理结果 | frame_number、result、output_buffers、partial_result |
camera_metadata_t |
存储控制参数和结果元数据(key-value 形式) | 内部以 camera_metadata_entry_t 组织,支持 int32/float/int64/double/rational 类型 |
1.3.4 元数据系统
camera_metadata_t 是 HAL3 中最重要的数据结构之一。它使用紧凑的二进制格式存储数百个控制项(如 ANDROID_SENSOR_EXPOSURE_TIME)和结果项(如 ANDROID_SENSOR_TIMESTAMP)。
// 元数据查找示例
camera_metadata_entry_t entry;
int ret = find_camera_metadata_entry(metadata,
ANDROID_SENSOR_SENSITIVITY, &entry);
if (ret == 0) {
int32_t iso = entry.data.i32[0]; // 读取 ISO 值
}
camera_metadata_t 中是否包含了所有必需的 result 项。使用 adb shell dumpsys media.camera 可以导出当前会话的元数据内容,对比预期值与实际值即可快速定位问题。