3、Android分区布局详解:boot、system、vendor、recovery、misc、cache等分区的功能与作用,以及动态分区和超级分区的概念
Android系统的分区布局是OTA升级的物理基础。无论是增量升级、整包升级还是A/B无缝升级,系统都需要精确地读写特定分区。如果对分区的作用、挂载点、大小限制和读写权限理解不透彻,轻则导致升级包制作失败,重则造成设备变砖。本章将逐一剖析传统分区与动态分区(Dynamic Partition)的核心差异,并深入讲解超级分区(Super Partition)在OTA中的实际意义。
3.1 传统物理分区的功能与作用
在Android 10之前的设备上,系统固件直接烧录到eMMC或UFS芯片的固定物理分区中。这些分区在出厂时由分区表(Partition Table)定义,大小固定,无法在运行时调整。理解这些分区是掌握动态分区的前提。
3.1.1 核心分区逐一解析
| 分区名 | 挂载点 | 文件系统 | 核心作用 | OTA相关特性 |
|---|---|---|---|---|
| boot | 无(直接引导) | 原始分区 | 存放Linux内核、ramdisk、dtb设备树 | 升级时需整体重写,损坏会导致无法开机 |
| system | /system | ext4/erofs | Android系统框架、核心应用、系统库 | 只读挂载,OTA时需卸载后写入 |
| vendor | /vendor | ext4/erofs | 硬件抽象层(HAL)、厂商驱动、SoC相关库 | 与system分离,便于厂商独立升级 |
| recovery | /recovery | 原始分区 | 独立的恢复系统内核和ramdisk | 用于执行OTA脚本、工厂重置 |
| misc | 无 | 原始分区 | 存储bootloader与recovery的通信信息 | 记录升级命令、启动原因(如BCB) |
| cache | /cache | ext4 | 系统缓存、OTA包暂存、日志 | 升级前需清空,空间不足会导致升级失败 |
| userdata | /data | f2fs/ext4 | 用户应用数据、设置、媒体文件 | OTA通常不触碰,但factory reset会格式化 |
以 boot分区 为例,它包含的ramdisk中存放了init进程和first_stage_mount等关键文件。在OTA升级时,如果boot分区写入不完整,设备将无法进入系统,只能进入fastboot或recovery模式重新刷写。而 misc分区 虽然只有几KB大小,却承载着Bootloader Control Block(BCB)信息,recovery模式通过读取misc分区来判断是执行正常启动还是进入升级流程。
3.1.2 传统分区的局限性
传统分区最大的问题在于空间利用率低。例如,某设备system分区分配了3GB,但实际固件只有2.2GB,剩余的800MB无法被其他分区使用。当system分区需要扩容时,必须修改分区表并重新烧录整个存储芯片,这在OTA场景下几乎不可行。此外,多个物理分区(system、vendor、product)各自独立,升级时需要对每个分区分别写入,增加了升级包制作和校验的复杂度。
3.2 动态分区与超级分区(Super Partition)
Android 10引入了动态分区机制,将多个物理分区合并为一个名为 super 的容器分区。在super内部,system、vendor、product、odm等不再是物理分区,而是由内核设备映射器(Device Mapper)管理的逻辑卷。这种设计借鉴了Linux LVM(逻辑卷管理)的思想,实现了分区大小的动态调整。
3.2.1 超级分区的内部结构
super分区本身是一个物理分区,其内部包含一个元数据区域(Metadata)和多个逻辑卷。元数据记录了每个逻辑卷的名称、大小、起始偏移和校验信息。在系统启动时,init进程通过 first_stage_mount 读取super元数据,动态创建设备映射节点(如 /dev/block/mapper/system),然后挂载这些逻辑卷。
# 查看动态分区信息的典型命令(adb shell)
# 列出所有块设备
ls -l /dev/block/by-name/
# 查看super分区详情
sgdisk -p /dev/block/sda # 假设super位于sda
# 查看逻辑卷映射
dmsetup table
# 查看当前挂载情况
mount | grep -E "system|vendor|product"
动态分区带来的核心优势包括:
- 空间弹性:system分区不够用时,可以从super中未分配的空间扩展,无需修改物理分区表。
- 升级原子性:OTA时只需更新super内部的逻辑卷,配合A/B槽位可实现无缝升级。
- 简化分区表:物理分区数量从7-8个减少到4-5个(boot、super、recovery、misc、userdata等),降低bootloader复杂度。
3.2.2 动态分区与OTA的配合
在动态分区设备上,OTA升级包中的system.img、vendor.img等不再是直接写入物理分区的镜像,而是包含逻辑卷大小和内容的描述文件。升级脚本(updater-script)会调用 update_dynamic_partitions 函数,先调整逻辑卷大小,再写入新数据。整个过程在super分区的空闲空间内完成,即使写入失败,也不会影响当前系统的运行。
lpdump 工具可以查看super分区的空间使用情况。
3.3 分区布局对OTA升级的影响分析
不同的分区布局直接决定了OTA升级的策略和成功率。以下从三个维度进行对比:
| 对比维度 | 传统分区(Android 9及以下) | 动态分区(Android 10+) |
|---|---|---|
| 升级包大小 | 需包含完整分区镜像,包体较大 | 可只包含差异数据,包体更小 |
| 升级失败恢复 | 依赖recovery模式重新刷写 | 配合A/B槽位,可自动回滚 |
| 空间利用率 | 低,存在大量碎片 | 高,逻辑卷可动态调整 |
| 升级脚本复杂度 | 简单,直接写入固定分区 | 复杂,需处理逻辑卷调整 |
| 对bootloader要求 | 低,只需支持分区表 | 高,需支持super元数据解析 |
3.3.1 案例拆解:动态分区设备OTA失败排查
背景:某款Android 11设备在推送OTA升级时,部分用户反馈升级进度条到40%左右失败,设备重启后仍停留在旧版本。
初步排查:查看 /cache/recovery/last_log 日志,发现以下关键信息:
I:Update dynamic partitions...
E:Failed to resize logical volume "system" to 2147483648 bytes
E:Not enough free space in super partition
分析判断:super分区总大小为6GB,原有逻辑卷(system 2.5GB + vendor 1GB + product 1.5GB)已占用5GB,仅剩1GB空闲。新版本system需要扩展到2.2GB,需要额外200MB,但super中已无足够空间。
解决方案:与产品团队协商后,决定将product逻辑卷从1.5GB压缩到1.2GB,释放300MB空间。修改OTA包中的动态分区配置,重新生成升级包并推送。
结果与复盘:升级成功率恢复到99.7%。此次问题暴露了动态分区空间规划的重要性——在项目初期就应预留20%的super分区冗余空间,并建立逻辑卷大小变更的评审机制。
3.4 常见误区与最佳实践
在实际开发和OTA运维中,以下误区需要特别注意:
误区二:在OTA脚本中直接使用
mount /dev/block/by-name/system。动态分区设备上该路径不存在,必须使用 /dev/block/mapper/system 或通过 update_dynamic_partitions 处理。误区三:忽略misc分区的BCB信息。如果升级过程中断电,misc分区中的BCB会标记升级未完成,下次启动时recovery会重新尝试或回滚。
3.4.1 分区规划最佳实践清单
- 预留空间:super分区总大小应比所有逻辑卷总和多15%-20%,以应对未来版本增长。
- 监控使用率:在CI/CD流程中加入super分区空间检查,当使用率超过85%时触发告警。
- 统一命名:逻辑卷名称必须与
fstab中的挂载点严格对应,避免大小写或下划线不一致。 - 测试覆盖:在OTA测试矩阵中必须包含“super空间不足”的负向用例,验证升级脚本能正确报错并回滚。
- 备份元数据:在bootloader中保存super元数据的备份副本,防止元数据损坏导致无法挂载任何逻辑卷。
总结而言,Android分区布局从传统物理分区演进到动态分区,本质上是为OTA升级的可靠性、灵活性和空间效率服务的。理解每个分区的职责、动态分区的映射机制以及super分区的容量约束,是设计稳定OTA方案的基础。在实际项目中,建议使用 lpdump、sgdisk 和 dmsetup 等工具定期检查分区状态,并建立分区空间使用的自动化监控体系。