2. HAL3 Pipeline 详解
Camera HAL3 的核心是一个高度流水线化的请求-响应架构。理解其内部 Pipeline 的处理流程、从应用层到 HAL 层的请求流转以及同步与异步机制,是进行性能优化和 CTS 问题定位的基础。本章将深入剖析这一架构的每个关键环节。
2.1 HAL3 Pipeline 整体架构与处理流程
HAL3 的 Pipeline 设计旨在最大化吞吐量和降低延迟。它将一次拍照或预览过程分解为多个阶段,允许硬件在软件准备下一帧的同时处理当前帧。整个流程从应用层发起请求开始,经过框架层封装,最终由 HAL 层驱动硬件完成捕获和结果返回。
CaptureRequest 和 CaptureResult 的异步流水线模型。应用提交请求后不阻塞,通过回调或轮询获取结果。
下图展示了 HAL3 Pipeline 从应用层到 HAL 层的完整数据流与状态转换。
2.2 从应用层到 HAL 层的请求流转
一次完整的请求流转涉及多个层次的交互。应用层通过 Android 的 Camera2 API 发起请求,该请求经过框架层封装后,最终由 HAL 层处理。以下是详细的流转步骤:
- 应用层发起请求: 应用通过
CameraCaptureSession.capture()或setRepeatingRequest()提交CaptureRequest。 - 框架层封装: Android Framework 将
CaptureRequest转换为 HAL 层可识别的camera3_capture_request_t结构体,并分配帧编号 (Frame Number)。 - HAL 层接收: HAL 的
process_capture_request()函数被调用,传入封装后的请求结构体。 - 硬件处理: HAL 驱动 Sensor 曝光、ISP 处理,生成原始图像数据或经过处理的 YUV/JPEG 数据。
- 结果返回: HAL 通过
process_capture_result()回调将camera3_capture_result_t返回给框架层,框架层再将其转换为CaptureResult回调给应用。
CaptureRequest 对象,避免频繁创建和销毁。在 HAL 层,应减少 process_capture_request() 中的内存分配操作,使用预分配的内存池。
2.3 同步与异步机制详解
HAL3 架构中,同步与异步机制的正确实现是保证系统稳定性和性能的关键。错误的同步设计会导致死锁、帧率下降或 CTS 测试失败。
2.3.1 异步请求处理
HAL3 要求 process_capture_request() 必须是非阻塞的。HAL 在接收到请求后,应立即返回,并在后台线程中处理硬件操作。框架层通过 camera3_stream_buffer_t 中的 acquire_fence 和 release_fence 文件描述符来实现 Buffer 的同步。
2.3.2 Buffer 同步机制
Buffer 同步是 HAL3 中最复杂的同步场景。它使用 Sync Fence 机制来协调不同硬件模块(如 Sensor、ISP、Video Encoder)对同一块 Buffer 的访问。
| 同步对象 | 描述 | CTS 验证要点 |
|---|---|---|
| acquire_fence | HAL 在读取 Buffer 前必须等待的 Fence。框架层通过此 Fence 通知 HAL 数据已就绪。 | HAL 必须在访问 Buffer 数据前等待此 Fence;未等待直接访问会导致数据竞争。 |
| release_fence | HAL 在完成 Buffer 写入后发出的 Fence。框架层通过此 Fence 得知 HAL 已释放 Buffer 所有权。 | HAL 必须在完成写入后立即 Signal 此 Fence;延迟 Signal 会导致框架层 Buffer 饥饿。 |
| intermediate_buffer | 用于内部处理的临时 Buffer,不直接返回给框架层。 | HAL 必须正确管理其生命周期,避免内存泄漏。 |
process_capture_result() 中返回了尚未 Signal release_fence 的 Buffer,或者忽略了 acquire_fence 直接读取数据。这些都会导致框架层检测到超时或数据错误。
2.3.3 同步与异步流程对比
为了更清晰地展示同步与异步在 HAL3 中的不同表现,下图对比了两种模式下的请求处理路径。
2.4 Pipeline 深度与性能权衡
Pipeline 深度(即同时处理的请求数量)是影响延迟和吞吐量的关键参数。HAL 通过 camera3_device_ops_t 中的 get_metadata() 上报 ANDROID_REQUEST_PIPELINE_MAX_DEPTH 来声明其最大深度。
| Pipeline 深度 | 优势 | 劣势 | 典型场景 |
|---|---|---|---|
| 低 (1-2) | 延迟低,内存占用少 | 吞吐量受限,无法充分利用硬件 | 单帧拍照、高精度需求 |
| 中 (3-4) | 平衡延迟与吞吐量 | 需要更复杂的 Buffer 管理 | 30fps 视频预览、连拍 |
| 高 (5-6) | 高吞吐量,适合高速连拍 | 延迟增加,内存压力大 | 60fps 或 120fps 高速视频 |
2.5 关键代码路径示例
以下代码展示了 HAL 层 process_capture_request 函数中处理请求和 Fence 的标准流程。
// HAL 层 process_capture_request 实现片段
int32_t my_hal_process_capture_request(
const struct camera3_device *device,
camera3_capture_request_t *request) {
// 1. 验证请求参数
if (request->num_output_buffers == 0) {
ALOGE("No output buffers provided");
return -EINVAL;
}
// 2. 等待所有输入 Buffer 的 acquire_fence
for (size_t i = 0; i < request->num_output_buffers; ++i) {
camera3_stream_buffer_t *buf = &request->output_buffers[i];
if (buf->acquire_fence >= 0) {
// 阻塞等待 Fence 信号
sync_wait(buf->acquire_fence, 1000); // 超时 1 秒
close(buf->acquire_fence);
buf->acquire_fence = -1;
}
}
// 3. 将请求加入内部工作队列,立即返回
// 实际硬件操作在后台线程中执行
enqueue_request_to_hardware(request);
// 4. 返回 0 表示成功接收请求
return 0;
}
// 后台线程处理完成后,调用 process_capture_result 回调
void my_hal_on_capture_done(camera3_capture_result_t *result) {
// 设置 release_fence
for (size_t i = 0; i < result->num_output_buffers; ++i) {
camera3_stream_buffer_t *buf = &result->output_buffers[i];
// 创建并设置 release_fence,通知框架层 Buffer 已可用
buf->release_fence = create_release_fence();
}
// 调用框架层回调
result->result = build_capture_result_metadata();
g_camera3_callbacks->process_capture_result(g_callback_ops, result);
}
adb shell dumpsys media.camera 可以查看框架层维护的请求队列状态。