2. 打开相机设备
任务说明
本案例实现 Camera HAL 模块中的设备打开流程:编写 camera_module_t.open 回调,根据传入的相机 ID 创建设备实例,并正确填充 camera_device_t 接口结构体,最终通过 hw_module_methods_t 暴露给 Android HAL 框架层调用。
核心实现
// camera_hal.c
#include <hardware/hardware.h>
#include <hardware/camera_common.h>
#include <stdlib.h>
#include <string.h>
#define CAMERA_DEVICE_API_VERSION HARDWARE_DEVICE_API_VERSION(1, 0)
#define CAMERA_ID_BACK 0
#define CAMERA_ID_FRONT 1
#define MAX_CAMERAS 2
/* 前置声明 */
static int camera_device_close(struct hw_device_t* device);
/* 设备实例结构 */
typedef struct {
camera_device_t base;
int camera_id;
int ref_count;
} camera_device_impl_t;
/* 打开相机设备 */
static int camera_device_open(
const struct hw_module_t* module,
const char* id,
struct hw_device_t** device)
{
if (module == NULL || id == NULL || device == NULL) {
return -EINVAL;
}
/* 解析相机 ID */
char* endptr;
long camera_id = strtol(id, &endptr, 10);
if (*endptr != '\0' || camera_id < 0 || camera_id >= MAX_CAMERAS) {
return -ENODEV;
}
/* 分配设备实例 */
camera_device_impl_t* dev_impl = calloc(1, sizeof(camera_device_impl_t));
if (dev_impl == NULL) {
return -ENOMEM;
}
/* 填充 hw_device_t 公共字段 */
dev_impl->base.common.tag = HARDWARE_DEVICE_TAG;
dev_impl->base.common.version = CAMERA_DEVICE_API_VERSION;
dev_impl->base.common.module = (struct hw_module_t*)module;
dev_impl->base.common.close = camera_device_close;
/* 填充 camera_device_t 特有字段 */
dev_impl->base.ops = NULL; /* 后续案例实现具体操作集 */
/* 保存设备私有数据 */
dev_impl->camera_id = (int)camera_id;
dev_impl->ref_count = 1;
*device = &dev_impl->base.common;
return 0;
}
/* 关闭相机设备 */
static int camera_device_close(struct hw_device_t* device)
{
if (device == NULL) {
return -EINVAL;
}
camera_device_impl_t* dev_impl =
(camera_device_impl_t*)((camera_device_t*)device);
if (dev_impl->ref_count <= 0) {
return -EBUSY;
}
dev_impl->ref_count--;
if (dev_impl->ref_count == 0) {
free(dev_impl);
}
return 0;
}
/* HAL 模块方法表 */
static struct hw_module_methods_t camera_module_methods = {
.open = camera_device_open,
};
/* 模块定义 */
struct camera_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = CAMERA_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = CAMERA_HARDWARE_MODULE_ID,
.name = "Camera HAL Module",
.author = "Android HAL Course",
.methods = &camera_module_methods,
},
.get_number_of_cameras = NULL, /* 后续案例实现 */
.get_camera_info = NULL, /* 后续案例实现 */
};
关键说明
camera_device_open 是模块打开设备的核心入口。它首先校验传入参数,然后通过 strtol 将字符串形式的相机 ID(如 "0"、"1")转换为整数,并检查是否在有效范围内。设备实例使用 calloc 动态分配,确保所有字段初始为零。填充 hw_device_t 公共字段时,tag 必须为 HARDWARE_DEVICE_TAG,version 使用 HARDWARE_DEVICE_API_VERSION(1, 0) 表示支持 Camera Device API 1.0,module 指回所属模块,close 指向关闭函数。当前案例仅完成设备实例创建与接口返回,ops 操作集暂置 NULL,将在后续案例中填充具体相机操作。
编译与验证
# 编译(需 Android 源码环境或 NDK 头文件)
gcc -c camera_hal.c \
-I /path/to/android/system/core/include \
-I /path/to/android/hardware/libhardware/include \
-I /path/to/android/hardware/libhardware/modules/camera
# 验证:编写测试程序调用 open
cat > test_open.c << 'EOF'
#include <hardware/camera_common.h>
#include <hardware/hardware.h>
#include <stdio.h>
int main(void) {
hw_module_t* module = NULL;
hw_device_t* device = NULL;
/* 加载 HAL 模块 */
int ret = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t**)&module);
if (ret != 0) {
printf("hw_get_module failed: %d\n", ret);
return -1;
}
/* 打开相机 0 */
ret = module->methods->open(module, "0", &device);
if (ret != 0) {
printf("open camera 0 failed: %d\n", ret);
return -1;
}
printf("open camera 0 success, tag=0x%x\n", device->tag);
/* 关闭设备 */
device->close(device);
return 0;
}
EOF
gcc -o test_open test_open.c camera_hal.c \
-I /path/to/android/system/core/include \
-I /path/to/android/hardware/libhardware/include \
-L /path/to/android/out/target/product/generic/system/lib/hw \
-lhardware
./test_open
判定标准
- 编译无错误、无警告(
-Wall下) - 测试程序输出
open camera 0 success, tag=0x...,且 tag 值为HARDWARE_DEVICE_TAG的宏定义值 - 使用无效 ID(如
"2"或"abc")调用 open 时返回-ENODEV - 传入
NULL参数时返回-EINVAL - close 后再次 close 返回
-EINVAL(设备已释放)