Merge "Report error codes in the OTA update script" into nyc-dev
This commit is contained in:
commit
654e4fb023
2 changed files with 87 additions and 29 deletions
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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…
Reference in a new issue