Android差分包制作流程分析
整包与差分包⽣成流程
孰若孤差分包⽣成指令
make otapackage将编译⽣成的(xxx项⽬为例)
out/target/product/xxxxxxx/full_xxx_hxxxx-target_files-1527715386.zip
此时⽣成的是ba.zip包
脉翅目
在代码中做⼀些修改,产⽣⼀些差异,第⼆次make otapackage将编译⽣成的
out/target/product/xxxxxxx/full_xxx_hxxxx-target_files-1533195243.zip
此时⽣成的是target.zip包
两者之间的差分包⽣成 ./build/tools/releatools/ota_from_target_files-i ba.zip target.zip update.zip 注:-i指定制作差分包,update.zip 就是升级⽤的差分包,这个脚本要在Android源码的根⽬录下执⾏。
/build/tools/releatools/ota_from_target_files.py
-v (--verify)
Remount and verify the checksums of the files written to the
system and vendor (if ud) partitions. Incremental builds only.
-i (--incremental_from) <file>
Generate an incremental OTA using the given target-files zip as
the starting build.
-t (--worker_threads) <int>
Specifies the number of worker-threads that will be ud when
generating patches for incremental updates (defaults to 3).
......................
全包WriteFullOTAPackage函数主要功能
从ota_from_target_files.py脚本中WriteFullOTAPackage()和WriteBlockIncrementalOTAPackage这两个函数(分别⽤来⽣成全包和差分包)实现主要功能。
WriteFullOTAPackage将整包所需要的⽂件从差分资源包中读出并写⼊到整包中。
script = edify_generator.EdifyGenerator(target_api_version, target_info)
edify_generator对象,其FormatPartition、UnpackPackageDir等⽅法分别是向脚本⽂件update-script中写⼊格式化分区、解压包等指令。
.......
同时,它还会向整包中的META-INFO/com/google/android/updater-script⽂件中写⼊⼀些操作命令。⽽update-binary则是⼀个⼆进制⽂件,相当于⼀个脚本解释器,能够识别updater-script中描述的操作。
差分包WriteBlockIncrementalOTAPackage函数主要功能
Boot分区相关
def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):在函数中
.......
source_boot = common.GetBootableImage(
"/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
OPTIONS.source_info_dict)
target_boot = common.GetBootableImage(
"/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
六岁的故事updating_boot = (not OPTIONS.two_step and
(source_boot.data != target_boot.data))
在之前已经得到了source target_file.zip中的boot.img和dest target_file.zip的boot.img数据分别为source_boot 与 target_boot,这
⾥只是判断source_boot 与 target_boot是否相同来决定是否需要升级boot分区。
System数据来源
............
system_src = GetImage("system", OPTIONS.source_tmp)
system_tgt = GetImage("system", OPTIONS.target_tmp)
分别从source target_file.zip和dest target_file.zip中获取system数据,为后⾯⽣成w.dat、system.patch.dat、
⽣成差分包system dat,list⽂件
........
system_diff = common.BlockDifference("system", system_tgt, system_src,
check_first_block,
节约粮食的倡议书
version=blockimgdiff_version,
disable_imgdiff=disable_imgdiff)
⽣成差分包中的w.dat、system.patch.dat、ansfer.list三个⽂件 。
..........
d = common.Difference(target_boot, source_boot)
当boot.img有变化时⽣成boot.img.p⽂件,在updater-script脚本中对应下⾯命令:
apply_patch("EMMC:/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-
name/boot:8306944:eec9f25c26fa112a037e15b265445ae142c5cca6:8308992:9bfb4708a965363ec53cd8b15f8a0d640f490
"-", 9bfb4708a965363ec53cd8b15f8a0d640f490dbc, 8308992,
eec9f25c26fa112a037e15b265445ae142c5cca6,
package_extract_file("patch/boot.img.p"))
校验system分区
...............
# Verify the existing partitions.
system_diff.WriteVerifyScript(script, touched_blocks_only=True)
校验升级前的system分区是否为基准版本,如果不是的话当然⽆法升级,因为w.dat、system.patch.dat、
if (range_sha1("/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/system",”156,1,280,281,”) == "faaa340bde5fccec0374da568463286d9454ae5b
" || block_image_verify("/dev/block/platform/mtk-
msdc.0/11230000.msdc0/by-name/system", package_extract_file("ansfer.list"), "w.dat",
"system.patch.dat")) then
ui_print("Verified ");
⽣成升级system命令
.............
system_diff.WriteScript(script, output_zip,
progress=0.8 if vendor_diff el 0.9)
⽣成升级system的命令,在updater-script脚本中对应下⾯命令:
block_image_update("/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/system",
package_extract_file("ansfer.list"), "w.dat", "system.patch.dat") ||
abort("E1001: Failed to update system image.");
对应recovery中的BlockImageUpdateFn函数
update-binary
........
script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary)
把updater可执⾏程序放进升级包中,重命名为update-binary。update-binary是完成升级的程序,负责解析updater-script脚本中的命令并执⾏对应的C函数。
元数据
.........
FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
把元数据输出到升级包的META-INF/com/android/metadata中。
中国最大的医院差分包⽬录
差分升级包就是⽐较现存基础包与原来的基础包的差异⽽⽣成的,即该OTA包有特定的应⽤背景(⽤于两个差分包之间),⽤差分包升级不会格式化system分区,只是对其中部分存储段的内容进⾏重写。升级过程中,升级脚本(打开该升级包)会检测fingerprint,确保该升级包被正确应⽤。fingerprint这个属性存在于build.prop,可通过adb shell进⼊根路径,通过cat build.prop查看这个属性(或getprop)。内容在差分包的脚本META-INF/com/google/android/updater-script中。
getprop("ro.xxx.projectname") == "xxx_h5312_c1_in" || abort("E3004: This package is for \"x572_h5312_c1_in\" devices; this is a \"" + getprop("ro.rlk.proje
ui_print("Source: XXX/HXXX/XXX-XXX:8.1.0/O11019/XXX-XXX-O-IN-180531V42:ur/relea-keys");
ui_print("Target: XXX/HXXX/XXX-XXX:8.1.0/O11019/XXX-XXX-O-IN-180802V69:ur/relea-keys");
ui_print("Verifying ");
getprop("ro.xxx.fingerprint") == "XXX/HXXX/XXX-XXX:8.1.0/O11019/XXX-XXX-O-IN-180531V42:ur/relea-keys" ||
行相
getprop("ro.xxx.fingerprint") == "XXX/HXXX/XXX-XXX:8.1.0/O11019/XXX-XXX-O-IN-180802V69:ur/relea-keys" ||
abort("E3001: Package expects build fingerprint of XXX/HXXX/XXX-XXX:8.1.0/O11019/XXX-HXXX-O-IN-180531V42:ur/relea-keys or XXX/HXXX/XXX-XXX: apply_patch_check("EMMC:/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/boot:8306944:eec9f25c26fa112a037e15b265445ae142c5cca6:8308992: apply_patch_space(81530880) || abort("E3006: Not enough free space on /cache to apply patches.");
ui_print("Verified ");
差分包解压后主要包含了如下信息,如下截图是⼀个差分包的⽬录结构:
META-INF 该⽬录升级包的升级脚本
婚礼证婚词
换成为稀疏数组描述。
system.patch.dat(升级包中⽤于patch的数据)’
唐恭陵ansfer.list(升级命令执⾏列表)
out.inrt(0, "%d\n" % (lf.version,)) # format version number
out.inrt(1, "%d\n" % (total,))
# v3+: the number of stash slots is unud.
out.inrt(2, "0\n")
out.inrt(3, str(max_stashed_blocks) + "\n")
升级参数命令解释(此部分摘⾃⽹络)
整个升级过程中的数据操作,包括数据转移(move)、临时存储(stash)、差分⽬标数据写⼊(bsdiff/imgdiff)、新数据写⼊
(new)、数据删除(free/era)是⼀个极为复杂且严格依照顺序执⾏的过程,有的命令是上下相关甚⾄是⼀环扣着⼀环的。这些命令的
执⾏顺序是在⽣成升级包时即已确定。