Camera HAL3 接口层源码解析:createSession 与 configureStreams 全流程剖析

关键词:
Camera HAL3、createSession、configureStreams、Session 接口、流配置、设备适配、AIDL/HIDL、CameraDeviceSession、实际调用链

摘要:
Camera HAL3 是 Android 图像系统中连接 Framework 与底层硬件的关键桥梁。无论是 AIDL 还是 HIDL 模式,App 的一次 openCamera 实际上最终都会调用到 HAL3 接口中的 createSession()configureStreams(),完成 CameraDeviceSession 的构建与流的初始化。本篇将基于 AOSP 最新主线版本,结合典型厂商实现,深入拆解 Camera HAL3 接口调用链、流配置过程、结构体构成与平台差异,帮助工程师理解调试路径与稳定性优化的核心关键点。


目录

一、Camera HAL3 接口结构总览:从 ICameraDevice → HALModule → HAL3Wrapper 架构解读
二、createSession 调用路径解析:如何构建 CameraDeviceSession 并与 Framework 接口对齐
三、CameraDeviceSession 的核心职责:HAL 会话持久化、请求调度与通知传导
四、configureStreams 接口结构详解:CameraStreamConfiguration 的字段构成与 stream 映射机制
五、Stream ID、方向、格式、usage 与 bufferQueue 的绑定逻辑
六、厂商自定义行为分析:configure 中的延迟初始化、动态资源绑定与私有流支持
七、常见失败场景解析:createSession 返回错误、configure 崩溃、stream 配置不一致
八、调试建议与验证路径:logcat、atrace、dumpsys camera + HAL 层 log 的联合分析技巧


一、Camera HAL3 接口结构总览:从 ICameraDevice → HALModule → HAL3Wrapper 架构解读

在 Android Camera 框架中,HAL3(Camera Hardware Abstraction Layer v3)是 Framework 与硬件驱动的直接桥梁,主要负责 会话创建、流配置、请求处理与结果回调。该接口设计遵循模块化与面向对象原则,通过 ICameraDevice 接口与上层对接,并通过 HALModule 与 HAL3Wrapper 将最终调用分派至厂商自定义实现。

1.1 HAL3 接口的核心对象

  • ICameraDevice
    定义在 hardware/interfaces/camera/device 下,负责管理单个 Camera 设备的生命周期及会话创建。

  • Camera HAL Module (camera_module_t)
    位于 /hardware/libhardware/include/hardware/camera_common.h,是 HAL 的模块入口。
    其中 open 方法用于打开 Camera 设备并返回 camera3_device_t

  • camera3_device_t 与 camera3_device_ops
    camera3_device_t 代表底层 Camera 设备的实例,内部包含指向 HAL3 操作集合 camera3_device_ops 的指针,例如:

    struct camera3_device_ops {
        int (*initialize)(...);
        int (*configure_streams)(...);
        int (*process_capture_request)(...);
        ...
    };
    
  • HAL3Wrapper
    在部分平台中,Framework 会通过 HAL3Wrapper 层封装对 HAL3 的调用,以便实现兼容性、调试插桩或多 HAL 合并。


1.2 HAL3 接口初始化与绑定链路

调用链从 App 发起 CameraManager.openCamera() 开始,经由以下流程进入 HAL3:

CameraManager → CameraService → CameraProvider → ICameraDevice
→ Camera HAL Module (camera_module_t)
→ HAL3Wrapper (可选)
→ Vendor Camera3 HAL (camera3_device_ops)

关键动作:

  1. CameraService 从 Provider 获取 ICameraDevice 实例;
  2. 调用 ICameraDevice::open() 打开 HAL 设备;
  3. HAL3Wrapper 初始化并包装底层 camera3_device_t
  4. 等待上层发起 createSession()configureStreams()

二、createSession 调用路径解析:如何构建 CameraDeviceSession 并与 Framework 接口对齐

createSession() 是 HAL3 中连接 Framework 与 HAL 的核心接口,用于构建一个 CameraDeviceSession 实例。该实例承载 流配置(Stream Configuration)、请求下发(processCaptureRequest)、结果回调(processCaptureResult) 等操作。

2.1 调用链分解

  1. 应用层发起连接

    CameraManager.openCamera(cameraId, stateCallback, handler)
    

    内部通过 AIDL 调用 CameraService。

  2. CameraService 建立 Client

    CameraService::connectDevice()
    → CameraDeviceClient::initialize()
    
  3. Provider 调用 createSession

    ICameraDevice::createSession()
    

    这是 HAL3 接口的入口点,由厂商 HAL 实现。

  4. 返回 CameraDeviceSession
    createSession 完成后返回 ICameraDeviceSession 接口,Framework 将通过该接口调用 configureStreams()processCaptureRequest() 等方法。


2.2 createSession 的核心职责

  • 分配 HAL 会话资源:包括硬件队列、ISP pipeline 和 buffer 池;
  • 绑定回调接口:Framework 提供 ICameraDeviceCallback,用于 HAL 向上报送帧完成、错误状态等事件;
  • 初始化静态信息:在会话创建时读取 sensor 能力、可用 stream 格式等信息并缓存。

2.3 createSession 在源码中的关键逻辑

在 AIDL 模式下,createSession 定义于:

hardware/interfaces/camera/device/aidl/ICameraDevice.aidl

典型厂商实现伪代码:

Status CameraDevice::createSession(
    const shared_ptr<ICameraDeviceCallback>& callback,
    shared_ptr<ICameraDeviceSession>* session) {

    mSession = ndk::SharedRefBase::make<CameraDeviceSession>(callback);
    *session = mSession;
    return Status::ok();
}

2.4 调试与验证建议

  • 使用 logcat -s CameraProvider CameraService 查看 createSession 是否成功;
  • 若 createSession 阻塞,需检查 HAL 初始化逻辑是否存在硬件 I/O 等耗时操作;
  • 使用 dumpsys media.camera 确认 Session 是否已注册到 CameraService。

三、CameraDeviceSession 的核心职责:HAL 会话持久化、请求调度与通知传导

在 HAL3 架构下,CameraDeviceSession 是 Framework 与 HAL 通信的核心工作单元。自 createSession() 调用成功后,系统便创建出一个独立的 HAL 会话实例,在整个相机生命周期内维持该会话对象的有效性,直到 App 释放或系统回收。

3.1 会话的职责边界

  • 请求处理入口
    接收上层 Framework 下发的 processCaptureRequest() 请求,完成参数解析、流匹配、Buffer 准备与驱动下发。
  • 结果回调传导
    从底层驱动接收帧完成信号后,封装成 CaptureResultICameraDeviceCallback 汇报。
  • 流管理与资源释放
    对生命周期内的所有流(Preview、JPEG、Metadata 等)统一管理,包括创建、关闭、异常恢复。
  • 错误回调与状态维护
    在设备失联、流失败等场景下触发 notify() 回调,保障系统稳定性。

3.2 Session 的典型结构(以 AIDL 实现为例)

class CameraDeviceSession : public BnCameraDeviceSession {
  public:
    Status configureStreams(...);
    Status processCaptureRequest(...);
    void notify(const NotifyMsg&);
    ...
  private:
    std::map<int, HalStream> mStreams;
    std::shared_ptr<CallbackInterface> mCallback;
};

3.3 生命周期与同步要求

  • 每个 Session 对象只服务一个 CameraId;
  • 不支持多客户端并发连接(通过 Binder UID 限制);
  • 调用 close() 会触发 stream 销毁与内存释放,需完整对齐上层状态。

四、configureStreams 接口结构详解:CameraStreamConfiguration 的字段构成与 stream 映射机制

configureStreams() 是 HAL 与上层协商流能力、格式支持与 Buffer 管理策略的关键接口。无论是首次 openCamera 还是切换分辨率、变更 OutputSurface,最终都将调用该接口重新配置流链路。

4.1 configureStreams 的定义与调用链

  • 上层触发时机:首次 open、切换分辨率、增加 OutputSurface;
  • 下发路径:
    CameraDeviceClientCameraDeviceSession::configureStreams() → Vendor HAL

配置对象结构(AIDL):

struct Stream {
    int id;
    int width;
    int height;
    PixelFormat format;
    StreamType streamType;  // OUTPUT, BIDIRECTIONAL
    Usage usage;            // CPU_READ, GPU_TEXTURE, etc.
    ...
};

struct CameraStreamConfiguration {
    std::vector<Stream> streams;
    OperationMode operationMode;
    StreamConfigurationMode streamConfigMode;
};

4.2 HAL 内部流映射结构

厂商 HAL 需将 Stream 映射为硬件资源,如 ISP 路径、DMA 输出通道等:

std::map<int /* stream id */, HalStream> mStreamMap;

struct HalStream {
    buffer_handle_t bufferPool;
    int maxBuffers;
    int physicalCameraId;
    // Format translation, rotation, etc.
};

4.3 配置成功与否判断标准

  • 返回状态必须为 OK;
  • 每个 stream 都需映射到一个合法的输出路径;
  • 若不支持组合,需返回 Status::ILLEGAL_ARGUMENT,上层重新配置。

4.4 实战问题典型场景

  • stream id 重复:多个 Preview 使用同 id;
  • 不支持的格式:如 YUV_420_888 不被平台支持;
  • 高分辨率流失败:超过 ISP 或 DMA 带宽;
  • Jpeg 与 Video 混用崩溃:部分平台不支持异构流并发。

4.5 调试建议

  • 打印 HAL 层 stream config 接口的 format/size,确认与上层一致;
  • 使用 dumpsys media.camera 查看当前流状态;
  • 加入 ATRACE_CALL() 统计 configureStreams() 时间,判断耗时瓶颈;
  • 开启 vendor logcat(如 vendor.camera.hal)确认流映射异常点。

五、Stream ID、方向、格式、usage 与 bufferQueue 的绑定逻辑

在 HAL3 的 configureStreams() 流程中,每个 Stream 配置项都需要映射到底层硬件资源,这一过程涉及 Stream ID、方向(输入/输出)、格式、使用场景(usage)与 BufferQueue 的准确绑定。这个过程是 HAL 对上层能力宣称的核心体现,也是实现 Preview、Video、Snapshot 等功能稳定性的基础。

5.1 Stream ID 与内部资源映射

  • 每个 Stream 会在 Framework 分配一个唯一的 streamId,HAL 层需根据该 ID 建立与内部结构的映射关系。

  • HAL 可使用 map 或 vector 保存流结构,例如:

    std::unordered_map<int, HalStream> mStreamMap;
    

5.2 StreamType 与方向约定

  • StreamType::OUTPUT 是主流方向(Preview、Video、Jpeg)
  • StreamType::INPUT 一般用于 Reprocessing(如 Zero Shutter Lag)
  • StreamType::BIDIRECTIONAL 适用于 Camera2 legacy HAL

方向关系影响 BufferQueue 的建立与访问策略(如 CPU 写 vs GPU 读)。

5.3 格式匹配与转换策略

上层传入格式类型为 HAL PixelFormat 枚举,如:

上层 Format (PixelFormat)HAL 内部格式映射
YUV_420_888NV12 / NV21 / FLEXIBLE_YUV
JPEGBLOB + EXIF 封装
RAW10 / RAW_SENSORMIPI RAW + ISP Pass-through

厂商 HAL 通常会定义内部 format 类型,进行一次 format adapter 转换。

5.4 Usage 语义与 Buffer 属性

Usage 决定了 Buffer 的申请属性,常见组合:

  • CPU_READ | GPU_TEXTURE:Preview 流,SurfaceView + GPU 后处理
  • VIDEO_ENCODER:MediaCodec 对接时的硬编码流
  • CPU_READ_OFTEN:App 端直接访问 buffer 内容(风险大)
  • ZSL_INPUT | HW_CAMERA_ZSL:Zero Shutter Lag 输入流

使用 gralloc 申请时,这些 usage 会传递给 buffer allocator,用于决定 buffer flags。

5.5 bufferQueue 与 Stream 的绑定流程

  1. 上层将 Surface 封装为 ANativeWindow,调用 CameraDevice → setRepeatingRequest
  2. CameraService 通过 HAL session 的 configureStreams,为每个 stream 绑定其对应的 buffer queue
  3. HAL 实现调用 GraphicBufferAllocatorBufferHub 分配对应的 buffer pool
  4. stream ID 被映射为 hardware_pipe_id × usage_flags × format 的组合逻辑
// 典型 HAL 实现示例
for (const Stream& s : config.streams) {
    halStream.id = s.id;
    halStream.format = ConvertFormat(s.format);
    halStream.usage = ConvertUsage(s.usage);
    halStream.bufferQueue = CreateGrallocQueue(halStream.usage, halStream.format);
}

六、厂商自定义行为分析:configure 中的延迟初始化、动态资源绑定与私有流支持

在实际平台实现中,不同厂商对 configureStreams() 的处理存在较大差异,除了标准流程外,很多 HAL 实现引入了延迟初始化、动态资源绑定以及对私有流(Private Stream Type)的特殊支持逻辑。

6.1 延迟初始化策略

出于性能优化或硬件资源保护目的,部分平台将如下动作推迟执行:

  • Sensor pipeline 初始化
  • ISP 通道激活
  • Stream buffer queue 实体创建

这些动作在 configureStreams() 中记录,但不立即执行,等到 processCaptureRequest()requestStreamBuffers() 时再触发实际分配。

优点:冷启动快、资源只在使用时激活
风险:首次请求会卡顿或时序异常

6.2 动态资源绑定逻辑

当平台拥有多个 ISP / DMA / Pipe 资源通道时,可能在 configureStreams() 中根据需求进行如下行为:

  • 流类型与目标分辨率匹配最优 pipeline
  • 根据场景(人像、HDR、夜景)启用不同 Sensor Mode
  • 动态构建 sensor_output → ISP → memory_node 路径

部分高端平台使用 DSL(描述式配置表)定义每类 stream 的绑定策略。

6.3 私有流类型与扩展机制

有些厂商引入了自定义的 stream type,用于特定用途:

  • Meta Dump 流:输出调试用 metadata
  • IR 辅助流:用于夜拍 / 安防模式的红外图像
  • Sensor Statistics 流:专用于 AE/AWB/AF 的调试与学习
  • HDR Fusion Raw 流:只对内部算法开放的多帧原始数据

私有流通过 vendor tag 或 vendor usage flag 实现,通常不会暴露在标准 getCameraCharacteristics() 接口中。

6.4 工程调试建议

  • 使用 dumpsys media.camera 查看 configure 时流结构是否生效;
  • 使用 atrace --async_start -c gfx view camera 捕捉首次请求过程中的延迟;
  • 查看 vendor.camera.hal log,确认是否存在延迟 buffer allocate 行为;
  • 注意 check frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cppstream->isConfigurable()maybeClose() 的状态流转。

七、常见失败场景解析:createSession 返回错误、configure 崩溃、stream 配置不一致

在 Camera HAL3 实际工程中,createSession()configureStreams() 常被视为系统最敏感、最易失败的路径之一。由于该阶段涉及 HAL 模块初始化、buffer 映射、Sensor 通路开启等多个底层资源协同,一旦配置异常,将直接导致摄像头不可用或系统 crash。以下总结开发者常见的失败模式及其排查建议:


7.1 createSession 返回错误码

  • 返回 STATUS_INTERNAL_ERRORSTATUS_INVALID_OPERATION
    • HAL 实现未成功构造 CameraDeviceSessionImpl 实例;
    • HAL 与 CameraService 的接口签名不一致,导致 binder 交互失败;
    • camera HAL 进程 crash 后重启未完成,导致 session 创建失败;
    • 建议排查:
      • logcat | grep CameraProvider + dmesg | grep camera
      • 检查 HAL 中 new CameraDeviceSession() 是否有异常逻辑分支。

7.2 configureStreams 阶段直接崩溃或挂死

  • 现象: 调用 configure 时 ANR、HAL SIGSEGV、线程卡住;

  • 典型根因:

    • stream array 中格式 / usage 不在 HAL 支持列表;
    • HAL 内部资源未准备完毕(未能绑定 Sensor/ISP 节点);
    • 多线程竞争资源锁,导致死锁;
    • Stream 重复配置或 ID 冲突(特别是在 rapid switch 场景中);
  • 案例:

    E Camera3Device: configureStreamsLocked: Stream 3 failed to create.
    E Camera3Device: configureStreamsLocked: HAL returned error 1
    
    • 表示某一 stream 创建失败,HAL 返回失败码。

7.3 Stream 配置不一致导致上层异常

  • 错误表现:
    • configure 成功,但后续下发 request 时提示 stream invalid;
    • App 层报错:CameraAccessException: Illegal stream combination
  • 常见原因:
    • HAL 未正确返回 streamConfiguration 的最终格式 / usage;
    • HAL 只部分创建流结构,CameraService 判断不一致;
    • App 使用了重复 Surface(同一个 Surface 绑定多个用途);
  • 建议:
    • 关注 configureStreams() 返回的 StreamConfiguration::streams 与原始请求是否一致;
    • 加入 HAL 层对每个 stream 的 ID、格式、大小的 log 输出,方便核对。

7.4 其他失败典型场景

现象根因示例调试建议
createSession 成功但后续无法下发请求HAL Session 构造成功但未初始化流管理器检查 HAL 中初始化流程是否完整
configure 成功但 App 黑屏无预览HAL 分配了 buffer 但未触发 preview 输出检查 HAL 是否触发 request loop
configure 成功后调用 disconnect 崩溃stream 清理顺序不当,bufferPool 被提前释放增加 HAL 中 clear/flush 守护逻辑

八、调试建议与验证路径:logcat、atrace、dumpsys camera + HAL 层 log 的联合分析技巧

由于 HAL 层源码难以全部掌控,工程调试过程需要利用系统提供的各类可观测路径。以下是调试 Camera HAL 初始化链路的建议组合方式:


8.1 logcat:首选日志通路

重点关注模块:

  • CameraProviderLifecycle:设备服务状态变化
  • CameraService:服务创建 / Client 创建 / configure 日志
  • Camera3Device:configure 流程与 request 提交
  • CamX / QCamera3HWI(高通)或 mHal / ImxCamera(MTK)等厂商 HAL log tag

建议命令:

logcat | grep -E "Camera|HAL3|CameraService"

8.2 dumpsys camera:查看当前状态与上一次错误信息

常用命令:

dumpsys media.camera

重点字段:

  • Number of camera devices: N:是否识别完整设备
  • Camera ID 下的 stream configuration 区块:每个 stream 的 format、size、usage
  • Last error: <timestamp>:CameraService 记录的最后一个错误
  • Disconnected clients::最近一次挂起连接的 UID 和调用栈

8.3 atrace:全路径时序分析

场景:调试冷启动慢、首次 request 卡顿、configure 后长时间无响应

使用方式:

atrace --async_start -c gfx view camera hal camera_provider
# 重现问题后
atrace --async_stop -o trace_camera.html

可视化打开后,重点观察:

  • CameraService::connectDevicecreateSessionconfigureStreamssubmitRequest
  • HAL 中对应线程是否存在长时间阻塞(红块)

8.4 HAL 层 log 与 debug trace(厂商自定义)

  • 高通平台:开启 persist.vendor.camera.debug.logfile=1 并抓取 /data/vendor/camera/hal.log
  • MTK 平台:查看 /dev/log/camera_log 或 logcat 中 mHal 输出
  • 建议将每次 createSessionconfigure 的关键参数打印完整,包含 stream count、format、size、usage。

8.5 工程建议总结

调试目标推荐工具组合
HAL 初始化失败logcat + dmesg + dumpsys camera
configure 卡顿atrace + vendor HAL log
Stream 映射错误HAL log 中打印 format/size/usage + dumpsys 对比
App 黑屏无预览dumpsys + dumpsys SurfaceFlinger + logcat
Session 不释放/死锁logcat 死亡监听打印 + binder 调用跟踪

原文:https://zhxin.blog.csdn.net/article/details/149725180