2. 实现camera_device_t的open接口

任务说明

本案例目标是在Android Camera HAL层实现camera_device_t的open接口。该接口由Camera Service通过HAL_MODULE_INFO_SYM的open方法调用,用于打开指定摄像头设备,创建设备实例,初始化camera_device_t结构体,并设置ops回调函数指针。

核心实现

// camera_hal.cpp
#include <hardware/hardware.h>
#include <hardware/camera.h>
#include <cstdlib>
#include <cstring>

// 前向声明ops回调
static int camera_device_close(struct hw_device_t* device);

// 设备实例结构体
typedef struct camera_device_impl {
    camera_device_t base;  // 必须为第一个成员
    int camera_id;
    // 可扩展私有数据
} camera_device_impl_t;

// ops回调函数实现
static int camera_set_preview_window(struct camera_device* dev,
        struct preview_stream_ops* window) {
    // 实际项目中在此设置预览窗口
    return 0;
}

static void camera_set_callbacks(struct camera_device* dev,
        camera_notify_callback notify_cb,
        camera_data_callback data_cb,
        camera_data_timestamp_callback data_cb_timestamp,
        camera_request_memory get_memory,
        void* user) {
    // 实际项目中在此保存回调
}

// 完整ops结构体定义
static camera_device_ops_t camera_ops = {
    .set_preview_window = camera_set_preview_window,
    .set_callbacks = camera_set_callbacks,
    // ... 其他必要回调按需实现
};

// open接口实现
static int camera_device_open(const hw_module_t* module, const char* name,
        hw_device_t** device) {
    if (module == NULL || name == NULL || device == NULL) {
        return -EINVAL;
    }

    // 解析摄像头ID
    int camera_id = atoi(name);
    if (camera_id < 0 || camera_id >= CAMERA_MODULE_MAX_CAMERAS) {
        return -ENODEV;
    }

    // 创建设备实例
    camera_device_impl_t* dev_impl = (camera_device_impl_t*)calloc(1,
            sizeof(camera_device_impl_t));
    if (dev_impl == NULL) {
        return -ENOMEM;
    }

    // 初始化camera_device_t结构体
    dev_impl->base.common.tag = HARDWARE_DEVICE_TAG;
    dev_impl->base.common.version = CAMERA_DEVICE_API_VERSION_1_0;
    dev_impl->base.common.module = (hw_module_t*)module;
    dev_impl->base.common.close = camera_device_close;
    dev_impl->base.ops = &camera_ops;
    dev_impl->camera_id = camera_id;

    // 将实例返回给调用者
    *device = &dev_impl->base.common;
    return 0;
}

// close接口实现
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*)device;
    free(dev_impl);
    return 0;
}

// HAL模块入口
static hw_module_methods_t camera_module_methods = {
    .open = camera_device_open
};

camera_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .version_major = 1,
        .version_minor = 0,
        .id = CAMERA_HARDWARE_MODULE_ID,
        .name = "Camera HAL Module",
        .author = "Your Company",
        .methods = &camera_module_methods,
    },
    .get_number_of_cameras = NULL,  // 由实际实现填充
    .get_camera_info = NULL,        // 由实际实现填充
};

关键实现说明

camera_device_open函数接收三个参数:module指向当前HAL模块,name为摄像头标识字符串(如"0"、"1"),device为输出参数。函数内部首先校验参数有效性,然后通过atoi解析摄像头ID并检查范围。使用calloc分配设备实例内存并清零,确保所有字段初始化为安全值。初始化camera_device_t时,必须正确设置tag为HARDWARE_DEVICE_TAG,version为对应API版本,module指向所属模块,close指向关闭函数,ops指向已实现的回调集合。最后通过*device返回设备句柄。

编译与验证

在Android源码树中,将上述代码保存为camera_hal.cpp,并创建Android.bp构建文件:

cc_library_shared {
    name: "camera.primary",
    srcs: ["camera_hal.cpp"],
    shared_libs: ["libhardware", "libcamera_metadata"],
    vendor: true,
    proprietary: true,
}

编译产物为camera.primary.so,需放置到/vendor/lib64/hw/目录。验证方法:

  1. 在系统启动日志中搜索camera.primary加载记录,确认模块被成功加载;
  2. 使用dumpsys media.camera检查摄像头设备列表,确认设备枚举正常;
  3. 调用open后检查返回值,若返回0且device指针非空,且device->ops指向有效回调集合,则判定通过。

判定标准:open函数能正确创建设备实例,初始化所有必要字段,且close能正确释放资源,无内存泄漏。