4. 系统架构设计:Camera HAL 整体架构图、HAL 与 Framework 的交互流程、HAL 与 Kernel 的接口、模块划分(Stream、Device、Callback)

系统架构设计是 Camera HAL 工程落地的核心蓝图。本章从整体架构图出发,逐层拆解 HAL 与 Android Framework 的交互流程、与 Kernel 的接口定义,以及内部三大核心模块(Stream、Device、Callback)的职责划分。通过本章学习,你将掌握如何从零构建一个可维护、可扩展的 Camera HAL 系统。

4.1 Camera HAL 整体架构图

Camera HAL 位于 Android 相机系统的中间层,向上对接 Framework 的 CameraService,向下通过 V4L2 或自定义驱动接口与 Kernel 交互。整体架构采用分层解耦设计,确保各模块独立演进。

架构设计原则:
  • 分层隔离:Framework 与 HAL 通过 HIDL / AIDL 接口通信,HAL 与 Kernel 通过标准字符设备或 V4L2 交互。
  • 模块化:Stream、Device、Callback 三大模块各司其职,降低耦合度。
  • 异步驱动:所有数据流和事件回调均采用异步机制,避免阻塞上层调用。
Camera HAL 整体架构图 Android Framework (CameraService) Camera HAL (HIDL / AIDL 接口实现) Device 模块 Stream 模块 Callback 模块 Kernel 接口 (V4L2 / 自定义字符设备 / ION) Linux Kernel (Camera Sensor Driver / ISP / DMA) 关键说明: • Framework → HAL:通过 HIDL/AIDL 调用 openCamera、configureStreams、processCaptureRequest 等接口。 • HAL → Kernel:通过 V4L2 ioctl 打开设备、设置格式、申请 Buffer、启动/停止流。 • 数据流向:Sensor → ISP → DMA → Kernel Buffer → HAL 处理 → Framework Consumer。 • 回调机制:HAL 通过 notify() 上报事件,processCaptureResult() 返回帧数据。

4.2 HAL 与 Framework 的交互流程

HAL 与 Framework 的交互遵循 Android 定义的 HIDL/AIDL 接口规范。整个流程从应用打开相机开始,到帧数据返回结束,是一个典型的异步请求-响应模型。

4.2.1 核心交互接口

接口名称 方向 功能描述 关键参数
openCamera Framework → HAL 打开指定 Camera ID 的设备 cameraId, callback
configureStreams Framework → HAL 配置输出流(分辨率、格式、用途) stream_configuration
processCaptureRequest Framework → HAL 提交单次或批量捕获请求 capture_request, buffer_handles
processCaptureResult HAL → Framework 返回捕获结果(Metadata + Buffer) capture_result, buffer
notify HAL → Framework 上报错误、快门、3A 事件 notify_msg
flush Framework → HAL 清空所有待处理请求 无

4.2.2 交互流程时序

HAL 与 Framework 交互时序图 App / Framework Camera HAL Kernel / Sensor openCamera(cameraId, callback) open / ioctl 初始化 Status::OK configureStreams(streams) S_FMT / REQBUFS Status::OK processCaptureRequest(request) QBUF / STREAMON DQBUFF (Frame Data) processCaptureResult(result) notify(SHUTTER / ERROR) 说明:所有 HAL 回调(processCaptureResult / notify)必须在单独的 callback 线程中异步调用,严禁在 HAL 内部同步阻塞。
工程经验:在 configureStreams 阶段,HAL 需要根据 Framework 传入的 stream 配置(分辨率、格式、usage 标志)分配内部 buffer 池。如果平台支持 JPEG 编码 offload,建议在 HAL 层直接集成硬件编码器,避免数据在 Framework 和 HAL 之间多次拷贝。

4.3 HAL 与 Kernel 的接口

HAL 与 Kernel 的接口是 Camera 数据流的底层通道。主流方案基于 V4L2(Video for Linux 2)框架,部分平台使用自定义字符设备或 ION 内存管理接口。

4.3.1 接口类型对比

接口类型 适用场景 优点 缺点
V4L2 标准 Linux Camera 驱动 生态成熟、工具链丰富(v4l2-ctl) 对 ISP 私有特性支持有限
自定义字符设备 专用 ISP / 多传感器融合 灵活、可深度定制 驱动开发工作量大、兼容性差
ION / DMA-BUF 跨硬件模块共享内存 零拷贝、高效 依赖平台内存分配器

4.3.2 V4L2 关键 ioctl 调用

/* 打开设备 */
int fd = open("/dev/video0", O_RDWR);

/* 查询设备能力 */
struct v4l2_capability cap;
ioctl(fd, VIDIOC_QUERYCAP, &cap);

/* 设置格式 */
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.width = 1920;
fmt.fmt.pix_mp.height = 1080;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
fmt.fmt.pix_mp.num_planes = 2;
ioctl(fd, VIDIOC_S_FMT, &fmt);

/* 申请 buffer */
struct v4l2_requestbuffers req;
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
req.memory = V4L2_MEMORY_DMABUF;
ioctl(fd, VIDIOC_REQBUFS, &req);

/* 入队 buffer */
struct v4l2_buffer buf;
struct v4l2_plane planes[2];
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.index = 0;
buf.m.planes = planes;
buf.length = 2;
ioctl(fd, VIDIOC_QBUF, &buf);

/* 启动流 */
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
ioctl(fd, VIDIOC_STREAMON, &type);

/* 出队已填满的 buffer */
ioctl(fd, VIDIOC_DQBUF, &buf);

/* 停止流 */
ioctl(fd, VIDIOC_STREAMOFF, &type);

/* 关闭设备 */
close(fd);
避坑指南:
  • V4L2 的 QBUF/DQBUF 必须在 STREAMON 之后才能正常工作,顺序错误会导致 ioctl 返回 EINVAL。
  • 多平面格式(M Plane)需要正确设置 planes 数组长度和每个 plane 的 bytesperline/sizeimage。
  • 使用 DMA-BUF 时,必须确保 HAL 层和驱动层使用相同的 ION heap 类型,否则会导致内存映射失败。

4.4 模块划分:Stream、Device、Callback

Camera HAL 内部按职责划分为三个核心模块:Device 模块负责设备生命周期管理,Stream 模块负责数据流配置和 buffer 管理,Callback 模块负责异步事件上报。三者协同工作,构成完整的 HAL 内部架构。

4.4.1 模块职责矩阵

模块 核心职责 关键数据结构 线程模型
Device Camera 设备打开/关闭、初始化、3A 控制、Metadata 管理 CameraDevice, CameraMetadata, SensorInfo 主线程 + 3A 线程
Stream Stream 配置、Buffer 申请/入队/出队、格式转换、帧数据处理 CameraStream, StreamBuffer, BufferPool Capture 线程 + 处理线程池
Callback 结果回调、事件通知、错误上报、状态同步 CaptureResult, NotifyMsg, CallbackQueue 独立 Callback 线程

4.4.2 模块间协作关系

Stream / Device / Callback 模块协作图 Device 模块 • 设备打开/关闭 • 3A 算法控制 • Metadata 生成 Stream 模块 • Stream 配置管理 • Buffer 申请/流转 • 格式转换/缩放 Callback 模块 • 结果回调上报 • 事件通知 • 错误处理 配置 结果 事件/错误通知 Kernel 接口层 (V4L2 / DMA-BUF / ION) 模块协作流程: 1. Framework 调用 openCamera → Device 模块初始化传感器和 3A 算法。 2. Framework 调用 configureStreams → Stream 模块根据配置创建 Buffer 池并设置 Kernel 格式。 3. Framework 调用 processCaptureRequest → Stream 模块从 Buffer 池取出空闲 Buffer,入队到 Kernel。 4. Kernel 填充数据后,Stream 模块出队 Buffer,组装 Metadata,通过 Callback 模块回调给 Framework。 5. 任何错误或事件(如快门、曝光完成)由 Device 模块触发 Callback 模块上报 notify()。

4.4.3 模块接口定义示例

// Device 模块核心接口
class CameraDevice {
public:
    virtual int openCamera(int cameraId, const CameraDeviceCallback& callback) = 0;
    virtual int closeCamera() = 0;
    virtual int initialize(const CameraMetadata& sessionParams) = 0;
    virtual int set3AState(ControlMode mode, AeMode ae, AwbMode awb) = 0;
    virtual CameraMetadata getDefaultRequestSettings(int templateType) = 0;
};

// Stream 模块核心接口
class CameraStream {
public:
    virtual int configureStreams(const StreamConfiguration& config) = 0;
    virtual int processCaptureRequest(const CaptureRequest& request) = 0;
    virtual int flush() = 0;
    virtual BufferPool* getBufferPool() = 0;
private:
    virtual int enqueueBufferToKernel(int streamId, buffer_handle_t buffer) = 0;
    virtual int dequeueBufferFromKernel(int streamId, buffer_handle_t* buffer) = 0;
};

// Callback 模块核心接口
class CameraCallback {
public:
    virtual void processCaptureResult(const CaptureResult& result) = 0;
    virtual void notify(const NotifyMsg& msg) = 0;
    virtual void setCallbackThread(Thread* thread) = 0;
};
架构决策要点:
  • Device 模块应保持无状态设计,所有 3A 参数通过 Metadata 传递,避免内部缓存导致状态不一致。
  • Stream 模块的 Buffer 池建议使用环形队列(Ring Buffer)管理,减少内存分配和释放的开销。
  • Callback 模块必须使用独立线程,且回调函数内部不能执行耗时操作,否则会阻塞 Framework 的消息循环。
  • 三个模块之间通过接口依赖注入,方便单元测试和模块替换。