4、动态分区工具链:lpmake、lpadd、lpdump、lpunpack 命令详解

好,咱们今天来聊聊动态分区这套工具链。说实话,我刚接触 Android 动态分区那会儿,面对 lpmake、lpadd 这些命令,心里是有点懵的。它们不像 adb 那样天天用,但一旦你要做 OTA 或者定制系统,这些工具就是绕不开的坎。

我个人的习惯是,先把工具链分成两类:一类是打包工具(lpmake、lpadd),一类是分析工具(lpdump、lpunpack)。这样思路就清晰多了。你想想看,打包工具负责把零散的镜像文件组装成超级镜像,分析工具则负责从超级镜像里提取信息或者拆解出来。说白了,一个管“合”,一个管“拆”。

核心逻辑:动态分区工具链的核心就是围绕“超级镜像(super.img)”做文章。打包工具生成它,分析工具解析它。

动态分区工具链知识体系 超级镜像 (super.img) 打包工具 lpmake lpadd 分析工具 lpdump lpunpack lpmake:组装多个分区镜像为 super.img lpadd:向已有的 super.img 追加分区 lpdump:解析 super.img 的元数据 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 升级流程是这样的:

  1. 构建阶段:用 lpmake 把 system、vendor、product 等分区打包成 super.img。
  2. 验证阶段:用 lpdump 检查 super.img 的元数据是否正确。
  3. 调整阶段:如果发现漏了分区,用 lpadd 追加,再用 lpdump 确认。
  4. 调试阶段:从设备上拉取 super.img,用 lpunpack 拆解分析。

这套流程我用了好几年,基本没出过大的纰漏。当然,工具只是工具,关键还是得理解动态分区的底层逻辑。你把这些命令用熟了,再回头看 OTA 脚本,会发现一切都豁然开朗。


公众号:蓝海资料掘金营,微信deep3321