9、动态分区与Logical Volume:super分区概念、lpmake与lpdump工具、动态分区映射表、在OTA中处理动态分区
各位同学,今天我们来聊聊动态分区。说实话,这个知识点在车载OTA里属于「你绕不过去」的那种。我最早接触动态分区是在做某个车机项目时,客户要求系统分区能灵活调整大小,传统静态分区根本玩不转。嗯,那会儿我花了整整一周才把整套逻辑吃透。今天我把这些经验掰开揉碎讲给你听。
9.1 为什么需要动态分区?
传统Android分区是静态的——system、vendor、product这些分区在编译时就把大小定死了。你想想看,如果某次OTA需要增大system分区,但隔壁vendor还有空闲空间,怎么办?静态分区下只能干瞪眼。
动态分区的核心思路很简单:把物理分区抽象成逻辑卷。说白了,就是用一个「超级分区」(super分区)来管理所有系统分区的物理空间,各个逻辑分区(logical volume)按需从super里分配空间。
核心概念:super分区是一个物理分区,里面包含了多个逻辑分区(如system_a、vendor_a、product_a)。逻辑分区的大小可以动态调整,只要super分区总空间够用就行。
9.2 super分区长什么样?
super分区本质上是一个容器。它的布局分为三部分:
- 头部(Header):记录super分区的版本、总大小、逻辑分区数量等信息
- 几何描述(Geometry):描述super分区的物理布局,包括槽位信息
- 逻辑分区表(Logical Partition Table):记录每个逻辑分区的名称、大小、起始偏移等
我习惯把super分区比作一个「硬盘柜」——柜子本身有固定尺寸,但里面的抽屉(逻辑分区)可以自由调整大小。每个抽屉都有标签(分区名),比如system_a、vendor_b。
个人经验:super分区的大小通常在4GB到8GB之间,具体取决于你的系统镜像有多大。我在一个项目中遇到过super分区设小了,导致OTA时空间不足,最后不得不重新刷机。所以,super分区大小一定要留够余量,建议至少比所有逻辑分区总和多出20%。
9.3 lpmake:创建动态分区的瑞士军刀
lpmake是Android提供的工具,用来生成super分区的镜像。它的工作流程是这样的:
- 定义所有逻辑分区的名称、大小、属性
- 指定super分区的总大小和槽位数量
- lpmake把这些信息打包成一个完整的super.img
来看一个实际例子:
# 创建一个super分区镜像
lpmake \
--metadata-size 65536 \
--super-name super \
--metadata-slots 2 \
--device super:4294967296 \
--group main_a:2147483648 \
--group main_b:2147483648 \
--partition system_a:readonly:1073741824:main_a \
--partition vendor_a:readonly:536870912:main_a \
--partition product_a:readonly:536870912:main_a \
--partition system_b:readonly:1073741824:main_b \
--partition vendor_b:readonly:536870912:main_b \
--partition product_b:readonly:536870912:main_b \
--sparse \
--output super.img
这里我解释几个关键参数:
--metadata-slots 2:表示有两个槽位(A/B分区),每个槽位都有自己的元数据--group:定义分区组,同一个组内的逻辑分区共享空间--partition:定义具体的逻辑分区,格式是「名称:属性:大小:所属组」--sparse:生成稀疏镜像,减少镜像文件大小
注意:lpmake生成的super.img是稀疏格式的,烧录到设备时需要先解稀疏。我曾经犯过一个低级错误——直接把稀疏镜像dd到super分区,结果设备起不来。嗯,后来我学乖了,每次都用simg2img先转换。
9.4 lpdump:查看动态分区的「CT扫描仪」
lpdump用来解析super分区里的元数据,把逻辑分区的布局信息dump出来。这个工具在调试时特别有用。
# 从super.img中读取元数据
lpdump --slot 0 super.img
# 从设备上直接读取
adb shell lpdump --slot 0 /dev/block/by-name/super
输出结果大概长这样:
Slot 0:
Name: system_a
Group: main_a
Size: 1073741824 bytes (1024 MB)
Extents:
0: 0..2097151 (linear, 2097152 sectors)
Name: vendor_a
Group: main_a
Size: 536870912 bytes (512 MB)
Extents:
0: 2097152..3145727 (linear, 1048576 sectors)
Name: product_a
Group: main_a
Size: 536870912 bytes (512 MB)
Extents:
0: 3145728..4194303 (linear, 1048576 sectors)
看到那个Extents了吗?它表示逻辑分区在super分区里的物理位置。比如system_a从第0个扇区开始,占了2097152个扇区(每个扇区512字节)。
避坑指南:我曾经在调试时发现lpdump输出的分区大小和实际不符,后来发现是metadata-slots参数设错了。如果你看到分区大小异常,先检查metadata-slots是不是和实际槽位数一致。
9.5 动态分区映射表:内核怎么找到逻辑分区?
设备启动时,内核需要知道每个逻辑分区在super分区里的位置。这个映射关系是通过设备映射器(Device Mapper)实现的。
流程是这样的:
- Bootloader读取super分区的元数据
- 根据元数据创建dm-linear设备映射
- 每个逻辑分区对应一个dm-linear设备,比如system_a映射到/dev/dm-0
- 内核通过这些dm设备访问逻辑分区
用命令查看映射表:
# 查看所有dm设备
adb shell ls -la /dev/block/dm-*
# 查看具体映射关系
adb shell dmsetup table system_a
输出示例:
0 2097152 linear 259:0 0
这表示:从扇区0开始,共2097152个扇区,映射到主设备号259、次设备号0的设备(也就是super分区),偏移为0。
9.6 OTA中如何处理动态分区?
OTA升级时,动态分区的处理比静态分区复杂得多。核心问题有两个:
- 空间分配:新版本的分区大小可能变了,需要重新分配空间
- 数据迁移:如果分区位置变了,需要把数据搬到新位置
Android的OTA机制通过update_engine来处理这些。大致流程如下:
- 解析OTA包中的新super分区布局
- 检查当前super分区是否有足够空间
- 如果有,直接调整逻辑分区大小(通过lpresize工具)
- 如果没有,需要先合并或压缩现有分区
- 写入新数据到对应的逻辑分区
这里有个关键点:动态分区支持在线调整大小。也就是说,系统运行时也能改分区大小,不需要重启。但要注意,调整大小期间不能读写该分区。
实战经验:我在做某个OTA方案时,遇到一个坑——新版本的vendor分区比旧版本大了200MB,但super分区里没有连续空间了。解决方案是:先把product分区缩小200MB,腾出空间给vendor。这个操作需要保证product分区里的数据不丢失,嗯,当时我用了lpresize的--shrink选项,配合文件系统resize,折腾了两天才搞定。
9.7 动态分区操作的核心命令
总结一下常用的动态分区操作命令:
| 命令 | 用途 | 示例 |
|---|---|---|
| lpmake | 创建super分区镜像 | lpmake --device super:4G --group main:2G --partition system:1G:main |
| lpdump | 查看super分区元数据 | lpdump --slot 0 super.img |
| lpresize | 调整逻辑分区大小 | lpresize --size 2G /dev/block/by-name/system_a |
| lpadd | 添加逻辑分区 | lpadd --partition test:1G /dev/block/by-name/super |
| lpremove | 删除逻辑分区 | lpremove test /dev/block/by-name/super |
重要提醒:lpresize、lpadd、lpremove这些操作都有风险,操作前一定要备份数据。我见过有人直接在量产设备上执行lpresize,结果分区表损坏,设备变砖。所以,永远不要在未测试的环境下执行这些命令。
9.8 动态分区架构图
下面这张图展示了动态分区的整体架构,从super分区到逻辑分区的映射关系一目了然:
从这张图可以清楚看到:super分区是物理载体,里面包含元数据和多个逻辑分区。设备映射器负责把逻辑分区映射成内核可见的dm块设备。这样,上层文件系统就能像访问普通分区一样访问逻辑分区了。
9.9 小结
动态分区是Android车载系统OTA的核心技术之一。说白了,它解决了传统静态分区「空间无法灵活调整」的痛点。你需要掌握:
- super分区的结构和布局
- lpmake和lpdump的使用方法
- 设备映射器的工作原理
- OTA中动态分区的处理流程
我个人觉得,动态分区最难的不是概念,而是实际调试。尤其是分区大小调整时,一不小心就会搞坏分区表。我的建议是:先在模拟器上反复练习lpmake和lpresize的操作,等完全熟练了再上真机。
好了,动态分区的内容就讲到这里。记住一句话:super分区是容器,逻辑分区是抽屉,设备映射器是钥匙。搞懂这三者的关系,动态分区你就掌握了八成。