resolve merge conflicts of 50f6417 to nyc-dev-plus-aosp

Change-Id: I42c127f7946e678acf6596f6352f090abc0ca019
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 885a517..f78342d 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -44,6 +44,7 @@
 
 #include "applypatch/applypatch.h"
 #include "edify/expr.h"
+#include "error_code.h"
 #include "install.h"
 #include "openssl/sha.h"
 #include "minzip/Hash.h"
@@ -68,6 +69,7 @@
     std::vector<size_t> pos;  // Actual limit is INT_MAX.
 };
 
+static CauseCode failure_type = kNoCause;
 static std::map<std::string, RangeSet> stash_map;
 
 static void parse_range(const std::string& range_text, RangeSet& rs) {
@@ -145,6 +147,7 @@
     while (so_far < size) {
         ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
         if (r == -1) {
+            failure_type = kFreadFailure;
             fprintf(stderr, "read failed: %s\n", strerror(errno));
             return -1;
         }
@@ -162,6 +165,7 @@
     while (written < size) {
         ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
         if (w == -1) {
+            failure_type = kFwriteFailure;
             fprintf(stderr, "write failed: %s\n", strerror(errno));
             return -1;
         }
@@ -178,6 +182,7 @@
 static bool check_lseek(int fd, off64_t offset, int whence) {
     off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
     if (rc == -1) {
+        failure_type = kLseekFailure;
         fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
         return false;
     }
@@ -646,6 +651,7 @@
     }
 
     if (ota_fsync(fd) == -1) {
+        failure_type = kFsyncFailure;
         fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
         return -1;
     }
@@ -660,11 +666,13 @@
     android::base::unique_fd dfd(TEMP_FAILURE_RETRY(ota_open(dname.c_str(),
                                                              O_RDONLY | O_DIRECTORY)));
     if (dfd == -1) {
+        failure_type = kFileOpenFailure;
         fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
         return -1;
     }
 
     if (ota_fsync(dfd) == -1) {
+        failure_type = kFsyncFailure;
         fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
         return -1;
     }
@@ -693,19 +701,21 @@
     int res = stat(dirname.c_str(), &sb);
 
     if (res == -1 && errno != ENOENT) {
-        ErrorAbort(state, "stat \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
+        ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n",
+                   dirname.c_str(), strerror(errno));
         return -1;
     } else if (res != 0) {
         fprintf(stderr, "creating stash %s\n", dirname.c_str());
         res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
 
         if (res != 0) {
-            ErrorAbort(state, "mkdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
+            ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n",
+                       dirname.c_str(), strerror(errno));
             return -1;
         }
 
         if (CacheSizeCheck(maxblocks * BLOCKSIZE) != 0) {
-            ErrorAbort(state, "not enough space for stash\n");
+            ErrorAbort(state, kStashCreationFailure, "not enough space for stash\n");
             return -1;
         }
 
@@ -725,7 +735,8 @@
     size = maxblocks * BLOCKSIZE - size;
 
     if (size > 0 && CacheSizeCheck(size) != 0) {
-        ErrorAbort(state, "not enough space for stash (%d more needed)\n", size);
+        ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%d more needed)\n",
+                   size);
         return -1;
     }
 
@@ -1342,19 +1353,21 @@
     std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue);
 
     if (blockdev_filename->type != VAL_STRING) {
-        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
+                   name);
         return StringValue(strdup(""));
     }
     if (transfer_list_value->type != VAL_BLOB) {
-        ErrorAbort(state, "transfer_list argument to %s must be blob", name);
+        ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name);
         return StringValue(strdup(""));
     }
     if (new_data_fn->type != VAL_STRING) {
-        ErrorAbort(state, "new_data_fn argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name);
         return StringValue(strdup(""));
     }
     if (patch_data_fn->type != VAL_STRING) {
-        ErrorAbort(state, "patch_data_fn argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string",
+                   name);
         return StringValue(strdup(""));
     }
 
@@ -1412,7 +1425,8 @@
     const std::string transfer_list(transfer_list_value->data, transfer_list_value->size);
     std::vector<std::string> lines = android::base::Split(transfer_list, "\n");
     if (lines.size() < 2) {
-        ErrorAbort(state, "too few lines in the transfer list [%zd]\n", lines.size());
+        ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n",
+                   lines.size());
         return StringValue(strdup(""));
     }
 
@@ -1427,7 +1441,7 @@
     // Second line in transfer list is the total number of blocks we expect to write
     int total_blocks;
     if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) {
-        ErrorAbort(state, "unexpected block count [%s]\n", lines[1].c_str());
+        ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str());
         return StringValue(strdup(""));
     }
 
@@ -1438,7 +1452,8 @@
     size_t start = 2;
     if (params.version >= 2) {
         if (lines.size() < 4) {
-            ErrorAbort(state, "too few lines in the transfer list [%zu]\n", lines.size());
+            ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n",
+                       lines.size());
             return StringValue(strdup(""));
         }
 
@@ -1448,7 +1463,8 @@
         // Fourth line is the maximum number of blocks that will be stashed simultaneously
         int stash_max_blocks;
         if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) {
-            ErrorAbort(state, "unexpected maximum stash blocks [%s]\n", lines[3].c_str());
+            ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n",
+                       lines[3].c_str());
             return StringValue(strdup(""));
         }
 
@@ -1502,6 +1518,7 @@
 
         if (params.canwrite) {
             if (ota_fsync(params.fd) == -1) {
+                failure_type = kFsyncFailure;
                 fprintf(stderr, "fsync failed: %s\n", strerror(errno));
                 goto pbiudone;
             }
@@ -1536,6 +1553,7 @@
 
 pbiudone:
     if (ota_fsync(params.fd) == -1) {
+        failure_type = kFsyncFailure;
         fprintf(stderr, "fsync failed: %s\n", strerror(errno));
     }
     // params.fd will be automatically closed because it's a unique_fd.
@@ -1546,6 +1564,10 @@
         DeleteStash(params.stashbase);
     }
 
+    if (failure_type != kNoCause && state->cause_code == kNoCause) {
+        state->cause_code = failure_type;
+    }
+
     return StringValue(rc == 0 ? strdup("t") : strdup(""));
 }
 
@@ -1651,17 +1673,19 @@
             FreeValue);
 
     if (blockdev_filename->type != VAL_STRING) {
-        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
+                   name);
         return StringValue(strdup(""));
     }
     if (ranges->type != VAL_STRING) {
-        ErrorAbort(state, "ranges argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
         return StringValue(strdup(""));
     }
 
     android::base::unique_fd fd(ota_open(blockdev_filename->data, O_RDWR));
     if (fd == -1) {
-        ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno));
+        ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", blockdev_filename->data,
+                   strerror(errno));
         return StringValue(strdup(""));
     }
 
@@ -1674,14 +1698,15 @@
     std::vector<uint8_t> buffer(BLOCKSIZE);
     for (size_t i = 0; i < rs.count; ++i) {
         if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) {
-            ErrorAbort(state, "failed to seek %s: %s", blockdev_filename->data, strerror(errno));
+            ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data,
+                       strerror(errno));
             return StringValue(strdup(""));
         }
 
         for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) {
             if (read_all(fd, buffer, BLOCKSIZE) == -1) {
-                ErrorAbort(state, "failed to read %s: %s", blockdev_filename->data,
-                           strerror(errno));
+                ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data,
+                        strerror(errno));
                 return StringValue(strdup(""));
             }
 
@@ -1708,13 +1733,14 @@
     std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue);
 
     if (filename->type != VAL_STRING) {
-        ErrorAbort(state, "filename argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
         return StringValue(strdup(""));
     }
 
     android::base::unique_fd fd(ota_open(arg_filename->data, O_RDONLY));
     if (fd == -1) {
-        ErrorAbort(state, "open \"%s\" failed: %s", arg_filename->data, strerror(errno));
+        ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data,
+                   strerror(errno));
         return StringValue(strdup(""));
     }
 
@@ -1722,7 +1748,8 @@
     std::vector<uint8_t> block0_buffer(BLOCKSIZE);
 
     if (ReadBlocks(blk0, block0_buffer, fd) == -1) {
-        ErrorAbort(state, "failed to read %s: %s", arg_filename->data, strerror(errno));
+        ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data,
+                strerror(errno));
         return StringValue(strdup(""));
     }
 
@@ -1757,11 +1784,11 @@
     std::unique_ptr<Value, decltype(&FreeValue)> ranges(arg_ranges, FreeValue);
 
     if (filename->type != VAL_STRING) {
-        ErrorAbort(state, "filename argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
         return StringValue(strdup(""));
     }
     if (ranges->type != VAL_STRING) {
-        ErrorAbort(state, "ranges argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
         return StringValue(strdup(""));
     }
 
@@ -1772,19 +1799,20 @@
     fec::io fh(filename->data, O_RDWR);
 
     if (!fh) {
-        ErrorAbort(state, "fec_open \"%s\" failed: %s", filename->data, strerror(errno));
+        ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data,
+                   strerror(errno));
         return StringValue(strdup(""));
     }
 
     if (!fh.has_ecc() || !fh.has_verity()) {
-        ErrorAbort(state, "unable to use metadata to correct errors");
+        ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors");
         return StringValue(strdup(""));
     }
 
     fec_status status;
 
     if (!fh.get_status(status)) {
-        ErrorAbort(state, "failed to read FEC status");
+        ErrorAbort(state, kLibfecFailure, "failed to read FEC status");
         return StringValue(strdup(""));
     }
 
@@ -1801,8 +1829,8 @@
             }
 
             if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) {
-                ErrorAbort(state, "failed to recover %s (block %zu): %s", filename->data,
-                    j, strerror(errno));
+                ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s",
+                           filename->data, j, strerror(errno));
                 return StringValue(strdup(""));
             }
 
diff --git a/updater/install.cpp b/updater/install.cpp
index bab2fe1..dc27561 100644
--- a/updater/install.cpp
+++ b/updater/install.cpp
@@ -48,10 +48,11 @@
 #include "cutils/misc.h"
 #include "cutils/properties.h"
 #include "edify/expr.h"
-#include "openssl/sha.h"
+#include "error_code.h"
 #include "minzip/DirUtil.h"
 #include "mtdutils/mounts.h"
 #include "mtdutils/mtdutils.h"
+#include "openssl/sha.h"
 #include "ota_io.h"
 #include "updater.h"
 #include "install.h"
@@ -114,7 +115,7 @@
 Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
     if (argc != 4 && argc != 5) {
-        return ErrorAbort(state, "%s() expects 4-5 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc);
     }
     char* fs_type;
     char* partition_type;
@@ -137,20 +138,21 @@
     }
 
     if (strlen(fs_type) == 0) {
-        ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name);
         goto done;
     }
     if (strlen(partition_type) == 0) {
-        ErrorAbort(state, "partition_type argument to %s() can't be empty",
+        ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty",
                    name);
         goto done;
     }
     if (strlen(location) == 0) {
-        ErrorAbort(state, "location argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name);
         goto done;
     }
     if (strlen(mount_point) == 0) {
-        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty",
+                   name);
         goto done;
     }
 
@@ -213,14 +215,14 @@
 Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
     if (argc != 1) {
-        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
     }
     char* mount_point;
     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
         return NULL;
     }
     if (strlen(mount_point) == 0) {
-        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
+        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to unmount() can't be empty");
         goto done;
     }
 
@@ -243,14 +245,14 @@
 Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
     if (argc != 1) {
-        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
     }
     char* mount_point;
     if (ReadArgs(state, argv, 1, &mount_point) < 0) {
         return NULL;
     }
     if (strlen(mount_point) == 0) {
-        ErrorAbort(state, "mount_point argument to unmount() can't be empty");
+        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to unmount() can't be empty");
         goto done;
     }
 
@@ -301,7 +303,7 @@
 Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
     if (argc != 5) {
-        return ErrorAbort(state, "%s() expects 5 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc);
     }
     char* fs_type;
     char* partition_type;
@@ -314,21 +316,22 @@
     }
 
     if (strlen(fs_type) == 0) {
-        ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name);
         goto done;
     }
     if (strlen(partition_type) == 0) {
-        ErrorAbort(state, "partition_type argument to %s() can't be empty",
+        ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty",
                    name);
         goto done;
     }
     if (strlen(location) == 0) {
-        ErrorAbort(state, "location argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name);
         goto done;
     }
 
     if (strlen(mount_point) == 0) {
-        ErrorAbort(state, "mount_point argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty",
+                   name);
         goto done;
     }
 
@@ -403,7 +406,7 @@
 Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) {
     char* result = NULL;
     if (argc != 2) {
-        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
     }
 
     char* src_name;
@@ -413,21 +416,21 @@
         return NULL;
     }
     if (strlen(src_name) == 0) {
-        ErrorAbort(state, "src_name argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name);
         goto done;
     }
     if (strlen(dst_name) == 0) {
-        ErrorAbort(state, "dst_name argument to %s() can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name);
         goto done;
     }
     if (make_parents(dst_name) != 0) {
-        ErrorAbort(state, "Creating parent of %s failed, error %s",
+        ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s",
           dst_name, strerror(errno));
     } else if (access(dst_name, F_OK) == 0 && access(src_name, F_OK) != 0) {
         // File was already moved
         result = dst_name;
     } else if (rename(src_name, dst_name) != 0) {
-        ErrorAbort(state, "Rename of %s to %s failed, error %s",
+        ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s",
           src_name, dst_name, strerror(errno));
     } else {
         result = dst_name;
@@ -470,7 +473,7 @@
 
 Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 2) {
-        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
     }
     char* frac_str;
     char* sec_str;
@@ -491,7 +494,7 @@
 
 Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 1) {
-        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
     }
     char* frac_str;
     if (ReadArgs(state, argv, 1, &frac_str) < 0) {
@@ -510,7 +513,7 @@
 Value* PackageExtractDirFn(const char* name, State* state,
                           int argc, Expr* argv[]) {
     if (argc != 2) {
-        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
     }
     char* zip_path;
     char* dest_path;
@@ -538,7 +541,7 @@
 Value* PackageExtractFileFn(const char* name, State* state,
                            int argc, Expr* argv[]) {
     if (argc < 1 || argc > 2) {
-        return ErrorAbort(state, "%s() expects 1 or 2 args, got %d",
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d",
                           name, argc);
     }
     bool success = false;
@@ -646,7 +649,7 @@
 //    unlinks any previously existing src1, src2, etc before creating symlinks.
 Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc == 0) {
-        return ErrorAbort(state, "%s() expects 1+ args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1+ args, got %d", name, argc);
     }
     char* target;
     target = Evaluate(state, argv[0]);
@@ -682,7 +685,7 @@
     }
     free(srcs);
     if (bad) {
-        return ErrorAbort(state, "%s: some symlinks failed", name);
+        return ErrorAbort(state, kSymlinkFailure, "%s: some symlinks failed", name);
     }
     return StringValue(strdup(""));
 }
@@ -906,14 +909,16 @@
     bool recursive = (strcmp(name, "set_metadata_recursive") == 0);
 
     if ((argc % 2) != 1) {
-        return ErrorAbort(state, "%s() expects an odd number of arguments, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure,
+                          "%s() expects an odd number of arguments, got %d", name, argc);
     }
 
     char** args = ReadVarArgs(state, argc, argv);
     if (args == NULL) return NULL;
 
     if (lstat(args[0], &sb) == -1) {
-        result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno));
+        result = ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s",
+                            name, args[0], strerror(errno));
         goto done;
     }
 
@@ -942,7 +947,7 @@
     }
 
     if (bad > 0) {
-        return ErrorAbort(state, "%s: some changes failed", name);
+        return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name);
     }
 
     return StringValue(strdup(""));
@@ -950,7 +955,7 @@
 
 Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 1) {
-        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
     }
     char* key = Evaluate(state, argv[0]);
     if (key == NULL) return NULL;
@@ -979,20 +984,22 @@
 
     struct stat st;
     if (stat(filename, &st) < 0) {
-        ErrorAbort(state, "%s: failed to stat \"%s\": %s", name, filename, strerror(errno));
+        ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name, filename,
+                   strerror(errno));
         goto done;
     }
 
 #define MAX_FILE_GETPROP_SIZE    65536
 
     if (st.st_size > MAX_FILE_GETPROP_SIZE) {
-        ErrorAbort(state, "%s too large for %s (max %d)", filename, name, MAX_FILE_GETPROP_SIZE);
+        ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %d)", filename, name,
+                   MAX_FILE_GETPROP_SIZE);
         goto done;
     }
 
     buffer = reinterpret_cast<char*>(malloc(st.st_size+1));
     if (buffer == NULL) {
-        ErrorAbort(state, "%s: failed to alloc %zu bytes", name,
+        ErrorAbort(state, kFileGetPropFailure, "%s: failed to alloc %zu bytes", name,
                    static_cast<size_t>(st.st_size+1));
         goto done;
     }
@@ -1000,12 +1007,14 @@
     FILE* f;
     f = ota_fopen(filename, "rb");
     if (f == NULL) {
-        ErrorAbort(state, "%s: failed to open %s: %s", name, filename, strerror(errno));
+        ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, filename,
+                   strerror(errno));
         goto done;
     }
 
     if (ota_fread(buffer, 1, st.st_size, f) != static_cast<size_t>(st.st_size)) {
-        ErrorAbort(state, "%s: failed to read %zu bytes from %s",
+        ota_fclose(f);
+        ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s",
                    name, static_cast<size_t>(st.st_size), filename);
         ota_fclose(f);
         goto done;
@@ -1071,16 +1080,16 @@
 
     char* partition = NULL;
     if (partition_value->type != VAL_STRING) {
-        ErrorAbort(state, "partition argument to %s must be string", name);
+        ErrorAbort(state, kArgsParsingFailure, "partition argument to %s must be string", name);
         goto done;
     }
     partition = partition_value->data;
     if (strlen(partition) == 0) {
-        ErrorAbort(state, "partition argument to %s can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "partition argument to %s can't be empty", name);
         goto done;
     }
     if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
-        ErrorAbort(state, "file argument to %s can't be empty", name);
+        ErrorAbort(state, kArgsParsingFailure, "file argument to %s can't be empty", name);
         goto done;
     }
 
@@ -1161,7 +1170,8 @@
 
     size_t bytes;
     if (!android::base::ParseUint(bytes_str, &bytes)) {
-        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n", name, bytes_str);
+        ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count\n\n",
+                   name, bytes_str);
         free(bytes_str);
         return nullptr;
     }
@@ -1173,9 +1183,8 @@
 
 Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc < 6 || (argc % 2) == 1) {
-        return ErrorAbort(state, "%s(): expected at least 6 args and an "
-                                 "even number, got %d",
-                          name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 6 args and an "
+                                 "even number, got %d", name, argc);
     }
 
     char* source_filename;
@@ -1189,7 +1198,8 @@
 
     size_t target_size;
     if (!android::base::ParseUint(target_size_str, &target_size)) {
-        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count", name, target_size_str);
+        ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count",
+                   name, target_size_str);
         free(source_filename);
         free(target_filename);
         free(target_sha1);
@@ -1213,11 +1223,11 @@
 
     for (int i = 0; i < patchcount; ++i) {
         if (patch_shas[i]->type != VAL_STRING) {
-            ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
+            ErrorAbort(state, kArgsParsingFailure, "%s(): sha-1 #%d is not string", name, i);
             return nullptr;
         }
         if (patches[i]->type != VAL_BLOB) {
-            ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
+            ErrorAbort(state, kArgsParsingFailure, "%s(): patch #%d is not blob", name, i);
             return nullptr;
         }
     }
@@ -1240,7 +1250,7 @@
 Value* ApplyPatchCheckFn(const char* name, State* state,
                          int argc, Expr* argv[]) {
     if (argc < 1) {
-        return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
+        return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 1 arg, got %d",
                           name, argc);
     }
 
@@ -1285,7 +1295,7 @@
 
 Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 0) {
-        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc);
     }
     fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n");
     return StringValue(strdup("t"));
@@ -1293,7 +1303,7 @@
 
 Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc < 1) {
-        return ErrorAbort(state, "%s() expects at least 1 arg", name);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name);
     }
     char** args = ReadVarArgs(state, argc, argv);
     if (args == NULL) {
@@ -1347,7 +1357,7 @@
 //
 Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc < 1) {
-        return ErrorAbort(state, "%s() expects at least 1 arg", name);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name);
     }
 
     std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc, argv), free);
@@ -1395,7 +1405,7 @@
 // is actually a FileContents*).
 Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 1) {
-        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
     }
     char* filename;
     if (ReadArgs(state, argv, 1, &filename) < 0) return NULL;
@@ -1431,7 +1441,7 @@
 // partition.
 Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 2) {
-        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
     }
 
     char* filename;
@@ -1457,7 +1467,7 @@
 
     sleep(5);
     free(property);
-    ErrorAbort(state, "%s() failed to reboot", name);
+    ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name);
     return NULL;
 }
 
@@ -1473,7 +1483,7 @@
 // bytes.
 Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 2) {
-        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
     }
 
     char* filename;
@@ -1503,7 +1513,7 @@
 // is the block device for the misc partition.
 Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 1) {
-        return ErrorAbort(state, "%s() expects 1 arg, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc);
     }
 
     char* filename;
@@ -1521,7 +1531,7 @@
 
 Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 2) {
-        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc);
     }
 
     char* filename;
@@ -1543,7 +1553,7 @@
 
 Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc != 0) {
-        return ErrorAbort(state, "%s() expects no args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc);
     }
     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
     fprintf(ui->cmd_pipe, "enable_reboot\n");
@@ -1552,12 +1562,12 @@
 
 Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) {
     if (argc == 0) {
-        return ErrorAbort(state, "%s() expects args, got %d", name, argc);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() expects args, got %d", name, argc);
     }
 
     char** args = ReadVarArgs(state, argc, argv);
     if (args == NULL) {
-        return ErrorAbort(state, "%s() could not read args", name);
+        return ErrorAbort(state, kArgsParsingFailure, "%s() could not read args", name);
     }
 
     char** args2 = reinterpret_cast<char**>(malloc(sizeof(char*) * (argc+1)));
@@ -1575,7 +1585,8 @@
     free(args2[0]);
     free(args2);
     if (result != 0) {
-        return ErrorAbort(state, "%s() returned error code %d", name, result);
+        return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d",
+                          name, result);
     }
     return StringValue(strdup("t"));
 }
diff --git a/updater/updater.cpp b/updater/updater.cpp
index 0497d6a..f51a6db 100644
--- a/updater/updater.cpp
+++ b/updater/updater.cpp
@@ -159,11 +159,28 @@
             printf("script aborted: %s\n", state.errmsg);
             char* line = strtok(state.errmsg, "\n");
             while (line) {
+                // Parse the error code in abort message.
+                // Example: "E30: This package is for bullhead devices."
+                if (*line == 'E') {
+                    if (sscanf(line, "E%u: ", &state.error_code) != 1) {
+                         printf("Failed to parse error code: [%s]\n", line);
+                    }
+                }
                 fprintf(cmd_pipe, "ui_print %s\n", line);
                 line = strtok(NULL, "\n");
             }
             fprintf(cmd_pipe, "ui_print\n");
         }
+
+        if (state.error_code != kNoError) {
+            fprintf(cmd_pipe, "log error: %d\n", state.error_code);
+            // Cause code should provide additional information about the abort;
+            // report only when an error exists.
+            if (state.cause_code != kNoCause) {
+                fprintf(cmd_pipe, "log cause: %d\n", state.cause_code);
+            }
+        }
+
         free(state.errmsg);
         return 7;
     } else {