3. HAL模块初始化:从加载到配置的完整链路
好,咱们今天聊聊HAL模块初始化这块。说实话,这是整个相机HAL最基础也最容易出问题的地方。我见过太多同事,明明上层逻辑写得飞起,结果卡在模块加载这一步,半天找不到原因。
说白了,HAL模块初始化就是三件事:加载模块、打开设备、填充信息。咱们一个一个来拆解。
3.1 HAL Module加载流程
Android系统是怎么找到你的HAL库的?嗯,这里有个关键文件——android.hardware.camera.provider@2.4-service.rc。系统通过这个rc文件启动服务,然后服务会去加载你编译好的so库。
我个人习惯把加载流程分成三步:
- 服务注册:CameraProvider服务向hwservicemanager注册
- 库加载:通过
dlopen打开camera.xxx.so - 符号解析:找到
HAL_MODULE_INFO_SYM这个关键符号
这里有个坑,我曾经踩过——库路径不对。Android 10以后,HAL库的存放路径变了。你想想看,如果你的库放在/vendor/lib64/,但系统去/system/lib64/找,那肯定找不到。
- Android 8-9:
/vendor/lib/hw/或/vendor/lib64/hw/ - Android 10+:
/vendor/lib64/直接存放
Android.bp或Android.mk中relative_install_path配置正确。
3.2 open/close接口实现
加载完模块,下一步就是打开设备。这里对应的是hw_module_methods_t结构体中的open函数。
先看一个典型的open实现:
static int camera_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device) {
// 1. 参数检查
if (module == NULL || name == NULL || device == NULL) {
ALOGE("Invalid parameters");
return -EINVAL;
}
// 2. 分配设备结构体
camera_device_t* camera_dev = (camera_device_t*)malloc(sizeof(camera_device_t));
if (camera_dev == NULL) {
ALOGE("Failed to allocate camera device");
return -ENOMEM;
}
// 3. 初始化公共头
camera_dev->common.tag = HARDWARE_DEVICE_TAG;
camera_dev->common.version = CAMERA_DEVICE_API_VERSION_3_4;
camera_dev->common.module = (hw_module_t*)module;
camera_dev->common.close = camera_device_close;
// 4. 设置ops回调
camera_dev->ops = &camera_device_ops;
// 5. 初始化私有数据
camera_dev->priv = init_private_data();
*device = &camera_dev->common;
return 0;
}
这里有个细节,版本号一定要填对。我记得有一次,我填了CAMERA_DEVICE_API_VERSION_3_3,但上层框架用的是3.4的接口,结果打开后调用某些方法直接crash。你想想看,版本不匹配,函数指针表对不上,不出问题才怪。
close接口相对简单,但要注意资源释放的顺序:
static int camera_device_close(struct hw_device_t* device) {
camera_device_t* camera_dev = (camera_device_t*)device;
// 1. 先停止所有流
stop_all_streams(camera_dev);
// 2. 释放私有数据
free_private_data(camera_dev->priv);
// 3. 最后释放设备本身
free(camera_dev);
return 0;
}
3.3 camera_info获取与填充
这部分是上层框架了解你相机能力的关键。说白了,就是告诉系统:我这颗摄像头能干什么,不能干什么。
camera_info结构体包含两个核心字段:
| 字段 | 说明 | 常见值 |
|---|---|---|
facing |
摄像头朝向 | CAMERA_FACING_BACK 或 CAMERA_FACING_FRONT |
orientation |
图像方向(角度) | 0, 90, 180, 270 |
resource_cost |
资源消耗等级 | 0-100,主摄通常为50 |
conflicting_devices |
冲突设备列表 | 如前后摄同时使用时需配置 |
填充代码示例:
static int get_camera_info(int camera_id, struct camera_info* info) {
switch (camera_id) {
case 0: // 后摄
info->facing = CAMERA_FACING_BACK;
info->orientation = 90; // 竖屏时图像旋转90度
info->resource_cost = 50;
info->conflicting_devices = NULL;
info->conflicting_devices_length = 0;
break;
case 1: // 前摄
info->facing = CAMERA_FACING_FRONT;
info->orientation = 270;
info->resource_cost = 50;
break;
default:
return -EINVAL;
}
return 0;
}
3.4 静态元数据配置
静态元数据,说白了就是相机的「身份证」。它告诉框架:你的传感器多大、支持哪些格式、能做多少帧率等等。
这部分工作量大,而且容易出错。我建议你按照这个顺序来配置:
- 基础信息:厂商、型号、传感器尺寸
- 能力声明:支持的AE/AWB/AF模式、闪光灯类型
- 格式支持:YUV、JPEG、RAW等
- 性能参数:帧率范围、分辨率列表
- 特性开关:HDR、夜景、人像等
看一个典型的配置片段:
static void init_static_metadata(camera_metadata_t* metadata) {
// 传感器信息
int32_t sensor_size[] = {4032, 3024}; // 12MP
camera_metadata_entries[ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE] = {
.data = sensor_size,
.count = 2
};
// 支持的帧率
int32_t fps_range[] = {15, 30, 60};
camera_metadata_entries[ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES] = {
.data = fps_range,
.count = 3
};
// 支持的输出格式
int32_t formats[] = {
HAL_PIXEL_FORMAT_YCbCr_420_888,
HAL_PIXEL_FORMAT_BLOB, // JPEG
HAL_PIXEL_FORMAT_RAW16
};
camera_metadata_entries[ANDROID_SCALER_AVAILABLE_FORMATS] = {
.data = formats,
.count = 3
};
}
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE时,把active array size和pixel array size搞混了。前者是有效像素区域,后者是传感器总像素。如果填错了,你会发现拍照出来的画面有黑边或者被裁剪了。一定要仔细看传感器datasheet!
还有一个容易忽略的点——元数据大小。静态元数据不能超过ANDROID_METADATA_MAX_SIZE(默认64KB)。如果你的摄像头功能特别多,比如支持几十种场景模式,元数据很容易超限。我建议你配置完后加个断言检查:
// 调试时检查元数据大小
size_t metadata_size = get_camera_metadata_size(metadata);
if (metadata_size > ANDROID_METADATA_MAX_SIZE) {
ALOGE("Static metadata too large: %zu bytes (max %d)",
metadata_size, ANDROID_METADATA_MAX_SIZE);
// 这里要裁剪一些不常用的配置
}
好了,HAL模块初始化这块就聊到这儿。总结一下:加载要确认路径、打开要匹配版本、信息要填对朝向、元数据要控制大小。这四个点抓住了,初始化阶段基本不会出大问题。
下一章咱们聊聊更刺激的——Camera Device Session 的创建与管理。到时候我会分享一个我调试过的「流配置失败」的经典案例,保证让你少走弯路。