第三章:升级包制作与管理

升级包,说白了就是给车“喂”的那颗药。药好不好,直接决定系统能不能活过来。我做了这么多年OTA,见过太多升级包出问题导致车辆变砖的案例。今天咱们就聊聊,怎么把这颗药做对、做安全、做高效。

3.1 升级包格式规范

先说说格式。你可能觉得这有什么好讲的?不就是打个包吗?嗯,还真不是。

我见过一个团队,升级包格式自己定了一套,结果换了个供应商,两边解析方式不一样,升级到一半直接崩溃。从那以后,我坚持用标准格式。

目前主流的有两种:

  • SWP(Software Package)格式:特斯拉、宝马等车企在用。结构清晰,支持多分区。
  • UDS-based 格式:基于ISO 14229标准,诊断仪直接刷写。

我个人习惯用SWP格式,因为它天然支持差分升级。一个标准的SWP包长这样:

| 包头 (Header)     | 元数据 (Metadata)  | 载荷 (Payload)     | 签名 (Signature)   |
| 4字节魔数+版本号  | 目标ECU列表+哈希值 | 压缩后的二进制数据 | RSA-2048签名       |

这里有个坑:魔数一定要固定。我曾经遇到一个项目,魔数写成了0xDEADBEEF,结果某个工具链把它当成了非法数据直接丢弃。后来我改成了0x4F5441(OTA的ASCII码),再没出过问题。

我的建议:魔数用4字节,最好是人眼可读的ASCII字符。比如"OTA1"、"SWUP"这种,调试时一眼就能认出来。

3.2 差分升级技术

差分升级,说白了就是只传变化的部分。你想想看,一个系统镜像动辄几百MB,每次全量升级,流量费都够买辆车了。

差分升级的核心算法,我接触过三种:

算法 压缩率 内存消耗 适用场景
bsdiff 高(通常80%以上) 高(需要原文件) 大文件升级(如Linux内核)
hdiffpatch 中(60%-70%) 通用场景
xdelta3 低(40%-50%) 嵌入式MCU升级

我在项目中遇到过一个问题:用bsdiff给一个MCU升级,结果MCU只有256KB RAM,根本装不下原文件。后来换成了xdelta3,虽然压缩率低点,但能跑起来才是硬道理。

差分升级的流程是这样的:

  1. 生成差分:在云端对比新旧版本,生成patch文件。
  2. 传输差分:只传输patch文件到车端。
  3. 合并还原:车端用旧版本+patch,还原出新版本。
注意:差分升级依赖旧版本的完整性。如果旧版本已经被篡改或损坏,合并出来的新版本也是坏的。所以,一定要在合并前校验旧版本的哈希值

3.3 升级包签名与加密

安全这块,我吃过亏。有一次,一个测试车被黑客截获了升级包,他们反编译后发现了我们内部的一些调试接口。从那以后,我对签名和加密的要求变得极其严格。

先说签名。签名的作用是防篡改。流程如下:

# 生成密钥对
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem

# 签名升级包
openssl dgst -sha256 -sign private.pem -out upgrade.bin.sig upgrade.bin

# 车端验签
openssl dgst -sha256 -verify public.pem -signature upgrade.bin.sig upgrade.bin

这里有个细节:私钥一定要离线保存。我见过有人把私钥放在CI/CD服务器上,结果一次安全扫描就泄露了。现在我的做法是:私钥放在硬件加密机里,每次签名都要人工授权。

再说加密。加密的作用是防窃听。差分升级包虽然小,但里面可能包含敏感数据(比如地图数据、用户配置)。我建议用AES-256-GCM模式,既加密又带认证。

核心原则:先签名后加密。先签名保证内容没被改过,再加密保证内容不被偷看。顺序不能反,否则别人可以替换你的加密包。

3.4 版本管理策略

版本管理,听起来简单,做起来全是坑。我见过一个团队,版本号用日期命名,结果同一天发布了两个版本,直接搞混了。

我推荐用语义化版本

主版本号.次版本号.修订号
例如:2.1.3

- 主版本号:不兼容的API变更
- 次版本号:向下兼容的功能新增
- 修订号:向下兼容的问题修复

但自动驾驶系统有点特殊。你想想看,一个感知模型升级,可能只是改了权重,但功能上却是颠覆性的。所以我在语义化版本基础上,加了一个构建号

2.1.3.20240315
↑  ↑  ↑    ↑
主 次 修  构建日期

版本管理的另一个重点是回滚策略。我坚持一个原则:永远保留上一个可用版本。具体做法:

  • 车端保留A/B分区,一个跑当前版本,一个存上一个版本。
  • 升级时先写备用分区,校验通过后再切换。
  • 如果升级失败,自动回滚到上一个版本。
避坑指南:我曾经遇到过一个问题,回滚时发现上一个版本也被覆盖了。后来我规定:升级包必须包含上一个版本的完整镜像,这样即使备用分区坏了,也能从云端重新下载。

最后说一句,版本管理不只是技术问题,更是流程问题。我建议每个版本发布前,都要经过:

  1. 单元测试:每个模块单独测。
  2. 集成测试:所有模块一起测。
  3. 实车测试:至少跑1000公里。
  4. 灰度发布:先推给1%的车,观察24小时。

嗯,做到这步,基本就不会出大问题了。但记住,OTA升级没有100%的安全,我们能做的,就是把风险降到最低。