4. A-B分区系统架构

A-B 无缝升级并不是简单地把系统分区复制两份,而是由 bootloader、misc 分区、slot metadata 以及各 slot 内的 system/vendor/boot 等分区共同组成的一套“可切换、可回退、可校验”的启动体系。理解这套架构的关键,是分清“谁决定启动哪个 slot”“谁记录升级意图”“谁承载真正的系统内容”以及“谁在失败时兜底”。

一、核心角色分工

在 A-B 架构中,每个分区都有明确职责,不能混用。bootloader 是启动链的第一执行者,它读取 misc 分区和 slot metadata,决定本次从 A 还是 B 启动;misc 分区是跨 slot 共享的“通信信箱”,用于传递升级命令、重试次数和启动状态;slot metadata 则记录每个 slot 是否可启动、是否已成功、是否被标记为 active。system、vendor、boot、init_boot、dtbo 等分区则按 slot 成对存在,例如 system_a/system_b、vendor_a/vendor_b、boot_a/boot_b。

A-B 分区系统架构与启动决策链 Bootloader 读取 misc / metadata,决定启动 slot misc 分区 升级命令 / 重试计数 / 启动状态 跨 slot 共享,不参与 A/B 复制 slot metadata slot 可启动性 / 成功标记 / 优先级 记录 active、bootable、successful Slot A(当前运行) boot_a init_boot_a system_a vendor_a dtbo_a vbmeta_a 状态:active + successful Slot B(待升级 / 备用) boot_b init_boot_b system_b vendor_b dtbo_b vbmeta_b 状态:bootable,等待切换 切换

二、启动决策链:bootloader 如何选择 slot

设备上电后,bootloader 首先读取 misc 分区中的启动命令。如果 misc 中写入了“切换到 B”的指令,bootloader 会检查 slot B 的 metadata 是否标记为 bootable。若满足条件,则从 boot_b 加载内核,并挂载 system_b、vendor_b 等分区。启动过程中,Android 系统会通过 HAL 层向 bootloader 回写“启动成功”标记,将当前 slot 的 successful 置为 true。如果启动失败或超时,bootloader 会根据重试计数决定是否回退到原 slot。

关键规则:bootloader 只信任 misc 和 slot metadata 中的状态,不会自行猜测哪个 slot 更“新”。因此升级工具必须在写入新 slot 后,正确更新 metadata 和 misc,否则切换不会发生。

三、各分区在 A-B 中的具体角色

分区/组件 是否分 slot 核心职责 升级时是否写入
bootloader 否(通常单份) 启动决策、加载 kernel、校验 slot 状态 一般不随 A/B 升级更新
misc 否(共享) 传递升级命令、重试计数、启动状态 是,写入切换指令
slot metadata 否(共享) 记录 slot 可启动性、成功标记、优先级 是,更新 bootable/successful
boot / init_boot 是(_a / _b) 承载 kernel 与 ramdisk 是,写入非活动 slot
system 是(_a / _b) Android 框架与系统应用 是,写入非活动 slot
vendor 是(_a / _b) 厂商 HAL 与驱动 是,写入非活动 slot
dtbo / vbmeta 是(_a / _b) 设备树覆盖与验证启动元数据 是,写入非活动 slot

四、典型升级场景与状态流转

假设当前运行在 slot A,系统收到 OTA 包后,升级流程如下:

  1. OTA 客户端将新版本镜像写入 slot B 的 system_b、vendor_b、boot_b 等分区。
  2. 写入完成后,更新 slot metadata,将 slot B 标记为 bootable,并设置优先级高于 A。
  3. 向 misc 分区写入“切换到 B”的启动命令,并设置重试次数(例如 3 次)。
  4. 重启设备,bootloader 读取 misc 后选择从 slot B 启动。
  5. 若 slot B 启动成功,Android 将 slot B 标记为 successful,并清除 misc 中的切换命令。
  6. 若 slot B 启动失败,bootloader 在重试次数耗尽后自动回退到 slot A,保证设备可用。
# 查看当前 slot 与 metadata 状态(示例)
$ adb shell getprop ro.boot.slot_suffix
_a

$ adb shell cmd bootcontrol get-number-of-slots
2

$ adb shell cmd bootcontrol get-slot-info 0
slot=0, bootable=true, successful=true

$ adb shell cmd bootcontrol get-slot-info 1
slot=1, bootable=true, successful=false

五、常见误区与复盘要点

误区一:认为 system 和 vendor 必须同时切换。实际上 bootloader 只负责选择 slot,system 与 vendor 的 slot 后缀由系统启动时统一决定,二者必须保持一致,否则会出现 HAL 与框架版本不匹配。

误区二:忽略 misc 分区的写入时机。如果先写 misc 再写 system_b,重启后可能从 B 启动但系统不完整,导致启动失败。正确顺序是先完成所有 slot 镜像写入,再更新 metadata,最后写 misc。

误区三:把 slot metadata 当作普通文件。它通常由 bootloader 和 Android 的 bootcontrol HAL 共同维护,不能通过简单文件拷贝修改,必须使用 fastboot 或 bootcontrol 接口操作。

复盘建议:在调试 A-B 升级问题时,优先确认三件事——misc 中的命令是否正确、slot metadata 中目标 slot 是否 bootable、目标 slot 的 boot/system/vendor 是否完整写入。这三者构成启动决策的最小闭环,任何一环缺失都会导致切换失败或回退。

总体来看,A-B 分区架构的核心思想是“用空间换可靠性”:通过成对分区承载系统内容,通过 misc 和 metadata 记录状态与意图,通过 bootloader 执行切换与回退。只有理解每个组件在启动链中的位置和职责,才能在 OTA 开发、排障和定制中做出正确判断。