1. Camera HAL概览:Android Camera架构简介、HAL3 vs HAL1区别、HAL稳定性问题分类

大家好,我是你们的讲师。今天咱们正式开讲《Camera HAL稳定性问题定位与修复实战》的第一章。

做Camera HAL开发,说白了就是跟底层硬件打交道,把摄像头的能力暴露给上层应用。这个过程中,稳定性是头等大事。我见过太多项目因为HAL层的一个小bug,导致整机相机打不开、预览黑屏、拍照卡死……嗯,那场面,真叫一个惨烈。

所以,在动手解决问题之前,咱们得先把地基打牢。这一章,我就带大家快速过一遍Android Camera的整体架构,聊聊HAL3和HAL1到底差在哪,最后再给稳定性问题分个类。这样后面讲到具体案例时,你心里就有谱了。

1.1 Android Camera架构简介

先看整体。Android Camera的软件栈,从下往上大致分四层:

  • 应用层(App):你写的相机App,或者系统自带的Camera2应用。它通过Framework的API来请求拍照、预览。
  • Framework层:核心是CameraService。它负责管理多个客户端、协调资源、处理权限。说白了,就是个调度中心。
  • HAL层(Camera HAL):这是咱们的主战场。它实现了camera_module_tcamera_device_t接口,直接跟硬件驱动打交道。
  • Kernel层:V4L2驱动、Sensor驱动、ISP驱动。HAL通过ioctl或者内存映射来操作它们。

我个人习惯把HAL层比作「翻译官」。上层说「我要拍一张1080p的照片」,HAL得把它翻译成「Sensor上电、设置曝光、抓取RAW、送ISP处理、输出YUV」这一串硬件指令。翻译错了,或者翻译慢了,问题就来了。

关键点:HAL是Android Camera性能与稳定性的瓶颈所在。Framework的bug相对容易复现和修复,但HAL的问题往往跟硬件时序、内存管理、多线程竞争深度绑定,排查起来非常头疼。

1.2 HAL3 vs HAL1:到底差在哪?

很多刚入行的朋友问我:「老师,HAL1和HAL3到底选哪个?」我的回答是:现在新项目基本都用HAL3,除非你还在维护Android 5.0之前的古董机。

但理解HAL1的设计思路,对理解HAL3的改进点很有帮助。咱们来对比一下。

对比维度 HAL1 HAL3
设计理念 固定流水线,操作简单 灵活管线,应用可自定义
数据流 Preview/Record/Snapshot三路独立 单一Request-Response模型
控制粒度 粗粒度,只能开关功能 细粒度,每帧可设置参数
性能 延迟低,但灵活性差 延迟略高,但吞吐量高
稳定性挑战 状态机简单,不易死锁 多线程复杂,容易竞态

举个例子。在HAL1时代,你要开启预览,就调用start_preview(),然后HAL内部启动一个线程不断送帧。你要拍照,就调用take_picture(),HAL会暂停预览,拍一张,再恢复预览。流程很死板。

到了HAL3,一切都变了。应用通过createCaptureSession()创建会话,然后提交一个个CaptureRequest。每个Request可以指定不同的输出目标(Surface)、不同的参数(AE/AWB/AF)。HAL3内部有一个Pipeline,按顺序处理这些Request。

我的经验:HAL3的稳定性问题,十有八九出在Pipeline的同步上。我曾经遇到一个案子,预览和拍照同时进行时,底层Buffer被两个线程同时访问,导致花屏。排查了三天,最后发现是HAL内部没有做好Buffer的引用计数。

另外,HAL3引入了flush()接口。这个接口在应用退出或切换场景时调用,要求HAL尽快停止所有正在处理的Request。很多HAL实现里,flush()处理不当会导致死锁。嗯,这个坑后面我们会专门讲。

1.3 HAL稳定性问题分类

做稳定性工作,首先得知道敌人长什么样。根据我多年的踩坑经验,我把HAL稳定性问题分成四大类:

1.3.1 初始化与去初始化问题

这类问题发生在相机打开和关闭的过程中。典型表现:

  • 打开相机超时(比如超过5秒没返回)
  • 关闭相机时崩溃(double free、野指针)
  • 反复打开关闭后,内存泄漏导致OOM

为什么会这样?说白了,很多HAL实现里,open()close()没有做好对称处理。你申请了资源,但异常路径下忘了释放。我建议大家在写HAL时,把初始化流程画成状态机,每个状态都要考虑异常退出。

1.3.2 数据流异常问题

这类问题最头疼,因为它不是必现的。典型表现:

  • 预览黑屏(有帧回调但数据全黑)
  • 拍照卡顿(按下快门后几秒才出图)
  • 录像丢帧(录出来的视频一顿一顿的)

我遇到过最离谱的一次,是某个平台的ISP驱动在特定光照条件下会输出全黑帧。HAL层没有做帧校验,直接送了上去。用户反馈「晚上拍照没问题,白天拍照全黑」……后来加了帧内容的亮度直方图检测,才把这个坑填上。

1.3.3 并发与竞态问题

HAL3的多线程模型是重灾区。典型表现:

  • 多个Session同时运行时,某个Session的Request被另一个Session的线程处理了
  • Callback回调时,对象已经被销毁
  • 共享资源(如Sensor的I2C总线)没有加锁

这里我给大家一个避坑指南:HAL内部的所有回调,尽量post到独立的worker线程去执行,不要在ISR或者驱动回调里直接调用Framework的接口。我曾经因为偷懒,在V4L2的buffer done回调里直接调了process_capture_result(),结果导致Framework层的锁被中断上下文持有,整个系统卡死。

1.3.4 超时与ANR问题

这类问题直接导致用户无响应,是优先级最高的bug。典型表现:

  • CameraService的waitUntilIdle()超时
  • Flush操作超过5秒没返回
  • 底层驱动DMA传输卡住

我建议大家在HAL层实现一个看门狗机制。每个Request提交时记录时间戳,如果超过阈值(比如3秒)还没返回,就打印堆栈并尝试恢复。别指望驱动层能自己恢复,很多时候你得主动reset Sensor或者ISP。

注意:超时问题往往不是HAL单方面的责任。Framework层也可能因为Binder通信阻塞导致HAL的调用无法返回。排查时,一定要同时看HAL的log和Framework的trace。

1.4 本章小结

好了,第一章的内容就到这里。咱们快速回顾一下:

  • Android Camera架构分四层,HAL是承上启下的关键
  • HAL3比HAL1更灵活,但也更复杂,稳定性挑战更大
  • 稳定性问题分四类:初始化、数据流、并发、超时。每一类都有典型的根因和排查思路

下一章,我会带大家搭建一个HAL稳定性问题的调试环境。工欲善其事,必先利其器。没有趁手的工具,定位问题就像在黑夜里找一只黑猫。咱们下章见。