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内部触发以下注册流程:
- 创建回调代理:CameraService为每个CameraDevice创建一个
Camera3Device实例,内部持有Camera3Callback代理对象。 - 构造回调结构体:将
Camera3Callback的成员函数地址填充到camera3_callback_ops_t结构体中。 - 调用HAL的initialize():将填充好的
camera3_callback_ops_t指针作为参数传入HAL。 - HAL保存回调指针:HAL设备实现将回调指针保存到内部上下文,供后续Result上报使用。
- 返回成功状态: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的完整传递链路:
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 注册流程的时序图
下面以时序图展示回调注册的完整交互过程:
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上报的完整链路至关重要。