system.transfer.list文件解析

在进行system.transfer.list文件分析前,我们先对Android系统recovery升级模式做一个简单的了解,并从中引出system.transfer.list文件在整个升级流程中发挥的重要作用。
一.Android Recovery mode分析
1、前提条件
要进行Android系统升级,必须首先进入recovery模式,进入recovery模式的方式有:
(1). 通过读取 /cache 分区中文件 /cache/recovery/command 内容进入,当然在重启之前已经向文件/cache/recovery/command 写入了命令字段。
(2). 通过按键操作进入 。

2、基本升级过程
Android 升级分为两种,一种是对系统中单个文件升级,一种是对 mtd 整个分区进行升级,升级包是用 zip 格式压缩的经过签名的压缩文件。升级过程主要流程描述如下:
(1). bootloader 发现用户按住升级键或/cache/recovery/command中有对应字段,将 recovery.img 作为 ramdisk 读取到内存。
(2). 内核根据 ramdisk 中的init.rc 执行 recovery 脚本。Recovery 脚本在 sdcard 中找到升级文件后调用recovery 程序依次做以下操作:
1) 检查升级文件的数字签名是否可靠。检查签名使用的本地密钥为 /res/keys。
2) 如果签名合法则执行提取压缩包中META-INF/com/google/android/update-binary 文件重命名到/tmp/update_binary 并执行该文件。
3) update_binary 解析压缩文件中的 META-INF/com/google/android/updater-script 文件并执行。updater-script将继续调用system.transfer.list文件依次执行其中的各个指令完成update升级操作,其升级进度通过管道回传给 recovery 程序。升级 / 更新可以直接覆盖目标文件,也可采用二进制补丁形式以减少升级文件的容量,采用的工具为 bsdiff 和 imgdiff (system.transfer.list文件调用)。
4)对于补丁包升级形式,升级数据源可靠性鉴别的依据为 sha1 校验和数据长度比对。具体要求为: 1 升 级包提供的目标文件的 sha1 值和目标文件计算值符合,即目标正确。 2 进行补丁后的文件 sha1 值和长度符合升级包提供的补丁后的目标文件的长度和 sha1 数值,保证结果正确。两项有一项不符合则升级过程停止。为保证第二项操作不损毁最终目标,打补丁的文件会先临时存储到 cache 中,等到结果比对正确才进行实际写入 / 替换目标文件操作。所以此过程要求 cache 目录必须有足够空间能够保存临时文件。

二. 升级包update.zip简单分析
从Android 5.0开始,即使是update.zip包,也是仿照增量包的方式进行打包了。使用makeotapackage得到一个update.zip文件,下面为我们此次要升级的update.zip文件打开后的内容:
patch
META-INF
system.new.dat (升级包新数据)
system.patch.dat(升级包中用于patch的数据)
system.transfer.list(升级命令执行列表)
显然system.img不再提供,而是提供了三个文件,利用这三个文件的脚本在/META-INF/com/google/android/updater-script文件中:
1.ifblock_image_verify("/dev/block/bootdevice/by-name/system",package_extract_file("system.transfer.list"),"system.new.dat", "system.patch.dat") then
ui_print("Verifiedsystem image...");

2.block_image_update("/dev/block/bootdevice/by-name/system",package_extract_file("system.transfer.list"),"system.new.dat", "system.patch.dat");

三. system.transfer.list文件解析
下面我们以此次升级包中的system.transfer.list文件进行分析(blockimg.c代码中有对本文件的部分注释)。

文件前面几行如下:
3
314733
108
10584
1) 文件的第一行是版本号,当前是3;
2) 文件的第二行是总共需要写入的block数量;
3) 文件的第三行为同时并存的stash文件数;
4) 第四行为最大stash文件所占用的block空间数;

上述参数之后,就是具体的操作命令,我们逐条仔细分析(相同的命令将略过):
1.move3b8219cff7a8035c5cfe4e82a5e718c32f7439e8 2,289578,289582 4 2,287350,287354
格式:"cmdname" + "source hash"+ "tg block pos" +"sourceblock num" + "source block pos"
解析:将源block 287350至block 287354(共4 block,hash值为3b8219cff7a8035c5cfe4e82a5e718c32f7439e8)的数据移动至目标block 289578至block 289582的空间。

2.move1e100337aa3a13fd57fdd76ff3923aaff3c3c597 2,285947,288845 2898 2,283719,286617
本命令执行格式及目标与命令1相同,但由于源块区间(283719,286617)与目标块区间(285947,288845)产生重叠,所以在命令执行的过程中会先将读出的源数据临时存储于cache目录下文件名为1e100337aa3a13fd57fdd76ff3923aaff3c3c597的stash文件中,然后再将stash的数据读出写入目标块区间,写完之后再删除这个stash 文件。

3.movec182ec1c52cb74fd5eb8c9ae87df62d5778d91c4 2,229351,229363 12 -c182ec1c52cb74fd5eb8c9ae87df62d5778d91c4:2,0,12
格式:"cmdname" + "source hash"+ "tg block pos" + "sourceblocknum" + "source stash file";
解析:将存储于cache目录下文件名为c182ec1c52cb74fd5eb8c9ae87df62d5778d91c4的stash文件中从0至12 block的数据读出,写入目标块区间(229351,229363)。

4.freec182ec1c52cb74fd5eb8c9ae87df62d5778d91c4
解析: 删除存储于cache/reovery目录下指定的stash文件;

5.bsdiff 0 3169086 ffc645d03fa4f56e72fefa872b792a76c26f9bb44bc0c9ddf123d54a04c800824c0951873e195ef1 2,295583,311859 16290 2,295583,311873
格式:"cmdname" +"patch offset" + "patch length" + "source hash" +"target hash" + "tg block pos" + "sourceblocknum" + "source block pos"
解析:读取源block区间数据(block 295583至block 311873,hash值为 ffc645d03fa4f56e72fefa872b792a76c26f9bb4),与system.patch.dat文件里偏移量为0,长度为3169086的数据进行bsdiff差分算法运算,生成的新数据存储至目标块区间blokc 295583至block 311859(hash值为4bc0c9ddf123d54a04c800824c0951873e195ef1)。

6.bsdiff 30447439 8190624a0bae2be2c5c40d562a7f3d26e7d7ef3433296da9fb7c288322db82365bcafbe1371b3441a444 2,210082,210263 181 -624a0bae2be2c5c40d562a7f3d26e7d7ef343329:2,0,181
格式:"cmdname" +"patch offset" + "patch length" + "source hash" +"target hash" + "tg block pos" + "stash hash" +"stash range"
解析:读取stash文件624a0bae2be2c5c40d562a7f3d26e7d7ef343329数据(block 0至block 181,hash值为624a0bae2be2c5c40d562a7f3d26e7d7ef343329),与system.patch.dat文件里偏移量为30447439,长度为8190字节的数据进行bsdiff差分算法运算,生成的新数据存储至目标块区间block210082至block 210263(hash值为6da9fb7c288322db82365bcafbe1371b3441a444)。

7.imgdiff 6249859 22259bc3809a88c9f9b80b40fc23aeb5646333440717af4f900ef6c78fa7fca2ff6c2870aa88ec0247c7 2,155835,156013 178 2,153161,153339
解析:与命令6格式及执行流程一致,只是调用的差分算法为imgdiff算法。

8.stash 087da7ef6fac4bd7f31f19b428fead8067e4ac218,287287,287288,287417,287420,287444,287445,287457,287458
格式:"cmdname"+ "stash hash id" + "source range"
解析:将读取到的源块数据(从287287至287288,287417至287420,287444至287445,287457至287458),并确认其hash值为087da7ef6fac4bd7f31f19b428fead8067e4ac21后,存储于cache目录下文件名为087da7ef6fac4bd7f31f19b428fead8067e4ac21的stash文件。

9.new 2,633274,634729
解析:update/system.new.dat文件中的数据被system.transfer.list文件中的new命令按顺序读取(634729-633274)*4096个字节,offset为前(n-1)new命令读取的字节总数;读取到的数据存储于block 633274至block 634729中。

10. erase6,32770,32929,32931,33439,65535,65536
解析:删除block 32770至32929,block32931至33439,block 65535至65536的数据。

四. 总结
【system.transfer.list文件解析】整个升级过程中的数据操作,包括数据转移(move)、临时存储(stash)、差分目标数据写入(bsdiff/imgdiff)、新数据写入(new)、数据删除(free/erase)是一个极为复杂且严格依照顺序执行的过程,有的命令是上下相关甚至是一环扣着一环的。这些命令的执行顺序是在生成升级包时即已确定。

    推荐阅读