diff options
-rw-r--r-- | adb_install.cpp | 2 | ||||
-rw-r--r-- | edify/Android.mk | 4 | ||||
-rw-r--r-- | edify/expr.cpp | 39 | ||||
-rw-r--r-- | edify/expr.h | 18 | ||||
-rw-r--r-- | error_code.h | 46 | ||||
-rw-r--r-- | install.cpp | 13 | ||||
-rw-r--r-- | install.h | 4 | ||||
-rw-r--r-- | recovery.cpp | 16 | ||||
-rw-r--r-- | updater/blockimg.cpp | 84 | ||||
-rw-r--r-- | updater/install.cpp | 128 | ||||
-rw-r--r-- | updater/updater.cpp | 17 |
11 files changed, 266 insertions, 105 deletions
diff --git a/adb_install.cpp b/adb_install.cpp index 4cfcb2ab8..4aed9d4b1 100644 --- a/adb_install.cpp +++ b/adb_install.cpp @@ -113,7 +113,7 @@ apply_from_adb(RecoveryUI* ui_, bool* wipe_cache, const char* install_file) { break; } } - result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false); + result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, install_file, false, 0); break; } diff --git a/edify/Android.mk b/edify/Android.mk index 038dec088..71cf7652a 100644 --- a/edify/Android.mk +++ b/edify/Android.mk @@ -22,6 +22,8 @@ LOCAL_YACCFLAGS := -v 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-unused-parameter 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 c34342f76..ecb1bea1a 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 @@ char* Evaluate(State* state, Expr* expr) { 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; } @@ -494,15 +499,29 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) { return args; } +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 = strdup(buffer.c_str()); + return; +} + // Use printf-style arguments to compose an error message to put into -// *state. Returns NULL. +// *state. Returns nullptr. 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); - free(state->errmsg); - state->errmsg = buffer; - return NULL; + 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 36f8e9612..5c06de846 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 @@ typedef struct { // 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 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]); // 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); diff --git a/error_code.h b/error_code.h new file mode 100644 index 000000000..259319ab4 --- /dev/null +++ b/error_code.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ERROR_CODE_H_ +#define _ERROR_CODE_H_ + +enum ErrorCode { + kNoError = -1, + kLowBattery = 20, + kZipVerificationFailure, + kZipOpenFailure +}; + +enum CauseCode { + kNoCause = -1, + kArgsParsingFailure = 100, + kStashCreationFailure, + kFileOpenFailure, + kLseekFailure, + kFreadFailure, + kFwriteFailure, + kFsyncFailure, + kLibfecFailure, + kFileGetPropFailure, + kFileRenameFailure, + kSymlinkFailure, + kSetMetadataFailure, + kTune2FsFailure, + kRebootFailure, + kVendorFailure = 200 +}; + +#endif diff --git a/install.cpp b/install.cpp index 2faabcbc2..9d2971c8c 100644 --- a/install.cpp +++ b/install.cpp @@ -27,7 +27,11 @@ #include <string> #include <vector> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> + #include "common.h" +#include "error_code.h" #include "install.h" #include "minui/minui.h" #include "minzip/SysUtil.h" @@ -253,6 +257,8 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err); if (err != VERIFY_SUCCESS) { LOGE("signature verification failed\n"); + log_buffer.push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure)); + sysReleaseMap(&map); return INSTALL_CORRUPT; } @@ -262,6 +268,8 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, err = mzOpenZipArchive(map.addr, map.length, &zip); if (err != 0) { LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad"); + log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure)); + sysReleaseMap(&map); return INSTALL_CORRUPT; } @@ -280,7 +288,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, int install_package(const char* path, bool* wipe_cache, const char* install_file, - bool needs_mount) + bool needs_mount, int retry_count) { modified_flash = true; auto start = std::chrono::system_clock::now(); @@ -300,13 +308,14 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, } else { result = really_install_package(path, wipe_cache, needs_mount, log_buffer); } - if (install_log) { + if (install_log != nullptr) { fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); fputc('\n', install_log); std::chrono::duration<double> duration = std::chrono::system_clock::now() - start; int count = static_cast<int>(duration.count()); // Report the time spent to apply OTA update in seconds. fprintf(install_log, "time_total: %d\n", count); + fprintf(install_log, "retry: %d\n", retry_count); for (const auto& s : log_buffer) { fprintf(install_log, "%s\n", s.c_str()); @@ -28,8 +28,8 @@ enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SK // Install the package specified by root_path. If INSTALL_SUCCESS is // returned and *wipe_cache is true on exit, caller should wipe the // cache partition. -int install_package(const char* root_path, bool* wipe_cache, - const char* install_file, bool needs_mount); +int install_package(const char* root_path, bool* wipe_cache, const char* install_file, + bool needs_mount, int retry_count); #ifdef __cplusplus } diff --git a/recovery.cpp b/recovery.cpp index c681c8ce7..573ae1abb 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -51,6 +51,7 @@ #include "bootloader.h" #include "common.h" #include "device.h" +#include "error_code.h" #include "fuse_sdcard_provider.h" #include "fuse_sideload.h" #include "install.h" @@ -985,7 +986,7 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) { } result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache, - TEMPORARY_INSTALL_FILE, false); + TEMPORARY_INSTALL_FILE, false, 0/*retry_count*/); break; } @@ -1438,10 +1439,21 @@ int main(int argc, char **argv) { if (!is_battery_ok()) { ui->Print("battery capacity is not enough for installing package, needed is %d%%\n", BATTERY_OK_PERCENTAGE); + // Log the error code to last_install when installation skips due to + // low battery. + FILE* install_log = fopen_path(LAST_INSTALL_FILE, "w"); + if (install_log != nullptr) { + fprintf(install_log, "%s\n", update_package); + fprintf(install_log, "0\n"); + fprintf(install_log, "error: %d\n", kLowBattery); + fclose(install_log); + } else { + LOGE("failed to open last_install: %s\n", strerror(errno)); + } status = INSTALL_SKIPPED; } else { status = install_package(update_package, &should_wipe_cache, - TEMPORARY_INSTALL_FILE, true); + TEMPORARY_INSTALL_FILE, true, retry_count); if (status == INSTALL_SUCCESS && should_wipe_cache) { wipe_cache(false, device); } diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 885a517ec..f78342d36 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 @@ struct RangeSet { 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 @@ static int read_all(int fd, uint8_t* data, size_t size) { 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 @@ static int write_all(int fd, const uint8_t* data, size_t size) { 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 int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) { 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 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks } 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 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks 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 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s 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 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg // 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg // 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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 @@ pbiudone: 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 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) 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 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) 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 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) 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 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) 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 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ 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 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ 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 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ } 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 bab2fe166..a65b32d81 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 @@ char* PrintSha1(const uint8_t* digest) { 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 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { } 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 @@ done: 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 @@ done: 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 @@ static int exec_cmd(const char* path, char* const argv[]) { 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 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { } 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 @@ done: 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 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { 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* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { 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* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { 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* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { 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* PackageExtractDirFn(const char* name, State* state, 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 @@ static int make_parents(char* name) { // 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 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { } 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 @@ static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv 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 @@ done: } 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 @@ done: 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 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 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,13 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { 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", + 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 +1079,16 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1169,8 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, 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 +1182,8 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, 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 +1197,8 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1222,11 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1249,7 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1294,7 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1302,7 @@ Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1356,7 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { // 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 +1404,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { // 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 +1440,7 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { // 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 +1466,7 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { sleep(5); free(property); - ErrorAbort(state, "%s() failed to reboot", name); + ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name); return NULL; } @@ -1473,7 +1482,7 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { // 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 +1512,7 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { // 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 +1530,7 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1552,7 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) 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 +1561,12 @@ Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { 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 +1584,8 @@ Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { 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 0497d6a85..f51a6db73 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -159,11 +159,28 @@ int main(int argc, char** argv) { 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 { |