1. HAL架构全景:Android Camera HAL整体架构、HIDL与AIDL接口演进、HAL进程模型
各位同学,咱们今天聊聊Camera HAL的架构全景。
说实话,我刚接触Android Camera时,也被这一层层的抽象搞晕过。但搞懂了HAL,你就掌握了相机性能优化的钥匙。为什么?因为所有底层的硬件操作,都得经过HAL这道门。
1.1 整体架构:Camera HAL在系统中的位置
先看一张宏观图(嗯,我脑子里有,你也要有)。
Android Camera系统从上到下分四层:
- 应用层:Camera2 API,你写的App调用的地方
- 框架层:CameraService,系统服务,管理权限、流、会话
- HAL层:咱们今天的主角,连接框架和硬件
- 内核层:V4L2、Sensor驱动、ISP驱动
说白了,HAL就是一道桥。桥这边是Android框架的标准接口,桥那边是各家芯片商的私有实现。
核心要点:HAL层屏蔽了硬件差异。你换一颗Sensor,只要HAL实现对了,上层代码一行都不用改。我在项目中遇到过,某厂商换了OV的Sensor,HAL层改了三天,上层零改动——这就是HAL的价值。
1.2 HIDL与AIDL接口演进
接口演进这块,我踩过不少坑。咱们捋一捋。
1.2.1 传统HAL(Legacy HAL)
Android 8.0之前,HAL是hw_module_t结构体,直接以共享库形式加载到CameraService进程。说白了,HAL和框架跑在同一个进程里。
这样做有什么问题?
- HAL崩溃,CameraService跟着崩
- 没法热插拔
- 调试起来,嗯,你懂的
1.2.2 HIDL时代(Android 8.0 - 12)
Google终于想明白了——得把HAL隔离出去。于是HIDL(HAL Interface Definition Language)诞生了。
HIDL的核心思想:
- HAL跑在独立进程里
- 通过Binder或HwBinder通信
- 接口用
.hal文件定义
// 一个典型的Camera HIDL接口
package android.hardware.camera@3.4;
interface ICameraDevice {
open() generates (Status status);
configureStreams(Vec<Stream> streams) generates (Status status);
processCaptureRequest(CaptureRequest request) generates (Status status);
};
我个人习惯把HIDL理解为「带版本管理的Binder接口」。每个版本可以叠加新功能,比如从@3.2到@3.4,加了physicalCameraId支持。
避坑指南:我曾经在项目中遇到HIDL版本不匹配的问题。HAL实现了@3.4,但框架只加载了@3.2的库,结果configureStreams一直返回UNKNOWN。排查了两天,最后发现是manifest文件里版本号写错了。记住:manifest里的版本号必须和HAL实现一致。
1.2.3 AIDL时代(Android 13+)
到了Android 13,Google又推了一把——用AIDL统一HAL接口。
为什么?
- HIDL和AIDL两套系统,维护成本高
- AIDL更成熟,工具链更完善
- 支持Java和C++双向绑定
说白了,就是Google觉得「别搞两套了,都用AIDL吧」。
| 特性 | HIDL | AIDL |
|---|---|---|
| 定义文件 | .hal | .aidl |
| 传输层 | HwBinder / Binder | Binder |
| 版本管理 | 包名+版本号 | @VendorExtension注解 |
| 稳定性 | 稳定(VTS测试) | 稳定(CTS测试) |
| 推荐场景 | Android 8-12 | Android 13+ |
你想想看,从HIDL切到AIDL,最直观的变化是什么?接口定义更简洁了,而且可以直接用@nullable、@utf8InCpp这些注解。我最近在做一个Android 14的项目,全部用AIDL,开发效率确实高了不少。
1.3 HAL进程模型
进程模型这块,我把它分成三种模式。每种模式都有它的脾气。
1.3.1 同进程模式(Pass-through HAL)
这是最老的模式。HAL以共享库形式加载到CameraService进程。
- 优点:延迟低,没有IPC开销
- 缺点:HAL崩了,整个服务崩
嗯,现在基本不用了。除非你在做非常老的平台。
1.3.2 绑定式HAL(Binderized HAL)
HIDL时代的主流模式。HAL跑在独立进程里,通过HwBinder通信。
- HAL进程:
cameraserver或provider@2.4-service - 框架进程:
cameraserver - 通信方式:HwBinder + 共享内存(用于传大块图像数据)
这里有个关键点:进程隔离。HAL进程崩溃了,CameraService会收到死亡通知,然后尝试重启HAL。我在项目中遇到过,某款手机在弱光下拍照,HAL进程因为ISP驱动bug频繁崩溃,但上层只是闪了一下「相机重启」,用户体验还算过得去——这就是进程隔离的好处。
注意:进程隔离不是万能的。如果HAL进程频繁崩溃,CameraService的重试机制会触发「死亡螺旋」——重启→崩溃→重启→崩溃。我建议在HAL层加一个看门狗机制,连续崩溃3次就上报错误,而不是无限重试。
1.3.3 AIDL服务模式(Android 13+)
到了AIDL时代,进程模型又简化了。
- HAL作为AIDL Service注册到
vendor分区 - 框架通过
ServiceManager查找服务 - 支持多实例(比如双摄、三摄)
// AIDL服务注册示例
// 在init.rc中启动
service vendor.camera-provider /vendor/bin/hw/android.hardware.camera.provider@2.4-service
class hal
user cameraserver
group camera
capabilities SYS_NICE
onrestart restart cameraserver
说白了,AIDL模式就是把HAL当成一个普通的Android Service来管理。你想想看,这样有什么好处?
- 可以用
adb shell dumpsys查看状态 - 可以用
ServiceManager做服务发现 - 调试起来方便多了
1.4 我的经验总结
讲了这么多,我总结几条实战经验:
- 接口选择:新项目直接用AIDL,别犹豫。老项目如果还在Android 11以下,继续用HIDL,别折腾。
- 进程模型:一定要用绑定式HAL。同进程模式在2024年已经没有任何理由使用了。
- 性能关键点:HAL和框架之间的数据传输,尽量用共享内存(
hidl_memory或NativeHandle),别用Binder传大块数据。我见过有人用Binder传10MB的YUV图像,结果帧率直接掉到5fps。 - 调试技巧:在HAL进程里加
ALOGD,然后用logcat -b all | grep cameraserver看日志。我曾经靠这个定位了一个「预览黑屏」的问题——原来是Sensor的GPIO没拉高。
一句话总结:HAL架构的核心就是「隔离」和「标准化」。隔离让系统更稳定,标准化让开发更高效。搞懂了这两点,你就掌握了Camera HAL的精髓。
下一章,咱们聊聊HAL层的性能瓶颈分析。到时候我会分享一个真实案例——某款手机在4K60fps录像时,HAL层CPU占用率飙到80%,最后怎么优化的。嗯,敬请期待。