27、Camera系统OTA升级:固件升级、HAL升级、兼容性保障、回滚机制

OTA升级,说白了就是让车上的摄像头系统能“空中换血”。

我做了这么多年车载Camera,最怕听到的一句话就是:“车已经量产了,但ISP固件有个bug,得升级。” 这时候如果OTA链路没设计好,那就只能回厂刷机,成本高得吓人。

今天我们就聊聊Camera系统的OTA升级。核心就三件事:固件怎么升、HAL怎么升、升坏了怎么回来

一、固件升级:ISP与Sensor的“换脑手术”

Camera的固件,主要分两块:

  • ISP固件:图像信号处理器的微码,控制3A、HDR融合、降噪等算法。
  • Sensor固件:感光芯片的寄存器配置,包括曝光模式、帧率、增益表。

这两类固件通常跑在MCU或专用DSP上,不依赖Android系统。所以升级方式也特殊——通过SPI或I2C通道,由主控SoC下发固件包

关键点:固件升级必须保证“原子性”。

什么意思?就是要么升级成功,要么保持原样。绝对不能出现写到一半断电,固件变成“半成品”的情况。

我习惯的做法是:

  1. 先把新固件下载到SoC的临时分区(比如/data/ota/camera_fw.bin)。
  2. 校验哈希值(SHA256),确保文件没损坏。
  3. 通知ISP进入“固件升级模式”,把新固件通过SPI DMA刷进去。
  4. 刷完后,ISP自动重启,读取新固件并做自检。
  5. 自检通过后,SoC读取ISP的状态寄存器,确认升级成功。

这里有个坑:ISP在刷固件时,不能响应Camera HAL的请求。所以升级前,HAL必须暂停所有预览和拍照流。我在项目中遇到过,升级时没停流,结果ISP一边刷固件一边处理图像,直接导致内存访问冲突,系统挂了。

避坑指南:我曾经因为没做“升级超时重试”机制,导致某次OTA升级时,ISP固件刷到99%卡住了。原因是SPI时钟受电磁干扰,最后一个包没传完。后来我加了个策略:如果升级超时,SoC主动复位ISP,重新尝试。最多重试3次,3次都失败就标记升级失败,保持旧固件。

二、HAL升级:Framework与底层之间的“换桥”

HAL升级比固件升级更敏感。因为HAL是Android Camera Framework和硬件之间的桥梁。桥换了,两边的协议必须对得上。

HAL升级通常有两种方式:

  • 全量替换:把整个camera HAL库(比如camera..so)替换掉。
  • 增量补丁:只替换部分函数或配置(比如camera_profiles.xml)。

我个人更推荐全量替换。为什么?因为增量补丁容易产生“版本碎片”。你想想看,如果HAL的某个结构体大小变了,但补丁只替换了部分函数,那新旧代码混在一起,很容易踩内存越界的坑。

HAL升级的流程,我总结为三步:

  1. 停服务:通过setprop ctl.stop cameraserver停掉CameraService。注意,这里要等所有Camera客户端释放资源。
  2. 替换文件:把新的HAL库拷贝到/vendor/lib/hw//vendor/lib64/hw/下。
  3. 重启服务:通过setprop ctl.start cameraserver拉起CameraService。

嗯,这里要注意:HAL升级不能跨Android大版本。比如Android 12的HAL不能直接用在Android 13上,因为Framework侧的ICameraDevice.hal接口可能变了。我建议在OTA包中携带HAL版本号,升级前做兼容性检查。

小技巧:我习惯在HAL的initialize()函数里加一个版本校验。Framework传一个“期望的HAL版本号”,HAL检查自己是否匹配。如果不匹配,直接返回错误,拒绝工作。这样能避免Framework和HAL版本不一致导致的诡异问题。

三、兼容性保障:别让升级变成“拆东墙补西墙”

OTA升级最怕什么?最怕新固件修了A问题,却引入了B问题。而且B问题可能更严重,比如导致摄像头无法点亮。

兼容性保障,我总结为三个层面:

层面 检查内容 我的做法
接口兼容 HAL导出的函数签名、结构体大小、枚举值是否变化 用ABI Compliance Checker工具自动比对
行为兼容 新固件/新HAL在相同输入下,输出是否一致 在实验室录制标准测试视频,对比新旧版本的图像质量指标
性能兼容 帧率、延迟、功耗是否退化 跑自动化压力测试,记录FPS和CPU/GPU占用率

说白了,兼容性保障就是“先验证,再上线”。我见过有些团队,OTA包直接推到量产车上,结果新HAL把某个私有接口的返回值类型从int改成了long,导致上层Framework直接crash。这种问题,在实验室里跑一遍CTS就能发现。

我的经验:每次Camera OTA升级前,必须跑一遍Camera CTS和VTS。特别是VTS的CameraHidlTest,它能验证HAL是否遵循了HIDL接口规范。如果VTS没过,坚决不能推送。

四、回滚机制:最后的救命稻草

回滚机制,说白了就是“升坏了能退回去”。

我做过一个项目,OTA升级后,新ISP固件导致夜间模式下的HDR融合算法异常,画面出现鬼影。当时车已经交付给客户了,怎么办?只能靠回滚。

回滚机制的设计,我建议遵循以下原则:

  • 双分区备份:固件和HAL都保留两个版本——当前版本和上一个版本。升级时,新版本写入备用分区,不覆盖当前分区。
  • 启动时校验:每次系统启动,Camera HAL检查固件和HAL的版本是否匹配。如果不匹配,自动切换到备用分区。
  • 用户触发回滚:在诊断工具中提供“回滚到上一版本”的接口。我习惯把这个接口放在vendor.camera.rollback属性里,通过setprop触发。

回滚的流程大致如下:

  1. 检测到升级失败(比如HAL初始化返回错误,或者ISP自检失败)。
  2. HAL自动调用rollback()函数,把备用分区的旧固件刷回主分区。
  3. 重启CameraService,重新初始化。
  4. 如果回滚成功,记录日志并通知OTA服务器“升级失败,已回滚”。

避坑指南:我曾经遇到过回滚后,旧固件和新HAL不兼容的情况。原因是HAL升级时改了某个私有数据结构的大小,回滚固件后,HAL还是新的,结果访问旧固件的数据时越界了。后来我规定:固件和HAL必须一起回滚,不能只回滚其中一个。

五、整体OTA升级架构

下面这张图,是我自己项目里用的Camera OTA升级架构。你可以参考一下:

Camera OTA升级架构图 OTA服务器 OTA Manager (Android) HAL升级模块 替换camera.*.so 固件升级模块 刷写ISP/Sensor固件 回滚模块 双分区切换/恢复 Camera HAL ISP / Sensor 回滚路径 下载 管理 HAL升级 固件升级 回滚

从图中可以看到,OTA Manager负责从服务器下载升级包,然后分发给三个模块:HAL升级模块、固件升级模块和回滚模块。这三个模块各自独立工作,但回滚模块可以干预前两个模块——一旦检测到升级失败,立即启动回滚。

最后说一句:OTA升级不是一锤子买卖。你设计的时候,就要想好“升坏了怎么办”。回滚机制不是可有可无的,它是Camera系统的最后一道防线。我见过太多项目,因为赶进度砍掉了回滚功能,结果线上出问题后,只能派工程师挨个去4S店刷机。那场面,真的很难看。

好了,Camera OTA升级的核心要点就这些。记住:固件升级要原子性,HAL升级要兼容性,回滚机制要双分区。这三条做到了,你的Camera系统就能经得起OTA的考验。