diff options
Diffstat (limited to 'tools/releasetools')
-rwxr-xr-x | tools/releasetools/check_target_files_signatures | 5 | ||||
-rw-r--r-- | tools/releasetools/common.py | 126 | ||||
-rw-r--r-- | tools/releasetools/edify_generator.py | 32 | ||||
-rwxr-xr-x | tools/releasetools/img_from_target_files | 35 | ||||
-rwxr-xr-x | tools/releasetools/ota_from_target_files | 105 | ||||
-rwxr-xr-x | tools/releasetools/sign_target_files_apks | 19 |
6 files changed, 205 insertions, 117 deletions
diff --git a/tools/releasetools/check_target_files_signatures b/tools/releasetools/check_target_files_signatures index 99bc801..1325ef4 100755 --- a/tools/releasetools/check_target_files_signatures +++ b/tools/releasetools/check_target_files_signatures @@ -116,7 +116,7 @@ class CertDB(object): self.certs[cert] = self.certs[cert] + "," + name else: if name is None: - name = "unknown cert %s (%s)" % (sha1(cert).hexdigest()[:12], + name = "unknown cert %s (%s)" % (common.sha1(cert).hexdigest()[:12], GetCertSubject(cert)) self.certs[cert] = name @@ -249,7 +249,7 @@ class TargetFiles(object): self.max_fn_len = 20 def LoadZipFile(self, filename): - d = common.UnzipTemp(filename, '*.apk') + d, z = common.UnzipTemp(filename, '*.apk') try: self.apks = {} self.apks_by_basename = {} @@ -267,7 +267,6 @@ class TargetFiles(object): finally: shutil.rmtree(d) - z = zipfile.ZipFile(open(filename, "rb")) self.certmap = common.ReadApkCerts(z) z.close() diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index fd098ea..2cb5680 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -165,11 +165,27 @@ def LoadRecoveryFSTab(zip): p.mount_point = pieces[0] p.fs_type = pieces[1] p.device = pieces[2] - if len(pieces) == 4: - p.device2 = pieces[3] + p.length = 0 + options = None + if len(pieces) >= 4: + if pieces[3].startswith("/"): + p.device2 = pieces[3] + if len(pieces) >= 5: + options = pieces[4] + else: + p.device2 = None + options = pieces[3] else: p.device2 = None + if options: + options = options.split(",") + for i in options: + if i.startswith("length="): + p.length = int(i[7:]) + else: + print "%s: unknown option \"%s\"" % (p.mount_point, i) + d[p.mount_point] = p return d @@ -178,23 +194,6 @@ def DumpInfoDict(d): for k, v in sorted(d.items()): print "%-25s = (%s) %s" % (k, type(v).__name__, v) -def BuildAndAddBootableImage(sourcedir, targetname, output_zip, info_dict): - """Take a kernel, cmdline, and ramdisk directory from the input (in - 'sourcedir'), and turn them into a boot image. Put the boot image - into the output zip file under the name 'targetname'. Returns - targetname on success or None on failure (if sourcedir does not - appear to contain files for the requested image).""" - - print "creating %s..." % (targetname,) - - img = BuildBootableImage(sourcedir) - if img is None: - return None - - CheckSize(img, targetname, info_dict) - ZipWriteStr(output_zip, targetname, img) - return targetname - def BuildBootableImage(sourcedir): """Take a kernel, cmdline, and ramdisk directory from the input (in 'sourcedir'), and turn them into a boot image. Return the image @@ -252,28 +251,53 @@ def BuildBootableImage(sourcedir): return data -def AddRecovery(output_zip, info_dict): - BuildAndAddBootableImage(os.path.join(OPTIONS.input_tmp, "RECOVERY"), - "recovery.img", output_zip, info_dict) +def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir): + """Return a File object (with name 'name') with the desired bootable + image. Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name + 'prebuilt_name', otherwise construct it from the source files in + 'unpack_dir'/'tree_subdir'.""" + + prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name) + if os.path.exists(prebuilt_path): + print "using prebuilt %s..." % (prebuilt_name,) + return File.FromLocalFile(name, prebuilt_path) + else: + print "building image from target_files %s..." % (tree_subdir,) + return File(name, BuildBootableImage(os.path.join(unpack_dir, tree_subdir))) -def AddBoot(output_zip, info_dict): - BuildAndAddBootableImage(os.path.join(OPTIONS.input_tmp, "BOOT"), - "boot.img", output_zip, info_dict) def UnzipTemp(filename, pattern=None): - """Unzip the given archive into a temporary directory and return the name.""" + """Unzip the given archive into a temporary directory and return the name. + + If filename is of the form "foo.zip+bar.zip", unzip foo.zip into a + temp dir, then unzip bar.zip into that_dir/BOOTABLE_IMAGES. + + Returns (tempdir, zipobj) where zipobj is a zipfile.ZipFile (of the + main file), open for reading. + """ tmp = tempfile.mkdtemp(prefix="targetfiles-") OPTIONS.tempfiles.append(tmp) - cmd = ["unzip", "-o", "-q", filename, "-d", tmp] - if pattern is not None: - cmd.append(pattern) - p = Run(cmd, stdout=subprocess.PIPE) - p.communicate() - if p.returncode != 0: - raise ExternalError("failed to unzip input target-files \"%s\"" % - (filename,)) - return tmp + + def unzip_to_dir(filename, dirname): + cmd = ["unzip", "-o", "-q", filename, "-d", dirname] + if pattern is not None: + cmd.append(pattern) + p = Run(cmd, stdout=subprocess.PIPE) + p.communicate() + if p.returncode != 0: + raise ExternalError("failed to unzip input target-files \"%s\"" % + (filename,)) + + m = re.match(r"^(.*[.]zip)\+(.*[.]zip)$", filename, re.IGNORECASE) + if m: + unzip_to_dir(m.group(1), tmp) + unzip_to_dir(m.group(2), os.path.join(tmp, "BOOTABLE_IMAGES")) + filename = m.group(1) + else: + unzip_to_dir(filename, tmp) + + return tmp, zipfile.ZipFile(filename, "r") def GetKeyPasswords(keylist): @@ -330,7 +354,7 @@ def SignFile(input_name, output_name, key, password, align=None, else: sign_name = output_name - cmd = ["java", "-Xmx512m", "-jar", + cmd = ["java", "-Xmx2048m", "-jar", os.path.join(OPTIONS.search_path, "framework", "signapk.jar")] if whole_file: cmd.append("-w") @@ -371,18 +395,17 @@ def CheckSize(data, target, info_dict): # image size should be increased by 1/64th to account for the # spare area (64 bytes per 2k page) limit = limit / 2048 * (2048+64) - - size = len(data) - pct = float(size) * 100.0 / limit - msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit) - if pct >= 99.0: - raise ExternalError(msg) - elif pct >= 95.0: - print - print " WARNING: ", msg - print - elif OPTIONS.verbose: - print " ", msg + size = len(data) + pct = float(size) * 100.0 / limit + msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit) + if pct >= 99.0: + raise ExternalError(msg) + elif pct >= 95.0: + print + print " WARNING: ", msg + print + elif OPTIONS.verbose: + print " ", msg def ReadApkCerts(tf_zip): @@ -665,6 +688,13 @@ class File(object): self.size = len(data) self.sha1 = sha1(data).hexdigest() + @classmethod + def FromLocalFile(cls, name, diskname): + f = open(diskname, "rb") + data = f.read() + f.close() + return File(name, data) + def WriteToTemp(self): t = tempfile.NamedTemporaryFile() t.write(self.data) diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py index a7c8e32..6c53f9e 100644 --- a/tools/releasetools/edify_generator.py +++ b/tools/releasetools/edify_generator.py @@ -161,11 +161,13 @@ class EdifyGenerator(object): """Format the given partition, specified by its mount point (eg, "/system").""" + reserve_size = 0 fstab = self.info.get("fstab", None) if fstab: p = fstab[partition] - self.script.append('format("%s", "%s", "%s");' % - (p.fs_type, common.PARTITION_TYPES[p.fs_type], p.device)) + self.script.append('format("%s", "%s", "%s", "%s");' % + (p.fs_type, common.PARTITION_TYPES[p.fs_type], + p.device, p.length)) def DeleteFiles(self, file_list): """Delete all files in file_list.""" @@ -187,18 +189,6 @@ class EdifyGenerator(object): cmd = "".join(cmd) self.script.append(self._WordWrap(cmd)) - def WriteFirmwareImage(self, kind, fn): - """Arrange to update the given firmware image (kind must be - "hboot" or "radio") when recovery finishes.""" - if self.version == 1: - self.script.append( - ('assert(package_extract_file("%(fn)s", "/tmp/%(kind)s.img"),\n' - ' write_firmware_image("/tmp/%(kind)s.img", "%(kind)s"));') - % {'kind': kind, 'fn': fn}) - else: - self.script.append( - 'write_firmware_image("PACKAGE:%s", "%s");' % (fn, kind)) - def WriteRawImage(self, mount_point, fn): """Write the given package file into the partition for the given mount point.""" @@ -239,6 +229,20 @@ class EdifyGenerator(object): ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");") self.script.append(self._WordWrap(cmd)) + def RetouchBinaries(self, file_list): + """Execute the retouch instructions in files listed.""" + cmd = ('retouch_binaries(' + + ', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) + + ');') + self.script.append(self._WordWrap(cmd)) + + def UndoRetouchBinaries(self, file_list): + """Undo the retouching (retouch to zero offset).""" + cmd = ('undo_retouch_binaries(' + + ', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) + + ');') + self.script.append(self._WordWrap(cmd)) + def AppendExtra(self, extra): """Append text verbatim to the output script.""" self.script.append(extra) diff --git a/tools/releasetools/img_from_target_files b/tools/releasetools/img_from_target_files index 4a23ab4..c5b9886 100755 --- a/tools/releasetools/img_from_target_files +++ b/tools/releasetools/img_from_target_files @@ -23,6 +23,10 @@ Usage: img_from_target_files [flags] input_target_files output_image_zip -b (--board_config) <file> Deprecated. + -z (--bootable_zip) + Include only the bootable images (eg 'boot' and 'recovery') in + the output. + """ import sys @@ -78,7 +82,7 @@ def AddUserdata(output_zip): build_command.append(user_dir) build_command.append(img.name) - p = common.Run(build_command) + p = common.Run(build_command); p.communicate() assert p.returncode == 0, "build userdata.img image failed" @@ -149,35 +153,44 @@ def CopyInfo(output_zip): def main(argv): + bootable_only = [False] def option_handler(o, a): if o in ("-b", "--board_config"): pass # deprecated + if o in ("-z", "--bootable_zip"): + bootable_only[0] = True else: return False return True args = common.ParseOptions(argv, __doc__, - extra_opts="b:", - extra_long_opts=["board_config="], + extra_opts="b:z", + extra_long_opts=["board_config=", + "bootable_zip"], extra_option_handler=option_handler) + bootable_only = bootable_only[0] + if len(args) != 2: common.Usage(__doc__) sys.exit(1) - OPTIONS.input_tmp = common.UnzipTemp(args[0]) - - input_zip = zipfile.ZipFile(args[0], "r") + OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) OPTIONS.info_dict = common.LoadInfoDict(input_zip) output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) - common.AddBoot(output_zip, OPTIONS.info_dict) - common.AddRecovery(output_zip, OPTIONS.info_dict) - AddSystem(output_zip) - AddUserdata(output_zip) - CopyInfo(output_zip) + common.GetBootableImage( + "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT").AddToZip(output_zip) + common.GetBootableImage( + "recovery.img", "recovery.img", OPTIONS.input_tmp, + "RECOVERY").AddToZip(output_zip) + + if not bootable_only: + AddSystem(output_zip) + AddUserdata(output_zip) + CopyInfo(output_zip) print "cleaning up..." output_zip.close() diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files index 78f37db..aead38f 100755 --- a/tools/releasetools/ota_from_target_files +++ b/tools/releasetools/ota_from_target_files @@ -44,6 +44,8 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package -e (--extra_script) <file> Insert the contents of file at the end of the update script. + -a (--aslr_mode) <on|off> + Specify whether to turn on ASLR for the package (on by default). """ import sys @@ -78,6 +80,7 @@ OPTIONS.patch_threshold = 0.95 OPTIONS.wipe_user_data = False OPTIONS.omit_prereq = False OPTIONS.extra_script = None +OPTIONS.aslr_mode = True OPTIONS.worker_threads = 3 def MostPopularKey(d, default): @@ -94,6 +97,10 @@ def IsSymlink(info): symlink.""" return (info.external_attr >> 16) == 0120777 +def IsRegular(info): + """Return true if the zipfile.ZipInfo object passed in represents a + symlink.""" + return (info.external_attr >> 28) == 010 class Item: """Items represent the metadata (user, group, mode) of files and @@ -248,13 +255,15 @@ def CopySystemFiles(input_zip, output_zip=None, substitute=None): """Copies files underneath system/ in the input zip to the output zip. Populates the Item class with their metadata, and returns a - list of symlinks. output_zip may be None, in which case the copy is - skipped (but the other side effects still happen). substitute is an - optional dict of {output filename: contents} to be output instead of - certain input files. + list of symlinks as well as a list of files that will be retouched. + output_zip may be None, in which case the copy is skipped (but the + other side effects still happen). substitute is an optional dict + of {output filename: contents} to be output instead of certain input + files. """ symlinks = [] + retouch_files = [] for info in input_zip.infolist(): if info.filename.startswith("SYSTEM/"): @@ -272,6 +281,9 @@ def CopySystemFiles(input_zip, output_zip=None, data = substitute[fn] else: data = input_zip.read(info.filename) + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + common.sha1(data).hexdigest())) output_zip.writestr(info2, data) if fn.endswith("/"): Item.Get(fn[:-1], dir=True) @@ -279,7 +291,7 @@ def CopySystemFiles(input_zip, output_zip=None, Item.Get(fn, dir=False) symlinks.sort() - return symlinks + return (symlinks, retouch_files) def SignOutput(temp_zip_name, output_zip_name): @@ -304,7 +316,8 @@ def MakeRecoveryPatch(output_zip, recovery_img, boot_img): patching and install the new recovery image. recovery_img and boot_img should be File objects for the - corresponding images. + corresponding images. info should be the dictionary returned by + common.LoadInfoDict() on the input target_files. Returns an Item for the shell script, which must be made executable. @@ -322,7 +335,7 @@ def MakeRecoveryPatch(output_zip, recovery_img, boot_img): # we check to see if this recovery has already been installed by # testing just the first 2k. HEADER_SIZE = 2048 - header_sha1 = sha1(recovery_img.data[:HEADER_SIZE]).hexdigest() + header_sha1 = common.sha1(recovery_img.data[:HEADER_SIZE]).hexdigest() sh = """#!/system/bin/sh if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(header_size)d:%(header_sha1)s; then log -t recovery "Installing new recovery image" @@ -382,13 +395,17 @@ def WriteFullOTAPackage(input_zip, output_zip): script.UnpackPackageDir("recovery", "/system") script.UnpackPackageDir("system", "/system") - symlinks = CopySystemFiles(input_zip, output_zip) + (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip) script.MakeSymlinks(symlinks) + if OPTIONS.aslr_mode: + script.RetouchBinaries(retouch_files) + else: + script.UndoRetouchBinaries(retouch_files) - boot_img = common.File("boot.img", common.BuildBootableImage( - os.path.join(OPTIONS.input_tmp, "BOOT"))) - recovery_img = common.File("recovery.img", common.BuildBootableImage( - os.path.join(OPTIONS.input_tmp, "RECOVERY"))) + 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(output_zip, recovery_img, boot_img) Item.GetMetadata(input_zip) @@ -424,12 +441,17 @@ def LoadSystemFiles(z): """Load all the files from SYSTEM/... in a given target-files ZipFile, and return a dict of {filename: File object}.""" out = {} + retouch_files = [] for info in z.infolist(): if info.filename.startswith("SYSTEM/") and not IsSymlink(info): - fn = "system/" + info.filename[7:] + basefilename = info.filename[7:] + fn = "system/" + basefilename data = z.read(info.filename) out[fn] = common.File(fn, data) - return out + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + out[fn].sha1)) + return (out, retouch_files) def GetBuildProp(property, z): @@ -451,7 +473,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): if source_version == 0: print ("WARNING: generating edify script for a source that " "can't install it.") - script = edify_generator.EdifyGenerator(source_version, OPTIONS.info_dict) + script = edify_generator.EdifyGenerator(source_version, OPTIONS.target_info_dict) metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip), "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip), @@ -468,9 +490,9 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): info_dict=OPTIONS.info_dict) print "Loading target..." - target_data = LoadSystemFiles(target_zip) + (target_data, target_retouch_files) = LoadSystemFiles(target_zip) print "Loading source..." - source_data = LoadSystemFiles(source_zip) + (source_data, source_retouch_files) = LoadSystemFiles(source_zip) verbatim_targets = [] patch_list = [] @@ -505,7 +527,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): verbatim_targets.append((tf.name, tf.size)) else: common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d) - patch_list.append((tf.name, tf, sf, tf.size, sha1(d).hexdigest())) + patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest())) largest_source_size = max(largest_source_size, sf.size) source_fp = GetBuildProp("ro.build.fingerprint", source_zip) @@ -516,20 +538,16 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): script.Mount("/system") script.AssertSomeFingerprint(source_fp, target_fp) - source_boot = common.File("/tmp/boot.img", - common.BuildBootableImage( - os.path.join(OPTIONS.source_tmp, "BOOT"))) - target_boot = common.File("/tmp/boot.img", - common.BuildBootableImage( - os.path.join(OPTIONS.target_tmp, "BOOT"))) + source_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT") + target_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") updating_boot = (source_boot.data != target_boot.data) - source_recovery = common.File("system/recovery.img", - common.BuildBootableImage( - os.path.join(OPTIONS.source_tmp, "RECOVERY"))) - target_recovery = common.File("system/recovery.img", - common.BuildBootableImage( - os.path.join(OPTIONS.target_tmp, "RECOVERY"))) + source_recovery = common.GetBootableImage( + "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY") + target_recovery = common.GetBootableImage( + "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") updating_recovery = (source_recovery.data != target_recovery.data) # Here's how we divide up the progress bar: @@ -639,7 +657,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): script.ShowProgress(0.1, 10) - target_symlinks = CopySystemFiles(target_zip, None) + (target_symlinks, target_retouch_dummies) = CopySystemFiles(target_zip, None) target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) temp_script = script.MakeTemporary() @@ -648,7 +666,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): # 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, source_retouch_dummies) = 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 @@ -682,6 +700,10 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): to_create.append((dest, link)) script.DeleteFiles([i[1] for i in to_create]) script.MakeSymlinks(to_create) + if OPTIONS.aslr_mode: + script.RetouchBinaries(target_retouch_files) + else: + script.UndoRetouchBinaries(target_retouch_files) # Now that the symlinks are created, we can set all the # permissions. @@ -691,7 +713,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): device_specific.IncrementalOTA_InstallEnd() if OPTIONS.extra_script is not None: - scirpt.AppendExtra(OPTIONS.extra_script) + script.AppendExtra(OPTIONS.extra_script) script.AddToZip(target_zip, output_zip) WriteMetadata(metadata, output_zip) @@ -712,6 +734,11 @@ def main(argv): OPTIONS.omit_prereq = True elif o in ("-e", "--extra_script"): OPTIONS.extra_script = a + elif o in ("-a", "--aslr_mode"): + if a in ("on", "On", "true", "True", "yes", "Yes"): + OPTIONS.aslr_mode = True + else: + OPTIONS.aslr_mode = False elif o in ("--worker_threads"): OPTIONS.worker_threads = int(a) else: @@ -719,14 +746,16 @@ def main(argv): return True args = common.ParseOptions(argv, __doc__, - extra_opts="b:k:i:d:wne:", + extra_opts="b:k:i:d:wne:a:", extra_long_opts=["board_config=", "package_key=", "incremental_from=", "wipe_user_data", "no_prereq", "extra_script=", - "worker_threads="], + "worker_threads=", + "aslr_mode=", + ], extra_option_handler=option_handler) if len(args) != 2: @@ -737,10 +766,9 @@ def main(argv): OPTIONS.extra_script = open(OPTIONS.extra_script).read() print "unzipping target target-files..." - OPTIONS.input_tmp = common.UnzipTemp(args[0]) + OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) OPTIONS.target_tmp = OPTIONS.input_tmp - input_zip = zipfile.ZipFile(args[0], "r") OPTIONS.info_dict = common.LoadInfoDict(input_zip) if OPTIONS.verbose: print "--- target info ---" @@ -764,8 +792,7 @@ def main(argv): WriteFullOTAPackage(input_zip, output_zip) else: print "unzipping source target-files..." - OPTIONS.source_tmp = common.UnzipTemp(OPTIONS.incremental_source) - source_zip = zipfile.ZipFile(OPTIONS.incremental_source, "r") + OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source) OPTIONS.target_info_dict = OPTIONS.info_dict OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) if OPTIONS.verbose: diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks index 5fca691..5353063 100755 --- a/tools/releasetools/sign_target_files_apks +++ b/tools/releasetools/sign_target_files_apks @@ -204,6 +204,17 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip): except KeyError: raise ExternalError("can't read META/otakeys.txt from input") + misc_info = common.LoadInfoDict(input_tf_zip) + + extra_recovery_keys = misc_info.get("extra_recovery_keys", None) + if extra_recovery_keys: + extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem" + for k in extra_recovery_keys.split()] + if extra_recovery_keys: + print "extra recovery-only key(s): " + ", ".join(extra_recovery_keys) + else: + extra_recovery_keys = [] + mapped_keys = [] for k in keylist: m = re.match(r"^(.*)\.x509\.pem$", k) @@ -217,15 +228,18 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip): print "for OTA package verification" else: mapped_keys.append( - OPTIONS.key_map["build/target/product/security/testkey"] + ".x509.pem") + OPTIONS.key_map.get("build/target/product/security/testkey", + "build/target/product/security/testkey") + + ".x509.pem") print "META/otakeys.txt has no keys; using", mapped_keys[0] # recovery uses a version of the key that has been slightly # predigested (by DumpPublicKey.java) and put in res/keys. + # extra_recovery_keys are used only in recovery. p = common.Run(["java", "-jar", os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")] - + mapped_keys, + + mapped_keys + extra_recovery_keys, stdout=subprocess.PIPE) data, _ = p.communicate() if p.returncode != 0: @@ -234,6 +248,7 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip): # SystemUpdateActivity uses the x509.pem version of the keys, but # put into a zipfile system/etc/security/otacerts.zip. + # We DO NOT include the extra_recovery_keys (if any) here. tempfile = cStringIO.StringIO() certs_zip = zipfile.ZipFile(tempfile, "w") |