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进程:cameraserverprovider@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 我的经验总结

讲了这么多,我总结几条实战经验:

  1. 接口选择:新项目直接用AIDL,别犹豫。老项目如果还在Android 11以下,继续用HIDL,别折腾。
  2. 进程模型:一定要用绑定式HAL。同进程模式在2024年已经没有任何理由使用了。
  3. 性能关键点:HAL和框架之间的数据传输,尽量用共享内存(hidl_memoryNativeHandle),别用Binder传大块数据。我见过有人用Binder传10MB的YUV图像,结果帧率直接掉到5fps。
  4. 调试技巧:在HAL进程里加ALOGD,然后用logcat -b all | grep cameraserver看日志。我曾经靠这个定位了一个「预览黑屏」的问题——原来是Sensor的GPIO没拉高。

一句话总结:HAL架构的核心就是「隔离」和「标准化」。隔离让系统更稳定,标准化让开发更高效。搞懂了这两点,你就掌握了Camera HAL的精髓。

下一章,咱们聊聊HAL层的性能瓶颈分析。到时候我会分享一个真实案例——某款手机在4K60fps录像时,HAL层CPU占用率飙到80%,最后怎么优化的。嗯,敬请期待。