Camera HAL黑屏排查与功耗优化工程落地 - 第1节

1.1 HAL3 vs HAL1:架构差异与演进动因

Camera HAL 是 Android 相机子系统中连接 Framework 与硬件驱动的关键层。从 HAL1 到 HAL3 的演进,本质上是从“黑盒控制”向“显式 Pipeline 控制”的转变。HAL3 为现代多帧 HDR、计算摄影、高帧率录像提供了架构基础,但也带来了更复杂的排查与调试挑战。

核心结论:HAL3 并非简单的版本升级,而是相机控制模型的彻底重构。理解两者差异是排查黑屏、预览异常、功耗异常的第一步。

1.1.1 核心差异对比

对比维度 HAL1 HAL3
控制模型 流式控制(Stream-based) 请求-响应模型(Request-Response)
数据流 固定 Pipeline,应用被动接收帧 应用主动提交 Capture Request,HAL 返回 Result
多流支持 有限(通常仅预览+拍照) 原生支持多流(预览、录像、YUV、RAW 同时输出)
逐帧控制 不支持(全局参数设置) 支持逐帧指定 AE/AWB/AF、输出格式、ROI
Buffer 管理 HAL 内部管理,Framework 不感知 Framework 通过 Gralloc 分配 Buffer,HAL 填充
黑屏排查难度 较低(Pipeline 固定,问题易定位) 较高(需追踪 Request 生命周期、Buffer 流转、Stream 配置)
典型功耗场景 Sensor 常开,无精细调度 支持 Sensor 分时复用、Stream 动态开关、逐帧参数优化

1.1.2 HAL3 Pipeline 模型详解

HAL3 的核心是 Pipeline 抽象。每个 Camera 设备内部包含一个或多个 Pipeline,每个 Pipeline 由一组硬件单元(Sensor、ISP、DMA、JPEG Encoder)串联而成。应用通过 configure_streams() 定义输出流集合,然后通过 process_capture_request() 提交请求,HAL 异步返回结果。

HAL3 Pipeline 请求-响应模型 Camera App Camera Framework Camera HAL Pipeline 内部硬件抽象 Sensor ISP DMA Capture Request Capture Result + Buffer Preview Video YUV/RAW 关键特性 • 每个 Request 可独立指定 Sensor/ISP 参数 • 多 Stream 可同时输出不同格式/分辨率 • Buffer 由 Framework 管理,HAL 只负责填充
排查要点:黑屏问题常出现在 Request 提交后 HAL 未及时返回 Result,或 Buffer 未正确填充。建议在 HAL 层增加 Request ID 日志,追踪每个 Request 从提交到返回的完整生命周期。

1.2 Camera Provider 进程模型

Android 8.0 引入 Treble 架构后,Camera HAL 运行在独立的 Camera Provider 进程(cameraserver 或 provider@2.4-service)中,与 Framework 进程隔离。这种架构提升了系统稳定性,但也带来了 IPC 通信开销和跨进程调试复杂度。

1.2.1 进程模型架构

Camera Provider 进程模型 App 进程 Camera2 API 调用 Binder 客户端 cameraserver CameraService Binder 服务端 Camera Provider HAL 实现 HIDL / AIDL 服务 Binder IPC HIDL/AIDL IPC Kernel 驱动层(V4L2、CSI、ISP 驱动) Sensor 驱动 | ISP 固件 | DMA 引擎 进程隔离带来的影响 • 黑屏排查时需区分是 cameraserver 崩溃还是 Provider 进程异常 • IPC 超时(默认 5s)会导致 ANR 或黑屏,需关注 Binder/HIDL 调用耗时

1.2.2 关键进程职责与排查入口

进程名称 职责 黑屏排查入口
App 进程 调用 Camera2 API,创建 CaptureSession,提交 Request 检查 onCaptureFailed()、onDisconnected() 回调
cameraserver 管理 CameraService,协调多个 App 访问,转发 Request logcat -s CameraService,关注 connect/disconnect 日志
Camera Provider 执行 HAL 实现,操作硬件,返回 Result logcat -s CameraHAL,关注 process_capture_request 返回值
Kernel 驱动 控制 Sensor、ISP、MIPI CSI 等硬件 dmesg,关注 mipi_err、isp_timeout、sensor_power
常见陷阱:Provider 进程崩溃后,cameraserver 不会立即通知 App,而是等待超时(默认 3-5 秒)后才回调 onError()。这段时间内 App 界面会保持黑屏。排查时建议先检查 Provider 进程是否存活:ps -A | grep camera。

1.3 HAL3 关键数据结构与生命周期

HAL3 的核心数据结构包括 camera3_device_t、camera3_stream_t、camera3_capture_request_t 和 camera3_capture_result_t。理解这些结构的生命周期是排查黑屏和优化功耗的基础。

1.3.1 核心数据结构关系

HAL3 核心数据结构关系 camera3_device_t 设备句柄,ops 函数表 camera3_stream_t 输出流配置(格式/分辨率) camera3_capture_request_t 逐帧请求(参数+Buffer) camera3_capture_result_t 返回结果(元数据+Buffer) 生命周期管理 configure_streams → 分配 Stream process_capture_request → 提交 Request

1.3.2 典型 Request 生命周期代码示例

以下代码展示了 HAL3 中一个典型 Request 从提交到返回的完整流程,包含关键日志埋点位置:

// HAL 端 process_capture_request 实现片段
int hal_process_capture_request(
    const camera3_device_t *device,
    camera3_capture_request_t *request) {

    // [1] 校验 Request 有效性
    if (request == NULL || request->settings == NULL) {
        ALOGE("Invalid request: NULL pointer");
        return -EINVAL;
    }

    // [2] 记录 Request ID 和 Frame Number
    ALOGI("HAL: process request id=%d frame=%d",
          request->request_id, request->frame_number);

    // [3] 解析 Stream 配置
    for (uint32_t i = 0; i < request->num_output_buffers; i++) {
        const camera3_stream_buffer_t *buf = &request->output_buffers[i];
        ALOGI("  stream=%p format=%d w=%d h=%d",
              buf->stream, buf->stream->format,
              buf->stream->width, buf->stream->height);
    }

    // [4] 硬件操作(Sensor 曝光、ISP 处理)
    // ... 实际硬件调用 ...

    // [5] 返回 Result
    camera3_capture_result_t result;
    memset(&result, 0, sizeof(result));
    result.frame_number = request->frame_number;
    result.result = &metadata;  // 填充元数据
    result.num_output_buffers = request->num_output_buffers;
    result.output_buffers = request->output_buffers;

    device->ops->process_capture_result(device, &result);
    ALOGI("HAL: result returned for frame=%d", request->frame_number);

    return 0;
}
排查技巧:在 process_capture_request 入口和 process_capture_result 出口分别打印 frame_number。如果入口有日志但出口没有,说明 HAL 内部卡死或崩溃;如果入口都没有,说明 Request 未到达 HAL,问题在 cameraserver 或 IPC 层。

1.4 功耗优化视角下的 HAL 架构要点

从功耗优化角度看,HAL3 架构提供了比 HAL1 更精细的控制粒度,但也引入了新的功耗陷阱:

  • Stream 配置开销:每次 configure_streams() 都会重新配置 ISP 和 DMA,频繁配置会显著增加功耗。建议在应用启动时一次性配置所有需要的 Stream,避免运行时反复配置。
  • Request 提交频率:HAL3 允许逐帧控制,但高频 Request(如 60fps 录像)会持续唤醒 ISP 和 DMA。在预览静止场景时,可适当降低帧率或使用 REPEATING_REQUEST 模式。
  • Buffer 管理:Framework 分配的 Buffer 需要经过 Gralloc 映射,跨进程传递时会产生内存拷贝。建议使用 Gralloc4 的 BUFFER_USAGE_CAMERA_OUTPUT 标志,减少不必要的格式转换。
  • Sensor 电源管理:HAL3 支持 ANDROID_SENSOR_FRAME_DURATION 控制帧间隔,可在低帧率场景下让 Sensor 进入低功耗模式。
功耗排查 Checklist:
□ 检查 configure_streams() 调用次数(理想值:1 次/会话)
□ 检查 Request 提交间隔是否与目标帧率一致
□ 检查 Buffer 格式是否匹配硬件原生格式(避免 ISP 额外转换)
□ 检查 Sensor 是否在无 Request 时进入 standby 模式