Allow recovery to return error codes

Write error code, cause code, and retry count into last_install. So we
can have more information about the reason of a failed OTA.

Example of new last_install:
@/cache/recovery/block.map     package name
0                              install result
retry: 1                       retry count (new)
error: 30                      error code (new)
cause: 12                      error cause (new)

Details in:
go/android-ota-errorcode

Bug: 28471955
Change-Id: I00e7153c821e7355c1be81a86c7f228108f3dc37
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index d67af66..2efa1cd 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -43,6 +43,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;
     }
@@ -648,6 +653,7 @@
     }
 
     if (ota_fsync(fd) == -1) {
+        failure_type = kFsyncFailure;
         fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
         return -1;
     }
@@ -663,11 +669,13 @@
     unique_fd dfd_holder(dfd);
 
     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;
     }
@@ -696,19 +704,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;
         }
 
@@ -728,7 +738,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;
     }
 
@@ -1346,19 +1357,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(""));
     }
 
@@ -1418,7 +1431,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(""));
     }
 
@@ -1433,7 +1447,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(""));
     }
 
@@ -1444,7 +1458,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(""));
         }
 
@@ -1454,7 +1469,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(""));
         }
 
@@ -1508,6 +1524,7 @@
 
         if (params.canwrite) {
             if (ota_fsync(params.fd) == -1) {
+                failure_type = kFsyncFailure;
                 fprintf(stderr, "fsync failed: %s\n", strerror(errno));
                 goto pbiudone;
             }
@@ -1542,6 +1559,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 of the fd_holder above.
@@ -1552,6 +1570,10 @@
         DeleteStash(params.stashbase);
     }
 
+    if (failure_type != kNoCause && state->cause_code == kNoCause) {
+        state->cause_code = failure_type;
+    }
+
     return StringValue(rc == 0 ? strdup("t") : strdup(""));
 }
 
@@ -1657,18 +1679,20 @@
             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(""));
     }
 
     int fd = open(blockdev_filename->data, O_RDWR);
     unique_fd fd_holder(fd);
     if (fd < 0) {
-        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(""));
     }
 
@@ -1681,13 +1705,14 @@
     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,
+                ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data,
                         strerror(errno));
                 return StringValue(strdup(""));
             }
@@ -1715,14 +1740,15 @@
     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(""));
     }
 
     int fd = open(arg_filename->data, O_RDONLY);
     unique_fd fd_holder(fd);
     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(""));
     }
 
@@ -1730,7 +1756,7 @@
     std::vector<uint8_t> block0_buffer(BLOCKSIZE);
 
     if (ReadBlocks(blk0, block0_buffer, fd) == -1) {
-        ErrorAbort(state, "failed to read %s: %s", arg_filename->data,
+        ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data,
                 strerror(errno));
         return StringValue(strdup(""));
     }
@@ -1766,11 +1792,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(""));
     }
 
@@ -1781,19 +1807,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(""));
     }
 
@@ -1810,8 +1837,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(""));
             }