3. 生成增量OTA升级包
任务目标
在Android系统OTA升级开发中,增量升级包(Incremental OTA Package)只包含两个版本之间的差异数据,体积远小于全量包。本案例使用bsdiff差分工具,基于给定系统镜像文件生成增量升级包,并验证生成包的完整性。
环境与依赖
- 操作系统:Ubuntu 18.04+ / CentOS 7+(x86_64)
- 差分工具:bsdiff 4.3(
apt install bsdiff或yum install bsdiff) - 校验工具:md5sum(系统自带)
实现原理
增量升级包的核心是二进制差分算法。bsdiff基于后缀排序算法找出新旧文件的最长公共子串,将差异编码为补丁文件。生成增量包时,以旧版本镜像为基准(oldfile),新版本镜像为输入(newfile),输出补丁文件(patch)。该补丁即为增量升级包的核心内容,后续可被恢复工具(bspatch)用于将旧版本还原为新版本。
关键完整代码
#!/bin/bash
# generate_incremental_ota.sh
# 用法: ./generate_incremental_ota.sh <old_image> <new_image> <output_patch>
set -e
OLD_IMG="$1"
NEW_IMG="$2"
PATCH_FILE="$3"
if [ $# -ne 3 ]; then
echo "错误: 需要3个参数"
echo "用法: $0 <old_image> <new_image> <output_patch>"
exit 1
fi
if [ ! -f "$OLD_IMG" ] || [ ! -f "$NEW_IMG" ]; then
echo "错误: 输入文件不存在"
exit 1
fi
echo "=== 生成增量升级包 ==="
echo "旧版本: $OLD_IMG ($(stat -c%s "$OLD_IMG") bytes)"
echo "新版本: $NEW_IMG ($(stat -c%s "$NEW_IMG") bytes)"
# 调用bsdiff生成差分补丁
bsdiff "$OLD_IMG" "$NEW_IMG" "$PATCH_FILE"
echo "增量包已生成: $PATCH_FILE ($(stat -c%s "$PATCH_FILE") bytes)"
# 计算校验值用于验证
echo "=== 校验信息 ==="
echo "旧版本 MD5: $(md5sum "$OLD_IMG" | cut -d' ' -f1)"
echo "新版本 MD5: $(md5sum "$NEW_IMG" | cut -d' ' -f1)"
echo "增量包 MD5: $(md5sum "$PATCH_FILE" | cut -d' ' -f1)"
# 验证增量包可恢复性
echo "=== 验证增量包正确性 ==="
TEMP_RESTORED="/tmp/restored_$$.img"
bspatch "$OLD_IMG" "$TEMP_RESTORED" "$PATCH_FILE"
if cmp -s "$NEW_IMG" "$TEMP_RESTORED"; then
echo "✓ 验证通过: 增量包可完整恢复新版本"
rm -f "$TEMP_RESTORED"
exit 0
else
echo "✗ 验证失败: 恢复结果与新版本不一致"
rm -f "$TEMP_RESTORED"
exit 1
fi
运行与验证
准备测试镜像:若无现成镜像,可用以下命令生成两个测试文件模拟新旧版本:
# 生成10MB随机测试文件作为旧版本
dd if=/dev/urandom of=old_v1.img bs=1M count=10
# 复制并修改部分内容作为新版本
cp old_v1.img new_v2.img
# 修改文件末尾1KB数据模拟版本更新
printf '\x00\x01\x02\x03' | dd of=new_v2.img bs=1 seek=$((10*1024*1024-4)) conv=notrunc
执行生成脚本:
chmod +x generate_incremental_ota.sh
./generate_incremental_ota.sh old_v1.img new_v2.img update_patch.bin
通过条件:脚本输出包含以下内容即判定成功:
- 增量包文件已生成,且体积明显小于新版本镜像(本例中应远小于10MB)
- 三行MD5校验值正常输出
- 最后一行显示
✓ 验证通过: 增量包可完整恢复新版本
预期输出示例:
=== 生成增量升级包 ===
旧版本: old_v1.img (10485760 bytes)
新版本: new_v2.img (10485760 bytes)
增量包已生成: update_patch.bin (296 bytes)
=== 校验信息 ===
旧版本 MD5: 3a7b...
新版本 MD5: 8f2c...
增量包 MD5: b1e9...
=== 验证增量包正确性 ===
✓ 验证通过: 增量包可完整恢复新版本
注意:由于新旧镜像仅4字节差异,增量包极小(约几百字节),这正体现了差分升级在版本迭代中的带宽节省优势。实际OTA场景中,增量包通常为全量包的5%~20%。
常见问题
- bsdiff内存不足:处理超大镜像(>2GB)时可能耗尽内存,建议使用
bsdiff4或分块处理。 - 恢复验证失败:确认新旧镜像未被修改,且bspatch版本与bsdiff匹配。
- 实际OTA集成:本案例生成的patch文件需封装为Android OTA包格式(含META-INF签名等),该封装流程在后续案例中展开。