def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file): target_info = common.BuildInfo(OPTIONS.target_info_dict, OPTIONS.oem_dicts) source_info = common.BuildInfo(OPTIONS.source_info_dict, OPTIONS.oem_dicts) target_api_version = target_info["recovery_api_version"] source_api_version = source_info["recovery_api_version"] if source_api_version == 0: logger.warning( "Generating edify script for a source that can't install it.") script = edify_generator.EdifyGenerator( source_api_version, target_info, fstab=source_info["fstab"]) if target_info.oem_props or source_info.oem_props: if not OPTIONS.oem_no_mount: source_info.WriteMountOemScript(script) metadata = GetPackageMetadata(target_info, source_info) if not OPTIONS.no_signing: staging_file = common.MakeTempFile(suffix='.zip') else: staging_file = output_file output_zip = zipfile.ZipFile( staging_file, "w", compression=zipfile.ZIP_DEFLATED) device_specific = common.DeviceSpecificParams( source_zip=source_zip, source_version=source_api_version, source_tmp=OPTIONS.source_tmp, target_zip=target_zip, target_version=target_api_version, target_tmp=OPTIONS.target_tmp, output_zip=output_zip, script=script, metadata=metadata, info_dict=source_info) source_boot = common.GetBootableImage( "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", source_info) target_boot = common.GetBootableImage( "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT", target_info) updating_boot = (not OPTIONS.two_step and (source_boot.data != target_boot.data)) target_recovery = common.GetBootableImage( "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") block_diff_dict = GetBlockDifferences(target_zip=target_zip, source_zip=source_zip, target_info=target_info, source_info=source_info, device_specific=device_specific) CheckVintfIfTrebleEnabled(OPTIONS.target_tmp, target_info) # Assertions (e.g. device properties check). target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount) 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 source_info.get("multistage_support"): assert False, "two-step packages not supported by this build" fs = source_info["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") == "2/3" then """ % bcb_dev) # Stage 2/3: Write recovery image to /recovery (currently running /boot). script.Comment("Stage 2/3") 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") != "3/3" then """ % bcb_dev) # Stage 1/3: (a) Verify the current system. script.Comment("Stage 1/3") # Dump fingerprints script.Print("Source: {}".format(source_info.fingerprint)) script.Print("Target: {}".format(target_info.fingerprint)) script.Print("Verifying current system...") device_specific.IncrementalOTA_VerifyBegin() WriteFingerprintAssertion(script, target_info, source_info) # Check the required cache size (i.e. stashed blocks). required_cache_sizes = [diff.required_cache for diff in block_diff_dict.values()] if updating_boot: boot_type, boot_device_expr = common.GetTypeAndDeviceExpr("/boot", source_info) d = common.Difference(target_boot, source_boot) _, _, d = d.ComputePatch() if d is None: include_full_boot = True common.ZipWriteStr(output_zip, "boot.img", target_boot.data) else: include_full_boot = False logger.info( "boot target: %d source: %d diff: %d", target_boot.size, source_boot.size, len(d)) common.ZipWriteStr(output_zip, "boot.img.p", d) target_expr = 'concat("{}:",{},":{}:{}")'.format( boot_type, boot_device_expr, target_boot.size, target_boot.sha1) source_expr = 'concat("{}:",{},":{}:{}")'.format( boot_type, boot_device_expr, source_boot.size, source_boot.sha1) script.PatchPartitionExprCheck(target_expr, source_expr) required_cache_sizes.append(target_boot.size) if required_cache_sizes: script.CacheFreeSpaceCheck(max(required_cache_sizes)) # Verify the existing partitions. for diff in block_diff_dict.values(): diff.WriteVerifyScript(script, touched_blocks_only=True) device_specific.IncrementalOTA_VerifyEnd() if OPTIONS.two_step: # Stage 1/3: (b) Write recovery image to /boot. _WriteRecoveryImageToBoot(script, output_zip) script.AppendExtra(""" set_stage("%(bcb_dev)s", "2/3"); reboot_now("%(bcb_dev)s", ""); else """ % bcb_dev) # Stage 3/3: Make changes. script.Comment("Stage 3/3") script.Comment("---- start making changes here ----") device_specific.IncrementalOTA_InstallBegin() progress_dict = {partition: 0.1 for partition in block_diff_dict} progress_dict["system"] = 1 - len(block_diff_dict) * 0.1 if OPTIONS.source_info_dict.get("use_dynamic_partitions") == "true": if OPTIONS.target_info_dict.get("use_dynamic_partitions") != "true": raise RuntimeError( "can't generate incremental that disables dynamic partitions") dynamic_partitions_diff = common.DynamicPartitionsDifference( info_dict=OPTIONS.target_info_dict, source_info_dict=OPTIONS.source_info_dict, block_diffs=block_diff_dict.values(), progress_dict=progress_dict) dynamic_partitions_diff.WriteScript( script, output_zip, write_verify_script=OPTIONS.verify) else: for block_diff in block_diff_dict.values(): block_diff.WriteScript(script, output_zip, progress=progress_dict.get(block_diff.partition), write_verify_script=OPTIONS.verify) if OPTIONS.two_step: common.ZipWriteStr(output_zip, "boot.img", target_boot.data) script.WriteRawImage("/boot", "boot.img") logger.info("writing full boot image (forced by two-step mode)") if not OPTIONS.two_step: if updating_boot: if include_full_boot: logger.info("boot image changed; including full.") script.Print("Installing boot image...") script.WriteRawImage("/boot", "boot.img") else: # Produce the boot image by applying a patch to the current # contents of the boot partition, and write it back to the # partition. logger.info("boot image changed; including patch.") script.Print("Patching boot image...") script.ShowProgress(0.1, 10) target_expr = 'concat("{}:",{},":{}:{}")'.format( boot_type, boot_device_expr, target_boot.size, target_boot.sha1) source_expr = 'concat("{}:",{},":{}:{}")'.format( boot_type, boot_device_expr, source_boot.size, source_boot.sha1) script.PatchPartitionExpr(target_expr, source_expr, '"boot.img.p"') else: logger.info("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.wipe_user_data: script.Print("Erasing user data...") script.FormatPartition("/data") if OPTIONS.two_step: script.AppendExtra(""" set_stage("%(bcb_dev)s", ""); endif; endif; """ % bcb_dev) script.SetProgress(1) # For downgrade OTAs, we prefer to use the update-binary in the source # build that is actually newer than the one in the target build. if OPTIONS.downgrade: script.AddToZip(source_zip, output_zip, input_path=OPTIONS.updater_binary) else: script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) metadata.required_cache = script.required_cache # We haven't written the metadata entry yet, which will be handled in # FinalizeMetadata(). common.ZipClose(output_zip) # Sign the generated zip package unless no_signing is specified. needed_property_files = ( NonAbOtaPropertyFiles(), ) FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
def WriteFullOTAPackage(input_zip, output_file): target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts) # We don't know what version it will be installed on top of. We expect the API # just won't change very often. Similarly for fstab, it might have changed in # the target build. target_api_version = target_info["recovery_api_version"] script = edify_generator.EdifyGenerator(target_api_version, target_info) if target_info.oem_props and not OPTIONS.oem_no_mount: target_info.WriteMountOemScript(script) metadata = GetPackageMetadata(target_info) if not OPTIONS.no_signing: staging_file = common.MakeTempFile(suffix='.zip') else: staging_file = output_file output_zip = zipfile.ZipFile( staging_file, "w", compression=zipfile.ZIP_DEFLATED) device_specific = common.DeviceSpecificParams( input_zip=input_zip, input_version=target_api_version, output_zip=output_zip, script=script, input_tmp=OPTIONS.input_tmp, metadata=metadata, info_dict=OPTIONS.info_dict) assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict) # Assertions (e.g. downgrade check, device properties check). #ts = target_info.GetBuildProp("ro.build.date.utc") #ts_text = target_info.GetBuildProp("ro.build.date") #script.AssertOlderBuild(ts, ts_text) target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount) device_specific.FullOTA_Assertions() block_diff_dict = GetBlockDifferences(target_zip=input_zip, source_zip=None, target_info=target_info, source_info=None, device_specific=device_specific) # Two-step 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": # 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") # set stage to "" # do normal full package installation: # wipe and install system, boot image, etc. # set up system to update recovery partition on first boot # complete script normally # (allow recovery to mark itself finished and reboot) #recovery_img = common.GetBootableImage("recovery.img", "recovery.img", # OPTIONS.input_tmp, "RECOVERY") if OPTIONS.two_step: if not target_info.get("multistage_support"): assert False, "two-step packages not supported by this build" fs = target_info["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", recovery_img.data) script.AppendExtra(""" if get_stage("%(bcb_dev)s") == "2/3" then """ % bcb_dev) # Stage 2/3: Write recovery image to /recovery (currently running /boot). script.Comment("Stage 2/3") #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") == "3/3" then """ % bcb_dev) # Stage 3/3: Make changes. script.Comment("Stage 3/3") # Dump fingerprints script.Print("Target: {}".format(target_info.fingerprint)) androidver = target_info.GetBuildProp("ro.build.version.release") buildid = target_info.GetBuildProp("ro.build.id") builddate = target_info.GetBuildProp("ro.build.date") securep = target_info.GetBuildProp("ro.build.version.security_patch") name = target_info.GetBuildProp("ro.product.name") model = target_info.GetBuildProp("ro.product.model") manufacturer = target_info.GetBuildProp("ro.product.manufacturer") builduser = target_info.GetBuildProp("ro.build.user") buildsdk = target_info.GetBuildProp("ro.build.version.sdk") # Start output script.Print("----------------------------------------------") script.Print(" _____ _ _ _ _ ___ ") script.Print(" _____ _|_ _| | | |_ __ ___ | | | |_ _|") script.Print(" / _ \ \/ / | | | |_| | '_ ` _ \ | | | || |") script.Print("| __/> < | | | _ | | | | | | | |_| || |") script.Print(" \___/_/\_\ |_| |_| |_|_| |_| |_| \___/|___|") script.Print("") script.Print(" extended TouHou modified UI") script.Print(" Based on AOSP") script.Print("----------------------------------------------") script.Print("ROM Information :") script.Print("Build Date : %s"%(builddate)) script.Print("Android Version : %s"%(androidver)) script.Print("exTHmUI Version : %s"%(buildid)) script.Print("SDK Version : %s"%(buildsdk)) script.Print("Security Patch Date: %s"%(securep)) script.Print("----------------------------------------------") script.Print("Device Information :") script.Print("Manufacturer : %s"%(manufacturer)) script.Print("Name : %s"%(name)) script.Print("Model : %s"%(model)) script.Print("----------------------------------------------") script.Print("Installing exTHmUI to your device...") script.Print("") device_specific.FullOTA_InstallBegin() CopyInstallTools(output_zip) script.UnpackPackageDir("install", "/tmp/install") script.SetPermissionsRecursive("/tmp/install", 0, 0, 0o755, 0o644, None, None) script.SetPermissionsRecursive("/tmp/install/bin", 0, 0, 0o755, 0o755, None, None) if target_info.get("system_root_image") == "true": sysmount = "/" else: sysmount = "/system" if OPTIONS.backuptool: script.RunBackup("backup", sysmount, target_info.get('use_dynamic_partitions') == "true") # All other partitions as well as the data wipe use 10% of the progress, and # the update of the system partition takes the remaining progress. system_progress = 0.9 - (len(block_diff_dict) - 1) * 0.1 if OPTIONS.wipe_user_data: system_progress -= 0.1 progress_dict = {partition: 0.1 for partition in block_diff_dict} progress_dict["system"] = system_progress if target_info.get('use_dynamic_partitions') == "true": # Use empty source_info_dict to indicate that all partitions / groups must # be re-added. dynamic_partitions_diff = common.DynamicPartitionsDifference( info_dict=OPTIONS.info_dict, block_diffs=block_diff_dict.values(), progress_dict=progress_dict, build_without_vendor=(not HasPartition(input_zip, "vendor"))) dynamic_partitions_diff.WriteScript(script, output_zip, write_verify_script=OPTIONS.verify) else: for block_diff in block_diff_dict.values(): block_diff.WriteScript(script, output_zip, progress=progress_dict.get(block_diff.partition), write_verify_script=OPTIONS.verify) CheckVintfIfTrebleEnabled(OPTIONS.input_tmp, target_info) boot_img = common.GetBootableImage( "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") common.CheckSize(boot_img.data, "boot.img", target_info) common.ZipWriteStr(output_zip, "boot.img", boot_img.data) device_specific.FullOTA_PostValidate() if OPTIONS.backuptool: script.ShowProgress(0.02, 10) script.RunBackup("restore", sysmount, target_info.get('use_dynamic_partitions') == "true") script.WriteRawImage("/boot", "boot.img") script.ShowProgress(0.1, 10) device_specific.FullOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) script.UnmountAll() if OPTIONS.wipe_user_data: script.ShowProgress(0.1, 10) script.FormatPartition("/data") if OPTIONS.two_step: script.AppendExtra(""" set_stage("%(bcb_dev)s", ""); """ % bcb_dev) script.AppendExtra("else\n") # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot. script.Comment("Stage 1/3") _WriteRecoveryImageToBoot(script, output_zip) script.AppendExtra(""" set_stage("%(bcb_dev)s", "2/3"); reboot_now("%(bcb_dev)s", ""); endif; endif; """ % bcb_dev) script.SetProgress(1) script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) metadata.required_cache = script.required_cache # We haven't written the metadata entry, which will be done in # FinalizeMetadata. common.ZipClose(output_zip) needed_property_files = ( NonAbOtaPropertyFiles(), ) FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
def WriteIncrementalOTAPackage(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) if OPTIONS.override_prop: metadata = { "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.target_info_dict), } else: 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) print "Loading target..." target_data = LoadSystemFiles(target_zip) print "Loading source..." source_data = LoadSystemFiles(source_zip) verbatim_targets = [] patch_list = [] diffs = [] renames = {} largest_source_size = 0 matching_file_cache = {} for fn in source_data.keys(): sf = source_data[fn] assert fn == sf.name matching_file_cache["path:" + fn] = sf # Only allow eligability for filename/sha matching # if there isn't a perfect path match. if target_data.get(sf.name) is None: matching_file_cache["file:" + fn.split("/")[-1]] = sf matching_file_cache["sha:" + sf.sha1] = sf for fn in sorted(target_data.keys()): tf = target_data[fn] assert fn == tf.name sf = ClosestFileMatch(tf, matching_file_cache, renames) if sf is not None and sf.name != tf.name: print "File has moved from " + sf.name + " to " + tf.name renames[sf.name] = tf if sf is None or fn in OPTIONS.require_verbatim: # This file should be included verbatim if fn in OPTIONS.prohibit_verbatim: raise common.ExternalError("\"%s\" must be sent verbatim" % (fn, )) print "send", fn, "verbatim" tf.AddToZip(output_zip) verbatim_targets.append((fn, tf.size)) elif tf.sha1 != sf.sha1: # File is different; consider sending as a patch diffs.append(common.Difference(tf, sf)) else: # Target file data identical to source (may still be renamed) pass # common.ComputeDifferences(diffs) # # for diff in diffs: # tf, sf, d = diff.GetPatch() # if d is None or len(d) > tf.size * OPTIONS.patch_threshold: # # patch is almost as big as the file; don't bother patching # tf.AddToZip(output_zip) # verbatim_targets.append((tf.name, tf.size)) # else: # common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d) # patch_list.append((sf.name, tf, sf, tf.size, common.sha1(d).hexdigest())) # largest_source_size = max(largest_source_size, sf.size) if not OPTIONS.override_prop: 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 script.Mount("/system") script.AssertSomeFingerprint(source_fp, 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 = (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) updating_recovery = False # Here's how we divide up the progress bar: # 0.1 for verifying the start state (PatchCheck calls) # 0.8 for applying patches (ApplyPatch calls) # 0.1 for unpacking verbatim files, symlinking, and doing the # device-specific commands. AppendAssertions(script, OPTIONS.target_info_dict) device_specific.IncrementalOTA_Assertions() script.Print("Verifying current system...") device_specific.IncrementalOTA_VerifyBegin() script.ShowProgress(0.1, 0) total_verify_size = float(sum([i[2].size for i in patch_list]) + 1) if updating_boot: total_verify_size += source_boot.size so_far = 0 for fn, tf, sf, size, patch_sha in patch_list: script.PatchCheck("/" + fn, tf.sha1, sf.sha1) so_far += sf.size script.SetProgress(so_far / total_verify_size) if updating_boot: 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)) so_far += source_boot.size script.SetProgress(so_far / total_verify_size) if patch_list or updating_recovery or updating_boot: script.CacheFreeSpaceCheck(largest_source_size) device_specific.IncrementalOTA_VerifyEnd() 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("Removing unneeded files...") script.DeleteFiles(["/" + i[0] for i in verbatim_targets] + [ "/" + i for i in sorted(source_data) if i not in target_data and i not in renames ] + ["/system/recovery.img"]) script.ShowProgress(0.8, 0) total_patch_size = float(sum([i[1].size for i in patch_list]) + 1) if updating_boot: total_patch_size += target_boot.size so_far = 0 script.Print("Patching system files...") deferred_patch_list = [] for item in patch_list: fn, tf, sf, size, _ = item if tf.name == "system/build.prop": deferred_patch_list.append(item) continue script.ApplyPatch("/" + fn, "-", tf.size, tf.sha1, sf.sha1, "patch/" + fn + ".p") so_far += tf.size script.SetProgress(so_far / total_patch_size) 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") so_far += target_boot.size script.SetProgress(so_far / total_patch_size) print "boot image changed; including." else: print "boot image unchanged; skipping." if updating_recovery: # Recovery is generated as a patch using both the boot image # (which contains the same linux kernel as recovery) and the file # /system/etc/recovery-resource.dat (which contains all the images # used in the recovery UI) as sources. This lets us minimize the # size of the patch, which must be included in every OTA package. # # For older builds where recovery-resource.dat is not present, we # use only the boot image as the source. MakeRecoveryPatch(OPTIONS.target_tmp, output_zip, target_recovery, target_boot) script.DeleteFiles([ "/system/recovery-from-boot.p", "/system/etc/install-recovery.sh" ]) print "recovery image changed; including as patch from boot." else: print "recovery image unchanged; skipping." script.ShowProgress(0.1, 10) target_symlinks = CopySystemFiles(target_zip, None) target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) temp_script = script.MakeTemporary() Item.GetMetadata(target_zip) Item.Get("system").SetPermissions(temp_script) # Note that this call will mess up the tree of Items, so make sure # we're done with it. source_symlinks = CopySystemFiles(source_zip, None) source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) # Delete all the symlinks in source that aren't in target. This # needs to happen before verbatim files are unpacked, in case a # symlink in the source is replaced by a real file in the target. to_delete = [] for dest, link in source_symlinks: if link not in target_symlinks_d: to_delete.append(link) script.DeleteFiles(to_delete) if verbatim_targets: script.Print("Unpacking new files...") script.UnpackPackageDir("system", "/system") #if updating_recovery: # script.Print("Unpacking new recovery...") # script.UnpackPackageDir("recovery", "/system") if len(renames) > 0: script.Print("Renaming files...") for src in renames: print "Renaming " + src + " to " + renames[src].name script.RenameFile(src, renames[src].name) script.Print("Symlinks and permissions...") # Create all the symlinks that don't already exist, or point to # somewhere different than what we want. Delete each symlink before # creating it, since the 'symlink' command won't overwrite. to_create = [] for dest, link in target_symlinks: if link in source_symlinks_d: if dest != source_symlinks_d[link]: to_create.append((dest, link)) else: to_create.append((dest, link)) script.DeleteFiles([i[1] for i in to_create]) script.MakeSymlinks(to_create) # Now that the symlinks are created, we can set all the # permissions. script.AppendScript(temp_script) # Do device-specific installation (eg, write radio image). device_specific.IncrementalOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) # Patch the build.prop file last, so if something fails but the # device can still come up, it appears to be the old build and will # get set the OTA package again to retry. script.Print("Patching remaining system files...") for item in deferred_patch_list: fn, tf, sf, size, _ = item script.ApplyPatch("/" + fn, "-", tf.size, tf.sha1, sf.sha1, "patch/" + fn + ".p") script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None) script.AddToZip(target_zip, output_zip) WriteMetadata(metadata, output_zip)
def WriteFullOTAPackage(input_zip, output_file): target_info = common.BuildInfo(OPTIONS.info_dict, OPTIONS.oem_dicts) # We don't know what version it will be installed on top of. We expect the API # just won't change very often. Similarly for fstab, it might have changed in # the target build. target_api_version = target_info["recovery_api_version"] script = edify_generator.EdifyGenerator(target_api_version, target_info) if target_info.oem_props and not OPTIONS.oem_no_mount: target_info.WriteMountOemScript(script) metadata = GetPackageMetadata(target_info) if not OPTIONS.no_signing: staging_file = common.MakeTempFile(suffix='.zip') else: staging_file = output_file output_zip = zipfile.ZipFile(staging_file, "w", compression=zipfile.ZIP_DEFLATED) device_specific = common.DeviceSpecificParams( input_zip=input_zip, input_version=target_api_version, output_zip=output_zip, script=script, input_tmp=OPTIONS.input_tmp, metadata=metadata, info_dict=OPTIONS.info_dict) assert HasRecoveryPatch(input_zip, info_dict=OPTIONS.info_dict) # Assertions (e.g. downgrade check, device properties check). ts = target_info.GetBuildProp("ro.build.date.utc") ts_text = target_info.GetBuildProp("ro.build.date") script.AssertOlderBuild(ts, ts_text) target_info.WriteDeviceAssertions(script, OPTIONS.oem_no_mount) device_specific.FullOTA_Assertions() block_diff_dict = GetBlockDifferences(target_zip=input_zip, source_zip=None, target_info=target_info, source_info=None, device_specific=device_specific) # Two-step 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": # 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") # set stage to "" # do normal full package installation: # wipe and install system, boot image, etc. # set up system to update recovery partition on first boot # complete script normally # (allow recovery to mark itself finished and reboot) #recovery_img = common.GetBootableImage("recovery.img", "recovery.img", # OPTIONS.input_tmp, "RECOVERY") if OPTIONS.two_step: if not target_info.get("multistage_support"): assert False, "two-step packages not supported by this build" fs = target_info["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", recovery_img.data) script.AppendExtra(""" if get_stage("%(bcb_dev)s") == "2/3" then """ % bcb_dev) # Stage 2/3: Write recovery image to /recovery (currently running /boot). script.Comment("Stage 2/3") #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") == "3/3" then """ % bcb_dev) # Stage 3/3: Make changes. script.Comment("Stage 3/3") # Dump fingerprints script.Print("Target: {}".format(target_info.fingerprint)) script.AppendExtra( "ifelse(is_mounted(\"/system\"), unmount(\"/system\"));") device_specific.FullOTA_InstallBegin() # All other partitions as well as the data wipe use 10% of the progress, and # the update of the system partition takes the remaining progress. system_progress = 0.9 - (len(block_diff_dict) - 1) * 0.1 if OPTIONS.wipe_user_data: system_progress -= 0.1 progress_dict = {partition: 0.1 for partition in block_diff_dict} progress_dict["system"] = system_progress if target_info.get('use_dynamic_partitions') == "true": # Use empty source_info_dict to indicate that all partitions / groups must # be re-added. dynamic_partitions_diff = common.DynamicPartitionsDifference( info_dict=OPTIONS.info_dict, block_diffs=block_diff_dict.values(), progress_dict=progress_dict) dynamic_partitions_diff.WriteScript(script, output_zip, write_verify_script=OPTIONS.verify) else: for block_diff in block_diff_dict.values(): block_diff.WriteScript(script, output_zip, progress=progress_dict.get( block_diff.partition), write_verify_script=OPTIONS.verify) CheckVintfIfTrebleEnabled(OPTIONS.input_tmp, target_info) boot_img = common.GetBootableImage("boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") common.CheckSize(boot_img.data, "boot.img", target_info) common.ZipWriteStr(output_zip, "boot.img", boot_img.data) script.WriteRawImage("/boot", "boot.img") script.ShowProgress(0.1, 10) device_specific.FullOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) script.UnmountAll() if OPTIONS.wipe_user_data: script.ShowProgress(0.1, 10) script.FormatPartition("/data") if OPTIONS.two_step: script.AppendExtra(""" set_stage("%(bcb_dev)s", ""); """ % bcb_dev) script.AppendExtra("else\n") # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot. script.Comment("Stage 1/3") _WriteRecoveryImageToBoot(script, output_zip) script.AppendExtra(""" set_stage("%(bcb_dev)s", "2/3"); reboot_now("%(bcb_dev)s", ""); endif; endif; """ % bcb_dev) script.SetProgress(1) script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) metadata.required_cache = script.required_cache # We haven't written the metadata entry, which will be done in # FinalizeMetadata. common.ZipClose(output_zip) needed_property_files = (NonAbOtaPropertyFiles(), ) FinalizeMetadata(metadata, staging_file, output_file, needed_property_files)
def WriteFullOTAPackage(input_zip, output_zip): # TODO: how to determine this? We don't know what version it will # be installed on top of. For now, we expect the API just won't # change very often. script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict) if OPTIONS.override_prop: metadata = { "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), } else: metadata = { "post-build": GetBuildProp("ro.build.fingerprint", OPTIONS.info_dict), "pre-device": GetBuildProp("ro.product.device", OPTIONS.info_dict), "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), } device_specific = common.DeviceSpecificParams( input_zip=input_zip, input_version=OPTIONS.info_dict["recovery_api_version"], output_zip=output_zip, script=script, input_tmp=OPTIONS.input_tmp, metadata=metadata, info_dict=OPTIONS.info_dict) #if not OPTIONS.omit_prereq: # ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict) # ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict) # script.AssertOlderBuild(ts, ts_text) AppendAssertions(script, OPTIONS.info_dict) device_specific.FullOTA_Assertions() device_specific.FullOTA_InstallBegin() if OPTIONS.backuptool: script.Mount("/system") script.RunBackup("backup") script.Unmount("/system") script.ShowProgress(0.5, 0) if OPTIONS.wipe_user_data: script.FormatPartition("/data") if "selinux_fc" in OPTIONS.info_dict: WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) script.FormatPartition("/system") script.Mount("/system") #script.UnpackPackageDir("recovery", "/system") script.UnpackPackageDir("system", "/system") symlinks = CopySystemFiles(input_zip, output_zip) script.MakeSymlinks(symlinks) boot_img = common.GetBootableImage("boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") #recovery_img = common.GetBootableImage("recovery.img", "recovery.img", # OPTIONS.input_tmp, "RECOVERY") #MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img) Item.GetMetadata(input_zip) Item.Get("system").SetPermissions(script) common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) common.ZipWriteStr(output_zip, "boot.img", boot_img.data) script.ShowProgress(0.2, 0) if OPTIONS.backuptool: script.ShowProgress(0.2, 10) script.RunBackup("restore") script.ShowProgress(0.2, 10) script.WriteRawImage("/boot", "boot.img") script.ShowProgress(0.1, 0) device_specific.FullOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) script.UnmountAll() script.AddToZip(input_zip, output_zip) WriteMetadata(metadata, output_zip)