4. Camera HAL 初始化流程:HAL模块加载、open流程、camera_info填充、static_metadata构建
Camera HAL 的初始化是上层 Camera Service 与底层硬件驱动建立通信通道的关键阶段。该流程涉及四个核心步骤:HAL 模块加载、open 设备、camera_info 填充以及 static_metadata 构建。理解这一流程对于调试相机启动速度、设备识别失败以及元数据缺失等问题至关重要。
4.1 整体初始化流程概览
以下 SVG 图展示了从 Camera Service 调用 HAL 到应用层获取相机信息的完整初始化链路。
4.2 HAL 模块加载
HAL 模块加载是初始化的第一步,由 Camera Service 通过 hw_get_module() 或 HAL_MODULE_INFO_SYM 机制完成。加载过程的核心是找到并打开对应平台的 HAL 动态库(如 camera.xxx.so)。
| 步骤 | 函数/操作 | 说明 |
|---|---|---|
| 1 | hw_get_module(CAMERA_HARDWARE_MODULE_ID, &module) |
根据 HAL 类型 ID 查找并加载对应的 .so 文件 |
| 2 | dlopen("camera.xxx.so", RTLD_NOW) |
底层通过 dlopen 打开动态库,获取符号表 |
| 3 | dlsym(handle, "HAL_MODULE_INFO_SYM_AS_STR") |
获取 hw_module_t 结构体指针,其中包含 open、get_number_of_cameras 等函数指针 |
| 4 | 验证 module->tag == HARDWARE_MODULE_TAG |
校验模块版本和标签,确保 HAL 接口兼容 |
.so 文件路径错误、依赖库缺失、HAL_MODULE_INFO_SYM 未正确导出。建议在 hw_get_module 前后添加 log,检查 module->id 和 module->methods->open 是否非空。
4.3 open 流程
模块加载成功后,Camera Service 调用 module->methods->open() 打开具体的 camera 设备。该函数返回一个 hw_device_t 指针,实际类型为 camera_device_t,其中包含了操作相机的函数表。
// HAL 层 open 函数典型实现
static int camera_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device) {
int camera_id = atoi(name);
camera_device_t* camera_dev = (camera_device_t*)malloc(sizeof(camera_device_t));
memset(camera_dev, 0, sizeof(camera_device_t));
// 填充 hw_device_t 公共字段
camera_dev->common.tag = HARDWARE_DEVICE_TAG;
camera_dev->common.version = CAMERA_DEVICE_API_VERSION_1_0;
camera_dev->common.module = (hw_module_t*)module;
camera_dev->common.close = camera_device_close;
// 填充 camera_device_t 操作函数表
camera_dev->ops = &camera_ops; // 包含 set_preview_window, start_preview 等
*device = &camera_dev->common;
return 0;
}
name 参数转换的 camera_id 越界、malloc 失败未处理、ops 函数表未完全初始化导致后续调用空指针。建议在 open 函数内增加 ALOGI 打印 camera_id 和设备指针地址。
4.4 camera_info 填充
在 open 设备之后,Camera Service 通过 get_camera_info() 获取每个相机的静态信息。该信息填充到 camera_info 结构体中,主要包括设备方向、是否支持闪光灯、以及最重要的 static_camera_characteristics 元数据。
// camera_info 结构体定义
typedef struct camera_info {
int device_version; // 设备版本,如 CAMERA_DEVICE_API_VERSION_1_0
char device_id[256]; // 设备 ID,如 "0"、"1"
int facing; // 朝向:CAMERA_FACING_BACK / FRONT
int orientation; // 图像方向,0/90/180/270
camera_metadata_t* static_camera_characteristics; // 静态元数据
} camera_info_t;
| 字段 | 典型值 | 调试检查点 |
|---|---|---|
facing |
0 (BACK) / 1 (FRONT) | 确认前后摄分配正确,避免应用调用错摄像头 |
orientation |
90 (后摄) / 270 (前摄) | 方向错误会导致预览图像旋转 90° 或 180° |
device_version |
CAMERA_DEVICE_API_VERSION_1_0 |
版本不匹配会导致 Service 拒绝加载设备 |
4.5 static_metadata 构建
static_camera_characteristics 是 Android Camera 框架中最重要的元数据集合,它描述了相机硬件的能力和限制。该元数据在 HAL 初始化时构建,并在整个相机生命周期内保持不变。
构建过程通常分为以下步骤:
- 创建元数据缓冲区: 使用
allocate_camera_metadata()分配足够大的缓冲区。 - 填充标准 Tag: 调用
camera_metadata_ops中的函数,逐个添加ANDROID_SENSOR_INFO_*、ANDROID_SCALER_*、ANDROID_CONTROL_*等 Tag。 - 填充厂商自定义 Tag: 如果平台有私有扩展能力,通过
ANDROID_REQUEST_AVAILABLE_CAPABILITIES中的BACKWARD_COMPATIBLE或PRIVATE_REPROCESSING等标记。 - 排序并锁定: 调用
sort_camera_metadata()确保元数据有序,便于快速查找。
// static_metadata 构建示例(伪代码)
static camera_metadata_t* build_static_metadata() {
camera_metadata_t* metadata = allocate_camera_metadata(
CAMERA_METADATA_ENTRY_MAX, CAMERA_METADATA_DATA_MAX);
// 添加传感器尺寸
int32_t sensor_size[] = {1920, 1080};
add_camera_metadata_entry(metadata,
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, sensor_size, 2);
// 添加支持的帧率范围
int32_t fps_range[] = {15, 30};
add_camera_metadata_entry(metadata,
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fps_range, 2);
// 添加闪光灯能力
uint8_t flash_available = 1;
add_camera_metadata_entry(metadata,
ANDROID_FLASH_INFO_AVAILABLE, &flash_available, 1);
sort_camera_metadata(metadata);
return metadata;
}
dump_camera_metadata() 函数可以打印所有静态元数据内容,用于验证 HAL 层是否正确上报了能力。常见问题包括:ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE 与实际 sensor 输出尺寸不一致、ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES 缺失导致预览帧率异常。
4.6 初始化流程中的常见问题与排查
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| Camera Service 无法找到 HAL 模块 | .so 未正确安装或 hw_get_module 路径错误 |
检查 /vendor/lib/hw/ 或 /system/lib/hw/ 下是否存在对应 .so |
open 返回 -ENODEV |
sensor 驱动未初始化或 I2C 通信失败 | 检查 kernel log 中 sensor 驱动 probe 是否成功 |
| camera_info 中 orientation 错误 | HAL 层硬编码了错误的方向值 | 对比 sensor 物理安装角度与 HAL 中 orientation 值 |
| static_metadata 缺失关键 Tag | 构建时未添加必要的 ANDROID 标准 Tag | 使用 dump_camera_metadata 对比 CTS 要求的最小 Tag 集合 |
初始化流程的稳定性直接决定了相机应用能否正常启动。在调试过程中,建议在 HAL 层的每个关键函数入口和出口添加 ALOGI 日志,并结合 logcat -s CameraService 和 logcat -s CameraHal 分别观察 Framework 和 HAL 层的交互状态。