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/edify/Android.mk b/edify/Android.mk
index 038dec0..71cf765 100644
--- a/edify/Android.mk
+++ b/edify/Android.mk
@@ -22,6 +22,8 @@
 LOCAL_CPPFLAGS += -Wno-unused-parameter
 LOCAL_CPPFLAGS += -Wno-deprecated-register
 LOCAL_CLANG := true
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_STATIC_LIBRARIES += libbase
 
 include $(BUILD_HOST_EXECUTABLE)
 
@@ -36,5 +38,7 @@
 LOCAL_CPPFLAGS += -Wno-deprecated-register
 LOCAL_MODULE := libedify
 LOCAL_CLANG := true
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_STATIC_LIBRARIES += libbase
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/edify/expr.cpp b/edify/expr.cpp
index cd1e087..cc14fbe 100644
--- a/edify/expr.cpp
+++ b/edify/expr.cpp
@@ -21,6 +21,11 @@
 #include <stdarg.h>
 #include <unistd.h>
 
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
 #include "expr.h"
 
 // Functions should:
@@ -36,7 +41,7 @@
     Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
     if (v == NULL) return NULL;
     if (v->type != VAL_STRING) {
-        ErrorAbort(state, "expecting string, got value type %d", v->type);
+        ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type);
         FreeValue(v);
         return NULL;
     }
@@ -493,15 +498,29 @@
     return args;
 }
 
-// Use printf-style arguments to compose an error message to put into
-// *state.  Returns NULL.
-Value* ErrorAbort(State* state, const char* format, ...) {
-    char* buffer = reinterpret_cast<char*>(malloc(4096));
-    va_list v;
-    va_start(v, format);
-    vsnprintf(buffer, 4096, format, v);
-    va_end(v);
+static void ErrorAbortV(State* state, const char* format, va_list ap) {
+    std::string buffer;
+    android::base::StringAppendV(&buffer, format, ap);
     free(state->errmsg);
-    state->errmsg = buffer;
-    return NULL;
+    state->errmsg = strdup(buffer.c_str());
+    return;
+}
+
+// Use printf-style arguments to compose an error message to put into
+// *state.  Returns nullptr.
+Value* ErrorAbort(State* state, const char* format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    ErrorAbortV(state, format, ap);
+    va_end(ap);
+    return nullptr;
+}
+
+Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    ErrorAbortV(state, format, ap);
+    va_end(ap);
+    state->cause_code = cause_code;
+    return nullptr;
 }
diff --git a/edify/expr.h b/edify/expr.h
index 36f8e96..5c06de8 100644
--- a/edify/expr.h
+++ b/edify/expr.h
@@ -19,6 +19,7 @@
 
 #include <unistd.h>
 
+#include "error_code.h"
 #include "yydefs.h"
 
 #define MAX_STRING_LEN 1024
@@ -39,6 +40,15 @@
     // Should be NULL initially, will be either NULL or a malloc'd
     // pointer after Evaluate() returns.
     char* errmsg;
+
+    // error code indicates the type of failure (e.g. failure to update system image)
+    // during the OTA process.
+    ErrorCode error_code = kNoError;
+
+    // cause code provides more detailed reason of an OTA failure (e.g. fsync error)
+    // in addition to the error code.
+    CauseCode cause_code = kNoCause;
+
 } State;
 
 #define VAL_STRING  1  // data will be NULL-terminated; size doesn't count null
@@ -152,7 +162,13 @@
 
 // Use printf-style arguments to compose an error message to put into
 // *state.  Returns NULL.
-Value* ErrorAbort(State* state, const char* format, ...) __attribute__((format(printf, 2, 3)));
+Value* ErrorAbort(State* state, const char* format, ...)
+    __attribute__((format(printf, 2, 3), deprecated));
+
+// ErrorAbort has an optional (but recommended) argument 'cause_code'. If the cause code
+// is set, it will be logged into last_install and provides reason of OTA failures.
+Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...)
+    __attribute__((format(printf, 3, 4)));
 
 // Wrap a string into a Value, taking ownership of the string.
 Value* StringValue(char* str);