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 侧积压,导致预览帧率下降。

Request 流转时序图 App setRepeatingRequest() Framework CameraService CameraProvider IPC 接收 HAL process_capture_request() T0 T1 T2 T3 请求队列(Request Queue) Binder IPC 延迟 + 队列调度 = Request 流转总耗时 典型值:0.5ms ~ 3ms(正常) / > 10ms(异常卡顿)

3.3 Stream 配置:预览管道的建立

在预览开始之前,App 必须通过 createCaptureSession() 配置一组 Stream。每个 Stream 代表一条从 HAL 到 Surface 的数据通道,包含分辨率、格式、使用场景等参数。

Stream 配置的核心是 HAL 的 configure_streams() 调用。HAL 在此阶段决定是否支持请求的配置组合,并分配内部硬件资源(如 ISP 管线、DMA 通道)。

常见陷阱: 如果 App 同时配置了预览 Stream(通常为 YUV 或 JPEG)和拍照 Stream(高分辨率 JPEG),HAL 可能因为 ISP 带宽不足而降低预览 Stream 的帧率。此时预览卡顿并非 HAL 处理慢,而是 Stream 配置阶段资源分配不合理。
Stream 配置流程 App Framework HAL ISP 硬件 configure_streams() 参数示例 Stream 0: 1920x1080, YCbCr_420_888, 用途: PREVIEW Stream 1: 4000x3000, JPEG, 用途: STILL_CAPTURE Stream 2: 640x480, YCbCr_420_888, 用途: VIDEO_RECORD HAL 在此阶段决定是否支持该配置组合,并分配 ISP 管线资源

3.4 Buffer 分配:内存管道的建立

每个 Stream 都需要一个 Buffer 队列来承载帧数据。Buffer 分配涉及 Android 的 GraphicBufferAllocator 和底层内存分配器(如 ION、DMA-BUF)。

分配流程如下:

  1. Surface 请求:App 端的 Surface 调用 dequeueBuffer() 从 BufferQueue 中获取一个空闲 Buffer。
  2. BufferQueue 分配:如果队列中没有可用 Buffer,BufferQueue 会触发 allocateBuffers(),调用 GraphicBufferAllocator 分配新的 GraphicBuffer。
  3. ION 分配:GraphicBufferAllocator 通过 ION 或 DMA-BUF 分配物理连续或非连续内存,返回 buffer_handle_t。
  4. HAL 接收:HAL 在 process_capture_request() 中通过 camera3_stream_buffer_t 获取该 Buffer 的句柄,准备填充数据。
性能关键指标:
  • 分配延迟:从 dequeueBuffer() 到拿到 buffer_handle_t 的时间。正常应 < 1ms,若 > 5ms 则表明内存分配成为瓶颈。
  • Buffer 数量:预览场景通常配置 3~5 个 Buffer。Buffer 太少会导致 dequeue 阻塞,太多则浪费内存并增加缓存一致性开销。
  • 内存碎片:ION 分配大块物理连续内存时,长时间运行后可能因碎片化导致分配失败或延迟飙升。
Buffer 分配与流转时序 Surface BufferQueue GraphicBufferAlloc ION HAL ① dequeueBuffer() ② allocateBuffers() ③ allocGraphicBuffer() ④ ION alloc ⑤ buffer_handle_t 总分配延迟 = ① + ② + ③ + ④ + ⑤,正常 < 1ms Buffer 数量配置:预览通常 3~5 个,拍照通常 1~2 个 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 对象,进行显示或编码。
卡顿根因: 如果 HAL 处理一帧的时间超过帧间隔(例如 60fps 时超过 16.67ms),则 Buffer 回流会延迟,导致 App 侧帧率下降。此时应检查 HAL 的 ISP 管线耗时、3A 算法耗时或 Sensor 读取延迟。
Buffer 回流时序 HAL Framework ImageReader App ① process_capture_result() ② 分发结果 ③ onImageAvailable() ④ 消费 Image 回流总延迟 = HAL 处理时间 + Framework 分发时间 + App 消费时间 60fps 场景下,HAL 处理时间必须 < 16.67ms,否则必然卡顿 App 消费时间过长也会阻塞 BufferQueue,导致后续帧延迟

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 回调耗时。