3、HAL层初始化流程:HAL_MODULE_INFO_SYM结构体解析、open()函数入口、camera_module_t与camera_device_t的初始化

好,我们直接进入正题。这一节讲的是HAL层初始化的核心骨架。说白了,就是Android系统怎么找到你的Camera HAL,然后怎么把摄像头硬件“拎起来”用的过程。

我个人习惯把这一章叫做“HAL的出生证明”。你想想看,系统启动时,它根本不知道你的摄像头长什么样。它唯一能依赖的,就是一个固定的符号——HAL_MODULE_INFO_SYM。这个符号就像一把钥匙,打开了整个Camera HAL的大门。

3.1 HAL_MODULE_INFO_SYM 结构体解析

每个合法的Camera HAL,都必须导出一个名为 HAL_MODULE_INFO_SYM 的全局变量。这个名字其实是宏定义展开来的,在Android源码里你搜一下就能看到:

// 定义在 hardware/libhardware/include/hardware/hardware.h
#define HAL_MODULE_INFO_SYM HMI

// 实际使用中,你会在C文件中这样写:
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .version_major = 1,
    .version_minor = 0,
    .id = CAMERA_HARDWARE_MODULE_ID,
    .name = "My Camera HAL Module",
    .author = "Your Company",
    .methods = &hal_module_methods,
    .dso = NULL,
    .reserved = {0},
};

这里有几个关键点,我当年踩过坑:

  • .tag:必须是 HARDWARE_MODULE_TAG,否则系统直接拒绝加载。我曾经手滑写成了0xFFFFFFFF,结果调试了一整天。
  • .id:必须是 CAMERA_HARDWARE_MODULE_ID,也就是字符串 "camera"。大小写敏感,别搞错了。
  • .methods:这个指针指向一个 hw_module_methods_t 结构体,里面只有一个函数指针——open。对,就是那个open()。

核心要点HAL_MODULE_INFO_SYM 是HAL层与Framework层之间的“握手信号”。没有它,你的摄像头驱动再牛,系统也认不出来。

3.2 open()函数入口——一切从这里开始

当Framework层调用 hw_get_module() 找到你的HAL后,下一步就是调用 module->methods->open()。这个open函数,就是你的HAL层真正开始工作的入口。

它的原型长这样:

// 定义在 hardware/libhardware/include/hardware/hardware.h
typedef struct hw_module_methods_t {
    int (*open)(const struct hw_module_t* module, const char* id,
                struct hw_device_t** device);
} hw_module_methods_t;

嗯,这里要注意:id 参数传进来的是摄像头ID,比如 "0""1"。你的open函数需要根据这个ID,找到对应的物理摄像头,然后创建一个 camera_device_t 实例。

我建议你在open函数里做这几件事:

  1. 参数校验:检查module和id是否合法。别嫌麻烦,野指针害死人。
  2. 分配内存:为 camera_device_t 分配内存。注意,这里要用 malloccalloc,不要用栈上的局部变量。
  3. 初始化ops:把 camera_device_t 里的 ops 指针指向你的操作函数表。
  4. 硬件初始化:打开设备节点、初始化传感器、分配buffer等。这一步可以延迟到第一次调用时再做,但我的习惯是尽早暴露问题。

个人经验:我曾经在open函数里做了太多初始化工作,导致系统启动时卡死。后来我改成“懒加载”——只在真正需要时才初始化硬件。这样系统启动更快,也更容易定位问题。

3.3 camera_module_t 与 camera_device_t 的初始化

这两个结构体,是Camera HAL里最重要的两个数据结构。一个代表“模块”,一个代表“设备”。

3.3.1 camera_module_t

camera_module_t 继承自 hw_module_t,额外增加了一些Camera特有的字段。比如:

// 定义在 hardware/libhardware/include/hardware/camera_common.h
typedef struct camera_module {
    hw_module_t common;
    int (*get_number_of_cameras)(void);
    int (*get_camera_info)(int camera_id, struct camera_info *info);
    int (*set_callbacks)(const camera_module_callbacks_t *callbacks);
    void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
    int (*open_legacy)(const struct hw_module_t* module, const char* id,
                       uint32_t halVersion, struct hw_device_t** device);
    int (*set_torch_mode)(const char* camera_id, bool enabled);
    int (*init)(void);
    int (*get_physical_camera_info)(int physical_camera_id,
                                    struct camera_metadata **static_metadata);
    int (*is_stream_combination_supported)(
        int camera_id,
        const struct camera_stream_combination *stream_combination);
} camera_module_t;

初始化时,你需要实现这些函数指针。其中 get_number_of_camerasget_camera_info 是必须的,否则Framework层会报错。

避坑指南set_callbacks 这个函数,我曾经忽略了它。结果摄像头热插拔时,Framework层收不到通知,导致上层应用崩溃。后来我老老实实实现了这个回调机制。

3.3.2 camera_device_t

camera_device_t 继承自 hw_device_t,它代表一个具体的摄像头实例。它的核心是 ops 指针,指向 camera_device_ops_t

// 定义在 hardware/libhardware/include/hardware/camera.h
typedef struct camera_device {
    hw_device_t common;
    camera_device_ops_t *ops;
    void *priv;  // 你可以在这里存放私有数据
} camera_device_t;

camera_device_ops_t 里包含了所有摄像头操作函数,比如:

  • set_preview_window
  • start_preview / stop_preview
  • take_picture
  • set_parameters / get_parameters
  • 等等……

初始化时,你需要把 ops 指向一个静态的 camera_device_ops_t 实例,里面填好你的函数实现。然后 priv 指针可以指向你自定义的上下文结构体,用来存放设备句柄、状态信息等。

举个例子:

// 假设你的私有数据结构
typedef struct camera_device_priv {
    int fd;                     // 设备文件描述符
    int camera_id;              // 摄像头ID
    bool is_open;               // 是否已打开
    // ... 其他状态
} camera_device_priv_t;

// 在open函数中初始化
static int camera_device_open(const struct hw_module_t* module,
                              const char* id,
                              struct hw_device_t** device) {
    camera_device_t *camera_dev = NULL;
    camera_device_priv_t *priv = NULL;

    // 1. 分配内存
    camera_dev = (camera_device_t*)malloc(sizeof(camera_device_t));
    if (!camera_dev) return -ENOMEM;

    priv = (camera_device_priv_t*)malloc(sizeof(camera_device_priv_t));
    if (!priv) {
        free(camera_dev);
        return -ENOMEM;
    }

    // 2. 初始化camera_device_t
    camera_dev->common.tag = HARDWARE_DEVICE_TAG;
    camera_dev->common.version = 0;
    camera_dev->common.module = (hw_module_t*)module;
    camera_dev->common.close = camera_device_close;
    camera_dev->ops = &camera_device_ops;  // 静态函数表
    camera_dev->priv = priv;

    // 3. 初始化私有数据
    priv->camera_id = atoi(id);
    priv->fd = -1;
    priv->is_open = false;

    // 4. 返回设备
    *device = &camera_dev->common;
    return 0;
}

总结一下camera_module_t 是工厂,负责发现和描述摄像头;camera_device_t 是产品,负责具体的操作。open()函数就是连接这两者的桥梁。

好了,这一节的内容就到这里。下一节我们会深入 camera_device_ops_t 里的各个函数,看看它们到底是怎么工作的。到时候我会分享一些我在调试预览流时遇到的奇葩问题,保证让你少走弯路。