Add support for block incremental OTAs
Change-Id: Ie72015e34ed8d7595a5c74c8df41cba73275afab
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index dcfbf83..7c9f80c 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -82,6 +82,7 @@
import common
import img_from_target_files
import edify_generator
+import build_image
OPTIONS = common.OPTIONS
OPTIONS.package_key = None
@@ -544,7 +545,213 @@
known_paths.add(path)
dirs.pop()
+def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):
+ source_version = OPTIONS.source_info_dict["recovery_api_version"]
+ target_version = OPTIONS.target_info_dict["recovery_api_version"]
+
+ if source_version == 0:
+ print ("WARNING: generating edify script for a source that "
+ "can't install it.")
+ script = edify_generator.EdifyGenerator(source_version,
+ OPTIONS.target_info_dict)
+
+ metadata = {"pre-device": GetBuildProp("ro.product.device",
+ OPTIONS.source_info_dict),
+ "post-timestamp": GetBuildProp("ro.build.date.utc",
+ OPTIONS.target_info_dict),
+ }
+
+ device_specific = common.DeviceSpecificParams(
+ source_zip=source_zip,
+ source_version=source_version,
+ target_zip=target_zip,
+ target_version=target_version,
+ output_zip=output_zip,
+ script=script,
+ metadata=metadata,
+ info_dict=OPTIONS.info_dict)
+
+ source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict)
+ target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict)
+ metadata["pre-build"] = source_fp
+ metadata["post-build"] = target_fp
+
+ 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_recovery = common.GetBootableImage(
+ "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY",
+ OPTIONS.source_info_dict)
+ target_recovery = common.GetBootableImage(
+ "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")
+ updating_recovery = (source_recovery.data != target_recovery.data)
+
+ with tempfile.NamedTemporaryFile() as src_file:
+ with tempfile.NamedTemporaryFile() as tgt_file:
+ print "building source system image..."
+ src_file = tempfile.NamedTemporaryFile()
+ src_data = img_from_target_files.BuildSystem(
+ OPTIONS.source_tmp, OPTIONS.source_info_dict, sparse=False)
+ src_sys_sha1 = sha1(src_data).hexdigest()
+ print "source system sha1:", src_sys_sha1
+ src_file.write(src_data)
+ src_data = None
+
+ print "building target system image..."
+ tgt_file = tempfile.NamedTemporaryFile()
+ tgt_data = img_from_target_files.BuildSystem(
+ OPTIONS.target_tmp, OPTIONS.target_info_dict, sparse=False)
+ tgt_sys_sha1 = sha1(tgt_data).hexdigest()
+ print "target system sha1:", tgt_sys_sha1
+ tgt_sys_len = len(tgt_data)
+ tgt_file.write(tgt_data)
+ tgt_data = None
+
+ system_type, system_device = common.GetTypeAndDevice("/system", OPTIONS.info_dict)
+ system_patch = common.MakeSystemPatch(src_file, tgt_file)
+ system_patch.AddToZip(output_zip, compression=zipfile.ZIP_STORED)
+
+ AppendAssertions(script, OPTIONS.target_info_dict)
+ device_specific.IncrementalOTA_Assertions()
+
+ # Two-step incremental package strategy (in chronological order,
+ # which is *not* the order in which the generated script has
+ # things):
+ #
+ # if stage is not "2/3" or "3/3":
+ # do verification on current system
+ # write recovery image to boot partition
+ # set stage to "2/3"
+ # reboot to boot partition and restart recovery
+ # else if stage is "2/3":
+ # write recovery image to recovery partition
+ # set stage to "3/3"
+ # reboot to recovery partition and restart recovery
+ # else:
+ # (stage must be "3/3")
+ # perform update:
+ # patch system files, etc.
+ # force full install of new boot image
+ # set up system to update recovery partition on first boot
+ # complete script normally (allow recovery to mark itself finished and reboot)
+
+ if OPTIONS.two_step:
+ if not OPTIONS.info_dict.get("multistage_support", None):
+ assert False, "two-step packages not supported by this build"
+ fs = OPTIONS.info_dict["fstab"]["/misc"]
+ assert fs.fs_type.upper() == "EMMC", \
+ "two-step packages only supported on devices with EMMC /misc partitions"
+ bcb_dev = {"bcb_dev": fs.device}
+ common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data)
+ script.AppendExtra("""
+if get_stage("%(bcb_dev)s", "stage") == "2/3" then
+""" % bcb_dev)
+ script.AppendExtra("sleep(20);\n");
+ script.WriteRawImage("/recovery", "recovery.img")
+ script.AppendExtra("""
+set_stage("%(bcb_dev)s", "3/3");
+reboot_now("%(bcb_dev)s", "recovery");
+else if get_stage("%(bcb_dev)s", "stage") != "3/3" then
+""" % bcb_dev)
+
+ script.Print("Verifying current system...")
+
+ device_specific.IncrementalOTA_VerifyBegin()
+
+ script.AssertRecoveryFingerprint(source_fp, target_fp)
+
+ if updating_boot:
+ total_verify_size += OPTIONS.info_dict["boot_size"]
+ d = common.Difference(target_boot, source_boot)
+ _, _, d = d.ComputePatch()
+ print "boot target: %d source: %d diff: %d" % (
+ target_boot.size, source_boot.size, len(d))
+
+ common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
+
+ boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
+
+ script.PatchCheck("%s:%s:%d:%s:%d:%s" %
+ (boot_type, boot_device,
+ source_boot.size, source_boot.sha1,
+ target_boot.size, target_boot.sha1))
+
+ device_specific.IncrementalOTA_VerifyEnd()
+
+ if OPTIONS.two_step:
+ script.WriteRawImage("/boot", "recovery.img")
+ script.AppendExtra("""
+set_stage("%(bcb_dev)s", "2/3");
+reboot_now("%(bcb_dev)s", "");
+else
+""" % bcb_dev)
+
+ script.Comment("---- start making changes here ----")
+
+ device_specific.IncrementalOTA_InstallBegin()
+
+ if OPTIONS.wipe_user_data:
+ script.Print("Erasing user data...")
+ script.FormatPartition("/data")
+
+ script.Print("Patching system image...")
+ script.Syspatch(system_device,
+ OPTIONS.info_dict["system_size"],
+ tgt_sys_sha1,
+ src_sys_sha1,
+ system_patch.name)
+
+ if OPTIONS.two_step:
+ common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
+ script.WriteRawImage("/boot", "boot.img")
+ print "writing full boot image (forced by two-step mode)"
+
+ if not OPTIONS.two_step:
+ if updating_boot:
+ # Produce the boot image by applying a patch to the current
+ # contents of the boot partition, and write it back to the
+ # partition.
+ script.Print("Patching boot image...")
+ script.ApplyPatch("%s:%s:%d:%s:%d:%s"
+ % (boot_type, boot_device,
+ source_boot.size, source_boot.sha1,
+ target_boot.size, target_boot.sha1),
+ "-",
+ target_boot.size, target_boot.sha1,
+ source_boot.sha1, "patch/boot.img.p")
+ print "boot image changed; including."
+ else:
+ print "boot image unchanged; skipping."
+
+ # Do device-specific installation (eg, write radio image).
+ device_specific.IncrementalOTA_InstallEnd()
+
+ if OPTIONS.extra_script is not None:
+ script.AppendExtra(OPTIONS.extra_script)
+
+ if OPTIONS.two_step:
+ script.AppendExtra("""
+set_stage("%(bcb_dev)s", "");
+endif;
+endif;
+""" % bcb_dev)
+
+ script.SetProgress(1)
+ script.AddToZip(target_zip, output_zip)
+ WriteMetadata(metadata, output_zip)
+
def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
+ target_has_recovery_patch = HasRecoveryPatch(target_zip)
+ source_has_recovery_patch = HasRecoveryPatch(source_zip)
+
+ if target_has_recovery_patch and source_has_recovery_patch:
+ return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip)
+
source_version = OPTIONS.source_info_dict["recovery_api_version"]
target_version = OPTIONS.target_info_dict["recovery_api_version"]
@@ -575,8 +782,6 @@
print "Loading source..."
source_data = LoadSystemFiles(source_zip)
- target_has_recovery_patch = HasRecoveryPatch(target_zip)
-
verbatim_targets = []
patch_list = []
diffs = []