1. 课程导入

在Android系统十多年的演进过程中,分区布局始终是系统启动、升级与安全机制的基础设施。从早期固定分区,到A/B无缝升级,再到动态分区与Virtual A-B,每一次变化都源于同一个矛盾:系统镜像越来越多、越来越大,而设备存储空间和升级体验要求却越来越苛刻。理解这条演进主线,是掌握动态分区与Virtual A-B工程实践的前提。

一、Android分区演进背景

早期Android设备采用固定分区方案,system、vendor、product、odm等分区在编译时确定大小,烧录后无法调整。这种方案实现简单,但带来三个明显问题:

  • 空间浪费与不足并存:某个分区预留过大则浪费,预留过小则无法容纳新版本镜像。
  • 升级依赖Recovery:OTA升级需要进入Recovery模式,升级期间设备不可用,失败还可能变砖。
  • 分区数量膨胀:随着Treble、模块化、GKI等机制引入,分区数量持续增加,固定布局难以维护。

为解决升级体验问题,Android 7.0引入A/B(Seamless Update)方案:设备拥有两套完整分区槽位(slot A与slot B),系统在后台向非活动槽写入新版本,重启后切换槽位完成升级,失败可自动回滚。A/B显著提升了升级可靠性,但代价是存储开销接近翻倍,且分区大小依然固定。

Android 10引入动态分区(Dynamic Partitions),将system、vendor、product等分区从固定分区改为逻辑分区,统一放入super物理分区中,由liblp元数据描述布局,运行时通过dm-linear映射为块设备。分区大小可在OTA时动态调整,不再受编译期固定尺寸限制。

Android 10之后,Google进一步提出Virtual A-B:在动态分区基础上,通过快照(snapshot)与COW(Copy-on-Write)机制,让单个super分区同时承载两个逻辑槽位,实现“无需双倍物理空间”的A/B升级体验。它把A/B的可靠性与动态分区的灵活性结合到了一起。

二、动态分区与Virtual A-B的核心价值

动态分区与Virtual A-B并非简单的“分区格式变化”,而是对Android升级模型的重构。其核心价值可归纳为四点:

价值维度 传统固定分区 动态分区 + Virtual A-B
空间利用率 各分区独立预留,易浪费 共享super空间,按需分配
升级方式 Recovery或整槽写入 后台快照写入,重启切换
回滚能力 依赖备份,回滚困难 COW保留原数据,可快速回滚
分区调整 编译期固定,无法变更 OTA时动态resize

一句话理解:动态分区解决“分区大小不能变”的问题,Virtual A-B解决“A/B升级太占空间”的问题,两者结合构成现代Android无缝升级的底座。

三、整体框架与关键对象

本课程围绕“从物理分区到逻辑分区,再到虚拟槽位”的主线展开。下图展示了动态分区与Virtual A-B的整体结构关系:

动态分区与 Virtual A-B 整体结构 物理存储层 boot / init_boot vbmeta / dtbo super(物理分区) 逻辑分区层(liblp 元数据 + dm-linear) system vendor product odm / system_ext 分区大小由 super 剩余空间动态决定,OTA 时可 resize Virtual A-B 虚拟槽位层(snapshot + COW) Slot A(当前活动) 读取原始逻辑分区数据 Slot B(升级目标) 写入 COW 快照,不覆盖原数据 COW 快照

从图中可以看到三层结构:最底层是物理存储,super分区承载所有动态逻辑分区;中间层是逻辑分区,由liblp元数据描述并通过dm-linear映射;最上层是Virtual A-B虚拟槽位,通过快照与COW实现单份物理数据支撑双槽位升级。

四、学习目标与常见误区

通过本课程,学习者应达到以下目标:

  1. 理解Android分区从固定到动态、从A/B到Virtual A-B的演进逻辑与驱动力。
  2. 掌握super分区、liblp元数据、dm-linear映射的基本原理与查看方法。
  3. 掌握Virtual A-B中snapshot、COW、slot切换、回滚的关键流程。
  4. 能够使用lpdump、dmctl、snapshotctl等工具进行调试与排障。
  5. 理解OTA包中动态分区与Virtual A-B相关配置的工程落地方式。

调试入口示例:在设备上可通过以下命令快速查看动态分区布局与快照状态。

adb shell lpdump
adb shell dmctl list devices
adb shell snapshotctl dump
adb shell getprop ro.boot.slot_suffix

常见误区一:把动态分区等同于“分区可以随便改”。实际上动态分区仍受super总容量约束,且元数据布局需要与bootloader、OTA包保持一致,随意修改可能导致设备无法启动。

常见误区二:认为Virtual A-B就是传统A/B。传统A/B需要两套完整物理分区,而Virtual A-B通过COW快照共享原始数据,只有被修改的块才会写入快照,空间占用显著降低。

常见误区三:忽略slot元数据与super元数据的对应关系。Virtual A-B的槽位信息、快照状态、COW设备路径都需要在liblp元数据与内核dm设备之间保持一致,排障时应同时检查两侧状态。