1. HAL基础概念:Android Camera HAL架构概述、HAL接口定义、HAL与Framework的交互流程

各位同学,咱们今天聊聊Android Camera HAL的基础。说实话,这个主题我讲了不下二十遍,但每次都有新感悟。HAL这东西,说白了就是一道桥梁——一头连着上层Framework,一头连着底层硬件。

我刚开始接触Camera HAL时,总觉得它就是个“黑盒子”。后来踩了不少坑,才慢慢摸清门道。今天我把这些经验整理出来,希望能帮你少走弯路。

1.1 Android Camera HAL架构概述

先看整体架构。Android Camera系统分三层:

  • 应用层:咱们写的拍照App,调用Camera API
  • Framework层:Android系统提供的CameraService、CameraManager等
  • HAL层:硬件抽象层,直接和传感器、ISP打交道

HAL存在的意义是什么?嗯,说白了就是让Google不用管你用的是哪家芯片。高通、联发科、展讯,每家都有自己的实现方式。但只要遵循HAL接口规范,上层代码就能无缝运行。

核心要点:HAL是Android Camera系统的“适配器”,它把千差万别的硬件实现,统一成标准接口暴露给上层。

我记得2018年做第一个项目时,用的是Android 8.0。那时候HAL还是HAL1,接口简单但功能有限。后来Android 9引入了HAL3,支持了更多高级特性。你想想看,如果没有HAL这一层抽象,每次换芯片都得重写Framework,那得多痛苦?

1.2 HAL接口定义

HAL接口定义在hardware/libhardware/include/hardware/camera.hcamera3.h中。咱们重点看HAL3,因为现在主流设备都在用。

核心结构体就这几个:

// camera3_device_t - 设备描述符
typedef struct camera3_device {
    hw_device_t common;
    camera3_device_ops_t *ops;
    void *priv;
} camera3_device_t;

// camera3_device_ops_t - 操作函数表
typedef struct camera3_device_ops {
    int (*initialize)(...);
    int (*configure_streams)(...);
    int (*register_stream_buffers)(...);
    int (*process_capture_request)(...);
    void (*dump)(...);
    int (*flush)(...);
} camera3_device_ops_t;

我个人习惯把camera3_device_ops_t看作一张“菜单”。上层Framework点菜(调用函数),HAL负责做菜(实现功能)。每个函数都有明确的职责:

函数名 职责 我踩过的坑
initialize 初始化相机设备 忘记检查权限,导致初始化失败
configure_streams 配置数据流(分辨率、格式等) 流配置顺序搞反,预览黑屏
process_capture_request 处理拍照请求 回调没及时返回,导致ANR
flush 清空所有待处理请求 多线程同步没做好,死锁了

小技巧:调试HAL时,我习惯在process_capture_request入口和出口加日志。这样能快速定位是HAL没收到请求,还是处理完没回调。

1.3 HAL与Framework的交互流程

交互流程,说白了就是“请求-响应”模式。咱们用一个拍照场景来走一遍:

  1. App发起拍照:调用Camera.takePicture()
  2. Framework创建请求:CameraService生成CaptureRequest
  3. 下发到HAL:调用process_capture_request
  4. HAL处理:驱动传感器曝光、ISP处理图像
  5. 回调结果:通过notify()process_capture_result()返回
  6. Framework返回给App:最终App拿到JPEG数据

这里有个关键点——异步机制。HAL处理请求时,不会阻塞Framework。它通过回调函数把结果送回来。我曾经遇到过一个bug:HAL处理完图像后,忘记调用process_capture_result,结果App一直卡在“正在拍照”的转圈动画里。排查了两天才发现是回调漏了。

避坑指南:我曾经在配置configure_streams时,把预览流和拍照流的顺序搞反了。结果预览正常,但拍照出来的图像是黑的。后来才发现,HAL内部对流的处理顺序有依赖——预览流必须先配置。

再聊聊Buffer管理。Framework和HAL之间传递图像数据,用的是gralloc分配的Buffer。HAL拿到Buffer后,往里面填数据,填完再还回去。这里容易出问题的是Buffer生命周期管理——HAL还在用Buffer,Framework就把它回收了,那画面就会花掉。

我个人建议:在HAL实现里,对每个Buffer加个引用计数。确保Framework释放前,HAL已经用完了。这个习惯帮我避免了好几次内存相关的crash。

小结

今天咱们聊了HAL的架构、接口定义和交互流程。说白了,HAL就是Camera系统的“翻译官”——把Framework的标准指令,翻译成硬件能理解的信号。理解了这个本质,后面学具体实现就轻松多了。

下一章,咱们会深入configure_streams的实现细节。到时候我会分享一个实际项目中的流配置案例,保证让你收获满满。