Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a912c14 authored by Tianjie Xu's avatar Tianjie Xu Committed by android-build-merger
Browse files

Merge "Report error codes in the OTA update script" into nyc-dev

am: 654e4fb0

* commit '654e4fb0':
  Report error codes in the OTA update script

Change-Id: Ic8d04a484bdf6d08af5109a71967c3d5f8f0be27
parents 349501c1 654e4fb0
Loading
Loading
Loading
Loading
+62 −11
Original line number Diff line number Diff line
@@ -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
+25 −18
Original line number Diff line number Diff line
@@ -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))