Merge "N is API 24" into nyc-dev
diff --git a/core/version_defaults.mk b/core/version_defaults.mk
index b7c4542..7774d1d 100644
--- a/core/version_defaults.mk
+++ b/core/version_defaults.mk
@@ -113,7 +113,7 @@
   # Must be of the form "YYYY-MM-DD" on production devices.
   #
   # If there is no $PLATFORM_SECURITY_PATCH set, keep it empty.
-  PLATFORM_SECURITY_PATCH := 2016-07-01
+  PLATFORM_SECURITY_PATCH := 2016-07-05
 endif
 
 ifeq "" "$(PLATFORM_BASE_OS)"
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 60f44db..b5c0114 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -73,6 +73,33 @@
 # 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 @@
           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 @@
       #    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 @@
                          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 @@
              '{}.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
diff --git a/tools/releasetools/edify_generator.py b/tools/releasetools/edify_generator.py
index 57f8cda..2ecc5cb 100644
--- a/tools/releasetools/edify_generator.py
+++ b/tools/releasetools/edify_generator.py
@@ -85,14 +85,17 @@
       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 @@
       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 @@
       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 @@
     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 @@
     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 @@
     """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 @@
         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 @@
            % (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))