4、动态分区工具链:lpmake、lpadd、lpdump、lpunpack 命令详解
好,咱们今天来聊聊动态分区这套工具链。说实话,我刚接触 Android 动态分区那会儿,面对 lpmake、lpadd 这些命令,心里是有点懵的。它们不像 adb 那样天天用,但一旦你要做 OTA 或者定制系统,这些工具就是绕不开的坎。
我个人的习惯是,先把工具链分成两类:一类是打包工具(lpmake、lpadd),一类是分析工具(lpdump、lpunpack)。这样思路就清晰多了。你想想看,打包工具负责把零散的镜像文件组装成超级镜像,分析工具则负责从超级镜像里提取信息或者拆解出来。说白了,一个管“合”,一个管“拆”。
核心逻辑:动态分区工具链的核心就是围绕“超级镜像(super.img)”做文章。打包工具生成它,分析工具解析它。
4.1 lpmake:组装超级镜像的“总指挥”
lpmake 是这套工具链里我最常用的一个。它的任务很简单:把 system、vendor、product 这些分区镜像,按照你指定的布局,打包成一个 super.img。
我记得第一次用 lpmake 的时候,被它的参数列表吓了一跳。但其实核心参数就那么几个,我给大家梳理一下:
| 参数 | 说明 | 示例 |
|---|---|---|
-d / --device-size |
指定 super 分区总大小(字节) | -d 8g |
-p / --partition |
定义分区名称、大小、属性 | -p system:readonly:2g |
-i / --image |
指定分区对应的镜像文件 | -i system=system.img |
-o / --output |
输出文件路径 | -o super.img |
--metadata-size |
元数据预留空间(默认 64KB) | --metadata-size 65536 |
来看一个实际例子。假设我们要打包一个 8GB 的 super 分区,里面包含 system(2GB)、vendor(1GB)、product(1.5GB):
lpmake \
--device-size 8589934592 \
--metadata-size 65536 \
--metadata-slots 3 \
-p "system:readonly:2147483648" \
-p "vendor:readonly:1073741824" \
-p "product:readonly:1610612736" \
-i "system=out/system.img" \
-i "vendor=out/vendor.img" \
-i "product=out/product.img" \
-o super.img
小技巧:我习惯把 --metadata-slots 设为 3,这样即使一次 OTA 失败,还有备份的元数据可用。曾经有个项目因为只设了 2 个 slot,OTA 中途断电导致设备变砖,教训深刻啊。
4.2 lpadd:给超级镜像“加塞”
lpadd 这个工具,说实话,我用的频率比 lpmake 低不少。但它在某些场景下特别好用——比如你已经在用 lpmake 生成了 super.img,突然发现漏了一个分区,又不想重新跑一遍整个流程。
这时候 lpadd 就派上用场了。它可以在不重新打包的情况下,往已有的 super.img 里追加一个分区。
lpadd \
--partition "vendor_dlkm:readonly:524288000" \
--image vendor_dlkm.img \
super.img
嗯,这里要注意一点:lpadd 追加的分区大小不能超过 super 分区剩余的空间。我曾经犯过这个错,追加了一个过大的分区,结果 lpdump 一看,元数据里显示分区大小超了,设备根本起不来。
警告:lpadd 操作会直接修改原 super.img 文件。建议操作前先备份一份,免得手滑把整个镜像搞坏了。
4.3 lpdump:超级镜像的“CT 扫描仪”
lpdump 是我排查问题时的第一选择。它能解析 super.img 里的元数据,把分区布局、大小、属性等信息全部打印出来。说白了,就是让你看清楚这个超级镜像肚子里到底装了啥。
用法极其简单:
lpdump super.img
输出内容大致长这样:
Slot 0:
Partition system:
Size: 2147483648 bytes
Attributes: readonly
Extent 0: 2048..2097152 (linear)
Partition vendor:
Size: 1073741824 bytes
Attributes: readonly
Extent 0: 2097152..3145728 (linear)
Partition product:
Size: 1610612736 bytes
Attributes: readonly
Extent 0: 3145728..4718592 (linear)
Metadata version: 10.0
Metadata size: 65536 bytes
Metadata max size: 65536 bytes
看到那个 Extent 了吗?它表示分区在物理设备上的起始块和结束块。我遇到过一个问题:OTA 升级后分区大小对不上,一查 lpdump,发现 Extent 的起始地址重叠了。这就是典型的元数据损坏。
避坑指南:我曾经在调试 OTA 脚本时,发现升级后 system 分区挂载失败。用 lpdump 一查,原来 metadata-slots 里的某个 slot 的校验和不对。从那以后,我每次生成 super.img 后都会跑一遍 lpdump 做校验。
4.4 lpunpack:从超级镜像里“拆零件”
lpunpack 是 lpmake 的逆操作。它能把 super.img 里的各个分区镜像提取出来。这个工具在调试和逆向分析时特别有用。
比如你拿到一个设备的 super.img,想看看里面的 vendor 分区里有什么文件,就可以用 lpunpack 把它拆出来:
lpunpack super.img output_dir/
执行完后,output_dir 里就会出现 system.img、vendor.img、product.img 等文件。你可以像挂载普通镜像一样挂载它们:
sudo mount -o loop output_dir/vendor.img /mnt/vendor
我个人习惯在分析 OTA 包时,先用 lpunpack 把 payload 里的 super.img 拆开,然后对比新旧分区镜像的差异。这样能快速定位 OTA 脚本里哪些分区被修改了。
提示:lpunpack 默认提取所有分区。如果你只想提取某一个,可以用 --partition 参数指定,比如 lpunpack --partition vendor super.img output_dir/。
4.5 工具链的协作流程
最后,我给大家总结一下这四个工具在实际项目中的协作方式。你想想看,一个典型的 OTA 升级流程是这样的:
- 构建阶段:用 lpmake 把 system、vendor、product 等分区打包成 super.img。
- 验证阶段:用 lpdump 检查 super.img 的元数据是否正确。
- 调整阶段:如果发现漏了分区,用 lpadd 追加,再用 lpdump 确认。
- 调试阶段:从设备上拉取 super.img,用 lpunpack 拆解分析。
这套流程我用了好几年,基本没出过大的纰漏。当然,工具只是工具,关键还是得理解动态分区的底层逻辑。你把这些命令用熟了,再回头看 OTA 脚本,会发现一切都豁然开朗。
公众号:蓝海资料掘金营,微信deep3321