From 596b342a0476629badb41b840494254a19c57dae Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 14 May 2013 11:03:02 -0700 Subject: recovery: turn on text display for install errors in debug builds Hopefully this will reduce the number of OTA "bugs" reported that are really just someone having changed their system partition, invalidating future incremental OTAs. Also fixes a longstanding TODO about putting LOGE() output in the on-screen display. Change-Id: I44e5be65b2dee7ebce2cce28ccd920dc3d6e522e --- recovery.cpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 7002cb8a4..a84d8333a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -15,11 +15,13 @@ */ #include +#include #include #include #include #include #include +#include #include #include #include @@ -27,7 +29,6 @@ #include #include #include -#include #include "bootloader.h" #include "common.h" @@ -801,6 +802,24 @@ load_locale_from_cache() { } } +static RecoveryUI* gCurrentUI = NULL; + +void +ui_print(const char* format, ...) { + char buffer[256]; + + va_list ap; + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + if (gCurrentUI != NULL) { + gCurrentUI->Print("%s", buffer); + } else { + fputs(buffer, stdout); + } +} + int main(int argc, char **argv) { time_t start = time(NULL); @@ -856,6 +875,7 @@ main(int argc, char **argv) { Device* device = make_device(); ui = device->GetUI(); + gCurrentUI = ui; ui->Init(); ui->SetLocale(locale); @@ -909,7 +929,18 @@ main(int argc, char **argv) { LOGE("Cache wipe (requested by package) failed."); } } - if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n"); + if (status != INSTALL_SUCCESS) { + ui->Print("Installation aborted.\n"); + + // If this is an eng or userdebug build, then automatically + // turn the text display on if the script fails so the error + // message is visible. + char buffer[PROPERTY_VALUE_MAX+1]; + property_get("ro.build.fingerprint", buffer, ""); + if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) { + ui->ShowText(true); + } + } } else if (wipe_data) { if (device->WipeData()) status = INSTALL_ERROR; if (erase_volume("/data")) status = INSTALL_ERROR; -- cgit v1.2.3 From 46bee63afcd1e2817cdc75a6a8cefdcfdc3e8429 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 16 May 2013 11:23:48 -0700 Subject: recovery: save logs from the last few invocations of recovery Extends the last_log mechanism to save logs from the last six invocations of recovery, so that we're more likely to have useful logs even if the device has repeatedly booted into recovery. Change-Id: I08ae7a09553ada45f9e0733fe1e55e5a22efd9f9 --- recovery.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index a84d8333a..840e63c42 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -59,10 +59,11 @@ static const struct option OPTIONS[] = { { NULL, 0, NULL, 0 }, }; +#define LAST_LOG_FILE "/cache/recovery/last_log" + static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; -static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install"; static const char *LOCALE_FILE = "/cache/recovery/last_locale"; static const char *CACHE_ROOT = "/cache"; @@ -260,6 +261,21 @@ copy_log_file(const char* source, const char* destination, int append) { } } +// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max +// Overwrites any existing last_log.$max. +static void +rotate_last_logs(int max) { + char oldfn[256]; + char newfn[256]; + + int i; + for (i = max-1; i >= 0; --i) { + snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i); + snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1); + // ignore errors + rename(oldfn, newfn); + } +} // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and @@ -843,6 +859,8 @@ main(int argc, char **argv) { printf("Starting recovery on %s", ctime(&start)); load_volume_table(); + ensure_path_mounted(LAST_LOG_FILE); + rotate_last_logs(5); get_args(&argc, &argv); int previous_runs = 0; -- cgit v1.2.3 From f24fd7e8479d54eaa2b73db5a3a3ad076a13f72d Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 2 Jul 2013 11:43:25 -0700 Subject: recovery: copy logs to cache more aggressively Copy logs to /cache immediately upon a package installation failure; don't wait for recovery to finish. (If the user reboots without exiting recovery the "right" way, the logs never get copied at all.) Change-Id: Iee342944e7ded63da5a4af33d11ebc876f6c0835 --- recovery.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index c82844d25..b7fb616ce 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -283,6 +283,19 @@ rotate_last_logs(int max) { } } +static void +copy_logs() { + // Copy logs to cache so the system can find out what happened. + copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); + copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); + copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); + chmod(LOG_FILE, 0600); + chown(LOG_FILE, 1000, 1000); // system user + chmod(LAST_LOG_FILE, 0640); + chmod(LAST_INSTALL_FILE, 0644); + sync(); +} + // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and // record any intent we were asked to communicate back to the system. @@ -312,14 +325,7 @@ finish_recovery(const char *send_intent) { check_and_fclose(fp, LOCALE_FILE); } - // Copy logs to cache so the system can find out what happened. - copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); - copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); - copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); - chmod(LOG_FILE, 0600); - chown(LOG_FILE, 1000, 1000); // system user - chmod(LAST_LOG_FILE, 0640); - chmod(LAST_INSTALL_FILE, 0644); + copy_logs(); // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; @@ -789,6 +795,7 @@ prompt_and_wait(Device* device, int status) { if (status != INSTALL_SUCCESS) { ui->SetBackground(RecoveryUI::ERROR); ui->Print("Installation aborted.\n"); + copy_logs(); } else if (!ui->IsTextVisible()) { return; // reboot if logs aren't visible } else { @@ -866,7 +873,7 @@ main(int argc, char **argv) { load_volume_table(); ensure_path_mounted(LAST_LOG_FILE); - rotate_last_logs(5); + rotate_last_logs(10); get_args(&argc, &argv); int previous_runs = 0; @@ -979,6 +986,7 @@ main(int argc, char **argv) { } if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { + copy_logs(); ui->SetBackground(RecoveryUI::ERROR); } if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { -- cgit v1.2.3 From fafc85b4ad7a5679c6b562bed64460732e05fd1e Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 9 Jul 2013 12:29:45 -0700 Subject: recovery: move log output to stdout Recovery currently has a random mix of messages printed to stdout and messages printed to stderr, which can make logs hard to read. Move everything to stdout. Change-Id: Ie33bd4a9e1272e731302569cdec918e0534c48a6 --- recovery.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index b7fb616ce..d95339733 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -920,8 +920,7 @@ main(int argc, char **argv) { sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { - fprintf(stderr, "Warning: No file_contexts\n"); - ui->Print("Warning: No file_contexts\n"); + ui->Print("Warning: No file_contexts\n"); } device->StartRecovery(); -- cgit v1.2.3 From 6d0d7ac051a0338c0e07e239e742b92e5ab8ea07 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 9 Jul 2013 13:34:55 -0700 Subject: recovery: preserve recovery logs across cache wipes When doing a cache wipe or a factory reset (which includes a cache wipe), save any last* log files in the /cache/recovery directory and write them back after reformatting the partition, so that wiping data doesn't lose useful log information. Change-Id: I1f52ae9131760b5e752e136645c19f71b7b166ee --- recovery.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index b7fb616ce..82cfc3f8d 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -61,6 +61,7 @@ static const struct option OPTIONS[] = { #define LAST_LOG_FILE "/cache/recovery/last_log" +static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; @@ -342,22 +343,95 @@ finish_recovery(const char *send_intent) { sync(); // For good measure. } +typedef struct _saved_log_file { + char* name; + struct stat st; + unsigned char* data; + struct _saved_log_file* next; +} saved_log_file; + static int erase_volume(const char *volume) { + bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); + ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); + + saved_log_file* head = NULL; + + if (is_cache) { + // If we're reformatting /cache, we load any + // "/cache/recovery/last*" files into memory, so we can restore + // them after the reformat. + + ensure_path_mounted(volume); + + DIR* d; + struct dirent* de; + d = opendir(CACHE_LOG_DIR); + if (d) { + char path[PATH_MAX]; + strcpy(path, CACHE_LOG_DIR); + strcat(path, "/"); + int path_len = strlen(path); + while ((de = readdir(d)) != NULL) { + if (strncmp(de->d_name, "last", 4) == 0) { + saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); + strcpy(path+path_len, de->d_name); + p->name = strdup(path); + if (stat(path, &(p->st)) == 0) { + // truncate files to 512kb + if (p->st.st_size > (1 << 19)) { + p->st.st_size = 1 << 19; + } + p->data = (unsigned char*) malloc(p->st.st_size); + FILE* f = fopen(path, "rb"); + fread(p->data, 1, p->st.st_size, f); + fclose(f); + p->next = head; + head = p; + } else { + free(p); + } + } + } + closedir(d); + } else { + if (errno != ENOENT) { + printf("opendir failed: %s\n", strerror(errno)); + } + } + } + ui->Print("Formatting %s...\n", volume); ensure_path_unmounted(volume); + int result = format_volume(volume); + + if (is_cache) { + while (head) { + FILE* f = fopen_path(head->name, "wb"); + if (f) { + fwrite(head->data, 1, head->st.st_size, f); + fclose(f); + chmod(head->name, head->st.st_mode); + chown(head->name, head->st.st_uid, head->st.st_gid); + } + free(head->name); + free(head->data); + saved_log_file* temp = head->next; + free(head); + head = temp; + } - if (strcmp(volume, "/cache") == 0) { // Any part of the log we'd copied to cache is now gone. // Reset the pointer so we copy from the beginning of the temp // log. tmplog_offset = 0; + copy_logs(); } - return format_volume(volume); + return result; } static char* -- cgit v1.2.3 From c0441d171914e59941ec4f815ae0aabf56d6504f Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 31 Jul 2013 11:28:24 -0700 Subject: notify about pending long press Recovery changes: - add a method to the UI class that is called when a key is held down long enough to be a "long press" (but before it is released). Device-specific subclasses can override this to indicate a long press. - do color selection for ScreenRecoveryUI's menu-and-log drawing function. Subclasses can override this to customize the colors they use for various elements. - Include the value of ro.build.display.id in the menu headers, so you can see on the screen what version of recovery you are running. Change-Id: I426a6daf892b9011638e2035aebfa2831d4f596d --- recovery.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index c5a589cc6..38366b65a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -75,6 +75,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; char* locale = NULL; +char recovery_version[PROPERTY_VALUE_MAX+1]; /* * The recovery tool communicates with the main system through /cache files. @@ -526,21 +527,17 @@ copy_sideloaded_package(const char* original_path) { static const char** prepend_title(const char* const* headers) { - const char* title[] = { "Android system recovery <" - EXPAND(RECOVERY_API_VERSION) "e>", - "", - NULL }; - // count the number of lines in our title, plus the // caller-provided headers. - int count = 0; + int count = 3; // our title has 3 lines const char* const* p; - for (p = title; *p; ++p, ++count); for (p = headers; *p; ++p, ++count); const char** new_headers = (const char**)malloc((count+1) * sizeof(char*)); const char** h = new_headers; - for (p = title; *p; ++p, ++h) *h = *p; + *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>"; + *(h++) = recovery_version; + *(h++) = ""; for (p = headers; *p; ++p, ++h) *h = *p; *h = NULL; @@ -1022,6 +1019,7 @@ main(int argc, char **argv) { printf("\n"); property_list(print_property, NULL); + property_get("ro.build.display.id", recovery_version, ""); printf("\n"); int status = INSTALL_SUCCESS; -- cgit v1.2.3 From 239ac6abac4524be93fce710360c0512c6cc2ab3 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 20 Aug 2013 16:03:25 -0700 Subject: recovery: install packages in a known mount environment When installing a package, we should have /tmp and /cache mounted and nothing else. Ensure this is true by explicitly mounting them and unmounting everything else as the first step of every install. Also fix an error in the progress bar that crops up when you do multiple package installs in one instance of recovery. Change-Id: I4837ed707cb419ddd3d9f6188b6355ba1bcfe2b2 --- recovery.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 38366b65a..654a66526 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -811,10 +811,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_EXT: - // Some packages expect /cache to be mounted (eg, - // standard incremental packages expect to use /cache - // as scratch space). - ensure_path_mounted(CACHE_ROOT); status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); @@ -860,7 +856,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_ADB_SIDELOAD: - ensure_path_mounted(CACHE_ROOT); status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE); if (status >= 0) { if (status != INSTALL_SUCCESS) { -- cgit v1.2.3 From 77ea71d6a85a93c9bf423466e87661b1bf67c512 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Fri, 30 Aug 2013 12:20:16 -0700 Subject: recovery: fix rebooting Change I84c0513acb549720cb0e8c9fcbda0050f5c396f5 moved reboot functionality into init but did not update the recovery partition; so "adb reboot" and /system/bin/reboot in recovery are both broken. Change-Id: Ie2d14627a686ffb5064256b6c399723636dff116 --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 654a66526..b78339314 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -1062,6 +1062,6 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui->Print("Rebooting...\n"); - android_reboot(ANDROID_RB_RESTART, 0, 0); + property_set(ANDROID_RB_PROPERTY, ""); return EXIT_SUCCESS; } -- cgit v1.2.3 From 3b5a987cd7fd76c038e9875b430028216d21ace3 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 3 Sep 2013 14:29:54 -0700 Subject: recovery: fix use of init reboot method We need to set the system property to "reboot,", not an empty string. Bug: 10605007 Change-Id: I776e0d273764cf254651ab2b25c2743395b990e0 --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index b78339314..d803cadf1 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -1062,6 +1062,6 @@ 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, ""); + property_set(ANDROID_RB_PROPERTY, "reboot,"); return EXIT_SUCCESS; } -- cgit v1.2.3