From 02ec6b88ed4e6cf40cc257572b07c7277b7b6341 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 22 Aug 2012 17:26:40 -0700 Subject: add simple text to recovery UI - recovery takes a --locale argument, which will be passed by the main system - the locale is saved in cache, in case the --locale argument is missing (eg, when recovery is started from fastboot) - we include images that have prerendered text for many locales - we split the background states into four (installing update, erasing, no command, error) so that appropriate text can be shown. Change-Id: I731b8108e83d5ccc09a4aacfc1dbf7e86b397aaf --- recovery.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 10 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index ce4358a53..e374c7d5a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -54,6 +54,7 @@ static const struct option OPTIONS[] = { { "wipe_cache", no_argument, NULL, 'c' }, { "show_text", no_argument, NULL, 't' }, { "just_exit", no_argument, NULL, 'x' }, + { "locale", required_argument, NULL, 'l' }, { NULL, 0, NULL, 0 }, }; @@ -62,6 +63,7 @@ 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/locale"; static const char *CACHE_ROOT = "/cache"; static const char *SDCARD_ROOT = "/sdcard"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; @@ -69,6 +71,7 @@ static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install"; static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; +char* locale = NULL; /* * The recovery tool communicates with the main system through /cache files. @@ -283,6 +286,15 @@ finish_recovery(const char *send_intent) { chmod(LAST_LOG_FILE, 0640); chmod(LAST_INSTALL_FILE, 0644); + // Save the locale to cache, so if recovery is next started up + // without a --locale argument (eg, directly from the bootloader) + // it will use the last-known locale. + if (locale != NULL) { + FILE* fp = fopen(LOCALE_FILE, "w"); + fwrite(locale, 1, strlen(locale), fp); + fclose(fp); + } + // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; memset(&boot, 0, sizeof(boot)); @@ -300,7 +312,7 @@ finish_recovery(const char *send_intent) { static int erase_volume(const char *volume) { - ui->SetBackground(RecoveryUI::INSTALLING); + ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); ui->Print("Formatting %s...\n", volume); @@ -658,6 +670,7 @@ prompt_and_wait(Device* device) { for (;;) { finish_recovery(NULL); + ui->SetBackground(RecoveryUI::NO_COMMAND); ui->SetProgressType(RecoveryUI::EMPTY); int chosen_item = get_menu_selection(headers, device->GetMenuItems(), 0, 0, device); @@ -679,6 +692,7 @@ prompt_and_wait(Device* device) { break; case Device::WIPE_CACHE: + ui->ShowText(false); ui->Print("\n-- Wiping cache...\n"); erase_volume("/cache"); ui->Print("Cache wipe complete.\n"); @@ -757,6 +771,24 @@ print_property(const char *key, const char *name, void *cookie) { printf("%s=%s\n", key, name); } +static void +load_locale_from_cache() { + FILE* fp = fopen_path(LOCALE_FILE, "r"); + char buffer[80]; + if (fp != NULL) { + fgets(buffer, sizeof(buffer), fp); + int j = 0; + int i; + for (i = 0; i < sizeof(buffer) && buffer[i]; ++i) { + if (!isspace(buffer[i])) { + buffer[j++] = buffer[i]; + } + } + buffer[j] = 0; + locale = strdup(buffer); + } +} + int main(int argc, char **argv) { time_t start = time(NULL); @@ -779,18 +811,13 @@ main(int argc, char **argv) { printf("Starting recovery on %s", ctime(&start)); - Device* device = make_device(); - ui = device->GetUI(); - - ui->Init(); - ui->SetBackground(RecoveryUI::NONE); load_volume_table(); 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; + int wipe_data = 0, wipe_cache = 0, show_text = 0; bool just_exit = false; int arg; @@ -801,14 +828,27 @@ main(int argc, char **argv) { case 'u': update_package = optarg; break; case 'w': wipe_data = wipe_cache = 1; break; case 'c': wipe_cache = 1; break; - case 't': ui->ShowText(true); break; + case 't': show_text = 1; break; case 'x': just_exit = true; break; + case 'l': locale = optarg; break; case '?': LOGE("Invalid command argument\n"); continue; } } + if (locale == NULL) { + load_locale_from_cache(); + } + printf("locale is [%s]\n", locale); + + Device* device = make_device(); + ui = device->GetUI(); + + ui->Init(); + ui->SetBackground(RecoveryUI::NONE); + if (show_text) ui->ShowText(true); + #ifdef HAVE_SELINUX struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } @@ -868,10 +908,13 @@ main(int argc, char **argv) { if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR; if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n"); } else if (!just_exit) { - status = INSTALL_ERROR; // No command specified + status = INSTALL_NONE; // No command specified + ui->SetBackground(RecoveryUI::NO_COMMAND); } - if (status != INSTALL_SUCCESS) ui->SetBackground(RecoveryUI::ERROR); + if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { + ui->SetBackground(RecoveryUI::ERROR); + } if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { prompt_and_wait(device); } -- cgit v1.2.3 From 4f33e55d1c38d2f72f3306a82c177850f3676408 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 23 Aug 2012 13:16:12 -0700 Subject: change recovery images to android with spinner Also make writing the locale a bit more robust. Change-Id: I803dd0aa0b9d6661fad74ea13fb085682402323c --- recovery.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index e374c7d5a..70817d307 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -277,6 +277,18 @@ finish_recovery(const char *send_intent) { } } + // Save the locale to cache, so if recovery is next started up + // without a --locale argument (eg, directly from the bootloader) + // it will use the last-known locale. + if (locale != NULL) { + LOGI("Saving locale \"%s\"\n", locale); + FILE* fp = fopen_path(LOCALE_FILE, "w"); + fwrite(locale, 1, strlen(locale), fp); + fflush(fp); + fsync(fileno(fp)); + 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); @@ -286,15 +298,6 @@ finish_recovery(const char *send_intent) { chmod(LAST_LOG_FILE, 0640); chmod(LAST_INSTALL_FILE, 0644); - // Save the locale to cache, so if recovery is next started up - // without a --locale argument (eg, directly from the bootloader) - // it will use the last-known locale. - if (locale != NULL) { - FILE* fp = fopen(LOCALE_FILE, "w"); - fwrite(locale, 1, strlen(locale), fp); - fclose(fp); - } - // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; memset(&boot, 0, sizeof(boot)); -- cgit v1.2.3 From 8b240ccca1ad32cbd09d3807614f3086914ceaaf Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 29 Aug 2012 15:19:29 -0700 Subject: recovery locale handling fixes - change locale filename to "last_locale" so the main system doesn't delete it - clean up some chatty logging - update images with real German (other languages TBD) Change-Id: I2ebb4ed4e054bd1808a3042d9efbb2c18f3a044d --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 70817d307..6ced420d0 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -63,7 +63,7 @@ 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/locale"; +static const char *LOCALE_FILE = "/cache/recovery/last_locale"; static const char *CACHE_ROOT = "/cache"; static const char *SDCARD_ROOT = "/sdcard"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; -- cgit v1.2.3 From 5fa8c23911759a9e81af0e7fb5eb431277b8e9a6 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 18 Sep 2012 12:37:02 -0700 Subject: localization for recovery messages Add images of text for all locales we support. Make the progress bar fill the correct way for RTL languages. (Flip the direction the spinner turns, too, just for good measure.) Bug: 7064142 Change-Id: I5dddb26e02ee5275c57c4dc4a03c6d68432ac7ba --- recovery.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 6ced420d0..3b5813876 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -781,7 +781,7 @@ load_locale_from_cache() { if (fp != NULL) { fgets(buffer, sizeof(buffer), fp); int j = 0; - int i; + unsigned int i; for (i = 0; i < sizeof(buffer) && buffer[i]; ++i) { if (!isspace(buffer[i])) { buffer[j++] = buffer[i]; @@ -849,6 +849,7 @@ main(int argc, char **argv) { ui = device->GetUI(); ui->Init(); + ui->SetLocale(locale); ui->SetBackground(RecoveryUI::NONE); if (show_text) ui->ShowText(true); -- cgit v1.2.3 From 6c8553dda8b7fb45adc9f48a294c130b7e283f40 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Mon, 24 Sep 2012 10:40:47 -0700 Subject: display error state on OTA failure We need prompt_with_wait() to show either the ERROR or NO_COMMAND state as appropriate. Bug: 7221068 Change-Id: I191526cf12630d08b7a8250a2a81e724a4a5d972 --- recovery.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 3b5813876..5c1e3cd21 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -668,12 +668,22 @@ wipe_data(int confirm, Device* device) { } static void -prompt_and_wait(Device* device) { +prompt_and_wait(Device* device, int status) { const char* const* headers = prepend_title(device->GetMenuHeaders()); for (;;) { finish_recovery(NULL); - ui->SetBackground(RecoveryUI::NO_COMMAND); + switch (status) { + case INSTALL_SUCCESS: + case INSTALL_NONE: + ui->SetBackground(RecoveryUI::NO_COMMAND); + break; + + case INSTALL_ERROR: + case INSTALL_CORRUPT: + ui->SetBackground(RecoveryUI::ERROR); + break; + } ui->SetProgressType(RecoveryUI::EMPTY); int chosen_item = get_menu_selection(headers, device->GetMenuItems(), 0, 0, device); @@ -683,7 +693,6 @@ prompt_and_wait(Device* device) { // statement below. chosen_item = device->InvokeMenuItem(chosen_item); - int status; int wipe_cache; switch (chosen_item) { case Device::REBOOT: @@ -920,7 +929,7 @@ main(int argc, char **argv) { ui->SetBackground(RecoveryUI::ERROR); } if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { - prompt_and_wait(device); + prompt_and_wait(device, status); } // Otherwise, get ready to boot the main system... -- cgit v1.2.3 From 6016d08b0c3b682f1f7000b42a9ea4b6b6d74f22 Mon Sep 17 00:00:00 2001 From: Devin Kim Date: Mon, 8 Oct 2012 09:47:37 -0700 Subject: recovery: fix failure to unmount "/cache" At load_locale_from_cache() function, LOCALE_FILE must get closed after it is opened and used. Otherwise it causes a failure to unmount "/cache" after load_locale_from_cache() function is called. Change-Id: I9cec0f29a8ec4452c8a6a52e2f3c8ce9930d5372 Signed-off-by: Iliyan Malchev --- recovery.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 5c1e3cd21..594774f5a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -798,6 +798,7 @@ load_locale_from_cache() { } buffer[j] = 0; locale = strdup(buffer); + check_and_fclose(fp, LOCALE_FILE); } } -- cgit v1.2.3 From 7eb7567aa3faebfb22bd052f3505d485ee23d585 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 16 Oct 2012 10:47:27 -0700 Subject: Remove HAVE_SELINUX guards Change-Id: Ia96201f20f7838d7d9e8926208977d3f8318ced4 --- recovery.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index ce4358a53..707eec354 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -809,7 +809,6 @@ main(int argc, char **argv) { } } -#ifdef HAVE_SELINUX struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } }; @@ -820,7 +819,6 @@ main(int argc, char **argv) { fprintf(stderr, "Warning: No file_contexts\n"); ui->Print("Warning: No file_contexts\n"); } -#endif device->StartRecovery(); -- cgit v1.2.3 From 6fd59ac07d91eb373f4269a40e688aa82a6ccc6e Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 6 Mar 2013 15:01:11 -0800 Subject: more font improvements and cleanup Get rid of the notion of a font's "ascent"; the reference point for drawing is the top-left corner of the character box rather than the baseline. Add some more space between the menu entries and make the highlight bar around the text. Replace the default font.png with two images; the build system will include one or the other based on the resolutions of the device. Restore the original compiled-in bitmap font, to fall back on when font.png can't be found (eg, in the charger binary). Add support for bold text (when a font.png image is used). Change-Id: I6d211a486a3636f20208502b1cd2aeae8b9f5b02 --- recovery.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 92aa50372..7002cb8a4 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -704,7 +704,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::WIPE_CACHE: - ui->ShowText(false); ui->Print("\n-- Wiping cache...\n"); erase_volume("/cache"); ui->Print("Cache wipe complete.\n"); -- cgit v1.2.3 From 7c3ae45ef9306d2ff4b491e0488c8849bf15ce90 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 da1ebaef0aa8e38db6edf8bfc3d96290461a424f 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 93ffa7579cd75d1bdb2d124aa5cc5f8b6025e3d8 Mon Sep 17 00:00:00 2001 From: Jin Feng Date: Tue, 4 Jun 2013 17:46:24 +0800 Subject: Fix the potential segmentation fault Extral newline can trigger recovery segmentation fault Test case: host$ adb shell 'echo -en "--update_package=ota_update.zip\n--show_text\n\n" > /cache/recovery/command' host$ adb reboot recovery Change-Id: If1781c1f5ad94a273f1cb122b67cedd9fb562433 Signed-off-by: Jin Feng --- recovery.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index 92aa50372..2541e54d8 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -198,6 +198,7 @@ get_args(int *argc, char ***argv) { if (*argc <= 1) { FILE *fp = fopen_path(COMMAND_FILE, "r"); if (fp != NULL) { + char *token; char *argv0 = (*argv)[0]; *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); (*argv)[0] = argv0; // use the same program name @@ -205,7 +206,12 @@ get_args(int *argc, char ***argv) { char buf[MAX_ARG_LENGTH]; for (*argc = 1; *argc < MAX_ARGS; ++*argc) { if (!fgets(buf, sizeof(buf), fp)) break; - (*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline. + token = strtok(buf, "\r\n"); + if (token != NULL) { + (*argv)[*argc] = strdup(token); // Strip newline. + } else { + --*argc; + } } check_and_fclose(fp, COMMAND_FILE); -- cgit v1.2.3