19、车载OTA升级:OTA系统架构(update_engine、recovery);AB分区与无缝升级;OTA包生成与签名;OTA升级流程与回滚机制
OTA升级,说白了就是让车“自己给自己治病”。
我最早接触车载OTA是在2018年,那时候很多车还得开到4S店插线刷机。你想想看,一辆车卖出去几万台,要是每个系统bug都得召回,那成本得多吓人?所以,Android Automotive从设计之初就把OTA当成核心能力来做的。
19.1 OTA系统架构:update_engine 与 recovery
整个OTA体系,其实就两个核心角色:update_engine 和 recovery。
- update_engine:运行在正常系统里,负责下载、校验、写入升级包。它是个常驻服务,开机就启动。
- recovery:一个独立的小系统,运行在单独的分区里。当主系统挂了,或者需要做关键操作时,由它来接管。
我习惯把update_engine比作“前台接待”,recovery比作“手术室”。前台接待处理日常事务,真到了动刀子的环节,就得进手术室。
核心架构图:OTA升级流程
19.2 AB分区与无缝升级
AB分区,这是Android从7.0开始引入的机制。说白了就是准备两套系统分区:slot A 和 slot B。
你当前在A分区跑着,升级包就往B分区写。写完了,下次重启切到B分区。整个过程你完全无感——这就是所谓的“无缝升级”。
我的经验:曾经有个项目,客户非要搞“单分区升级”,说是省存储空间。结果升级到一半断电,车机直接变砖。后来老老实实改回AB分区。省那几百MB空间,真不值得冒这个险。
| 特性 | AB分区 | 单分区 |
|---|---|---|
| 升级时可用 | 是(后台静默升级) | 否(必须重启进recovery) |
| 回滚能力 | 强(切回旧slot即可) | 弱(需重新刷写) |
| 存储占用 | 高(两套系统) | 低 |
| 升级失败风险 | 低 | 高 |
分区布局大概是这样的:
/dev/block/by-name/
├── boot_a
├── boot_b
├── system_a
├── system_b
├── vendor_a
├── vendor_b
├── userdata # 用户数据不分AB
└── misc # 存储启动信息
嗯,这里要注意:userdata不分AB。因为用户数据是持续增长的,你不可能维护两套。所以升级时,系统分区随便换,但用户数据始终是同一份。
19.3 OTA包生成与签名
OTA包本质上就是一个zip文件。但里面的内容是有严格结构的。
生成工具是Android源码里的 ota_from_target_files 脚本。我一般这么用:
# 先生成 target files
make target-files-package
# 然后生成 OTA 包
./build/tools/releasetools/ota_from_target_files \
-k build/target/product/security/releasekey \
-i previous_target_files.zip \
output_ota.zip
这里 -i 参数表示增量包。如果你不加,生成的就是完整包。完整包体积大,但兼容性好;增量包体积小,但只能从特定版本升级。
警告:签名密钥一定要妥善保管!我曾经见过一个团队把release key直接提交到git仓库里,结果被第三方拿到了,伪造了OTA包。那后果……嗯,你懂的。
签名流程其实就三步:
- 计算所有文件的SHA256哈希
- 用私钥对哈希列表签名
- 把签名和公钥证书打包进OTA包
车机收到包后,会用内置的公钥验证签名。验证通过才允许安装。这就是整个信任链的基础。
19.4 OTA升级流程与回滚机制
完整的升级流程,我习惯分成五个阶段:
- 检测阶段:update_engine定时向云端查询新版本。有的话,返回包信息。
- 下载阶段:下载OTA包到缓存分区。边下载边校验哈希,防止中途损坏。
- 验证阶段:校验签名、校验包完整性、校验版本号是否合法。
- 写入阶段:把包内容解压,写入非活跃slot。比如当前是A,就写B。
- 切换阶段:更新misc分区里的启动计数器,然后重启。bootloader根据计数器决定启动哪个slot。
回滚机制,说白了就是“启动失败了怎么办”。
Android Automotive里有个启动次数计数器。每次切到新slot,计数器+1。如果系统正常启动,计数器清零。如果启动失败,计数器不变。当计数器超过阈值(通常是7次),bootloader就自动切回旧slot。
回滚触发条件:
- 新系统连续启动失败(计数器超限)
- 用户手动选择回滚(通过诊断工具)
- 升级过程中断电(下次启动自动回退)
我遇到过最坑的一次:升级后系统能启动,但蓝牙模块死活不工作。计数器没超限,所以不会自动回滚。最后是远程推送了一个修复包才解决。所以你看,回滚机制也不是万能的——它只能检测“能不能启动”,检测不了“功能是否正常”。
后来我们在项目中加了一个健康检查服务。升级完成后,系统会跑一遍自检流程:检查蓝牙、Wi-Fi、GPS、音频等核心模块。如果自检失败,主动触发回滚。这个做法我建议你也加上。
嗯,关于OTA升级,核心就是这些。AB分区是骨架,签名验证是锁,回滚机制是安全绳。三者缺一不可。