From c87bab101893e8322b49d7c8600e3367b20ab50a Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Mon, 25 Nov 2013 13:53:25 -0800 Subject: add the functions for multi-stage packages to updater In order to support multi-stage recovery packages, we add the set_stage() and get_stage() functions, which store a short string somewhere it can be accessed across invocations of recovery. We also add reboot_now() which updater can invoke to immediately reboot the device, without doing normal recovery cleanup. (It can also choose whether to boot off the boot or recovery partition.) If the stage string is of the form "#/#", recovery's UI will be augmented with a simple indicator of what stage you're in, so it doesn't look like a reboot loop. Change-Id: I62f7ff0bc802b549c9bcf3cc154a6bad99f94603 --- recovery.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index d803cadf1..43cd9dafe 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -56,6 +56,7 @@ static const struct option OPTIONS[] = { { "show_text", no_argument, NULL, 't' }, { "just_exit", no_argument, NULL, 'x' }, { "locale", required_argument, NULL, 'l' }, + { "stages", required_argument, NULL, 'g' }, { NULL, 0, NULL, 0 }, }; @@ -76,6 +77,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; char* locale = NULL; char recovery_version[PROPERTY_VALUE_MAX+1]; +char* stage = NULL; /* * The recovery tool communicates with the main system through /cache files. @@ -172,6 +174,7 @@ get_args(int *argc, char ***argv) { struct bootloader_message boot; memset(&boot, 0, sizeof(boot)); get_bootloader_message(&boot); // this may fail, leaving a zeroed structure + stage = strndup(boot.stage, sizeof(boot.stage)); if (boot.command[0] != 0 && boot.command[0] != 255) { LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command); @@ -959,6 +962,14 @@ main(int argc, char **argv) { case 't': show_text = 1; break; case 'x': just_exit = true; break; case 'l': locale = optarg; break; + case 'g': { + if (stage == NULL || *stage == '\0') { + char buffer[20] = "1/"; + strncat(buffer, optarg, sizeof(buffer)-3); + stage = strdup(buffer); + } + break; + } case '?': LOGE("Invalid command argument\n"); continue; @@ -969,12 +980,19 @@ main(int argc, char **argv) { load_locale_from_cache(); } printf("locale is [%s]\n", locale); + printf("stage is [%s]\n", stage, stage); Device* device = make_device(); ui = device->GetUI(); gCurrentUI = ui; ui->Init(); + + int st_cur, st_max; + if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) { + ui->SetStage(st_cur, st_max); + } + ui->SetLocale(locale); ui->SetBackground(RecoveryUI::NONE); if (show_text) ui->ShowText(true); -- cgit v1.2.3 From 19a8e2463c31a97121c35b4666a8e6879fa7e338 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 21 Jan 2014 09:25:41 -0800 Subject: log extra info for debugging Make recovery log its PID, and when we use a block map file, log how many ranges it contains. Change-Id: I1b4299f8163af68a770b48c029ae25e6cb45d26b --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 43cd9dafe..0a8c3b52f 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -938,7 +938,7 @@ main(int argc, char **argv) { return 0; } - printf("Starting recovery on %s", ctime(&start)); + printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start)); load_volume_table(); ensure_path_mounted(LAST_LOG_FILE); -- cgit v1.2.3 From 0d32f259cddeaf46917bdc4af3514114c206dd76 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 13 Feb 2014 15:07:56 -0800 Subject: clean up some warnings when building recovery Change-Id: I1541534ee6978ddf8d548433986679ce9507d508 --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 0a8c3b52f..db35f1e97 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -980,7 +980,7 @@ main(int argc, char **argv) { load_locale_from_cache(); } printf("locale is [%s]\n", locale); - printf("stage is [%s]\n", stage, stage); + printf("stage is [%s]\n", stage); Device* device = make_device(); ui = device->GetUI(); -- cgit v1.2.3 From f3bb31c32fa879ccce358c15c93b7bd8582d1756 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Fri, 14 Mar 2014 09:39:48 -0700 Subject: Recovery 64-bit compile issues Change-Id: I92d5abd1a628feab3b0246924fab7f97ba3b9d34 --- recovery.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index d803cadf1..448f315b0 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -174,11 +174,11 @@ get_args(int *argc, char ***argv) { get_bootloader_message(&boot); // this may fail, leaving a zeroed structure if (boot.command[0] != 0 && boot.command[0] != 255) { - LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command); + LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command); } if (boot.status[0] != 0 && boot.status[0] != 255) { - LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status); + LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status); } // --- if arguments weren't supplied, look in the bootloader control block -- cgit v1.2.3 From a418aa7dd5e94cbf1ab2a6fa1c63f60e5e087d42 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Mon, 17 Mar 2014 12:10:02 -0700 Subject: refactor image resource loading code in minui Reduce the number of copies of libpng boilerplate. Rename res_create_* functions to be more clear. Make explicit the use of the framebuffer pixel format for images, and handle more combinations of input and output (eg, loading a grayscale image for display rather than use as a text alpha channel). Change-Id: I3d41c800a8f4c22b2f0167967ce6ee4d6b2b8846 --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 448f315b0..e956ed711 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -974,8 +974,8 @@ main(int argc, char **argv) { ui = device->GetUI(); gCurrentUI = ui; - ui->Init(); ui->SetLocale(locale); + ui->Init(); ui->SetBackground(RecoveryUI::NONE); if (show_text) ui->ShowText(true); -- cgit v1.2.3 From b1d1263453de7f0f155628b91658a7cccb2e95fd Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 18 Mar 2014 10:32:12 -0700 Subject: add --shutdown_after option to recovery The "--shutdown_after" option causes recovery to power down the device on completion rather than rebooting. Removes the last vestiges of the "--previous_runs" argument, which doesn't seem to be used for anything. Change-Id: I465eda2ef59d367e2b1c79a8dc69831263c69a4d --- recovery.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index e956ed711..e852ef87a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -56,6 +56,7 @@ static const struct option OPTIONS[] = { { "show_text", no_argument, NULL, 't' }, { "just_exit", no_argument, NULL, 'x' }, { "locale", required_argument, NULL, 'l' }, + { "shutdown_after", no_argument, NULL, 'p' }, { NULL, 0, NULL, 0 }, }; @@ -942,16 +943,15 @@ main(int argc, char **argv) { rotate_last_logs(10); get_args(&argc, &argv); - int previous_runs = 0; const char *send_intent = NULL; const char *update_package = NULL; int wipe_data = 0, wipe_cache = 0, show_text = 0; bool just_exit = false; + bool shutdown_after = false; int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { switch (arg) { - case 'p': previous_runs = atoi(optarg); break; case 's': send_intent = optarg; break; case 'u': update_package = optarg; break; case 'w': wipe_data = wipe_cache = 1; break; @@ -959,6 +959,7 @@ main(int argc, char **argv) { case 't': show_text = 1; break; case 'x': just_exit = true; break; case 'l': locale = optarg; break; + case 'p': shutdown_after = true; break; case '?': LOGE("Invalid command argument\n"); continue; @@ -1061,7 +1062,12 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); - ui->Print("Rebooting...\n"); - property_set(ANDROID_RB_PROPERTY, "reboot,"); + if (shutdown_after) { + ui->Print("Shutting down...\n"); + property_set(ANDROID_RB_PROPERTY, "shutdown,"); + } else { + ui->Print("Rebooting...\n"); + property_set(ANDROID_RB_PROPERTY, "reboot,"); + } return EXIT_SUCCESS; } -- cgit v1.2.3 From 8d9d3d5cbe240d09db10d08956d152dce934e892 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 1 Apr 2014 13:20:23 -0700 Subject: add reboot-to-bootloader and power down options to recovery menu Useful when debugging or developing for recovery. Change-Id: Ic3ab42d5e848ad3488f1c575339b55e45c8a024b --- recovery.cpp | 55 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 8d3731540..09af5f8b1 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -771,7 +771,10 @@ wipe_data(int confirm, Device* device) { ui->Print("Data wipe complete.\n"); } -static void +// Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION +// means to take the default, which is to reboot or shutdown depending +// on if the --shutdown_after flag was passed to recovery. +static Device::BuiltinAction prompt_and_wait(Device* device, int status) { const char* const* headers = prepend_title(device->GetMenuHeaders()); @@ -795,23 +798,28 @@ prompt_and_wait(Device* device, int status) { // device-specific code may take some action here. It may // return one of the core actions handled in the switch // statement below. - chosen_item = device->InvokeMenuItem(chosen_item); + Device::BuiltinAction chosen_action = device->InvokeMenuItem(chosen_item); int wipe_cache; - switch (chosen_item) { + switch (chosen_action) { + case Device::NO_ACTION: + break; + case Device::REBOOT: - return; + case Device::SHUTDOWN: + case Device::REBOOT_BOOTLOADER: + return chosen_action; case Device::WIPE_DATA: wipe_data(ui->IsTextVisible(), device); - if (!ui->IsTextVisible()) return; + if (!ui->IsTextVisible()) return Device::NO_ACTION; break; case Device::WIPE_CACHE: ui->Print("\n-- Wiping cache...\n"); erase_volume("/cache"); ui->Print("Cache wipe complete.\n"); - if (!ui->IsTextVisible()) return; + if (!ui->IsTextVisible()) return Device::NO_ACTION; break; case Device::APPLY_EXT: @@ -829,7 +837,7 @@ prompt_and_wait(Device* device, int status) { ui->SetBackground(RecoveryUI::ERROR); ui->Print("Installation aborted.\n"); } else if (!ui->IsTextVisible()) { - return; // reboot if logs aren't visible + return Device::NO_ACTION; // reboot if logs aren't visible } else { ui->Print("\nInstall from sdcard complete.\n"); } @@ -852,7 +860,7 @@ prompt_and_wait(Device* device, int status) { ui->SetBackground(RecoveryUI::ERROR); ui->Print("Installation aborted.\n"); } else if (!ui->IsTextVisible()) { - return; // reboot if logs aren't visible + return Device::NO_ACTION; // reboot if logs aren't visible } else { ui->Print("\nInstall from cache complete.\n"); } @@ -867,7 +875,7 @@ prompt_and_wait(Device* device, int status) { ui->Print("Installation aborted.\n"); copy_logs(); } else if (!ui->IsTextVisible()) { - return; // reboot if logs aren't visible + return Device::NO_ACTION; // reboot if logs aren't visible } else { ui->Print("\nInstall from ADB complete.\n"); } @@ -1074,18 +1082,31 @@ main(int argc, char **argv) { copy_logs(); ui->SetBackground(RecoveryUI::ERROR); } + Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT; if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { - prompt_and_wait(device, status); + Device::BuiltinAction temp = prompt_and_wait(device, status); + if (temp != Device::NO_ACTION) after = temp; } - // Otherwise, get ready to boot the main system... + // Save logs and clean up before rebooting or shutting down. finish_recovery(send_intent); - if (shutdown_after) { - ui->Print("Shutting down...\n"); - property_set(ANDROID_RB_PROPERTY, "shutdown,"); - } else { - ui->Print("Rebooting...\n"); - property_set(ANDROID_RB_PROPERTY, "reboot,"); + + switch (after) { + case Device::SHUTDOWN: + ui->Print("Shutting down...\n"); + property_set(ANDROID_RB_PROPERTY, "shutdown,"); + break; + + case Device::REBOOT_BOOTLOADER: + ui->Print("Rebooting to bootloader...\n"); + property_set(ANDROID_RB_PROPERTY, "reboot,bootloader"); + break; + + default: + ui->Print("Rebooting...\n"); + property_set(ANDROID_RB_PROPERTY, "reboot,"); + break; } + sleep(5); // should reboot before this finishes return EXIT_SUCCESS; } -- cgit v1.2.3 From 075ad800c539503d0515e5e0b4af160eccedead9 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 26 Jun 2014 15:35:51 -0700 Subject: sideload without holding the whole package in RAM Implement a new method of sideloading over ADB that does not require the entire package to be held in RAM (useful for low-RAM devices and devices using block OTA where we'd rather have more RAM available for binary patching). We communicate with the host using a new adb service called "sideload-host", which makes the host act as a server, sending us different parts of the package file on request. We create a FUSE filesystem that creates a virtual file "/sideload/package.zip" that is backed by the ADB connection -- users see a normal file, but when they read from the file we're actually fetching the data from the adb host. This file is then passed to the verification and installation systems like any other. To prevent a malicious adb host implementation from serving different data to the verification and installation phases of sideloading, the FUSE filesystem verifies that the contents of the file don't change between reads -- every time we fetch a block from the host we compare its hash to the previous hash for that block (if it was read before) and cause the read to fail if it changes. One necessary change is that the minadbd started by recovery in sideload mode no longer drops its root privileges (they're needed to mount the FUSE filesystem). We rely on SELinux enforcement to restrict the set of things that can be accessed. Change-Id: Ida7dbd3b04c1d4e27a2779d88c1da0c7c81fb114 --- recovery.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 09af5f8b1..5a2715cb8 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -712,7 +712,7 @@ update_directory(const char* path, const char* unmount_when_done, ensure_path_unmounted(unmount_when_done); } if (copy) { - result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE); + result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE, true); free(copy); } else { result = INSTALL_ERROR; @@ -1047,7 +1047,7 @@ main(int argc, char **argv) { int status = INSTALL_SUCCESS; if (update_package != NULL) { - status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE); + status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE, true); if (status == INSTALL_SUCCESS && wipe_cache) { if (erase_volume("/cache")) { LOGE("Cache wipe (requested by package) failed."); -- cgit v1.2.3 From 93950229cf9a991589f6bb071a966b00349d18d6 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 8 Jul 2014 14:10:23 -0700 Subject: drop APPLY_CACHE and refactor APPLY_EXT Drop support for sideloading OTA packages of the cache partition (a half-solution that's long since been deprecated by "adb sideload"). Refactor the code to sideload OTA packages from SD cards: remove the installation code from the file browser. Change-Id: Id0dff6b27c4a5837546f174f50e2e1d0379c43db --- recovery.cpp | 108 +++++++++++++++++++++++++---------------------------------- 1 file changed, 45 insertions(+), 63 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 5a2715cb8..1c7c0d6a4 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -604,9 +604,9 @@ static int compare_string(const void* a, const void* b) { return strcmp(*(const char**)a, *(const char**)b); } -static int -update_directory(const char* path, const char* unmount_when_done, - int* wipe_cache, Device* device) { +// Returns a malloc'd path, or NULL. +static char* +browse_directory(const char* path, Device* device) { ensure_path_mounted(path); const char* MENU_HEADERS[] = { "Choose a package to install:", @@ -618,10 +618,7 @@ update_directory(const char* path, const char* unmount_when_done, d = opendir(path); if (d == NULL) { LOGE("error opening %s: %s\n", path, strerror(errno)); - if (unmount_when_done != NULL) { - ensure_path_unmounted(unmount_when_done); - } - return 0; + return NULL; } const char** headers = prepend_title(MENU_HEADERS); @@ -677,58 +674,41 @@ update_directory(const char* path, const char* unmount_when_done, z_size += d_size; zips[z_size] = NULL; - int result; + char* result; int chosen_item = 0; - do { + while (true) { chosen_item = get_menu_selection(headers, zips, 1, chosen_item, device); char* item = zips[chosen_item]; int item_len = strlen(item); if (chosen_item == 0) { // item 0 is always "../" // go up but continue browsing (if the caller is update_directory) - result = -1; + result = NULL; break; - } else if (item[item_len-1] == '/') { + } + + char new_path[PATH_MAX]; + strlcpy(new_path, path, PATH_MAX); + strlcat(new_path, "/", PATH_MAX); + strlcat(new_path, item, PATH_MAX); + + if (item[item_len-1] == '/') { // recurse down into a subdirectory - char new_path[PATH_MAX]; - strlcpy(new_path, path, PATH_MAX); - strlcat(new_path, "/", PATH_MAX); - strlcat(new_path, item, PATH_MAX); new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/' - result = update_directory(new_path, unmount_when_done, wipe_cache, device); - if (result >= 0) break; + result = browse_directory(new_path, device); + if (result) break; } else { - // selected a zip file: attempt to install it, and return - // the status to the caller. - char new_path[PATH_MAX]; - strlcpy(new_path, path, PATH_MAX); - strlcat(new_path, "/", PATH_MAX); - strlcat(new_path, item, PATH_MAX); - - ui->Print("\n-- Install %s ...\n", path); - set_sdcard_update_bootloader_message(); - char* copy = copy_sideloaded_package(new_path); - if (unmount_when_done != NULL) { - ensure_path_unmounted(unmount_when_done); - } - if (copy) { - result = install_package(copy, wipe_cache, TEMPORARY_INSTALL_FILE, true); - free(copy); - } else { - result = INSTALL_ERROR; - } + // selected a zip file: return the malloc'd path to the caller. + result = strdup(new_path); break; } - } while (true); + } int i; for (i = 0; i < z_size; ++i) free(zips[i]); free(zips); free(headers); - if (unmount_when_done != NULL) { - ensure_path_unmounted(unmount_when_done); - } return result; } @@ -800,7 +780,7 @@ prompt_and_wait(Device* device, int status) { // statement below. Device::BuiltinAction chosen_action = device->InvokeMenuItem(chosen_item); - int wipe_cache; + int wipe_cache = 0; switch (chosen_action) { case Device::NO_ACTION: break; @@ -822,8 +802,28 @@ prompt_and_wait(Device* device, int status) { if (!ui->IsTextVisible()) return Device::NO_ACTION; break; - case Device::APPLY_EXT: - status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); + case Device::APPLY_EXT: { + ensure_path_mounted(SDCARD_ROOT); + char* path = browse_directory(SDCARD_ROOT, device); + if (path == NULL) { + ui->Print("\n-- No package file selected.\n", path); + break; + } + + ui->Print("\n-- Install %s ...\n", path); + set_sdcard_update_bootloader_message(); + char* copy = copy_sideloaded_package(path); + free(path); + ensure_path_unmounted(SDCARD_ROOT); + + int status; + if (copy) { + status = install_package(copy, &wipe_cache, TEMPORARY_INSTALL_FILE, true); + free(copy); + } else { + status = INSTALL_ERROR; + } + if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); if (erase_volume("/cache")) { @@ -843,28 +843,10 @@ prompt_and_wait(Device* device, int status) { } } break; + } case Device::APPLY_CACHE: - // Don't unmount cache at the end of this. - status = update_directory(CACHE_ROOT, NULL, &wipe_cache, device); - if (status == INSTALL_SUCCESS && wipe_cache) { - ui->Print("\n-- Wiping cache (at package request)...\n"); - if (erase_volume("/cache")) { - ui->Print("Cache wipe failed.\n"); - } else { - ui->Print("Cache wipe complete.\n"); - } - } - if (status >= 0) { - if (status != INSTALL_SUCCESS) { - ui->SetBackground(RecoveryUI::ERROR); - ui->Print("Installation aborted.\n"); - } else if (!ui->IsTextVisible()) { - return Device::NO_ACTION; // reboot if logs aren't visible - } else { - ui->Print("\nInstall from cache complete.\n"); - } - } + ui->Print("\nAPPLY_CACHE is deprecated.\n"); break; case Device::APPLY_ADB_SIDELOAD: -- cgit v1.2.3 From 945fc68c62692467ddb8b7d714bcf0bf01c783c2 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 10 Jul 2014 10:50:39 -0700 Subject: do sdcard sideloading through the fuse filesystem Make a fuse filesystem that sits on top of the selected package file on the sdcard, so we can verify that the file contents don't change while being read and avoid copying the file to /tmp (that is, RAM) before verifying and installing it. Change-Id: Ifd982aa68bfe469eda5f839042648654bf7386a1 --- recovery.cpp | 110 +++++------------------------------------------------------ 1 file changed, 9 insertions(+), 101 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 1c7c0d6a4..d2d85e7c7 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -44,6 +44,8 @@ #include "adb_install.h" extern "C" { #include "minadbd/adb.h" +#include "fuse_sideload.h" +#include "fuse_sdcard_provider.h" } struct selabel_handle *sehandle; @@ -73,7 +75,6 @@ static const char *CACHE_ROOT = "/cache"; static const char *SDCARD_ROOT = "/sdcard"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; -static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; char* locale = NULL; @@ -439,96 +440,6 @@ erase_volume(const char *volume) { return result; } -static char* -copy_sideloaded_package(const char* original_path) { - if (ensure_path_mounted(original_path) != 0) { - LOGE("Can't mount %s\n", original_path); - return NULL; - } - - if (ensure_path_mounted(SIDELOAD_TEMP_DIR) != 0) { - LOGE("Can't mount %s\n", SIDELOAD_TEMP_DIR); - return NULL; - } - - if (mkdir(SIDELOAD_TEMP_DIR, 0700) != 0) { - if (errno != EEXIST) { - LOGE("Can't mkdir %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno)); - return NULL; - } - } - - // verify that SIDELOAD_TEMP_DIR is exactly what we expect: a - // directory, owned by root, readable and writable only by root. - struct stat st; - if (stat(SIDELOAD_TEMP_DIR, &st) != 0) { - LOGE("failed to stat %s (%s)\n", SIDELOAD_TEMP_DIR, strerror(errno)); - return NULL; - } - if (!S_ISDIR(st.st_mode)) { - LOGE("%s isn't a directory\n", SIDELOAD_TEMP_DIR); - return NULL; - } - if ((st.st_mode & 0777) != 0700) { - LOGE("%s has perms %o\n", SIDELOAD_TEMP_DIR, st.st_mode); - return NULL; - } - if (st.st_uid != 0) { - LOGE("%s owned by %lu; not root\n", SIDELOAD_TEMP_DIR, st.st_uid); - return NULL; - } - - char copy_path[PATH_MAX]; - strcpy(copy_path, SIDELOAD_TEMP_DIR); - strcat(copy_path, "/package.zip"); - - char* buffer = (char*)malloc(BUFSIZ); - if (buffer == NULL) { - LOGE("Failed to allocate buffer\n"); - return NULL; - } - - size_t read; - FILE* fin = fopen(original_path, "rb"); - if (fin == NULL) { - LOGE("Failed to open %s (%s)\n", original_path, strerror(errno)); - return NULL; - } - FILE* fout = fopen(copy_path, "wb"); - if (fout == NULL) { - LOGE("Failed to open %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } - - while ((read = fread(buffer, 1, BUFSIZ, fin)) > 0) { - if (fwrite(buffer, 1, read, fout) != read) { - LOGE("Short write of %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } - } - - free(buffer); - - if (fclose(fout) != 0) { - LOGE("Failed to close %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } - - if (fclose(fin) != 0) { - LOGE("Failed to close %s (%s)\n", original_path, strerror(errno)); - return NULL; - } - - // "adb push" is happy to overwrite read-only files when it's - // running as root, but we'll try anyway. - if (chmod(copy_path, 0400) != 0) { - LOGE("Failed to chmod %s (%s)\n", copy_path, strerror(errno)); - return NULL; - } - - return strdup(copy_path); -} - static const char** prepend_title(const char* const* headers) { // count the number of lines in our title, plus the @@ -812,17 +723,13 @@ prompt_and_wait(Device* device, int status) { ui->Print("\n-- Install %s ...\n", path); set_sdcard_update_bootloader_message(); - char* copy = copy_sideloaded_package(path); - free(path); - ensure_path_unmounted(SDCARD_ROOT); + void* token = start_sdcard_fuse(path); - int status; - if (copy) { - status = install_package(copy, &wipe_cache, TEMPORARY_INSTALL_FILE, true); - free(copy); - } else { - status = INSTALL_ERROR; - } + int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, &wipe_cache, + TEMPORARY_INSTALL_FILE, false); + + finish_sdcard_fuse(token); + ensure_path_unmounted(SDCARD_ROOT); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); @@ -832,6 +739,7 @@ prompt_and_wait(Device* device, int status) { ui->Print("Cache wipe complete.\n"); } } + if (status >= 0) { if (status != INSTALL_SUCCESS) { ui->SetBackground(RecoveryUI::ERROR); -- cgit v1.2.3 From ee19387905650cab5da7dd97ada5502cd17ac93d Mon Sep 17 00:00:00 2001 From: Andres Morales Date: Tue, 5 Aug 2014 19:49:09 -0700 Subject: Erase PST partition if its marked to be erased. We need to wipe the challenges on this partition if OEM unlock is enabled, as this is a signal that the user has opted out of factory reset protection. go/factory-reset Bug: 16633064 Change-Id: Icb8f1433bf99ca57813f5b72d5a3dd15fa94a263 --- recovery.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index d2d85e7c7..f78d6e46c 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -659,6 +659,7 @@ wipe_data(int confirm, Device* device) { device->WipeData(); erase_volume("/data"); erase_volume("/cache"); + erase_persistent_partition(); ui->Print("Data wipe complete.\n"); } @@ -959,6 +960,7 @@ main(int argc, char **argv) { if (device->WipeData()) status = INSTALL_ERROR; if (erase_volume("/data")) status = INSTALL_ERROR; if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; + if (erase_persistent_partition() == -1 ) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n"); } else if (wipe_cache) { if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; -- cgit v1.2.3 From a6e13ae01bff5109361868f565187f16d045c82d Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 24 Sep 2014 11:46:17 -0700 Subject: Include reason when wiping data. This will help us track down who requested a data wipe. Bug: 17412160 Change-Id: I1c439fbd29f96b9851810baca9101f683a0f18d8 --- recovery.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index f78d6e46c..7f17b16ef 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -60,6 +60,7 @@ static const struct option OPTIONS[] = { { "locale", required_argument, NULL, 'l' }, { "stages", required_argument, NULL, 'g' }, { "shutdown_after", no_argument, NULL, 'p' }, + { "reason", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0 }, }; @@ -80,6 +81,7 @@ RecoveryUI* ui = NULL; char* locale = NULL; char recovery_version[PROPERTY_VALUE_MAX+1]; char* stage = NULL; +char* reason = NULL; /* * The recovery tool communicates with the main system through /cache files. @@ -870,6 +872,7 @@ main(int argc, char **argv) { break; } case 'p': shutdown_after = true; break; + case 'r': reason = optarg; break; case '?': LOGE("Invalid command argument\n"); continue; @@ -881,6 +884,7 @@ main(int argc, char **argv) { } printf("locale is [%s]\n", locale); printf("stage is [%s]\n", stage); + printf("reason is [%s]\n", reason); Device* device = make_device(); ui = device->GetUI(); -- cgit v1.2.3 From b8344b6f5908935ac2e36109c7433fde34646620 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Wed, 22 Oct 2014 18:38:48 -0700 Subject: Make /cache/recovery/last_log available in recovery Create a new recovery UI option to allow the user to view /cache/recovery/last_log for their device. This gives enhanced debugging information which may be necessary when a failed OTA occurs. Bug: 18094012 Change-Id: Ic3228de96e9bfc2a0141c7aab4ce392a38140cf3 --- recovery.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 4 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 7f17b16ef..e1a2a9678 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -77,6 +77,8 @@ static const char *SDCARD_ROOT = "/sdcard"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; +#define KEEP_LOG_COUNT 10 + RecoveryUI* ui = NULL; char* locale = NULL; char recovery_version[PROPERTY_VALUE_MAX+1]; @@ -161,6 +163,12 @@ fopen_path(const char *path, const char *mode) { return fp; } +static void redirect_stdio(const char* filename) { + // If these fail, there's not really anywhere to complain... + freopen(filename, "a", stdout); setbuf(stdout, NULL); + freopen(filename, "a", stderr); setbuf(stderr, NULL); +} + // close a file, log an error if the error indicator is set static void check_and_fclose(FILE *fp, const char *name) { @@ -665,6 +673,65 @@ wipe_data(int confirm, Device* device) { ui->Print("Data wipe complete.\n"); } +static void file_to_ui(const char* fn) { + FILE *fp = fopen_path(fn, "re"); + if (fp == NULL) { + ui->Print(" Unable to open %s: %s\n", fn, strerror(errno)); + return; + } + char line[1024]; + int ct = 0; + redirect_stdio("/dev/null"); + while(fgets(line, sizeof(line), fp) != NULL) { + ui->Print("%s", line); + ct++; + if (ct % 30 == 0) { + // give the user time to glance at the entries + ui->WaitKey(); + } + } + redirect_stdio(TEMPORARY_LOG_FILE); + fclose(fp); +} + +static void choose_recovery_file(Device* device) { + int i; + static const char** title_headers = NULL; + char *filename; + const char* headers[] = { "Select file to view", + "", + NULL }; + char* entries[KEEP_LOG_COUNT + 2]; + memset(entries, 0, sizeof(entries)); + + for (i = 0; i < KEEP_LOG_COUNT; i++) { + char *filename; + if (asprintf(&filename, (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i) == -1) { + // memory allocation failure - return early. Should never happen. + return; + } + if ((ensure_path_mounted(filename) != 0) || (access(filename, R_OK) == -1)) { + free(filename); + entries[i+1] = NULL; + break; + } + entries[i+1] = filename; + } + + entries[0] = strdup("Go back"); + title_headers = prepend_title((const char**)headers); + + while(1) { + int chosen_item = get_menu_selection(title_headers, entries, 1, 0, device); + if (chosen_item == 0) break; + file_to_ui(entries[chosen_item]); + } + + for (i = 0; i < KEEP_LOG_COUNT + 1; i++) { + free(entries[i]); + } +} + // Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION // means to take the default, which is to reboot or shutdown depending // on if the --shutdown_after flag was passed to recovery. @@ -760,6 +827,10 @@ prompt_and_wait(Device* device, int status) { ui->Print("\nAPPLY_CACHE is deprecated.\n"); break; + case Device::READ_RECOVERY_LASTLOG: + choose_recovery_file(device); + break; + case Device::APPLY_ADB_SIDELOAD: status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE); if (status >= 0) { @@ -824,9 +895,7 @@ int main(int argc, char **argv) { time_t start = time(NULL); - // If these fail, there's not really anywhere to complain... - freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL); - freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); + redirect_stdio(TEMPORARY_LOG_FILE); // If this binary is started with the single argument "--adbd", // instead of being the normal recovery binary, it turns into kind @@ -844,7 +913,7 @@ main(int argc, char **argv) { load_volume_table(); ensure_path_mounted(LAST_LOG_FILE); - rotate_last_logs(10); + rotate_last_logs(KEEP_LOG_COUNT); get_args(&argc, &argv); const char *send_intent = NULL; -- cgit v1.2.3