3. 预览流程全链路拆解:从App到HAL的Request流转、Stream配置、Buffer分配与回流的完整时序
预览卡顿的本质是帧率不稳定或帧间隔抖动。要定位卡顿根因,必须理解每一帧从应用层到硬件层的完整流转路径。本章将逐层拆解预览流程中的四个核心阶段:Request 流转、Stream 配置、Buffer 分配与Buffer 回流,并给出每个阶段的时序关键点和调试切入点。
3.1 预览全链路四阶段总览
一次完整的预览帧生命周期可划分为四个阶段,每个阶段都有明确的职责和性能敏感点:
| 阶段 | 起点 | 终点 | 核心对象 | 性能瓶颈 |
|---|---|---|---|---|
| ① Request 流转 | App 调用 setRepeatingRequest() |
HAL 收到 process_capture_request() |
CaptureRequest、CameraDevice |
IPC 延迟、队列积压 |
| ② Stream 配置 | App 调用 createCaptureSession() |
HAL 完成 configure_streams() |
OutputConfiguration、Stream |
分辨率切换、格式协商 |
| ③ Buffer 分配 | Surface 请求 dequeueBuffer() |
HAL 收到 buffer_handle_t |
GraphicBuffer、ION |
内存分配延迟、碎片化 |
| ④ Buffer 回流 | HAL 填充数据后 process_capture_result() |
App 收到 onImageAvailable() |
CaptureResult、ImageReader |
HAL 处理耗时、Buffer 排队 |
dumpsys media.camera 查看每个阶段的帧间隔(frame duration)。如果某一阶段的间隔突然增大超过 16ms(60fps 场景),则该阶段即为卡顿根因所在。
3.2 Request 流转:从 App 到 HAL 的指令通道
Request 是预览流程的“指令载体”。App 通过 CameraCaptureSession.setRepeatingRequest() 提交一个 CaptureRequest,该请求经过 Framework 的 CameraService 层,最终到达 HAL 的 process_capture_request() 接口。
- T0:App 调用
setRepeatingRequest(),请求进入 Framework 的请求队列。 - T1:CameraService 将请求序列化并通过 Binder IPC 发送到 CameraProvider 进程。
- T2:CameraProvider 将请求放入 HAL 的输入队列,等待 HAL 线程处理。
- T3:HAL 的
process_capture_request()被调用,开始处理该帧。
Request 流转的延迟主要来自 Binder IPC 和队列调度。如果 HAL 处理速度跟不上 App 提交速度,请求会在 Framework 侧积压,导致预览帧率下降。
3.3 Stream 配置:预览管道的建立
在预览开始之前,App 必须通过 createCaptureSession() 配置一组 Stream。每个 Stream 代表一条从 HAL 到 Surface 的数据通道,包含分辨率、格式、使用场景等参数。
Stream 配置的核心是 HAL 的 configure_streams() 调用。HAL 在此阶段决定是否支持请求的配置组合,并分配内部硬件资源(如 ISP 管线、DMA 通道)。
3.4 Buffer 分配:内存管道的建立
每个 Stream 都需要一个 Buffer 队列来承载帧数据。Buffer 分配涉及 Android 的 GraphicBufferAllocator 和底层内存分配器(如 ION、DMA-BUF)。
分配流程如下:
- Surface 请求:App 端的
Surface调用dequeueBuffer()从 BufferQueue 中获取一个空闲 Buffer。 - BufferQueue 分配:如果队列中没有可用 Buffer,BufferQueue 会触发
allocateBuffers(),调用 GraphicBufferAllocator 分配新的 GraphicBuffer。 - ION 分配:GraphicBufferAllocator 通过 ION 或 DMA-BUF 分配物理连续或非连续内存,返回
buffer_handle_t。 - HAL 接收:HAL 在
process_capture_request()中通过camera3_stream_buffer_t获取该 Buffer 的句柄,准备填充数据。
- 分配延迟:从
dequeueBuffer()到拿到buffer_handle_t的时间。正常应 < 1ms,若 > 5ms 则表明内存分配成为瓶颈。 - Buffer 数量:预览场景通常配置 3~5 个 Buffer。Buffer 太少会导致 dequeue 阻塞,太多则浪费内存并增加缓存一致性开销。
- 内存碎片:ION 分配大块物理连续内存时,长时间运行后可能因碎片化导致分配失败或延迟飙升。
3.5 Buffer 回流:从 HAL 到 App 的数据回传
HAL 完成帧处理后,通过 process_capture_result() 将填充好数据的 Buffer 回传给 Framework。Framework 再将 Buffer 放入对应的 Surface 的 BufferQueue 中,最终触发 App 的 onImageAvailable() 回调。
回流时序的关键节点:
- HAL 处理完成:HAL 的 ISP 管线完成一帧的采集和处理,将数据写入 Buffer。
- process_capture_result():HAL 调用此接口,将
camera3_capture_result_t返回给 Framework,其中包含camera3_stream_buffer_t数组。 - Framework 分发:CameraService 将结果分发到对应的
CaptureCallback和ImageReader。 - App 消费:App 在
onImageAvailable()中获取Image对象,进行显示或编码。
3.6 全链路时序整合与调试切入点
将四个阶段串联起来,可以得到一帧从 App 到 HAL 再回到 App 的完整时序。每个阶段都有对应的调试工具和日志标记:
| 阶段 | 调试工具 | 关键日志 Tag | 性能阈值(60fps) |
|---|---|---|---|
| Request 流转 | dumpsys media.camera |
CameraService、Camera3 |
< 2ms |
| Stream 配置 | dumpsys media.camera + HAL log |
Camera3-Stream |
配置阶段 < 50ms(一次性) |
| Buffer 分配 | systrace + ION debug |
GraphicBufferAlloc、ION |
< 1ms |
| Buffer 回流 | systrace + perfetto |
Camera3、ImageReader |
< 16.67ms(含 HAL 处理) |
systrace 中关注 Camera3::processCaptureRequest 和 Camera3::processCaptureResult 之间的时间差。如果这个差值超过帧间隔,说明 HAL 处理是瓶颈。如果差值正常但 App 侧帧率仍低,则检查 ImageReader 的 onImageAvailable 回调耗时。