15、OTA升级策略:全量OTA、增量OTA、增量包生成算法

说到OTA升级,很多刚入行的同学第一反应就是「把新系统包下载下来,然后刷进去」。嗯,这个理解没错,但实际工程里,事情远没那么简单。我这些年做过的项目里,OTA策略选错了,轻则升级失败率高,重则把用户手机搞成砖——这可不是开玩笑的。

今天咱们就把三种主流策略掰开揉碎讲清楚:全量OTA、增量OTA,以及增量包到底是怎么算出来的。

一、全量OTA:简单粗暴,但代价不小

全量OTA,说白了就是把整个系统镜像完整地推送到设备上。比如你的系统分区是4GB,那就推送一个4GB的包。

核心特点:

  • 升级包体积大,通常等于系统分区大小
  • 升级逻辑简单:下载 → 校验 → 刷写 → 重启
  • 兼容性好,不依赖当前系统版本

我在早期做平板项目时,就吃过全量OTA的亏。当时系统分区才2GB,觉得全量推送没问题。结果用户反馈说升级要下载2GB数据,流量费都够买杯奶茶了。更头疼的是,有些低端设备存储空间不够,下载完解压时直接报错。

适用场景:

  • 首次出厂后的第一次大版本升级
  • 系统版本跨度太大,增量包无法生成
  • 设备存储空间充裕,且用户连接Wi-Fi升级

二、增量OTA:精打细算,但依赖版本

增量OTA只推送「变化的部分」。比如你从Android 12升级到12.1,可能只改动了几百个文件,那增量包可能只有几十MB。

为什么会这样?你想想看,系统里大部分文件其实没变——内核、驱动、系统库,这些核心组件在同一个大版本里基本不动。真正变的是什么呢?

  • 系统应用更新(比如设置、电话、短信)
  • 框架层的小修小补
  • 配置文件调整
  • 安全补丁

我的经验:增量包的大小通常控制在原始系统分区的5%~20%之间。如果超过30%,我建议你重新评估一下——是不是版本改动太大了?这时候全量可能更划算。

但增量OTA有个致命弱点:它依赖当前系统版本。如果用户跳版本升级,比如从Android 11直接升到12.1,那增量包就没办法用了。这时候你得准备多个增量包,或者干脆走全量。

三、增量包生成算法:核心原理

增量包怎么生成的?这里我重点讲两种主流算法:bsdiff和imgdiff。

3.1 bsdiff:二进制级别的差异比较

bsdiff是Google官方推荐的增量算法,专门处理二进制文件。它的核心思路是:

  1. 把新旧两个文件切成小块
  2. 找出哪些块没变,哪些块变了
  3. 只记录变化的部分,以及变化的位置

举个例子:

# 旧文件(假设是libfoo.so)
0x0000: AABBCCDD
0x0004: EEFF0011
0x0008: 22334455

# 新文件(libfoo.so更新后)
0x0000: AABBCCDD  # 没变
0x0004: EEFF0022  # 变了最后一个字节
0x0008: 22334455  # 没变

# 增量包只记录:在0x0004位置,把0x11改成0x22

实际工程中,bsdiff还会做压缩和编码优化。我记得有一次,一个20MB的so文件,改动只有几KB,bsdiff生成的增量包才几百KB——效果非常明显。

3.2 imgdiff:针对Android镜像的优化

imgdiff是bsdiff的变种,专门处理Android的system.img这类稀疏镜像。它比bsdiff多了一个步骤:先解析镜像的稀疏表,然后只比较实际有数据的块。

注意:imgdiff不能直接处理普通文件。如果你要生成APK的增量包,得用bsdiff。我见过有人搞混了,结果生成的增量包在设备上解压失败——嗯,踩过这个坑。

四、增量包生成流程:从源码到OTA包

Android源码里有一套完整的OTA包生成工具链,核心脚本在build/tools/releasetools/目录下。我简单梳理一下流程:

  1. 准备新旧系统镜像:编译出target_files.zip,包含所有系统文件
  2. 调用ota_from_target_files脚本:指定新旧两个zip包
  3. 逐文件比较:对每个文件,判断是否变化
  4. 生成补丁:变化的文件用bsdiff或imgdiff生成补丁
  5. 打包:把所有补丁和元数据打包成OTA.zip

这里有个关键点:脚本会先比较文件的SHA1哈希值。如果哈希一样,说明文件没变,直接跳过。只有哈希不同时,才会调用bsdiff。

实际项目中的优化:我建议在生成增量包时,先做一次「文件级去重」。比如两个版本里都有同一个APK,只是签名不同,那其实可以只保留一个。这个优化能让增量包再小10%~20%。

五、三种策略的对比

对比维度 全量OTA 增量OTA
包体积 大(等于系统分区) 小(通常5%~20%)
升级成功率 高(不依赖当前版本) 中等(依赖版本一致性)
生成复杂度 低(直接打包) 高(需要差异算法)
用户流量消耗
适用版本跨度 任意 小版本升级

六、核心流程图:增量包生成与升级

下面这张图展示了从生成增量包到设备端升级的完整流程。我特意把关键决策点标出来了,方便你理解。

增量OTA包生成与升级流程 生成阶段(服务器端) 新旧target_files SHA1哈希比较 bsdiff/imgdiff 打包OTA.zip 哈希相同? 是 → 跳过 否 → 生成补丁 升级阶段(设备端) 下载OTA.zip 校验签名 应用补丁 重启验证 注:增量包生成时,bsdiff用于普通文件,imgdiff用于稀疏镜像文件

七、避坑指南

做OTA升级这么多年,我踩过的坑不少。挑几个典型的说说:

我曾经遇到过:增量包在设备上应用失败,原因是设备上的文件被root修改过。SHA1对不上,补丁自然打不上去。后来我们在升级前加了一步「文件完整性校验」,如果发现文件被篡改,就自动切换到全量升级。

还有一次,增量包生成时用了bsdiff,但目标文件是APK。APK本身是zip格式,bsdiff对zip文件的压缩内容做差异比较,效果很差。后来改用imgdiff(其实Google有专门处理APK的优化),增量包从15MB降到了3MB。

我的建议:生成增量包时,先做一次「文件类型分类」:

  • 普通二进制文件 → bsdiff
  • APK/JAR等zip文件 → 用zip-specific算法(如xz-compressed)
  • 稀疏镜像文件 → imgdiff

这样生成的增量包最小,升级成功率也最高。

最后说一句:OTA升级不是一锤子买卖。上线后一定要监控升级成功率、失败原因分布。如果某个版本的增量包失败率超过5%,赶紧查查是不是算法选错了,或者设备端有特殊情况。


公众号:蓝海资料掘金营,微信deep3321