Loading tools/releasetools/common.py +62 −11 Original line number Diff line number Diff line Loading @@ -73,6 +73,33 @@ OPTIONS = Options() # Values for "certificate" in apkcerts that mean special things. SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") class ErrorCode(object): """Define error_codes for failures that happen during the actual update package installation. Error codes 0-999 are reserved for failures before the package installation (i.e. low battery, package verification failure). Detailed code in 'bootable/recovery/error_code.h' """ SYSTEM_VERIFICATION_FAILURE = 1000 SYSTEM_UPDATE_FAILURE = 1001 SYSTEM_UNEXPECTED_CONTENTS = 1002 SYSTEM_NONZERO_CONTENTS = 1003 SYSTEM_RECOVER_FAILURE = 1004 VENDOR_VERIFICATION_FAILURE = 2000 VENDOR_UPDATE_FAILURE = 2001 VENDOR_UNEXPECTED_CONTENTS = 2002 VENDOR_NONZERO_CONTENTS = 2003 VENDOR_RECOVER_FAILURE = 2004 OEM_PROP_MISMATCH = 3000 FINGERPRINT_MISMATCH = 3001 THUMBPRINT_MISMATCH = 3002 OLDER_BUILD = 3003 DEVICE_MISMATCH = 3004 BAD_PATCH_FILE = 3005 INSUFFICIENT_CACHE_SPACE = 3006 TUNE_PARTITION_FAILURE = 3007 APPLY_PATCH_FAILURE = 3008 class ExternalError(RuntimeError): pass Loading Loading @@ -1433,15 +1460,19 @@ class BlockDifference(object): script.AppendExtra('check_first_block("%s");' % (self.device,)) # If version >= 4, try block recovery before abort update if partition == "system": code = ErrorCode.SYSTEM_RECOVER_FAILURE else: code = ErrorCode.VENDOR_RECOVER_FAILURE script.AppendExtra(( 'ifelse (block_image_recover("{device}", "{ranges}") && ' 'block_image_verify("{device}", ' 'package_extract_file("{partition}.transfer.list"), ' '"{partition}.new.dat", "{partition}.patch.dat"), ' 'ui_print("{partition} recovered successfully."), ' 'abort("{partition} partition fails to recover"));\n' 'abort("E{code}: {partition} partition fails to recover"));\n' 'endif;').format(device=self.device, ranges=ranges_str, partition=partition)) partition=partition, code=code)) # Abort the OTA update. Note that the incremental OTA cannot be applied # even if it may match the checksum of the target partition. Loading @@ -1449,8 +1480,13 @@ class BlockDifference(object): # unconditionally and damage the partition. # b) If version >= 3, it won't even reach here. else: script.AppendExtra(('abort("%s partition has unexpected contents");\n' 'endif;') % (partition,)) if partition == "system": code = ErrorCode.SYSTEM_VERIFICATION_FAILURE else: code = ErrorCode.VENDOR_VERIFICATION_FAILURE script.AppendExtra(( 'abort("E%d: %s partition has unexpected contents");\n' 'endif;') % (code, partition)) def _WritePostInstallVerifyScript(self, script): partition = self.partition Loading @@ -1470,18 +1506,28 @@ class BlockDifference(object): self.device, ranges_str, self._HashZeroBlocks(self.tgt.extended.size()))) script.Print('Verified the updated %s image.' % (partition,)) if partition == "system": code = ErrorCode.SYSTEM_NONZERO_CONTENTS else: code = ErrorCode.VENDOR_NONZERO_CONTENTS script.AppendExtra( 'else\n' ' abort("%s partition has unexpected non-zero contents after OTA ' 'update");\n' 'endif;' % (partition,)) ' abort("E%d: %s partition has unexpected non-zero contents after ' 'OTA update");\n' 'endif;' % (code, partition)) else: script.Print('Verified the updated %s image.' % (partition,)) if partition == "system": code = ErrorCode.SYSTEM_UNEXPECTED_CONTENTS else: code = ErrorCode.VENDOR_UNEXPECTED_CONTENTS script.AppendExtra( 'else\n' ' abort("%s partition has unexpected contents after OTA update");\n' 'endif;' % (partition,)) ' abort("E%d: %s partition has unexpected contents after OTA ' 'update");\n' 'endif;' % (code, partition)) def _WriteUpdate(self, script, output_zip): ZipWrite(output_zip, Loading @@ -1495,11 +1541,16 @@ class BlockDifference(object): '{}.patch.dat'.format(self.partition), compress_type=zipfile.ZIP_STORED) if self.partition == "system": code = ErrorCode.SYSTEM_UPDATE_FAILURE else: code = ErrorCode.VENDOR_UPDATE_FAILURE call = ('block_image_update("{device}", ' 'package_extract_file("{partition}.transfer.list"), ' '"{partition}.new.dat", "{partition}.patch.dat") ||\n' ' abort("Failed to update {partition} image.");'.format( device=self.device, partition=self.partition)) ' abort("E{code}: Failed to update {partition} image.");'.format( device=self.device, partition=self.partition, code=code)) script.AppendExtra(script.WordWrap(call)) def _HashBlocks(self, source, ranges): # pylint: disable=no-self-use Loading tools/releasetools/edify_generator.py +25 −18 Original line number Diff line number Diff line Loading @@ -85,14 +85,17 @@ class EdifyGenerator(object): raise ValueError("must specify the OEM value") if common.OPTIONS.oem_no_mount: cmd = ('getprop("{name}") == "{value}" || ' 'abort("This package expects the value \\"{value}\\" for ' 'abort("E{code}: This package expects the value \\"{value}\\" for ' '\\"{name}\\"; this has value \\"" + ' 'getprop("{name}") + "\\".");').format(name=name, value=value) 'getprop("{name}") + "\\".");').format( code=common.ErrorCode.OEM_PROP_MISMATCH, name=name, value=value) else: cmd = ('file_getprop("/oem/oem.prop", "{name}") == "{value}" || ' 'abort("This package expects the value \\"{value}\\" for ' 'abort("E{code}: This package expects the value \\"{value}\\" for ' '\\"{name}\\" on the OEM partition; this has value \\"" + ' 'file_getprop("/oem/oem.prop", "{name}") + "\\".");').format( code=common.ErrorCode.OEM_PROP_MISMATCH, name=name, value=value) self.script.append(cmd) Loading @@ -102,9 +105,9 @@ class EdifyGenerator(object): raise ValueError("must specify some fingerprints") cmd = (' ||\n '.join([('getprop("ro.build.fingerprint") == "%s"') % i for i in fp]) + ' ||\n abort("Package expects build fingerprint of %s; this ' 'device has " + getprop("ro.build.fingerprint") + ".");') % ( " or ".join(fp)) ' ||\n abort("E%d: Package expects build fingerprint of %s; ' 'this device has " + getprop("ro.build.fingerprint") + ".");') % ( common.ErrorCode.FINGERPRINT_MISMATCH, " or ".join(fp)) self.script.append(cmd) def AssertSomeThumbprint(self, *fp): Loading @@ -113,9 +116,9 @@ class EdifyGenerator(object): raise ValueError("must specify some thumbprints") cmd = (' ||\n '.join([('getprop("ro.build.thumbprint") == "%s"') % i for i in fp]) + ' ||\n abort("Package expects build thumbprint of %s; this ' ' ||\n abort("E%d: Package expects build thumbprint of %s; this ' 'device has " + getprop("ro.build.thumbprint") + ".");') % ( " or ".join(fp)) common.ErrorCode.THUMBPRINT_MISMATCH, " or ".join(fp)) self.script.append(cmd) def AssertOlderBuild(self, timestamp, timestamp_text): Loading @@ -123,16 +126,16 @@ class EdifyGenerator(object): the given timestamp.""" self.script.append( ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || ' 'abort("Can\'t install this package (%s) over newer ' 'abort("E%d: Can\'t install this package (%s) over newer ' 'build (" + getprop("ro.build.date") + ").");') % (timestamp, timestamp_text)) common.ErrorCode.OLDER_BUILD, timestamp_text)) def AssertDevice(self, device): """Assert that the device identifier is the given string.""" cmd = ('getprop("ro.product.device") == "%s" || ' 'abort("This package is for \\"%s\\" devices; ' 'abort("E%d: This package is for \\"%s\\" devices; ' 'this is a \\"" + getprop("ro.product.device") + "\\".");') % ( device, device) device, common.ErrorCode.DEVICE_MISMATCH, device) self.script.append(cmd) def AssertSomeBootloader(self, *bootloaders): Loading Loading @@ -162,7 +165,8 @@ class EdifyGenerator(object): self.script.append( 'apply_patch_check("%s"' % (filename,) + "".join([', "%s"' % (i,) for i in sha1]) + ') || abort("\\"%s\\" has unexpected contents.");' % (filename,)) ') || abort("E%d: \\"%s\\" has unexpected contents.");' % ( common.ErrorCode.BAD_PATCH_FILE, filename)) def Verify(self, filename): """Check that the given file (or MTD reference) has one of the Loading @@ -184,8 +188,10 @@ class EdifyGenerator(object): """Check that there's at least 'amount' space that can be made available on /cache.""" self._required_cache = max(self._required_cache, amount) self.script.append(('apply_patch_space(%d) || abort("Not enough free space ' 'on /cache to apply patches.");') % (amount,)) self.script.append(('apply_patch_space(%d) || abort("E%d: Not enough free ' 'space on /cache to apply patches.");') % ( amount, common.ErrorCode.INSUFFICIENT_CACHE_SPACE)) def Mount(self, mount_point, mount_options_by_format=""): """Mount the partition with the given mount_point. Loading Loading @@ -235,8 +241,8 @@ class EdifyGenerator(object): raise ValueError("Partition %s cannot be tuned\n" % (partition,)) self.script.append( 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) + '"%s") || abort("Failed to tune partition %s");' % ( p.device, partition)) '"%s") || abort("E%d: Failed to tune partition %s");' % ( p.device, common.ErrorCode.TUNE_PARTITION_FAILURE, partition)) def FormatPartition(self, partition): """Format the given partition, specified by its mount point (eg, Loading Loading @@ -298,7 +304,8 @@ class EdifyGenerator(object): % (srcfile, tgtfile, tgtsha1, tgtsize)] for i in range(0, len(patchpairs), 2): cmd.append(',\0%s,\0package_extract_file("%s")' % patchpairs[i:i+2]) cmd.append(') ||\n abort("Failed to apply patch to %s");' % (srcfile,)) cmd.append(') ||\n abort("E%d: Failed to apply patch to %s");' % ( common.ErrorCode.APPLY_PATCH_FAILURE, srcfile)) cmd = "".join(cmd) self.script.append(self.WordWrap(cmd)) Loading Loading
tools/releasetools/common.py +62 −11 Original line number Diff line number Diff line Loading @@ -73,6 +73,33 @@ OPTIONS = Options() # Values for "certificate" in apkcerts that mean special things. SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") class ErrorCode(object): """Define error_codes for failures that happen during the actual update package installation. Error codes 0-999 are reserved for failures before the package installation (i.e. low battery, package verification failure). Detailed code in 'bootable/recovery/error_code.h' """ SYSTEM_VERIFICATION_FAILURE = 1000 SYSTEM_UPDATE_FAILURE = 1001 SYSTEM_UNEXPECTED_CONTENTS = 1002 SYSTEM_NONZERO_CONTENTS = 1003 SYSTEM_RECOVER_FAILURE = 1004 VENDOR_VERIFICATION_FAILURE = 2000 VENDOR_UPDATE_FAILURE = 2001 VENDOR_UNEXPECTED_CONTENTS = 2002 VENDOR_NONZERO_CONTENTS = 2003 VENDOR_RECOVER_FAILURE = 2004 OEM_PROP_MISMATCH = 3000 FINGERPRINT_MISMATCH = 3001 THUMBPRINT_MISMATCH = 3002 OLDER_BUILD = 3003 DEVICE_MISMATCH = 3004 BAD_PATCH_FILE = 3005 INSUFFICIENT_CACHE_SPACE = 3006 TUNE_PARTITION_FAILURE = 3007 APPLY_PATCH_FAILURE = 3008 class ExternalError(RuntimeError): pass Loading Loading @@ -1433,15 +1460,19 @@ class BlockDifference(object): script.AppendExtra('check_first_block("%s");' % (self.device,)) # If version >= 4, try block recovery before abort update if partition == "system": code = ErrorCode.SYSTEM_RECOVER_FAILURE else: code = ErrorCode.VENDOR_RECOVER_FAILURE script.AppendExtra(( 'ifelse (block_image_recover("{device}", "{ranges}") && ' 'block_image_verify("{device}", ' 'package_extract_file("{partition}.transfer.list"), ' '"{partition}.new.dat", "{partition}.patch.dat"), ' 'ui_print("{partition} recovered successfully."), ' 'abort("{partition} partition fails to recover"));\n' 'abort("E{code}: {partition} partition fails to recover"));\n' 'endif;').format(device=self.device, ranges=ranges_str, partition=partition)) partition=partition, code=code)) # Abort the OTA update. Note that the incremental OTA cannot be applied # even if it may match the checksum of the target partition. Loading @@ -1449,8 +1480,13 @@ class BlockDifference(object): # unconditionally and damage the partition. # b) If version >= 3, it won't even reach here. else: script.AppendExtra(('abort("%s partition has unexpected contents");\n' 'endif;') % (partition,)) if partition == "system": code = ErrorCode.SYSTEM_VERIFICATION_FAILURE else: code = ErrorCode.VENDOR_VERIFICATION_FAILURE script.AppendExtra(( 'abort("E%d: %s partition has unexpected contents");\n' 'endif;') % (code, partition)) def _WritePostInstallVerifyScript(self, script): partition = self.partition Loading @@ -1470,18 +1506,28 @@ class BlockDifference(object): self.device, ranges_str, self._HashZeroBlocks(self.tgt.extended.size()))) script.Print('Verified the updated %s image.' % (partition,)) if partition == "system": code = ErrorCode.SYSTEM_NONZERO_CONTENTS else: code = ErrorCode.VENDOR_NONZERO_CONTENTS script.AppendExtra( 'else\n' ' abort("%s partition has unexpected non-zero contents after OTA ' 'update");\n' 'endif;' % (partition,)) ' abort("E%d: %s partition has unexpected non-zero contents after ' 'OTA update");\n' 'endif;' % (code, partition)) else: script.Print('Verified the updated %s image.' % (partition,)) if partition == "system": code = ErrorCode.SYSTEM_UNEXPECTED_CONTENTS else: code = ErrorCode.VENDOR_UNEXPECTED_CONTENTS script.AppendExtra( 'else\n' ' abort("%s partition has unexpected contents after OTA update");\n' 'endif;' % (partition,)) ' abort("E%d: %s partition has unexpected contents after OTA ' 'update");\n' 'endif;' % (code, partition)) def _WriteUpdate(self, script, output_zip): ZipWrite(output_zip, Loading @@ -1495,11 +1541,16 @@ class BlockDifference(object): '{}.patch.dat'.format(self.partition), compress_type=zipfile.ZIP_STORED) if self.partition == "system": code = ErrorCode.SYSTEM_UPDATE_FAILURE else: code = ErrorCode.VENDOR_UPDATE_FAILURE call = ('block_image_update("{device}", ' 'package_extract_file("{partition}.transfer.list"), ' '"{partition}.new.dat", "{partition}.patch.dat") ||\n' ' abort("Failed to update {partition} image.");'.format( device=self.device, partition=self.partition)) ' abort("E{code}: Failed to update {partition} image.");'.format( device=self.device, partition=self.partition, code=code)) script.AppendExtra(script.WordWrap(call)) def _HashBlocks(self, source, ranges): # pylint: disable=no-self-use Loading
tools/releasetools/edify_generator.py +25 −18 Original line number Diff line number Diff line Loading @@ -85,14 +85,17 @@ class EdifyGenerator(object): raise ValueError("must specify the OEM value") if common.OPTIONS.oem_no_mount: cmd = ('getprop("{name}") == "{value}" || ' 'abort("This package expects the value \\"{value}\\" for ' 'abort("E{code}: This package expects the value \\"{value}\\" for ' '\\"{name}\\"; this has value \\"" + ' 'getprop("{name}") + "\\".");').format(name=name, value=value) 'getprop("{name}") + "\\".");').format( code=common.ErrorCode.OEM_PROP_MISMATCH, name=name, value=value) else: cmd = ('file_getprop("/oem/oem.prop", "{name}") == "{value}" || ' 'abort("This package expects the value \\"{value}\\" for ' 'abort("E{code}: This package expects the value \\"{value}\\" for ' '\\"{name}\\" on the OEM partition; this has value \\"" + ' 'file_getprop("/oem/oem.prop", "{name}") + "\\".");').format( code=common.ErrorCode.OEM_PROP_MISMATCH, name=name, value=value) self.script.append(cmd) Loading @@ -102,9 +105,9 @@ class EdifyGenerator(object): raise ValueError("must specify some fingerprints") cmd = (' ||\n '.join([('getprop("ro.build.fingerprint") == "%s"') % i for i in fp]) + ' ||\n abort("Package expects build fingerprint of %s; this ' 'device has " + getprop("ro.build.fingerprint") + ".");') % ( " or ".join(fp)) ' ||\n abort("E%d: Package expects build fingerprint of %s; ' 'this device has " + getprop("ro.build.fingerprint") + ".");') % ( common.ErrorCode.FINGERPRINT_MISMATCH, " or ".join(fp)) self.script.append(cmd) def AssertSomeThumbprint(self, *fp): Loading @@ -113,9 +116,9 @@ class EdifyGenerator(object): raise ValueError("must specify some thumbprints") cmd = (' ||\n '.join([('getprop("ro.build.thumbprint") == "%s"') % i for i in fp]) + ' ||\n abort("Package expects build thumbprint of %s; this ' ' ||\n abort("E%d: Package expects build thumbprint of %s; this ' 'device has " + getprop("ro.build.thumbprint") + ".");') % ( " or ".join(fp)) common.ErrorCode.THUMBPRINT_MISMATCH, " or ".join(fp)) self.script.append(cmd) def AssertOlderBuild(self, timestamp, timestamp_text): Loading @@ -123,16 +126,16 @@ class EdifyGenerator(object): the given timestamp.""" self.script.append( ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || ' 'abort("Can\'t install this package (%s) over newer ' 'abort("E%d: Can\'t install this package (%s) over newer ' 'build (" + getprop("ro.build.date") + ").");') % (timestamp, timestamp_text)) common.ErrorCode.OLDER_BUILD, timestamp_text)) def AssertDevice(self, device): """Assert that the device identifier is the given string.""" cmd = ('getprop("ro.product.device") == "%s" || ' 'abort("This package is for \\"%s\\" devices; ' 'abort("E%d: This package is for \\"%s\\" devices; ' 'this is a \\"" + getprop("ro.product.device") + "\\".");') % ( device, device) device, common.ErrorCode.DEVICE_MISMATCH, device) self.script.append(cmd) def AssertSomeBootloader(self, *bootloaders): Loading Loading @@ -162,7 +165,8 @@ class EdifyGenerator(object): self.script.append( 'apply_patch_check("%s"' % (filename,) + "".join([', "%s"' % (i,) for i in sha1]) + ') || abort("\\"%s\\" has unexpected contents.");' % (filename,)) ') || abort("E%d: \\"%s\\" has unexpected contents.");' % ( common.ErrorCode.BAD_PATCH_FILE, filename)) def Verify(self, filename): """Check that the given file (or MTD reference) has one of the Loading @@ -184,8 +188,10 @@ class EdifyGenerator(object): """Check that there's at least 'amount' space that can be made available on /cache.""" self._required_cache = max(self._required_cache, amount) self.script.append(('apply_patch_space(%d) || abort("Not enough free space ' 'on /cache to apply patches.");') % (amount,)) self.script.append(('apply_patch_space(%d) || abort("E%d: Not enough free ' 'space on /cache to apply patches.");') % ( amount, common.ErrorCode.INSUFFICIENT_CACHE_SPACE)) def Mount(self, mount_point, mount_options_by_format=""): """Mount the partition with the given mount_point. Loading Loading @@ -235,8 +241,8 @@ class EdifyGenerator(object): raise ValueError("Partition %s cannot be tuned\n" % (partition,)) self.script.append( 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) + '"%s") || abort("Failed to tune partition %s");' % ( p.device, partition)) '"%s") || abort("E%d: Failed to tune partition %s");' % ( p.device, common.ErrorCode.TUNE_PARTITION_FAILURE, partition)) def FormatPartition(self, partition): """Format the given partition, specified by its mount point (eg, Loading Loading @@ -298,7 +304,8 @@ class EdifyGenerator(object): % (srcfile, tgtfile, tgtsha1, tgtsize)] for i in range(0, len(patchpairs), 2): cmd.append(',\0%s,\0package_extract_file("%s")' % patchpairs[i:i+2]) cmd.append(') ||\n abort("Failed to apply patch to %s");' % (srcfile,)) cmd.append(') ||\n abort("E%d: Failed to apply patch to %s");' % ( common.ErrorCode.APPLY_PATCH_FAILURE, srcfile)) cmd = "".join(cmd) self.script.append(self.WordWrap(cmd)) Loading