From b6918c7c433054ac4352d5f7746f7c2bf2971083 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 19 May 2015 17:02:16 -0700 Subject: Log update outputs in order Although stdout and stderr are both redirected to log file with no buffering, we are seeing some outputs are mixed in random order. This is because ui_print commands from the updater are passed to the recovery binary via a pipe, which may interleave with other outputs that go to stderr directly. In recovery, adding ui::PrintOnScreenOnly() function to handle ui_print command, which skips printing to stdout. Meanwhile, updater prints the contents to stderr in addition to piping them to recovery. Change-Id: Idda93ea940d2e23a0276bb8ead4aa70a3cb97700 --- install.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index c7d382f3e..7d88ed72a 100644 --- a/install.cpp +++ b/install.cpp @@ -164,9 +164,9 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { } else if (strcmp(command, "ui_print") == 0) { char* str = strtok(NULL, "\n"); if (str) { - ui->Print("%s", str); + ui->PrintOnScreenOnly("%s", str); } else { - ui->Print("\n"); + ui->PrintOnScreenOnly("\n"); } fflush(stdout); } else if (strcmp(command, "wipe_cache") == 0) { -- cgit v1.2.3 From 71e3e09ec2ac4f022e8f9213657746d8cad5dd97 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 2 Feb 2016 14:02:27 -0800 Subject: recovery: Refactor verifier and verifier_test. Move to using std::vector and std::unique_ptr to manage key certificates to stop memory leaks. Bug: 26908001 Change-Id: Ia5f799bc8dcc036a0ffae5eaa8d9f6e09abd031c --- install.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index 7d88ed72a..c0d007709 100644 --- a/install.cpp +++ b/install.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "common.h" #include "install.h" #include "mincrypt/rsa.h" @@ -221,19 +223,16 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount) return INSTALL_CORRUPT; } - int numKeys; - Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); - if (loadedKeys == NULL) { + std::vector loadedKeys; + if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) { LOGE("Failed to load keys\n"); return INSTALL_CORRUPT; } - LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE); + LOGI("%zu key(s) loaded from %s\n", loadedKeys.size(), PUBLIC_KEYS_FILE); ui->Print("Verifying update package...\n"); - int err; - err = verify_file(map.addr, map.length, loadedKeys, numKeys); - free(loadedKeys); + int err = verify_file(map.addr, map.length, loadedKeys); LOGI("verify_file returned %d\n", err); if (err != VERIFY_SUCCESS) { LOGE("signature verification failed\n"); -- cgit v1.2.3 From fa12b9737dd4ab36c3b4abaf25eb79f692e6eba6 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 5 Feb 2016 18:25:58 -0800 Subject: Reboot and retry on I/O errors When I/O error happens, reboot and retry installation two times before we abort this OTA update. Bug: 25633753 Change-Id: Iba6d4203a343a725aa625a41d237606980d62f69 (cherry picked from commit 3c62b67faf8a25f1dd1c44dc19759c3997fdfd36) --- install.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index c0d007709..8a82d7bc4 100644 --- a/install.cpp +++ b/install.cpp @@ -144,6 +144,7 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { close(pipefd[1]); *wipe_cache = false; + bool retry_update = false; char buffer[1024]; FILE* from_child = fdopen(pipefd[0], "r"); @@ -180,6 +181,8 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { // to be able to reboot during installation (useful for // debugging packages that don't exit). ui->SetEnableReboot(true); + } else if (strcmp(command, "retry_update") == 0) { + retry_update = true; } else { LOGE("unknown command [%s]\n", command); } @@ -188,6 +191,9 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { int status; waitpid(pid, &status, 0); + if (retry_update) { + return INSTALL_RETRY; + } if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status)); return INSTALL_ERROR; -- cgit v1.2.3 From 8febafa67e93b2159804b1130a41f15b009de1cd Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 13 Apr 2016 16:39:56 -0700 Subject: Use BoringSSL instead of mincrypt to speed up package verification. This changes the verification code in bootable/recovery to use BoringSSL instead of mincrypt. Cherry-pick of 452df6d99c81c4eeee3d2c7b2171901e8b7bc54a, with merge conflict resolution, extra logging in verifier.cpp, and an increase in the hash chunk size from 4KiB to 1MiB. Bug: http://b/28135231 Change-Id: I1ed7efd52223dd6f6a4629cad187cbc383d5aa84 --- install.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index 8a82d7bc4..d009513c3 100644 --- a/install.cpp +++ b/install.cpp @@ -23,19 +23,19 @@ #include #include +#include #include #include "common.h" #include "install.h" -#include "mincrypt/rsa.h" #include "minui/minui.h" #include "minzip/SysUtil.h" #include "minzip/Zip.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" #include "roots.h" -#include "verifier.h" #include "ui.h" +#include "verifier.h" extern RecoveryUI* ui; @@ -229,6 +229,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount) return INSTALL_CORRUPT; } + // Load keys. std::vector loadedKeys; if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) { LOGE("Failed to load keys\n"); @@ -236,18 +237,19 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount) } LOGI("%zu key(s) loaded from %s\n", loadedKeys.size(), PUBLIC_KEYS_FILE); + // Verify package. ui->Print("Verifying update package...\n"); - + auto t0 = std::chrono::system_clock::now(); int err = verify_file(map.addr, map.length, loadedKeys); - LOGI("verify_file returned %d\n", err); + std::chrono::duration duration = std::chrono::system_clock::now() - t0; + ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err); if (err != VERIFY_SUCCESS) { LOGE("signature verification failed\n"); sysReleaseMap(&map); return INSTALL_CORRUPT; } - /* Try to open the package. - */ + // Try to open the package. ZipArchive zip; err = mzOpenZipArchive(map.addr, map.length, &zip); if (err != 0) { @@ -256,8 +258,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount) return INSTALL_CORRUPT; } - /* Verify and install the contents of the package. - */ + // Verify and install the contents of the package. ui->Print("Installing update...\n"); ui->SetEnableReboot(false); int result = try_update_binary(path, &zip, wipe_cache); -- cgit v1.2.3 From dd874b1c87eb04f28db0db2629df0adde568a74c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 13 May 2016 12:13:15 -0700 Subject: Add time and I/O info to last_install One example of last_install is: /sideload/package.zip 1 time_total: 101 bytes_written_system: 14574000 bytes_stashed_system: 100 bytes_written_vendor: 5107400 bytes_stashed_vendor: 0 Bug: 28658632 Change-Id: I4bf79ea71a609068d38fbce6b41bcb892524aa7a --- install.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index d009513c3..d725c7b88 100644 --- a/install.cpp +++ b/install.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "common.h" @@ -50,7 +51,9 @@ static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1; // If the package contains an update binary, extract it and run it. static int -try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { +try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, + std::vector& log_buffer) +{ const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) { @@ -183,6 +186,10 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { ui->SetEnableReboot(true); } else if (strcmp(command, "retry_update") == 0) { retry_update = true; + } else if (strcmp(command, "log") == 0) { + // Save the logging request from updater and write to + // last_install later. + log_buffer.push_back(std::string(strtok(NULL, "\n"))); } else { LOGE("unknown command [%s]\n", command); } @@ -203,7 +210,8 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) { } static int -really_install_package(const char *path, bool* wipe_cache, bool needs_mount) +really_install_package(const char *path, bool* wipe_cache, bool needs_mount, + std::vector& log_buffer) { ui->SetBackground(RecoveryUI::INSTALLING_UPDATE); ui->Print("Finding update package...\n"); @@ -261,7 +269,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount) // Verify and install the contents of the package. ui->Print("Installing update...\n"); ui->SetEnableReboot(false); - int result = try_update_binary(path, &zip, wipe_cache); + int result = try_update_binary(path, &zip, wipe_cache, log_buffer); ui->SetEnableReboot(true); ui->Print("\n"); @@ -275,6 +283,7 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, bool needs_mount) { modified_flash = true; + auto start = std::chrono::system_clock::now(); FILE* install_log = fopen_path(install_file, "w"); if (install_log) { @@ -284,15 +293,25 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, LOGE("failed to open last_install: %s\n", strerror(errno)); } int result; + std::vector log_buffer; if (setup_install_mounts() != 0) { LOGE("failed to set up expected mounts for install; aborting\n"); result = INSTALL_ERROR; } else { - result = really_install_package(path, wipe_cache, needs_mount); + result = really_install_package(path, wipe_cache, needs_mount, log_buffer); } if (install_log) { fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); fputc('\n', install_log); + std::chrono::duration duration = std::chrono::system_clock::now() - start; + int count = static_cast(duration.count()); + // Report the time spent to apply OTA update in seconds. + fprintf(install_log, "time_total: %d\n", count); + + for (const auto& s : log_buffer) { + fprintf(install_log, "%s\n", s.c_str()); + } + fclose(install_log); } return result; -- cgit v1.2.3 From 162558382b768a4120b3e41090a4c7b53f11469a Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Sat, 30 Apr 2016 11:49:59 -0700 Subject: 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 --- install.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index d725c7b88..57328528c 100644 --- a/install.cpp +++ b/install.cpp @@ -27,7 +27,11 @@ #include #include +#include +#include + #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 duration = std::chrono::system_clock::now() - start; int count = static_cast(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()); -- cgit v1.2.3 From 7ce287d432dd3a4dc8841fc59e11ee1a0b7808a1 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 31 May 2016 09:29:49 -0700 Subject: Call ioctl before each write on retry If the update is a retry, ioctl(BLKDISCARD) the destination blocks before writing to these blocks. Bug: 28990135 Change-Id: I1e703808e68ebb1292cd66afd76be8fd6946ee59 --- install.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index 57328528c..d5c558306 100644 --- a/install.cpp +++ b/install.cpp @@ -56,7 +56,7 @@ static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1; // If the package contains an update binary, extract it and run it. static int try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, - std::vector& log_buffer) + std::vector& log_buffer, int retry_count) { const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); @@ -130,15 +130,19 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, // // - the name of the package zip file. // + // - an optional argument "retry" if this update is a retry of a failed + // update attempt. + // - const char** args = (const char**)malloc(sizeof(char*) * 5); + const char** args = (const char**)malloc(sizeof(char*) * 6); args[0] = binary; args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk char* temp = (char*)malloc(10); sprintf(temp, "%d", pipefd[1]); args[2] = temp; args[3] = (char*)path; - args[4] = NULL; + args[4] = retry_count > 0 ? "retry" : NULL; + args[5] = NULL; pid_t pid = fork(); if (pid == 0) { @@ -215,7 +219,7 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, static int really_install_package(const char *path, bool* wipe_cache, bool needs_mount, - std::vector& log_buffer) + std::vector& log_buffer, int retry_count) { ui->SetBackground(RecoveryUI::INSTALLING_UPDATE); ui->Print("Finding update package...\n"); @@ -276,8 +280,11 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount, // Verify and install the contents of the package. ui->Print("Installing update...\n"); + if (retry_count > 0) { + ui->Print("Retry attempt: %d\n", retry_count); + } ui->SetEnableReboot(false); - int result = try_update_binary(path, &zip, wipe_cache, log_buffer); + int result = try_update_binary(path, &zip, wipe_cache, log_buffer, retry_count); ui->SetEnableReboot(true); ui->Print("\n"); @@ -306,7 +313,7 @@ install_package(const char* path, bool* wipe_cache, const char* install_file, LOGE("failed to set up expected mounts for install; aborting\n"); result = INSTALL_ERROR; } else { - result = really_install_package(path, wipe_cache, needs_mount, log_buffer); + result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count); } if (install_log != nullptr) { fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); -- cgit v1.2.3 From b0ddae55e53c90880212caf0e19e439a3898abfd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 8 Jun 2016 14:30:04 -0700 Subject: Log source/target build version to last_install Parse the build.version.incremental from the metadata of the update package; and log it to last_install. Example: In metadata we read: post-build-incremental=2951741 pre-build-incremental=2943039 In last install we log: source_build: 2943039 target_build: 2951741 Bug: 28658632 Change-Id: I0a9cc2d01644846e18bda31f4193ff40e8924486 --- install.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'install.cpp') diff --git a/install.cpp b/install.cpp index d5c558306..5a439a1d6 100644 --- a/install.cpp +++ b/install.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -46,6 +47,7 @@ extern RecoveryUI* ui; #define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" #define PUBLIC_KEYS_FILE "/res/keys" +static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata"; // Default allocation of progress bar segments to operations static const int VERIFICATION_PROGRESS_TIME = 60; @@ -53,11 +55,64 @@ static const float VERIFICATION_PROGRESS_FRACTION = 0.25; static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4; static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1; +// This function parses and returns the build.version.incremental +static int parse_build_number(std::string str) { + size_t pos = str.find("="); + if (pos != std::string::npos) { + std::string num_string = android::base::Trim(str.substr(pos+1)); + int build_number; + if (android::base::ParseInt(num_string.c_str(), &build_number, 0)) { + return build_number; + } + } + + LOGE("Failed to parse build number in %s.\n", str.c_str()); + return -1; +} + +// Read the build.version.incremental of src/tgt from the metadata and log it to last_install. +static void read_source_target_build(ZipArchive* zip, std::vector& log_buffer) { + const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH); + if (meta_entry == nullptr) { + LOGE("Failed to find %s in update package.\n", METADATA_PATH); + return; + } + + std::string meta_data(meta_entry->uncompLen, '\0'); + if (!mzReadZipEntry(zip, meta_entry, &meta_data[0], meta_entry->uncompLen)) { + LOGE("Failed to read metadata in update package.\n"); + return; + } + + // Examples of the pre-build and post-build strings in metadata: + // pre-build-incremental=2943039 + // post-build-incremental=2951741 + std::vector lines = android::base::Split(meta_data, "\n"); + for (const std::string& line : lines) { + std::string str = android::base::Trim(line); + if (android::base::StartsWith(str, "pre-build-incremental")){ + int source_build = parse_build_number(str); + if (source_build != -1) { + log_buffer.push_back(android::base::StringPrintf("source_build: %d", + source_build)); + } + } else if (android::base::StartsWith(str, "post-build-incremental")) { + int target_build = parse_build_number(str); + if (target_build != -1) { + log_buffer.push_back(android::base::StringPrintf("target_build: %d", + target_build)); + } + } + } +} + // If the package contains an update binary, extract it and run it. static int try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, std::vector& log_buffer, int retry_count) { + read_source_target_build(zip, log_buffer); + const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) { -- cgit v1.2.3