第四节:OTA升级包制作与管理

好,咱们今天聊聊升级包。说实话,很多刚入行的朋友觉得升级包不就是把新固件打个包嘛。嗯,没那么简单。我做了这么多年OTA,踩过的坑有一半都跟升级包有关。

升级包做不好,轻则升级失败,重则把车刷成砖。你想想看,一台几十万的车,因为一个升级包的问题趴窝了,这责任谁担得起?

升级包类型:全量 vs 差分

先说说最基础的概念。升级包分两种:全量包和差分包。

全量包,说白了就是把整个系统镜像重新刷一遍。比如你的ECU固件是32MB,全量包就是32MB。好处是简单粗暴,坏处是——太大了。车上有几十个ECU,每个都传32MB,流量吃不消,下载时间也长。

差分包,只记录新旧版本之间的差异。比如你只改了一行代码,差分包可能就几百KB。我有个项目,全量包要传5分钟,换成差分包后30秒搞定。

那什么时候用全量,什么时候用差分?

我的经验是这样的:

  • 首次升级或版本跨度太大(比如从V1.0直接升到V3.0)→ 用全量包
  • 小版本迭代(V2.1到V2.2)→ 用差分包
  • 安全关键ECU(比如制动系统)→ 我建议用全量包,可靠性更高
  • 娱乐系统这种非安全件 → 差分包就够了

差分算法:bsdiff vs hdiff

差分包怎么做?这就涉及到算法了。目前主流的有两种:bsdiff和hdiff。

bsdiff,全称是Binary Suffix Diff。它基于后缀排序算法,生成的差分包非常小。我做过测试,同样的两个版本,bsdiff生成的包比hdiff小15%-20%。

但是,bsdiff有个致命缺点——内存消耗大。32MB的固件,bsdiff可能需要256MB内存。车上的MCU哪有这么大内存?所以bsdiff更适合服务器端生成,车端只负责合并。

hdiff,基于哈希匹配算法。它生成的包稍微大一点,但内存占用小得多。我记得有个项目,MCU只有64KB RAM,只能用hdiff。

对比项 bsdiff hdiff
压缩率 高(小15-20%) 中等
内存占用 高(约8倍原始大小) 低(约2倍原始大小)
生成速度
合并速度 中等
适用场景 服务器端生成 车端生成或资源受限设备

我个人的建议:

服务器端生成差分包,用bsdiff。车端合并,用bsdiff的合并算法(内存友好)。如果车端也要生成差分包(比如V2X场景),那就用hdiff。

版本管理策略

版本管理,嗯,这里要注意。很多团队一开始不重视,等到车卖了十万台才发现——版本乱成一锅粥。

语义化版本号,这是基础。我习惯用三段式:主版本.次版本.修订号。

  • 主版本:架构变更、不兼容升级
  • 次版本:功能新增、向下兼容
  • 修订号:Bug修复、小改动

举个例子:V2.1.3 → 主版本2,次版本1,修订号3。

版本兼容性矩阵,这个必须有。我曾经吃过亏——新版本不兼容旧版本的差分算法,结果升级到一半卡住了。从那以后,我要求每个版本发布前必须做兼容性测试。

避坑指南:

我曾经遇到过一个项目,版本号从V1.9直接跳到V2.0,结果差分包生成失败。为什么?因为V1.9和V2.0的镜像结构完全不同,差分算法根本找不到匹配块。后来我定了个规矩:主版本变更必须用全量包。

版本回滚策略,这个容易被忽略。升级失败了怎么办?你得有回滚方案。我一般保留最近两个版本的备份。比如当前是V2.1,升级V2.2失败,自动回滚到V2.1。如果V2.1也坏了,还有V2.0兜底。

代码里怎么实现?看个简单的版本管理示例:

// 版本结构体
typedef struct {
    uint8_t major;    // 主版本
    uint8_t minor;    // 次版本
    uint8_t patch;    // 修订号
    uint8_t build;    // 构建号
} version_t;

// 版本比较函数
bool version_is_newer(version_t *new, version_t *old) {
    if (new->major != old->major)
        return new->major > old->major;
    if (new->minor != old->minor)
        return new->minor > old->minor;
    return new->patch > old->patch;
}

// 差分包生成条件
bool can_use_delta(version_t *from, version_t *to) {
    // 主版本相同才允许差分
    return (from->major == to->major);
}

你看,代码很简单,但能避免很多问题。主版本不同强制用全量包,这就是血的教训换来的。

升级包管理平台

最后说说管理平台。车多了,版本就乱了。我建议用OTA管理平台来做版本管理,至少要有这些功能:

  • 版本仓库:存储所有历史版本,支持标签和搜索
  • 差分包生成:自动对比新旧版本,生成差分包
  • 兼容性检查:自动检测版本兼容性,不兼容就报警
  • 灰度发布:先推给10%的车,没问题再全量推
  • 回滚管理:一键回滚到上一个稳定版本

我记得有个项目,管理平台上存了300多个版本。没有平台的话,光找版本就能把人逼疯。

好了,升级包这块就聊这么多。下一节咱们讲讲升级过程中的安全机制——签名、校验、加密,这些一个都不能少。