From: Doug Zongker Date: Mon, 22 Jun 2009 18:32:31 +0000 (-0700) Subject: support hooks for device-specific code in OTA package generation X-Git-Tag: android-x86-2.2~558 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=05d3dea519688b61d86e30c2d4b99ff494aeca73;p=android-x86%2Fbuild.git support hooks for device-specific code in OTA package generation Replace the installation of the "radio image", which is an HTC-specific notion, with calls to device-specific python modules that can add whatever additional OTA script commands are necessary. Add the -s flag to specify the location of the device-specific script (replacing the unused -s flag in sign_target_files_apks). --- diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 0b3803f36..9ba85c684 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -15,6 +15,7 @@ import errno import getopt import getpass +import imp import os import re import shutil @@ -33,7 +34,7 @@ OPTIONS.search_path = "out/host/linux-x86" OPTIONS.max_image_size = {} OPTIONS.verbose = False OPTIONS.tempfiles = [] - +OPTIONS.device_specific = None class ExternalError(RuntimeError): pass @@ -233,6 +234,10 @@ COMMON_DOCSTRING = """ Prepend /bin to the list of places to search for binaries run by this script, and expect to find jars in /framework. + -s (--device_specific) + Path to the python module containing device-specific + releasetools code. + -v (--verbose) Show command lines being executed. @@ -257,8 +262,9 @@ def ParseOptions(argv, try: opts, args = getopt.getopt( - argv, "hvp:" + extra_opts, - ["help", "verbose", "path="] + list(extra_long_opts)) + argv, "hvp:s:" + extra_opts, + ["help", "verbose", "path=", "device_specific="] + + list(extra_long_opts)) except getopt.GetoptError, err: Usage(docstring) print "**", str(err), "**" @@ -274,6 +280,8 @@ def ParseOptions(argv, OPTIONS.verbose = True elif o in ("-p", "--path"): OPTIONS.search_path = a + elif o in ("-s", "--device_specific"): + OPTIONS.device_specific = a else: if extra_option_handler is None or not extra_option_handler(o, a): assert False, "unknown option \"%s\"" % (o,) @@ -398,3 +406,67 @@ def ZipWriteStr(zip, filename, data, perms=0644): zinfo.compress_type = zip.compression zinfo.external_attr = perms << 16 zip.writestr(zinfo, data) + + +class DeviceSpecificParams(object): + module = None + def __init__(self, **kwargs): + """Keyword arguments to the constructor become attributes of this + object, which is passed to all functions in the device-specific + module.""" + for k, v in kwargs.iteritems(): + setattr(self, k, v) + + if self.module is None: + path = OPTIONS.device_specific + if path is None: return + if os.path.isdir(path): + info = imp.find_module("releasetools", [path]) + else: + d, f = os.path.split(path) + b, x = os.path.splitext(f) + if x == ".py": + f = b + info = imp.find_module(f, [d]) + if not info or info[0] is None: + raise ValueError("unable to find device-specific module") + self.module = imp.load_module("device_specific", *info) + + def _DoCall(self, function_name, *args, **kwargs): + """Call the named function in the device-specific module, passing + the given args and kwargs. The first argument to the call will be + the DeviceSpecific object itself. If there is no module, or the + module does not define the function, return the value of the + 'default' kwarg (which itself defaults to None).""" + if self.module is None or not hasattr(self.module, function_name): + return kwargs.get("default", None) + return getattr(self.module, function_name)(*((self,) + args), **kwargs) + + def FullOTA_Assertions(self): + """Called after emitting the block of assertions at the top of a + full OTA package. Implementations can add whatever additional + assertions they like.""" + return self._DoCall("FullOTA_Assertions") + + def FullOTA_InstallEnd(self): + """Called at the end of full OTA installation; typically this is + used to install the image for the device's baseband processor.""" + return self._DoCall("FullOTA_InstallEnd") + + def IncrementalOTA_Assertions(self): + """Called after emitting the block of assertions at the top of an + incremental OTA package. Implementations can add whatever + additional assertions they like.""" + return self._DoCall("IncrementalOTA_Assertions") + + def IncrementalOTA_VerifyEnd(self): + """Called at the end of the verification phase of incremental OTA + installation; additional checks can be placed here to abort the + script before any changes are made.""" + return self._DoCall("IncrementalOTA_VerifyEnd") + + def IncrementalOTA_InstallEnd(self): + """Called at the end of incremental OTA installation; typically + this is used to install the image for the device's baseband + processor.""" + return self._DoCall("IncrementalOTA_InstallEnd") diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files index 11e669571..7261b1bab 100755 --- a/tools/releasetools/ota_from_target_files +++ b/tools/releasetools/ota_from_target_files @@ -302,19 +302,18 @@ def WriteFullOTAPackage(input_zip, output_zip): # change very often. script = edify_generator.EdifyGenerator(1) + device_specific = common.DeviceSpecificParams( + input_zip=input_zip, + output_zip=output_zip, + script=script, + input_tmp=OPTIONS.input_tmp) + if not OPTIONS.omit_prereq: ts = GetBuildProp("ro.build.date.utc", input_zip) script.AssertOlderBuild(ts) AppendAssertions(script, input_zip) - - script.ShowProgress(0.1, 0) - - try: - common.ZipWriteStr(output_zip, "radio.img", input_zip.read("RADIO/image")) - script.WriteFirmwareImage("radio", "radio.img") - except KeyError: - pass + device_specific.FullOTA_Assertions() script.ShowProgress(0.5, 0) @@ -335,10 +334,12 @@ def WriteFullOTAPackage(input_zip, output_zip): FixPermissions(script) common.AddBoot(output_zip) - script.ShowProgress(0.2, 0) - script.WriteRawImage("boot", "boot.img") 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) @@ -454,6 +455,12 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): else: raise ValueError('unknown script mode "%s"' % (OPTIONS.script_mode,)) + device_specific = common.DeviceSpecificParams( + source_zip=source_zip, + target_zip=target_zip, + output_zip=output_zip, + script=script) + print "Loading target..." target_data = LoadSystemFiles(target_zip) print "Loading source..." @@ -518,19 +525,15 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): os.path.join(OPTIONS.target_tmp, "RECOVERY"))) updating_recovery = (source_recovery.data != target_recovery.data) - source_radio = source_zip.read("RADIO/image") - target_radio = target_zip.read("RADIO/image") - updating_radio = (source_radio != target_radio) - - # The last 0.1 is reserved for creating symlinks, fixing - # permissions, and writing the boot image (if necessary). - progress_bar_total = 1.0 + # We reserve the last 0.3 of the progress bar for the + # device-specific IncrementalOTA_InstallEnd() call at the end, which + # will typically install a radio image. + progress_bar_total = 0.7 if updating_boot: progress_bar_total -= 0.1 - if updating_radio: - progress_bar_total -= 0.3 AppendAssertions(script, target_zip) + device_specific.IncrementalOTA_Assertions() script.Print("Verifying current system...") @@ -572,6 +575,8 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): script.Print("Unpacking patches...") script.UnpackPackageDir("patch", "/tmp/patchtmp") + device_specific.IncrementalOTA_VerifyEnd() + script.Comment("---- start making changes here ----") if OPTIONS.wipe_user_data: @@ -610,15 +615,6 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): else: print "recovery image unchanged; skipping." - if updating_radio: - script.ShowProgress(0.3, 10) - script.Print("Writing radio image...") - script.WriteFirmwareImage("radio", "radio.img") - common.ZipWriteStr(output_zip, "radio.img", target_radio) - print "radio image changed; including." - else: - print "radio image unchanged; skipping." - script.Print("Patching system files...") pb_apply = progress_bar_total * 0.7 * \ (total_patched_size / @@ -658,7 +654,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): script.Print("Unpacking new files...") script.UnpackPackageDir("system", "/system") - script.Print("Finishing up...") + 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 @@ -677,6 +673,10 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): # permissions. script.AppendScript(temp_script) + # Write the radio image, if necessary. + script.ShowProgress(0.3, 10) + device_specific.IncrementalOTA_InstallEnd() + if OPTIONS.extra_script is not None: scirpt.AppendExtra(OPTIONS.extra_script) diff --git a/tools/releasetools/sign_target_files_apks b/tools/releasetools/sign_target_files_apks index 6dd8ede43..5153398e1 100755 --- a/tools/releasetools/sign_target_files_apks +++ b/tools/releasetools/sign_target_files_apks @@ -20,10 +20,6 @@ target-files zip. Usage: sign_target_files_apks [flags] input_target_files output_target_files - -s (--signapk_jar) - Path of the signapks.jar file used to sign an individual APK - file. - -e (--extra_apks) Add extra APK name/key pairs as though they appeared in apkcerts.txt (so mappings specified by -k and -d are applied). @@ -302,9 +298,7 @@ def ReplaceOtaKeys(input_tf_zip, output_tf_zip): def main(argv): def option_handler(o, a): - if o in ("-s", "--signapk_jar"): - OPTIONS.signapk_jar = a - elif o in ("-e", "--extra_apks"): + if o in ("-e", "--extra_apks"): names, key = a.split("=") names = names.split(",") for n in names: @@ -334,9 +328,8 @@ def main(argv): return True args = common.ParseOptions(argv, __doc__, - extra_opts="s:e:d:k:ot:", - extra_long_opts=["signapk_jar=", - "extra_apks=", + extra_opts="e:d:k:ot:", + extra_long_opts=["extra_apks=", "default_key_mappings=", "key_mapping=", "replace_ota_keys",