11、OTA升级概述:A/B系统、无缝升级、OTA包结构

OTA升级,说白了就是让手机“空中换血”。不用连电脑,不用刷机线,系统自己就能完成版本迭代。这个能力在Android生态里有多重要?我举个例子——当年我参与的一个项目,设备出货后才发现有个致命的内存泄漏。要是没有OTA,那批设备就得全部召回,成本直接爆炸。所以,理解OTA,是搞Android系统的基础课。

11.1 什么是A/B系统?

A/B系统,也叫无缝升级系统。它把系统分成了两个槽位:Slot A 和 Slot B。一个槽位跑当前系统,另一个槽位作为备份。升级的时候,新系统直接写到空闲槽位里,写完后重启切换。

你想想看,这样做的好处是什么?

  • 升级失败不砖机:如果新系统起不来,系统会自动回退到旧槽位。用户甚至感觉不到升级失败了。
  • 后台静默升级:用户正常使用手机,系统在后台偷偷把新版本下载好、写入备份槽位。下次重启时直接切换,几乎没有停机时间。
  • 回滚方便:如果新版本有严重bug,用户可以手动回退到旧槽位。不需要重新刷机。

核心要点:A/B系统的本质是“双保险”。一个槽位负责运行,一个槽位负责接收更新。两者互不干扰。

我在项目中遇到过一种情况:某厂商的A/B分区大小不一致,导致升级时写入失败。嗯,这里要注意——A/B系统的两个槽位必须完全对称,包括分区大小、文件系统类型。否则升级脚本会报错。

11.2 无缝升级的流程

无缝升级,听起来很美好。但它的实现流程其实挺复杂的。我拆解一下给你看:

  1. 下载阶段:系统从服务器拉取OTA包。这个包通常是一个zip文件,里面包含了完整的系统镜像。
  2. 校验阶段:下载完成后,系统会校验OTA包的签名和哈希值。防止包被篡改或损坏。
  3. 写入阶段:系统把OTA包解压,把新镜像写入到空闲槽位。这个过程是流式写入的,边解压边写,不需要额外存储空间。
  4. 切换阶段:写入完成后,系统设置一个“启动标志”,告诉Bootloader下次启动时切换到新槽位。
  5. 重启阶段:用户重启手机,Bootloader读取启动标志,加载新槽位的系统。
  6. 回滚检测:如果新系统启动失败(比如内核崩溃),Bootloader会自动切回旧槽位,并清除启动标志。

个人经验:我曾经调试过一个bug,升级后系统反复重启。最后发现是Bootloader里的回滚计数器没清零。每次重启都触发回滚,形成了死循环。解决方案是:在系统完全启动后,手动清除回滚标志。

说白了,无缝升级的核心就是“先写后切”。写的时候不影响当前系统,切的时候保证原子性。这个设计思路,其实和数据库的事务日志很像。

11.3 OTA包的结构

OTA包,本质上是一个zip文件。但它的内部结构有严格规范。我直接给你看一个典型的OTA包结构:

ota_update.zip
├── META-INF/
│   ├── MANIFEST.MF          # 包清单,包含所有文件的哈希值
│   ├── CERT.RSA             # 签名文件,用于验证包完整性
│   └── COM/
│       └── GOOGLE/
│           └── ANDROID/
│               ├── updater-script    # 升级脚本(旧版)
│               └── update-binary     # 升级二进制程序
├── payload.bin              # 增量或全量镜像数据
├── payload_properties.txt   # 镜像属性,如版本号、哈希值
└── care_map.txt             # 需要校验的分区列表

我来解释一下每个文件的作用:

文件/目录 作用
META-INF/ 包含签名和升级脚本。系统会先验证这个目录里的签名,再执行升级脚本。
payload.bin 这是核心文件。它包含了所有需要更新的分区镜像。可以是全量镜像,也可以是增量补丁。
payload_properties.txt 记录了payload的元信息,比如原始版本号、目标版本号、文件大小、哈希值等。
care_map.txt 列出了哪些分区需要做完整性校验。通常包括system、vendor、product等关键分区。

注意:payload.bin 是二进制格式,不能直接用文本编辑器打开。它的内部结构是“头部+数据块”的格式。头部包含了数据块的偏移量和大小,数据块则是压缩后的镜像数据。

我曾经踩过一个坑:OTA包里的payload_properties.txt 中,版本号写错了。导致系统升级后,版本号显示异常,用户以为升级失败了。后来我养成了一个习惯——每次生成OTA包后,先手动检查一下这个文件里的版本号对不对。

11.4 增量升级 vs 全量升级

OTA包有两种常见类型:增量包和全量包。它们的区别很明显:

  • 全量包:包含完整的系统镜像。体积大(通常1-2GB),但兼容性好。任何版本都能直接升级。
  • 增量包:只包含两个版本之间的差异数据。体积小(通常几十到几百MB),但只能从特定版本升级。

你想想看,实际项目中怎么选?

我个人建议:首次出货用全量包,后续小版本更新用增量包。全量包虽然大,但能保证所有设备都能升级。增量包节省流量,但需要严格控制版本链。我在项目中就遇到过用户跳版本升级导致增量包不兼容的情况——那叫一个头疼。

11.5 知识体系总览

为了让你更直观地理解本章内容,我画了一张结构图:

OTA升级知识体系 OTA升级 A/B系统 无缝升级流程 OTA包结构 双槽位备份 失败自动回滚 后台静默下载 流式写入 重启切换 payload.bin 签名校验 核心目标:安全、无缝、可回滚 A/B系统 + 无缝流程 + 结构化OTA包 = 可靠升级

这张图把本章的三个核心知识点串起来了。A/B系统提供硬件层面的双保险,无缝升级流程保证用户体验,OTA包结构确保数据传输的完整性和安全性。三者缺一不可。

总结一下:OTA升级不是简单的文件拷贝。它涉及分区管理、签名校验、流式写入、回滚机制等多个环节。每一个环节出问题,都可能导致设备变砖。所以,搞OTA的人,必须对系统底层有深刻理解。

好了,这一章就到这里。内容不多,但都是干货。下一章我们会深入payload.bin的内部结构,看看增量升级到底是怎么算出差分数据的。


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