19、OTA升级与AB:AB分区、AB与动态分区共存
聊到OTA升级,就绕不开AB分区。说实话,我第一次接触AB分区时,脑子里就一个想法——这不就是给系统上了个“双保险”嘛。但真正深入进去才发现,里面的门道比想象中要多得多。
今天我们就来拆解一下AB分区机制,以及它和动态分区怎么和平共处。
什么是AB分区?
AB分区,也叫无缝升级(Seamless Update)。它的核心思想很简单:
系统准备两套分区槽位——Slot A 和 Slot B。一套在运行,另一套就闲着。升级时,把新系统写入空闲的那套分区。写完后,下次重启切过去就行。
我打个比方:就像你有两套房子,一套住着,另一套装修。装修完了,搬过去住,原来的房子再翻新。这样你永远有地方住,不会露宿街头。
AB分区的核心优势:
- 升级失败不影响当前系统
- 用户几乎感知不到升级过程
- 可以随时回滚到旧版本
AB分区的工作原理
咱们来看看具体流程。我习惯把AB升级分成三个阶段:
- 写入阶段:系统在后台把新固件写入空闲槽位。用户该干嘛干嘛,完全无感。
- 切换阶段:写入完成后,设置一个“启动标记”,告诉Bootloader下次从新槽位启动。
- 生效阶段:重启后,系统从新槽位启动。如果启动成功,旧槽位就变成“待更新”状态。
这里有个关键点——Bootloader怎么知道该从哪个槽位启动?
答案是:靠misc分区里的一个叫“bootctrl”的元数据。它记录了当前活跃槽位、槽位状态、是否成功启动等信息。
我个人习惯:在调试AB升级时,先用 adb shell getprop ro.boot.slot_suffix 查看当前槽位。这能帮你快速定位问题。
AB分区与动态分区共存
好,问题来了。动态分区把system、vendor这些分区都合并成了一个super分区。那AB分区怎么和它共存?
嗯,这里要分清楚:AB分区管的是“槽位”,动态分区管的是“分区布局”。两者是不同维度的东西。
共存的方式其实很直接:
- 每个槽位都有自己的super分区。比如
super_a和super_b。 - 每个super分区内部,再通过动态分区管理子分区。
- 升级时,把整个super分区的内容写入空闲槽位。
说白了,就是“双份的super分区”。
分区布局示例:
boot_a
boot_b
super_a (包含 system_a, vendor_a, product_a ...)
super_b (包含 system_b, vendor_b, product_b ...)
misc
userdata
...
你看,每个槽位都有自己的boot分区和super分区。这样升级时,Bootloader只需要知道切到哪个槽位,剩下的由动态分区自己搞定。
我踩过的坑
我曾经在一个项目里遇到过一个诡异的问题:升级后设备反复重启,就是进不了系统。
排查了半天,发现是super分区的大小没对齐。两个槽位的super分区大小不一致,导致写入时数据被截断了。
避坑指南:
- 两个槽位的super分区大小必须完全一致
- 分区表里要预留足够的空间给两个super分区
- 动态分区的metadata要放在super分区内部,不要依赖外部存储
AB升级的完整流程
咱们用一张图来梳理整个流程。我画了个SVG,把关键步骤都标出来了。
从图里你能看到,整个流程是线性的。但有个关键点——如果启动失败,Bootloader会自动回滚到旧槽位。这就是AB分区最牛的地方:永远有退路。
动态分区下的AB升级细节
在动态分区环境下,AB升级有几个特殊之处:
| 特性 | 说明 |
|---|---|
| super分区大小 | 两个槽位的super分区必须大小一致,否则写入会失败 |
| metadata管理 | 每个super分区有自己的metadata,互不干扰 |
| 逻辑分区映射 | 升级时,逻辑分区(如system、vendor)在super内部重新分配 |
| 回滚策略 | 回滚时,只需切换槽位,super分区内容不变 |
注意:动态分区下的AB升级,对分区表的要求更严格。我曾经遇到过因为super分区预留空间不足,导致升级包无法写入的情况。建议super分区大小至少是实际内容的1.2倍。
实际项目中的经验
我记得有个项目,客户要求实现“零 downtime”升级。我们用了AB分区+动态分区的方案,效果确实不错。
但有个细节让我印象深刻:升级完成后,旧槽位的数据怎么处理?
答案是:不处理。旧槽位的数据会保留,直到下一次升级时被覆盖。这样做的目的是:如果新系统有问题,用户可以随时回滚。
你想想看,如果升级完就把旧槽位清空了,那回滚功能就废了。所以,保留旧数据不是浪费空间,而是为了安全。
总结一下
AB分区和动态分区,说白了就是两个互补的技术。AB分区管“槽位切换”,动态分区管“空间管理”。两者结合,既能实现无缝升级,又能灵活分配分区空间。
我个人觉得,这套方案是目前Android OTA升级的最优解。虽然实现起来复杂一些,但带来的用户体验提升是实实在在的。
嗯,今天就聊到这里。如果你在实际项目中遇到AB分区的问题,欢迎交流。