4. Result回调的注册流程:CameraService如何注册回调、HAL设备初始化时的回调绑定、回调函数指针的传递机制

Result回调的注册是Camera HAL层通信的起点。整个注册流程涉及三个关键阶段:CameraService端的回调接口准备、HAL设备初始化时的回调绑定、以及函数指针的跨进程传递。理解这一流程,是掌握后续Result上报机制的基础。

4.1 回调注册的三层架构

从架构视角看,回调注册跨越了三个层级:

层级 组件 职责 关键接口
应用层 Camera App 注册CaptureCallback CameraCaptureSession.setRepeatingRequest()
框架层 CameraService 封装回调为HAL可调用的函数指针 camera3_callback_ops_t
HAL层 Camera HAL 接收回调指针,绑定到设备实例 initialize() / open()
关键理解:CameraService并不直接将Java层的回调对象传递给HAL,而是将回调转换为C语言函数指针结构体 camera3_callback_ops_t,HAL通过该结构体中的函数指针上报Result。

4.2 CameraService注册回调的完整步骤

当App调用 setRepeatingRequest() 时,CameraService内部触发以下注册流程:

  1. 创建回调代理:CameraService为每个CameraDevice创建一个 Camera3Device 实例,内部持有 Camera3Callback 代理对象。
  2. 构造回调结构体:将 Camera3Callback 的成员函数地址填充到 camera3_callback_ops_t 结构体中。
  3. 调用HAL的initialize():将填充好的 camera3_callback_ops_t 指针作为参数传入HAL。
  4. HAL保存回调指针:HAL设备实现将回调指针保存到内部上下文,供后续Result上报使用。
  5. 返回成功状态:HAL返回 0 表示回调注册成功,CameraService完成绑定。
代码示例:CameraService中回调结构体的构造
// frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

status_t Camera3Device::initialize(sp<ICameraDeviceCallbacks> callbacks) {
    // 1. 创建回调代理
    sp<Camera3Callback> cb = new Camera3Callback(callbacks);
    
    // 2. 填充camera3_callback_ops_t结构体
    camera3_callback_ops_t callbackOps;
    callbackOps.process_capture_result = 
        &Camera3Callback::processCaptureResultThunk;
    callbackOps.notify = 
        &Camera3Callback::notifyThunk;
    
    // 3. 调用HAL的initialize(),传递回调指针
    camera3_device_t *device = mHalDevice;
    status_t res = device->ops->initialize(device, &callbackOps);
    
    return res;
}

4.3 HAL设备初始化时的回调绑定

HAL层在 initialize() 调用中完成回调绑定。典型的HAL实现包含以下步骤:

  • 验证回调指针:检查传入的 camera3_callback_ops_t* 是否为 NULL,以及关键函数指针(如 process_capture_result)是否有效。
  • 存储回调上下文:将回调指针保存到HAL设备私有结构体(如 camera3_device_private_t)中。
  • 初始化内部状态:创建Result队列、同步锁、工作线程等基础设施。
  • 返回初始化结果:成功返回 0,失败返回负的错误码。
常见陷阱:HAL实现中必须确保回调指针的线程安全性。多个工作线程可能同时调用 process_capture_result,HAL需要使用互斥锁保护回调指针的访问,防止在设备关闭时出现野指针。

4.4 回调函数指针的传递机制

函数指针的传递是C语言层面的经典模式。下图展示了从CameraService到HAL的完整传递链路:

回调函数指针传递机制 CameraService Camera3Device camera3_callback_ops_t process_capture_result Camera HAL camera3_device_t 构造 initialize() HAL私有上下文 保存回调指针 保存 Result上报 调用回调函数 触发 说明: 函数指针传递是单向的:CameraService → HAL。HAL通过保存的指针反向调用CameraService中的处理函数。

4.5 回调结构体详解

camera3_callback_ops_t 是HAL与CameraService之间的核心契约。其定义如下:

// hardware/libhardware/include/hardware/camera3.h

typedef struct camera3_callback_ops {
    /**
     * process_capture_result: 上报捕获结果
     * @param frame_number: 帧序号
     * @param result: 包含metadata和buffer的结果结构体
     * @param partial_result: 部分结果序号
     */
    void (*process_capture_result)(
            const struct camera3_callback_ops *ops,
            uint32_t frame_number,
            const camera3_capture_result_t *result,
            int32_t partial_result);

    /**
     * notify: 上报异步通知事件
     * @param msg: 通知消息结构体
     */
    void (*notify)(
            const struct camera3_callback_ops *ops,
            const camera3_notify_msg_t *msg);

    /* 预留扩展字段 */
    void *reserved[8];
} camera3_callback_ops_t;
关键设计要点:
  • 第一个参数是自身指针:HAL调用回调时,传入 ops 指针,CameraService通过该指针定位到具体的设备实例。
  • reserved字段:预留8个指针空间,用于未来扩展,保持ABI兼容性。
  • 线程安全要求:HAL可以在任意线程中调用这些回调,CameraService内部必须处理并发。

4.6 注册流程的时序图

下面以时序图展示回调注册的完整交互过程:

回调注册时序图 Camera App CameraService Camera HAL HAL上下文 setRepeatingRequest() 构造callback_ops initialize(callback_ops) 验证指针 保存回调指针 return 0 onConfigured() 注册完成后,HAL即可通过保存的 callback_ops 指针,在任意时刻调用 process_capture_result 上报Result。

4.7 注册流程的关键检查点

在实际开发中,回调注册阶段需要重点关注以下检查点:

检查点 检查内容 失败后果 典型错误码
回调指针非空 callback_ops != NULL HAL无法上报Result,系统卡死 -EINVAL
函数指针有效 process_capture_result != NULL 调用时触发段错误 -ENODEV
设备状态正确 设备未初始化或已关闭 重复初始化导致资源泄漏 -EBUSY
内存分配成功 HAL内部上下文创建 后续操作无法进行 -ENOMEM
最佳实践:在HAL的 initialize() 实现中,建议使用 atomic_store() 或带锁的赋值操作保存回调指针,确保多线程环境下对回调指针的访问是安全的。同时,在 close() 或 flush() 中应将回调指针置为 NULL,防止野指针调用。

4.8 总结

Result回调的注册流程是Camera HAL通信的基石。CameraService通过构造 camera3_callback_ops_t 结构体,在 initialize() 调用中将函数指针传递给HAL。HAL保存这些指针后,即可在任意时刻通过回调上报捕获结果。理解这一机制,对于后续分析Result上报的完整链路至关重要。