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_t和camera_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稳定性问题的调试环境。工欲善其事,必先利其器。没有趁手的工具,定位问题就像在黑夜里找一只黑猫。咱们下章见。