From 412c02fffbeb137868945f6485b249cc4b49eaea Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 13 Feb 2014 10:58:24 -0800 Subject: [PATCH] rebuild recovery patch in sign_target_files_apks The target_files zip should now contain the recovery-from-boot patch and the script to install it. This means that sign_target_files_apks, which generates a signed target_files from an unsigned target_files, now needs to recompute the patch and script (taking into account the key replacement, property changes, etc., that it does) so its output contains the correct patch. Change-Id: I18afd73864ba5c480b7ec11de19d1f5e7763a8c0 --- tools/releasetools/common.py | 10 ++- tools/releasetools/sign_target_files_apks | 74 ++++++++++++++++++++--- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 6b8bf15b6..adbd32d77 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -990,7 +990,8 @@ def ParseCertificate(data): return cert -def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img): +def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, + info_dict=None): """Generate a binary patch that creates the recovery image starting with the boot image. (Most of the space in these images is just the kernel, which is identical for the two, so the resulting patch @@ -1003,6 +1004,9 @@ def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img): common.LoadInfoDict() on the input target_files. """ + if info_dict is None: + info_dict = OPTIONS.info_dict + diff_program = ["imgdiff"] path = os.path.join(input_dir, "SYSTEM", "etc", "recovery-resource.dat") if os.path.exists(path): @@ -1016,8 +1020,8 @@ def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img): _, _, patch = d.ComputePatch() output_sink("recovery-from-boot.p", patch) - boot_type, boot_device = GetTypeAndDevice("/boot", OPTIONS.info_dict) - recovery_type, recovery_device = GetTypeAndDevice("/recovery", OPTIONS.info_dict) + boot_type, boot_device = GetTypeAndDevice("/boot", info_dict) + recovery_type, recovery_device = GetTypeAndDevice("/recovery", info_dict) sh = """#!/system/bin/sh if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks index ab2470650..bf16436a6 100755 --- a/tools/releasetools/sign_target_files_apks +++ b/tools/releasetools/sign_target_files_apks @@ -77,6 +77,7 @@ import copy import errno import os import re +import shutil import subprocess import tempfile import zipfile @@ -139,14 +140,40 @@ def SignApk(data, keyname, pw): return data -def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords): +def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, + apk_key_map, key_passwords): maxsize = max([len(os.path.basename(i.filename)) for i in input_tf_zip.infolist() if i.filename.endswith('.apk')]) + rebuild_recovery = False + + tmpdir = tempfile.mkdtemp() + def write_to_temp(fn, attr, data): + fn = os.path.join(tmpdir, fn) + if fn.endswith("/"): + fn = os.path.join(tmpdir, fn) + os.mkdir(fn) + else: + d = os.path.dirname(fn) + if d and not os.path.exists(d): + os.makedirs(d) + + if attr >> 16 == 0xa1ff: + os.symlink(data, fn) + else: + with open(fn, "wb") as f: + f.write(data) for info in input_tf_zip.infolist(): data = input_tf_zip.read(info.filename) out_info = copy.copy(info) + + if (info.filename.startswith("BOOT/") or + info.filename.startswith("RECOVERY/") or + info.filename.startswith("META/") or + info.filename == "SYSTEM/etc/recovery-resource.dat"): + write_to_temp(info.filename, info.external_attr, data) + if info.filename.endswith(".apk"): name = os.path.basename(info.filename) key = apk_key_map[name] @@ -163,14 +190,43 @@ def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords): print "rewriting %s:" % (info.filename,) new_data = RewriteProps(data) output_tf_zip.writestr(out_info, new_data) + if info.filename == "RECOVERY/RAMDISK/default.prop": + write_to_temp(info.filename, info.external_attr, new_data) elif info.filename.endswith("mac_permissions.xml"): print "rewriting %s with new keys." % (info.filename,) new_data = ReplaceCerts(data) output_tf_zip.writestr(out_info, new_data) + elif info.filename in ("SYSTEM/recovery-from-boot.p", + "SYSTEM/bin/install-recovery.sh"): + rebuild_recovery = True + elif (OPTIONS.replace_ota_keys and + info.filename in ("RECOVERY/RAMDISK/res/keys", + "SYSTEM/etc/security/otacerts.zip")): + # don't copy these files if we're regenerating them below + pass else: # a non-APK file; copy it verbatim output_tf_zip.writestr(out_info, data) + if OPTIONS.replace_ota_keys: + new_recovery_keys = ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info) + if new_recovery_keys: + write_to_temp("RECOVERY/RAMDISK/res/keys", 0755 << 16, new_recovery_keys) + + if rebuild_recovery: + recovery_img = common.GetBootableImage( + "recovery.img", "recovery.img", tmpdir, "RECOVERY", info_dict=misc_info) + boot_img = common.GetBootableImage( + "boot.img", "boot.img", tmpdir, "BOOT", info_dict=misc_info) + + def output_sink(fn, data): + output_tf_zip.writestr("SYSTEM/"+fn, data) + + common.MakeRecoveryPatch(tmpdir, output_sink, recovery_img, boot_img, + info_dict=misc_info) + + shutil.rmtree(tmpdir) + def ReplaceCerts(data): """Given a string of data, replace all occurences of a set @@ -265,7 +321,8 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): for k in keylist: m = re.match(r"^(.*)\.x509\.pem$", k) if not m: - raise common.ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,)) + raise common.ExternalError( + "can't parse \"%s\" from META/otakeys.txt" % (k,)) k = m.group(1) mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem") @@ -287,10 +344,11 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")] + mapped_keys + extra_recovery_keys, stdout=subprocess.PIPE) - data, _ = p.communicate() + new_recovery_keys, _ = p.communicate() if p.returncode != 0: raise common.ExternalError("failed to run dumpkeys") - common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data) + common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", + new_recovery_keys) # SystemUpdateActivity uses the x509.pem version of the keys, but # put into a zipfile system/etc/security/otacerts.zip. @@ -304,6 +362,8 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", tempfile.getvalue()) + return new_recovery_keys + def BuildKeyMap(misc_info, key_mapping_options): for s, d in key_mapping_options: @@ -375,10 +435,8 @@ def main(argv): CheckAllApksSigned(input_zip, apk_key_map) key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) - SignApks(input_zip, output_zip, apk_key_map, key_passwords) - - if OPTIONS.replace_ota_keys: - ReplaceOtaKeys(input_zip, output_zip, misc_info) + ProcessTargetFiles(input_zip, output_zip, misc_info, + apk_key_map, key_passwords) input_zip.close() output_zip.close()