news 2026/10/28 10:43:51

IM安卓开发工具箱:ROM备份、动态分区与fastboot刷写链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
IM安卓开发工具箱:ROM备份、动态分区与fastboot刷写链路

简介:IM安卓开发工具箱imakit 9.13面向Android ROM开发者、刷机包制作者与系统定制爱好者,聚焦img镜像备份、刷机包制作、脚本自动化及img/dat/br格式互转等任务,可用于设备系统调整前的状态备份、批量处理与跨设备包格式适配。压缩包共283个文件,约18.26MB,包含h头文件、exe可执行工具、pyd扩展模块、c源码、dll库、py脚本及dat数据文件等,既有可直接调用的工具程序,也保留了底层源码与脚本接口,便于理解流程和二次改造。该资源已有4222人学习下载,适合需要一套完整工具链来完成ROM备份、刷机包生成与格式转换的开发者参考,也可作为排查镜像处理和脚本执行问题的实践素材。

1. IM安卓开发工具箱到底装了什么:从一份 ROM 备份说起

手里这台机器刷完第三方安卓 ROM 后,指纹失灵、基带丢失,售后要等两周,而我只有一个下午。翻出放在硬盘角落的 IM安卓开发工具箱,才把 boot、vendor、super 三个分区从半砖状态里捞回来——那一刻起,我对"ROM 备份"这四个字的理解从"复制个文件夹"变成了"要先知道自己在备份哪块物理区块"。这套工具箱的定位很明确:把安卓 ROM 的拆、备、改、回四条链路塞进一个可离线运行的目录,适合需要反复刷机验证的安卓端开发者,以及维护多台测试机的同学。它不是一键救砖软件,更像一把手术刀,用之前必须清楚分区表和槽位。

2. 环境与分区基础:为什么 ROM 备份不是"复制个文件夹"

很多人第一次做 ROM 备份,会打开文件管理器把/sdcard拖到电脑上,然后声称"我备份好了"。等真出事才发现,系统镜像住在/dev/block/by-name/下面,跟用户可见的存储完全是两套东西。这套工具箱的第一个门槛就在这里:它要求你对块设备、分区表、动态分区有基本概念,否则后面的 dd 命令跑起来只是在制造更大的麻烦。

2.1 工具链跑起来的最低环境

工具箱解压后目录大致分三块:宿主机侧的命令行工具(adb、fastboot、镜像解包器)、设备侧的临时脚本、以及一份记录分区布局的配置模板。宿主机这套东西对环境有硬性要求,版本太旧会出现协议不兼容,比如老版本 fastboot 刷动态分区时会报Sending sparse 'super' failed这类错误。

常见做法是固定一套版本组合,不要跟着系统包管理器升级:

组件建议版本口径用途版本不匹配的典型症状
adb / fastboot与设备 SDK 同代设备通信、分区刷写传输大文件中途断开、稀疏镜像识别失败
镜像解包器支持当前 boot 头格式拆 boot.img / vendor_boot.img解包后 kernel 段为空
payload 提取脚本支持全量 OTA 元数据从 OTA 包取分区镜像报不支持的 op 类型
lpunpack / lpmake与设备动态分区版本一致拆合 super.img回包后设备不进系统
校验工具系统自带 sha256sum备份完整性核对还原后校验失败但刷写成功

装完之后先做连通性验证,这一步别省:

# 确认设备被识别,且处于正常系统而非 fastboot 模式 adb devices -l # 查看设备分区布局,确认 by-name 映射存在 adb shell ls -l /dev/block/by-name/ | head -n 20 # 确认是否 A/B 双槽设备,输出 a 或 b 才是双槽 adb shell getprop ro.boot.slot_suffix

第一行adb devices -l输出里如果只有一串序列号加device状态,说明授权已经通过;出现unauthorized就在设备屏幕上点允许,出现offline一般是数据线或驱动问题,换根线比反复重装驱动有效。第二行的by-name目录是整篇文章的地基,安卓从 8.0 之后越来越多设备依赖它做分区寻址,/dev/block/by-name/boot这类路径本质是软链,指向真实的mmcblk0pXX或sdaXX。第三行的slot_suffix决定了你后面所有命令要不要带_a/_b后缀,带错槽位是还原失败的头号原因。

需要提醒的是,工具箱里的设备侧脚本依赖 root 权限。没有 root 的设备只能做读取类操作,凡是涉及dd写块设备、挂载super分区、修改vbmeta的步骤都会失败,而且失败信息往往很含糊,只报Permission denied而不说缺什么。我一般会先跑一条最小验证:

# 验证 root 是否真的可用(不是 su 存在,而是 su 能提权成功) adb shell su -c 'id' # 期望输出包含 uid=0(root)

如果这条命令卡住或者返回普通用户 uid,后面的备份流程直接停,别硬试。

2.2 分区表怎么读:从 /proc/partitions 到 by-name 映射

理解分区表是这套工具箱最值钱的部分。安卓设备的存储布局分三层:最底层是 eMMC/UFS 的物理块设备,中间是 GPT 分区表,最上层是 by-name 软链和动态分区。备份出错十有八九是搞错了层。

先看物理层:

# 列出所有块设备与分区,单位是 1K 块 adb shell su -c 'cat /proc/partitions' # 看某个分区的精确字节数,比 /proc/partitions 更准 adb shell su -c 'blockdev --getsize64 /dev/block/by-name/boot_a'

/proc/partitions的输出里,major和minor是内核设备号,#blocks是 1K 块数量,最后一列才是名字。真正有用的是把名字和 by-name 对上,因为不同厂商给同一功能分区起的物理名完全不同,只有 by-name 这层是标准化的。第二行的blockdev --getsize64返回字节数,这个数字要记下来,它是后面校验备份是否完整的基准——如果 dd 出来的文件比它小,说明备份被截断了。

再往下是槽位和分区属性的判断:

# 查看当前活动槽位与是否支持无缝更新 adb shell getprop ro.boot.slot_suffix adb shell getprop ro.build.ab_update # 查看 dm-verity / AVB 状态,决定了你能不能直接改分区内容 adb shell getprop ro.boot.veritymode adb shell getprop ro.boot.vbmeta.device_state

ro.build.ab_update为true说明是 A/B 双槽,备份时两个槽的 boot、dtbo、vbmeta 都要各存一份,不能只存当前槽。ro.boot.veritymode通常是enforcing,意思是 dm-verity 在强制校验,你往 system 分区里塞任何东西都会导致校验失败进而无法开机,这时候要么改vbmeta关掉校验,要么走修补 boot 的路子绕开。这套判断逻辑在工具箱的配置模板里有一份默认值,但我不建议直接信模板,设备型号一换就得重读。

2.3 动态分区与 super.img:备份对象到底是谁

从安卓 10 开始,system、vendor、product 这些分区不再各自占用独立的物理分区,而是被打包进一个叫super的大分区里,内部用 LP 元数据切分。这是 ROM 备份最容易翻车的地方:你在 by-name 里看到的system_a其实是个逻辑分区,直接 dd 它可能拿到空数据,因为真实数据在super里面。

判断方法很直接:

# 看 system 是不是独立块设备,还是 dm 映射出来的逻辑卷 adb shell su -c 'ls -l /dev/block/by-name/system_a' # 如果指向 /dev/block/dm-N,说明是动态分区内的逻辑卷 # 查看 super 分区本身的大小 adb shell su -c 'blockdev --getsize64 /dev/block/by-name/super'

第一行如果软链指向/dev/block/dm-0这类设备,就确认了它是 device-mapper 映射出来的逻辑卷,备份它等于备份一个正在被内核管理的内存视图,数据一致性没有保证。正确的备份对象是整个super分区。第二行返回的字节数通常在两到四 GB 之间,具体取决于设备,这个值在回包重建时必须原样对上,否则fastboot flash super会直接报空间不足。

理解了这三点,工具箱后面的所有操作才有意义。我见过太多人拿着 dd 命令乱跑,备份出来一堆十几 KB 的废文件,还以为是自己命令写错了,其实是备份了一个被 dm 映射的空壳。

3. 备份与还原的实操链路:adb、dd 与镜像校验

这套工具箱真正高频使用的功能是备份和还原。它的设计思路是把每个分区当成一个独立的二进制对象来处理,备份产出的是裸镜像文件,还原时按分区原样写回。这种做法的好处是可复现、可校验,坏处是对操作精度要求极高——写错分区名、写错槽位、漏掉元数据,任何一个都会让设备停在开机动画。

3.1 全量分区备份:dd 命令与块大小参数

先建目录再备份,别把文件堆在/sdcard根目录,后面拉取的时候会很痛苦。

# 在设备上建立备份目录 adb shell su -c 'mkdir -p /sdcard/rombackup' # 备份 boot 分区(单槽设备) adb shell su -c 'dd if=/dev/block/by-name/boot of=/sdcard/rombackup/boot.img bs=1048576 conv=fsync' # 备份 boot 分区(双槽设备,两个槽都要) adb shell su -c 'dd if=/dev/block/by-name/boot_a of=/sdcard/rombackup/boot_a.img bs=1048576 conv=fsync' adb shell su -c 'dd if=/dev/block/by-name/boot_b of=/sdcard/rombackup/boot_b.img bs=1048576 conv=fsync'

if是输入,of是输出,bs=1048576表示每次读写 1 MB,这个值不能随便设。设太小(比如默认 512 字节)会导致备份一个几十 MB 的 boot 分区要跑几分钟;设太大(比如 64 MB)在小内存设备上可能触发 OOM 被系统杀掉,表现为 dd 进程无声消失、文件只有几百 KB。1 MB 到 4 MB 之间是比较稳的区间。conv=fsync是关键参数,它要求 dd 在结束前把数据真正刷到磁盘,没有这个参数的话,命令返回成功但文件可能还在页缓存里,你立刻adb pull会拿到一个不完整的镜像。这个坑我踩过一次,备份的 super.img 比实际小了 200 MB,还原时才发现。

super 分区和 userdata 分区的备份单独说,因为它们体积大:

# 备份 super 分区,耗时较长,建议前台执行并观察进度 adb shell su -c 'dd if=/dev/block/by-name/super of=/sdcard/rombackup/super.img bs=4194304 conv=fsync' # 备份 metadata 分区(FBE 加密元数据,换机还原必需) adb shell su -c 'dd if=/dev/block/by-name/metadata of=/sdcard/rombackup/metadata.img bs=1048576 conv=fsync'

metadata分区经常被忽略,它存的是文件级加密(FBE)的密钥材料。如果你备份了 userdata 却没备份 metadata,还原到同一台设备上大概率还能开机,但一旦涉及恢复出厂或者跨设备,数据就永远解不开了。这个分区的体积通常只有几 MB,备份成本极低,没有理由不存。

拉回本地:

# 一次性拉取整个备份目录,-p 显示进度 adb pull /sdcard/rombackup ./rombackup_local

3.2 分区镜像的完整性校验与元数据记录

备份完不校验,等于没备份。工具箱里带了一份校验脚本的思路,核心是两头比对:设备侧算一次哈希,本地算一次哈希,两者必须一致。

# 设备侧对备份文件算 sha256 adb shell su -c 'sha256sum /sdcard/rombackup/*.img' # 拉回本地后再算一次,两份输出逐行比对 sha256sum ./rombackup_local/*.img

注意这里是对备份出来的文件算哈希,不是对块设备算。对块设备算哈希会读取整个物理分区包括未使用区域,速度慢且没有必要,因为未使用区域的内容在不同次读取之间可能不一致。对文件算就能保证"我拉回来的这份字节流,和设备上生成的那份字节流完全相同"。

光有哈希还不够,分区大小和槽位信息必须一起记录,否则半年后你打开这个目录根本想不起来这是哪台机器的:

# 生成一份备份清单,记录每个分区的字节数与来源设备 adb shell su -c ' for p in boot_a boot_b super metadata vbmeta_a vbmeta_b; do size=$(blockdev --getsize64 /dev/block/by-name/$p 2>/dev/null) echo "$p $size" done' > ./rombackup_local/partition_sizes.txt # 记录设备指纹与系统版本 adb shell getprop ro.product.device >> ./rombackup_local/device_info.txt adb shell getprop ro.build.display.id >> ./rombackup_local/device_info.txt adb shell getprop ro.boot.slot_suffix >> ./rombackup_local/device_info.txt

这段脚本用blockdev拿每个分区的真实字节数,写进一个纯文本清单。后面还原时拿备份文件大小和清单里的数字对一下,差一个字节都说明备份过程出过问题。第二段把设备代号、系统版本号、当前槽位追加到信息文件里——设备代号尤其重要,不同代号的分区布局可能完全不同,拿 A 机型的 boot 刷到 B 机型上,轻则不开机重则变砖。

3.3 还原路径:fastboot flash 与 dd 回写的边界

还原有两条路:走 fastboot 在 bootloader 层刷,或者走 adb 在系统内 dd 回写。两者的适用场景完全不同,混用会出问题。

fastboot 路径适合刷 boot、dtbo、vbmeta 这类小分区:

# 进入 bootloader adb reboot bootloader # 确认设备连接正常 fastboot devices # 刷入 boot 分区,注意槽位后缀 fastboot flash boot_a ./rombackup_local/boot_a.img fastboot flash boot_b ./rombackup_local/boot_b.img # vbmeta 必须跟着刷,否则 AVB 校验不过 fastboot flash vbmeta_a ./rombackup_local/vbmeta_a.img fastboot --disable-verity --disable-verification flash vbmeta_a ./rombackup_local/vbmeta_a.img

fastboot flash后面的分区名要和设备实际分区名一致,双槽设备不写后缀会默认刷到当前槽,这个默认行为在还原场景里很危险——你以为两个槽都还原了,实际上只动了一个。--disable-verity和--disable-verification这两个参数只在你改了分区内容时才需要,纯粹的原样还原不要加,加了等于主动关掉安全校验,后续系统更新会失败。

dd 回写路径适合 super 这类 fastboot 刷写容易超时的大分区:

# 先推回设备 adb push ./rombackup_local/super.img /sdcard/rombackup/super.img # 在系统内回写,同样是 4MB 块大小 adb shell su -c 'dd if=/sdcard/rombackup/super.img of=/dev/block/by-name/super bs=4194304 conv=fsync' # 回写后立即校验,比对源文件与目标分区前 N 字节 adb shell su -c 'dd if=/dev/block/by-name/super bs=4194304 count=10 2>/dev/null | sha256sum'

dd 回写的边界在于:它绕过 bootloader 的所有保护,写错了没有任何拦截。所以回写前必须做两件事,一是确认目标分区大小不小于源文件,二是确认当前不在 A/B 切换的中间状态。回写完成后那条校验命令只读前 10 个块,是个快速抽检,不是完整校验,完整校验要把 count 去掉跑全量,代价是时间翻倍。我一般对 super 做全量校验,对 boot 这种小分区直接抽检。

4. 镜像解包与重打包:boot.img、payload.bin、super.img 的处理方法

备份只是保底,这套工具箱更高频的用法是改。改分区镜像的流程可以概括成解包、修改、重打包、刷入四步,每一步都有对应的工具和格式约束。搞不清楚格式就动手,最常见的结果是打包出来的镜像刷进去直接不进系统,而且没有任何错误提示。

4.1 boot.img 解包与修补流程

boot.img 是安卓启动链的第一环,它的结构从安卓 10 之后变化很大,头部格式从 boot header v2 一路演进到 v4,还多出了 vendor_boot 这个独立分区。工具箱里的解包器会自己判断头部版本,但你要知道自己在处理哪一代格式。

# 解包 boot.img,输出目录里会出现 kernel、ramdisk、dtb 等组件 patcher unpack boot.img ./boot_out # 查看解包结果,确认关键组件都在 ls -lh ./boot_out/ # 典型输出:kernel、ramdisk.cpio、dtb、header.cfg

patcher这里代指工具箱里的修补命令行入口,具体名字按你解压后的目录来替换。解包后重点看两样东西:kernel的大小是否合理(几 MB 到十几 MB 之间),ramdisk.cpio是否存在。如果 kernel 是 0 字节,说明头部版本判断错了,换一个解包器版本重试。header.cfg里记录了原始头部参数,重打包时必须原样带回去,改一个字段都可能导致启动失败。

修补 ramdisk 的典型目的是往里面塞一个提权组件,流程是解 cpio、改内容、重新压:

# 解开 ramdisk mkdir ./ramdisk_root && cd ./ramdisk_root cpio -idmv < ../boot_out/ramdisk.cpio # 修改完成后重新打包,注意保持 cpio 的格式与权限 find . | cpio -o -H newc > ../boot_out/ramdisk_new.cpio # 用原头部参数重打包 patcher repack ./boot_out ./boot_new.img

cpio -H newc这个格式参数不能省,安卓的 ramdisk 用的是 newc 格式,用默认格式打出来的包内核认不出来。find . | cpio的顺序也有讲究,文件权限和属主信息会一起被打进去,如果你在解包目录里用普通用户身份改过文件,打包后属主变成非 root,启动时可能出现权限拒绝。稳妥的做法是全程在 root shell 里操作,或者打包后用repack工具统一修正属主。

重打包出来的镜像先别急着刷,本地做个结构检查:

# 对比新旧镜像的头部信息,确认关键字段一致 patcher info ./boot_new.img # 检查文件大小是否在合理范围,通常与原始镜像相差不超过 20% ls -l ./boot.img ./boot_new.img

4.2 payload.bin 的提取与 OTA 包拆解

很多人的 ROM 备份来源是官方 OTA 包,里面的分区镜像是打包在payload.bin里的,不能直接当镜像用。工具箱带了一份提取脚本,思路是解析 payload 的元数据,把每个分区的数据段按哈希校验后单独写出来。

# 从 OTA zip 里取出 payload.bin 和元数据 unzip ota_package.zip payload.bin payload_properties.txt -d ./ota/ # 提取全部分区镜像到输出目录 python payload_dumper.py ./ota/payload.bin --out ./ota/images # 只提取指定分区,节省时间 python payload_dumper.py ./ota/payload.bin --out ./ota/images --partition boot,vbmeta

第一条unzip只取两个文件,因为 OTA 包里动辄几个 GB,全解压没必要。第二条是核心提取命令,正常输出会看到每个分区的名字、大小、以及一行校验通过的提示。第三条的--partition参数在只想拿 boot 做修补时非常有用,能把提取时间从十几分钟压到几十秒。

这里有个格式上的硬约束:payload.bin分全量和增量两种。全量包里的每个分区都是完整镜像,提取出来可以直接用;增量包里的分区是差分的,只包含与基准版本的差异数据,提取脚本遇到增量操作类型会直接报错退出。判断方法看payload_properties.txt里有没有FILE_HASH之外的分区级差分标记,或者看提取时的报错信息里是否出现不支持的 op 类型。遇到增量包不要硬解,去找对应版本的全量包,这是唯一干净的路子。

提取完成后同样要做校验:

# 比对提取出的镜像哈希与 payload 元数据里记录的值 grep -E '^(boot|vbmeta)' ./ota/payload_properties.txt sha256sum ./ota/images/boot.img

4.3 super.img 的拆分与回包

动态分区的设备上,改完逻辑分区必须重新合成super.img再整体刷入。这一步是整条链路里参数最多、最容易错的地方,因为lpmake需要你手动指定每个分区的大小、所属 group、以及元数据槽位数。

先拆:

# 拆分 super.img,输出目录里会得到 system.img、vendor.img 等逻辑分区 lpunpack --slot=0 ./rombackup_local/super.img ./super_split/ # 查看拆分结果与每个分区的大小 ls -lh ./super_split/

--slot=0表示拆 A 槽,双槽设备的 super 里同时存着两个槽的逻辑分区,不指定 slot 会拆出带后缀的全部分区,目录会很乱。拆分出来的文件名通常带_a后缀,这是正常的。

改完之后回包,参数要一个字段一个字段对:

lpmake \ --device-size=9126805504 \ --metadata-size=65536 \ --metadata-slots=2 \ --super-name=super \ --group=main_a:9126805504 \ --partition=system_a:readonly:3221225472:main_a:./super_split/system_a.img \ --partition=vendor_a:readonly:1073741824:main_a:./super_split/vendor_a.img \ --partition=product_a:readonly:1073741824:main_a:./super_split/product_a.img \ --output=./super_new.img

--device-size必须等于原super分区的字节数,多一个字节刷不进去,少一个字节后面的分区放不下。--metadata-size和--metadata-slots必须和原设备一致,这两个值错了会报元数据校验失败。--group定义了一个分区组及其容量上限,组名要和分区名的 group 字段对应,容量上限一般等于--device-size。每个--partition的格式是名称:属性:大小:组名:镜像路径,属性只有readonly和none两种,系统分区必须是readonly。大小这一项要填镜像的实际大小向上对齐到 4096 字节,填小了 lpmake 直接报错,填大了浪费空间可能导致后面的分区分不到位置。

回包完成后验证:

# 用 lpdump 查看新 super 的分区布局 lpdump ./super_new.img # 与原始 super 的布局做对比,分区名、大小、group 必须一一对应 lpdump ./rombackup_local/super.img > ./super_orig.txt lpdump ./super_new.img > ./super_new.txt diff ./super_orig.txt ./super_new.txt

lpdump的输出里会列出每个分区的名字、大小、group、以及 extents 位置。diff 出来如果只有哈希或时间戳类的字段不同,说明布局是对的;如果出现分区大小或 group 不一致,别刷,回去改参数。

5. 避坑与排查:五条血泪记录

这套工具箱的文档写得比较克制,很多错误场景没展开。下面五条是我在实际使用里反复撞上的,每条都按现象、原因、解决的顺序记,希望能帮你少走几步。

第一条:备份出来的镜像只有几百 KB,但分区明明是几百 MB。

现象是ls -l一看文件大小和blockdev --getsize64差了一个数量级。原因通常是 dd 进程跑到一半被系统杀掉了,安卓的低内存管理对长时间占用 IO 的进程不友好,尤其是 super 这种几 GB 的分区。另一个可能是of=路径写在了/sdcard的某个被 FUSE 挂载的子目录下,写入被中间层截断。解决办法是备份前先adb shell free -m看一眼可用内存,把bs调到 4 MB 减少循环次数,备份过程中别让设备息屏,并且每备份完一个分区立刻用ls -l和blockdev的数字对一遍。

第二条:还原后卡在开机动画,进 recovery 提示校验失败。

现象是 fastboot 刷写全部成功,没有任何报错,重启后卡在厂商 logo 或者动画循环。原因基本是 AVB 校验没过:你刷了修改过的 boot,但 vbmeta 里记录的哈希还是旧的。还有一种情况是双槽设备上你只刷了当前槽,设备回滚到另一槽时读到的是旧镜像。解决分两步,先fastboot getvar current-slot确认当前槽,再决定只刷该槽还是两槽都刷;如果改过分区内容,必须跟着刷 vbmeta 并带上--disable-verity --disable-verification。刷完先用fastboot reboot recovery看一眼能不能进 recovery,能进说明 boot 链没问题,再正常重启。

第三条:payload 提取脚本报不支持的 op 类型,直接退出。

现象是脚本跑到某个分区时抛异常,提示未知操作类型,前面的分区已经正常输出。原因是这个 OTA 包是增量包,只包含与基准版本的差异数据,不是完整镜像。很多人第一反应是找补丁工具强行合并,但增量包需要完整的基准版本做底,缺了基准照样合不出来。正确处理是去查这个系统版本的完整包,重新下载,不要在同一份增量包上反复折腾。判断增量包有个快办法:看 OTA zip 里的payload_properties.txt,如果分区条目明显少于全量包,或者文件体积只有全量包的三分之一以下,基本就是增量。

第四条:lpmake 回包报空间不足,但镜像总大小明明小于 device-size。

现象是lpmake执行到一半报Not enough space to allocate partition。原因是--group的容量上限设置和实际分区总和之间没留对齐余量,LP 元数据会对每个分区做 4096 字节对齐,几十个分区累加下来多占的几百 KB 就足以撑爆一个刚好卡满的 group。另一个常见原因是--metadata-size给得太小,元数据槽位放不下所有分区条目。解决办法是把 group 容量设成--device-size减去 1 MB 的元数据余量,--metadata-size直接用原设备的 lpdump 输出里的值,不要自己估。

第五条:备份了 userdata,还原后能开机但数据全部丢失。

现象是刷回 userdata 镜像后系统正常启动,但所有应用数据变成了初始状态,等于做了次恢复出厂。原因是 FBE 加密的密钥材料存在metadata分区,你只还原了加密后的数据块,没还原解密所需的密钥。解决是把metadata分区一起备份、一起还原,且必须还原到同一台设备上——密钥和设备的硬件密钥绑定,跨设备还原必然解不开。这也是为什么我在第 3 章强调 metadata 体积小、没有理由不存。

6. 把工具箱用成流水线:脚本化校验与版本回滚的固定动作

单次备份还原靠手敲命令能应付,但如果你像我一样要在同一台设备上反复刷不同版本的 ROM,手敲迟早会出错。我的做法是把整条链路脚本化,核心是三个固定动作:备份前记录分区清单、备份后做双端哈希比对、归档时写一份 manifest。下面这段脚本是我现在每次动手前必跑的,把它放在工具箱根目录下,用bash backup_all.sh调用。

#!/usr/bin/env bash # 全量备份 + 校验 + 归档,设备需已 root 且 adb 授权通过 set -euo pipefail STAMP=$(date +%Y%m%d_%H%M%S) DEVICE=$(adb shell getprop ro.product.device | tr -d '\r') SLOT=$(adb shell getprop ro.boot.slot_suffix | tr -d '\r') WORK="./archive/${DEVICE}_${STAMP}" mkdir -p "$WORK" echo "device=${DEVICE} slot=${SLOT} stamp=${STAMP}" > "$WORK/manifest.txt" # 需要备份的分区列表,双槽设备自动展开 PARTITIONS="boot dtbo vbmeta metadata super" for p in $PARTITIONS; do # 有槽位后缀的分区优先按当前槽备,super 单独处理 if [ "$p" = "super" ]; then target="super" else target="${p}${SLOT}" fi # 记录分区真实大小,作为完整性基准 size=$(adb shell su -c "blockdev --getsize64 /dev/block/by-name/${target}" | tr -d '\r') echo "${target} ${size}" >> "$WORK/manifest.txt" # 备份到设备侧临时目录,4MB 块大小 + fsync 刷盘 adb shell su -c "dd if=/dev/block/by-name/${target} of=/sdcard/rombackup/${target}.img bs=4194304 conv=fsync" adb pull "/sdcard/rombackup/${target}.img" "$WORK/" > /dev/null done # 双端哈希比对,任何一条不一致直接退出 adb shell su -c 'sha256sum /sdcard/rombackup/*.img' | sed 's#/sdcard/rombackup/##' | sort > "$WORK/remote.sha256" (cd "$WORK" && sha256sum *.img | sort > local.sha256) diff "$WORK/remote.sha256" "$WORK/local.sha256" # 清掉设备侧临时文件,避免占满存储 adb shell su -c 'rm -rf /sdcard/rombackup' echo "backup done -> $WORK"

set -euo pipefail这三项一定要加。-e保证任何一条命令失败就停,避免备份到一半继续往下跑生成半成品;-u让未定义变量报错,防止槽位变量为空时命令变成boot而不是boot_a;pipefail保证管道中任意环节失败都能被捕获。STAMP用时间戳做归档目录名,是为了让同一台设备的多次备份彼此独立,回滚时能精确挑版本而不是在一堆同名文件里猜。

PARTITIONS这个列表是我根据自己的设备调整过的,你可以按实际需要增减,但metadata和vbmeta不建议删。循环里对super做了特殊处理,因为 super 不带槽位后缀,硬加_a会找不到设备。blockdev --getsize64的结果写进 manifest,这行的作用是给半年后的自己留证据——还原时拿文件大小和这个数字对,一比就知道备份有没有被截断。

最后那段哈希比对是整个脚本的价值所在。设备侧算一遍、本地算一遍、diff 一遍,任何一条不一致就退出,绝不进入下一步。我在这上面吃过亏,早期图省事跳过校验,结果一个备份了三次的 super 镜像里两次都是截断的,等到真要用的时候才发现全是废的。

归档目录的结构建议固定下来,方便回滚时按时间点找:

路径内容回滚时的用途
archive/<设备>_<时间>/manifest.txt分区名与字节数校验还原目标大小
archive/<设备>_<时间>/*.img裸分区镜像直接刷写或 dd 回写
archive/<设备>_<时间>/local.sha256本地哈希清单还原后比对
archive/<设备>_<时间>/remote.sha256设备侧哈希清单交叉验证备份来源

回滚的动作也固定成两步:先diffmanifest 里的分区大小和当前设备blockdev的输出,确认设备没有被 OTA 改过分区布局;再按镜像逐个刷写,每刷一个立刻用sha256sum抽检。设备布局变了的情况下还原必失败,这时候正确做法是重新备份当前状态再决定要不要回滚,而不是硬刷旧镜像。

这套流程跑顺之后,单次全量备份加校验大概十分钟,回滚一次五分钟以内。比起出问题后花两小时找救砖方案,这十分钟花得非常值。从那以后我每次动分区之前都强制走一遍这个脚本,不管多急,校验那一步绝不跳过——备份这件事,只有在你还不需要它的时候做,才叫备份。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 10:43:39

impeccable:专注前端设计的AI代理,CLI与浏览器扩展双形态实战

1. 从"impeccable"这个词说起&#xff1a;为什么前端设计需要一个新的AI代理第一次看到"impeccable"这个词被用作一个AI coding agent的名字&#xff0c;我的反应是——这名字起得挺狂。"无可挑剔"这个标准放在前端设计领域&#xff0c;基本等于…

作者头像 李华
网站建设 2026/10/28 10:42:09

Kestrel、Caddy、Nginx:Windows 下替代 IIS 的三大 HTTP 服务器方案

简介&#xff1a;本资源是一款面向Windows平台Web开发初学者与轻量级网站部署需求者的IIS替代方案&#xff0c;聚焦于简化ASP动态网页的本地托管与调试。资源提供一款名为“小旋风”的精简型ASP服务器软件&#xff0c;主打易安装、低配置、开箱即用&#xff0c;特别适合学习传统…

作者头像 李华
网站建设 2026/10/28 10:42:08

arc_conv_r55:卷积核重参数化实现硬件友好型模型部署

简介&#xff1a;arc_conv_r55 是一款面向嵌入式开发、逆向分析及游戏资源研究者的 ARC 格式专用处理工具集&#xff0c;专为解包、打包、格式转换与结构清理设计&#xff0c;适用于需深度操作 XP3、LPK、WARC 等常见游戏/固件封装格式的技术人员。资源共415个文件&#xff0c;…

作者头像 李华
网站建设 2026/10/28 10:41:33

DeepSeek API 批量处理与数据清洗实战指南

简介&#xff1a;《DeepSeek详细使用教学》面向希望快速上手DeepSeek的初学者、办公人员与数据分析学习者&#xff0c;围绕账号注册登录、核心功能认知和实际操作展开&#xff0c;帮助读者建立从数据导入、清洗、分析、可视化到文本生成与摘要的完整使用路径。压缩包内共1个doc…

作者头像 李华
网站建设 2026/10/28 10:41:26

2026年API安全核心技术解析与选型指南

1. 项目概述&#xff1a;API安全产品的行业变革与选型新标准2026年的API安全市场正在经历一场由技术驱动的大洗牌。作为连接现代应用的核心纽带&#xff0c;API承载着企业80%以上的数据流量&#xff0c;其安全性直接关系到业务系统的生死存亡。过去三年里&#xff0c;我亲历了超…

作者头像 李华
网站建设 2026/10/28 10:41:14

AniPortrait技术解析:静态照片动态化的AI突破

1. 项目背景&#xff1a;静态照片动态化的技术革命去年12月&#xff0c;香港科技大学团队在NeurIPS 2023会议上展示的AniPortrait技术引起了计算机视觉领域的广泛关注。这项技术实现了从单张静态照片生成带语音驱动的动态肖像视频&#xff0c;其核心突破在于将传统的3D人脸重建…

作者头像 李华