3. 分区基础概念
在 Android 系统分区与文件安全工程中,理解“分区”不能只停留在“磁盘被切成几块”的层面。Android 的分区体系同时受到存储介质、分区表格式、引导链、OTA 升级机制和文件系统挂载策略的共同约束。同一个术语在不同语境下可能指代不同层次的对象,因此必须先建立清晰的分层认知:物理分区描述介质上的实际区域,逻辑分区描述由分区表或映射机制暴露出来的可寻址单元,而 A/B 双分区、动态分区和 super 分区则属于 Android 为可靠升级与灵活布局引入的上层机制。
一、物理分区与逻辑分区:从介质到可寻址单元
物理分区是存储介质(eMMC、UFS、NVMe 等)上按 LBA 地址范围划分出的连续区域。它由分区表记录起始扇区和扇区数量,内核通过块设备节点(如 /dev/block/sda1、/dev/block/mmcblk0p1)暴露给上层。物理分区的边界一旦写入 GPT 或 MBR,就决定了该区域不能被其他分区直接占用。
逻辑分区则有两种常见含义。第一种是 MBR 扩展分区中的逻辑驱动器,用于突破 MBR 最多 4 个主分区的限制;第二种是 Android 动态分区体系中的逻辑分区,它们并不在 GPT 中各自占据独立条目,而是被封装在 super 物理分区内部,由 liblp 元数据和 dm-linear 设备映射动态创建。理解这一区别非常关键:前者是传统 PC 分区模型的产物,后者是 Android 10 以后为系统分区可调整大小而设计的机制。
二、GPT 分区表:Android 分区的骨架
GPT(GUID Partition Table)是现代 Android 设备的主流分区表格式。它位于磁盘开头,包含保护性 MBR、GPT 头、分区条目数组和备份 GPT。每个分区条目记录分区类型 GUID、唯一分区 GUID、起始 LBA、结束 LBA、属性标志和分区名。Android 设备通常还会在 GPT 中保留 misc、persist、modem、boot、recovery、system、vendor、userdata 等条目。
GPT 的优势在于支持超过 2TB 的磁盘、最多 128 个分区条目、分区名可读、具备 CRC32 校验和备份表。对于 Android 而言,GPT 还是引导链验证分区完整性的基础:bootloader 会按 GPT 中的分区名查找 boot、init_boot、vbmeta 等分区,再决定加载哪一路镜像。
# 查看 GPT 分区表(需 root 或 recovery 环境)
sgdisk -p /dev/block/sda
# 输出示例:
# Number Start (sector) End (sector) Size Code Name
# 1 2048 4095 1024.0 KiB EF02 gpt
# 2 4096 12287 4.0 MiB EF02 boot
# 3 12288 20479 4.0 MiB EF02 recovery
# 4 20480 262143 118.0 MiB EF02 super
# 5 262144 ... ... EF02 userdata
三、A/B 双分区:无缝升级与回滚的基础
A/B 双分区(Seamless Updates)为每个关键分区维护两份副本,分别标记为 slot A 和 slot B。设备当前运行的分区集合称为“活动槽位”,另一份则用于接收 OTA 更新。更新完成后,bootloader 通过 misc 分区中的 BCB(Bootloader Control Block)或 vbmeta 中的 slot 信息切换活动槽位,实现重启即生效,无需进入 recovery 长时间刷写。
A/B 分区的关键分区通常包括 boot_a/boot_b、init_boot_a/init_boot_b、system_a/system_b、vendor_a/vendor_b、vbmeta_a/vbmeta_b 等。用户数据分区 userdata 通常不参与 A/B,因为用户数据需要跨槽位共享。A/B 的代价是存储占用增加,因此 Android 10 之后引入动态分区来缓解固定大小分区带来的浪费。
四、动态分区与 super 分区:灵活布局的核心
动态分区(Dynamic Partitions)把 system、vendor、product、system_ext、odm 等分区从 GPT 中“搬进”一个名为 super 的物理分区。super 分区内部由 liblp 管理元数据,记录每个逻辑分区的名称、组、大小和块设备映射关系。系统启动时,init 通过 dm-linear 把这些逻辑分区映射为 /dev/block/dm-* 设备,再挂载到 /system、/vendor 等路径。
动态分区的最大价值在于:逻辑分区大小可以在 OTA 时按需调整,而不必重新划分 GPT。例如某次更新需要扩大 product 分区,只要 super 分区内还有未分配空间,就可以通过 lpmake 重新生成元数据并写入 super,无需改动 GPT 条目。super 分区本身的大小在出厂时确定,因此它决定了所有动态逻辑分区可分配空间的总上限。
# 查看 super 分区内的逻辑分区布局
lpdump /dev/block/by-name/super
# 输出示例:
# Slot 0:
# Metadata version: 10.0
# Partition: system_a
# Group: google_dynamic_partitions_a
# Size: 2147483648
# Partition: vendor_a
# Group: google_dynamic_partitions_a
# Size: 1073741824
# Partition: product_a
# Group: google_dynamic_partitions_a
# Size: 536870912
五、核心术语对比与常见误区
| 术语 | 所在层次 | 是否在 GPT 中有独立条目 | 典型设备节点 | 主要作用 |
|---|---|---|---|---|
| 物理分区 | 介质层 | 是 | /dev/block/sda1 | 直接划分存储区域 |
| 逻辑分区(MBR) | 分区表层 | 否(扩展分区内) | /dev/block/sda5 | 突破主分区数量限制 |
| GPT 分区表 | 分区表层 | — | — | 记录分区边界与属性 |
| A/B 双分区 | 升级机制层 | 是(成对出现) | /dev/block/by-name/boot_a | 无缝升级与回滚 |
| 动态分区 | 逻辑映射层 | 否(在 super 内) | /dev/block/dm-0 | 按需调整分区大小 |
| super 分区 | 物理分区层 | 是 | /dev/block/by-name/super | 承载动态逻辑分区 |
super 当成文件系统直接挂载。super 是物理分区,内部是 liblp 元数据和逻辑分区数据,不能直接 mount。误区二:认为 A/B 分区一定成对出现在 GPT 中。在动态分区设备上,system_a 和 system_b 是 super 内的逻辑分区,GPT 中只有 super 一个条目。误区三:认为动态分区可以无限扩大。super 分区总大小固定,所有逻辑分区之和不能超过 super 可用空间。六、场景复盘:一次 OTA 升级中的分区协作
假设设备当前运行 slot A,收到一次包含 system、vendor、product 更新的 OTA。升级流程大致如下:首先,OTA 客户端把新镜像写入 slot B 对应的逻辑分区;如果这些分区位于 super 内,则通过 lpmake 重新生成 super 元数据并写入 super 分区的 B 槽位区域。接着,vbmeta_b 被更新以记录新的哈希与签名。最后,misc 分区写入切换指令,重启后 bootloader 读取 BCB,将活动槽位切到 B,内核按新的 dm-linear 映射挂载 system_b、vendor_b 等。整个过程用户只感知到一次重启,旧槽位 A 仍保留,可用于回滚。
这个场景说明:物理分区提供存储边界,GPT 提供可发现的骨架,A/B 提供升级路径,动态分区和 super 提供灵活的空间分配。它们不是互相替代的关系,而是层层协作。排查分区问题时,也应按照“GPT 条目 → super 元数据 → dm 映射 → 文件系统挂载”的顺序逐层验证,才能快速定位是分区表损坏、元数据不一致,还是映射或挂载失败。