RK Camera HAL核心模块解析:入口函数与设备管理
大家好,我是你们的嵌入式Camera架构讲师。今天我们来聊聊RK Camera HAL里最核心的几个模块——说白了,就是整个HAL层怎么启动、怎么创建Camera设备、又是怎么管理起来的。
我个人习惯把Camera HAL比作一个酒店的前台。客人(Framework)来了,先找前台(HAL_MODULE_INFO_SYM),前台安排房间(CameraDevice),然后客人才能入住使用。嗯,这个比喻虽然简单,但核心逻辑就是这么回事。
一、HAL_MODULE_INFO_SYM:一切从这里开始
在Android Camera HAL架构里,HAL_MODULE_INFO_SYM是Framework找到HAL模块的入口点。它本质上是一个结构体变量,名字是固定的,不能改。
我记得第一次看RK的HAL代码时,找了半天入口在哪。后来发现,其实就是这个结构体:
static struct hw_module_methods_t camera_module_methods = {
.open = camera_device_open,
};
struct camera_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = CAMERA_MODULE_API_VERSION_2_4,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = CAMERA_HARDWARE_MODULE_ID,
.name = "Rockchip Camera HAL",
.author = "Rockchip Corporation",
.methods = &camera_module_methods,
.dso = NULL,
.reserved = {0},
},
.get_number_of_cameras = rk_get_number_of_cameras,
.get_camera_info = rk_get_camera_info,
.set_callbacks = rk_set_callbacks,
.get_vendor_tag_ops = rk_get_vendor_tag_ops,
.open_legacy = NULL,
.set_torch_mode = rk_set_torch_mode,
.init = rk_init,
.reserved = {0},
};
这里有个坑,我曾经踩过——HAL_MODULE_INFO_SYM这个变量名必须一字不差,否则Framework根本加载不到你的HAL。你想想看,编译通过了,但运行时log里死活找不到camera模块,多尴尬。
二、open/initialize流程:从模块到设备
Framework调用hw_get_module()拿到模块后,下一步就是调用open()方法。这个open()可不是Linux文件系统的open,它是HAL层创建Camera设备实例的入口。
我们来看看RK的实现逻辑:
static int camera_device_open(const struct hw_module_t* module,
const char* id,
struct hw_device_t** device)
{
int camera_id = atoi(id);
RKCameraDevice* camera_dev = NULL;
// 1. 参数检查
if (camera_id < 0 || camera_id >= g_camera_info_count) {
ALOGE("Invalid camera id: %d", camera_id);
return -EINVAL;
}
// 2. 分配设备结构体
camera_dev = (RKCameraDevice*)malloc(sizeof(RKCameraDevice));
if (!camera_dev) {
ALOGE("Failed to allocate camera device");
return -ENOMEM;
}
memset(camera_dev, 0, sizeof(*camera_dev));
// 3. 填充hw_device_t公共部分
camera_dev->device.common.tag = HARDWARE_DEVICE_TAG;
camera_dev->device.common.version = CAMERA_DEVICE_API_VERSION_2_4;
camera_dev->device.common.module = (hw_module_t*)module;
camera_dev->device.common.close = camera_device_close;
// 4. 填充camera_device_ops操作函数
camera_dev->device.ops = &camera_device_ops;
// 5. 初始化内部状态
camera_dev->camera_id = camera_id;
camera_dev->ops = &g_rk_camera_ops;
*device = &camera_dev->device.common;
return 0;
}
这里有个细节——open()只是创建了设备句柄,真正的初始化工作是在initialize()里完成的。为什么这么设计?我个人理解是:open负责"造房子",initialize负责"装修"。Framework拿到设备后,会调用initialize()传入Camera3Device的回调接口。
三、CameraModule与CameraDevice的创建与管理
在RK的实现中,CameraModule是一个全局单例,负责管理所有Camera设备的信息。而CameraDevice是每个Camera实例的抽象。
我画了一张图,帮你理清它们的关系:
从图中你可以看到,CameraModule和CameraDevice是1对N的关系。一个CameraModule管理多个CameraDevice,每个CameraDevice对应一个物理或虚拟Camera。
在RK的实现中,CameraModule的创建是在模块加载时完成的:
static int rk_init(const struct camera_module *module)
{
// 初始化Camera列表
g_camera_info_count = 0;
memset(g_camera_info, 0, sizeof(g_camera_info));
// 扫描系统中可用的Camera设备
// 这里会读取设备树或配置文件
int ret = rk_camera_hal_init();
if (ret != 0) {
ALOGE("rk_camera_hal_init failed: %d", ret);
return ret;
}
// 注册Camera信息
for (int i = 0; i < g_camera_info_count; i++) {
ALOGI("Camera[%d]: id=%d, facing=%s, orientation=%d",
i, g_camera_info[i].device_id,
g_camera_info[i].facing == CAMERA_FACING_BACK ? "BACK" : "FRONT",
g_camera_info[i].orientation);
}
return 0;
}
四、设备管理的关键数据结构
RK Camera HAL里,设备管理主要依赖两个核心结构体:
| 结构体 | 作用 | 关键字段 |
|---|---|---|
camera_module |
HAL模块入口,提供查询Camera数量、获取Camera信息等接口 | get_number_of_cameras, get_camera_info, init |
camera3_device_t |
单个Camera设备实例,包含所有操作函数指针 | ops, priv, common |
RKCameraDevice |
RK自定义的设备结构体,封装了底层驱动接口 | camera_id, ops, device |
嗯,这里要特别说一下RKCameraDevice。它是RK在标准camera3_device_t基础上做的扩展,里面包含了V4L2设备节点、ISP处理句柄、Sensor配置等底层信息。说白了,它就是连接HAL层和驱动层的桥梁。
五、避坑指南
最后,分享几个我在项目中踩过的坑:
- 我曾经在
open()里做了太多初始化工作,导致Framework超时。记住,open()要轻量,重活留给initialize()。 - 我曾经忘记在
close()里释放RKCameraDevice的内存,造成内存泄漏。每次创建都要对应释放,这个习惯要养成。 - 我曾经在
get_camera_info()里返回了错误的Camera朝向信息,导致预览画面是倒的。检查Sensor安装方向时,一定要和硬件工程师确认。
好了,这一章的内容就到这里。记住,代码是死的,思路是活的。多读代码,多动手调试,你也能成为Camera HAL的高手。