3. A-B分区机制概述

在传统 Android 设备上,系统分区(system、boot、vendor 等)只有一份。OTA 升级时,设备必须重启进入 Recovery 模式,把新镜像写入原分区,再重启进入新系统。这个过程中设备无法正常使用,一旦写入中断或新系统启动失败,设备就可能变砖。A-B 分区机制正是为解决这一系列问题而设计的。

一、A-B分区的设计动机

A-B 分区(也称 Seamless Update,无缝升级)的核心动机可以归纳为三点:

  • 可用性:升级在后台进行,用户可继续使用设备,只需一次重启即可切换到新系统。
  • 可回滚性:新系统启动失败时,Bootloader 可自动回退到旧槽位,保证设备始终可启动。
  • 可验证性:新槽位在切换为活动槽位前,可先做完整性和兼容性校验,降低升级风险。

这三点的共同前提是:设备上同时存在两套可独立启动的系统副本,即“双槽位”。

二、双槽位(Slot)概念

所谓槽位,是指一组可独立启动的分区集合。Android 将系统划分为两个槽位:slot A 与 slot B。每个槽位都包含自己的一套分区,例如:

slot A: boot_a, system_a, vendor_a, dtbo_a, vbmeta_a
slot B: boot_b, system_b, vendor_b, dtbo_b, vbmeta_b

设备在任意时刻只有一个槽位处于“活动(active)”状态,另一个槽位处于“非活动(inactive)”状态。正常运行时,系统从活动槽位启动;升级时,新镜像被写入非活动槽位,写入完成并校验通过后,通过设置元数据把非活动槽位标记为下一次启动的目标,重启后即完成切换。

关键点:A-B 分区不是把系统“复制一份”那么简单,而是让两个槽位在启动链路上完全对等,由 Bootloader 根据元数据决定从哪个槽位启动。

三、Slot元数据:谁来决定从哪个槽位启动

槽位的状态、优先级、重试次数等信息,统称为 slot 元数据。它通常保存在 misc 分区或专门的元数据分区中,由 Bootloader 和 Android 系统共同读写。核心字段包括:

字段 含义 典型取值
slot_suffix 当前活动槽位后缀 _a / _b
priority 槽位启动优先级 0~3,数值越大越优先
successful 该槽位是否已成功启动过 yes / no
tries_remaining 剩余启动尝试次数 整数,通常为 3~7
bootable 该槽位是否可启动 yes / no

Bootloader 启动时的判断逻辑大致如下:优先选择 priority 最高且 bootable=yes 的槽位;若该槽位启动失败,则递减 tries_remaining;当尝试次数耗尽仍失败时,将 successful 置为 no,并回退到另一个槽位。系统成功启动后,会将该槽位的 successful 置为 yes,并重置重试次数。

四、无缝升级的基本原理

无缝升级的完整流程可以概括为“后台写入—校验—切换—确认”四个阶段:

  1. 后台写入:系统在运行期间,把 OTA 包中的新镜像写入非活动槽位对应的分区。
  2. 校验:写入完成后,校验镜像哈希与签名,确保数据完整且来源可信。
  3. 切换:更新 slot 元数据,把非活动槽位的 priority 提高,并设置 tries_remaining,使其成为下一次启动目标。
  4. 确认:重启进入新槽位后,若系统正常启动,则把该槽位标记为 successful=yes;若启动失败,Bootloader 自动回退到旧槽位。

下面这张图展示了双槽位、元数据与启动切换之间的关系:

A-B 双槽位与 Slot 元数据启动切换 Bootloader Slot 元数据(misc / metadata) slot_suffix · priority · successful · tries_remaining · bootable Bootloader 依据元数据选择启动槽位 Slot A(活动槽位) boot_a · system_a · vendor_a dtbo_a · vbmeta_a priority = 3 · successful = yes tries_remaining = 0 · bootable = yes Slot B(非活动槽位) boot_b · system_b · vendor_b dtbo_b · vbmeta_b priority = 2 · successful = no tries_remaining = 3 · bootable = yes OTA 后台写入新镜像 切换:提升 Slot B priority → 重启

从图中可以看到,Slot A 当前是活动槽位,Slot B 是非活动槽位。OTA 在后台把新镜像写入 Slot B 后,元数据中 Slot B 的 priority 被提高,重启时 Bootloader 就会优先选择 Slot B。若 Slot B 启动成功,它成为新的活动槽位;若失败,则回退到 Slot A。

五、典型场景与常见误区

在实际项目中,A-B 分区最常见的应用场景包括:手机系统 OTA、Android TV 机顶盒升级、车载 IVI 系统升级等。这些场景的共同诉求是“升级不能影响用户使用,且必须能回滚”。

正确理解:A-B 分区解决的是“升级过程可用性”和“启动失败回滚”问题,它并不替代 Recovery 模式。部分设备仍保留 Recovery 用于恢复出厂设置或刷入完整包。
常见误区:
  • 误以为两个槽位必须完全一致。实际上非活动槽位可以是旧版本,也可以是新版本,取决于升级阶段。
  • 误以为切换槽位就是“复制数据”。切换只是修改元数据,真正的镜像写入在切换之前已完成。
  • 忽略 tries_remaining 的作用。若该值设置过小,新系统首次启动稍慢就可能被误判为失败而回滚。
  • 认为 A-B 分区可以无限回滚。一旦旧槽位被新镜像覆盖,回滚能力就取决于是否保留了可启动的旧版本。

六、小结