Merge branch 'cupcake'

This commit is contained in:
The Android Open Source Project 2009-01-09 18:03:37 -08:00
commit 6d12e0d6f8

View file

@ -22,6 +22,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/reboot.h> #include <sys/reboot.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
@ -63,6 +64,48 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
* --wipe_cache - wipe cache (but not user data), then reboot * --wipe_cache - wipe cache (but not user data), then reboot
* *
* After completing, we remove /cache/recovery/command and reboot. * After completing, we remove /cache/recovery/command and reboot.
* Arguments may also be supplied in the bootloader control block (BCB).
* These important scenarios must be safely restartable at any point:
*
* FACTORY RESET
* 1. user selects "factory reset"
* 2. main system writes "--wipe_data" to /cache/recovery/command
* 3. main system reboots into recovery
* 4. get_args() writes BCB with "boot-recovery" and "--wipe_data"
* -- after this, rebooting will restart the erase --
* 5. erase_root() reformats /data
* 6. erase_root() reformats /cache
* 7. finish_recovery() erases BCB
* -- after this, rebooting will restart the main system --
* 8. main() calls reboot() to boot main system
*
* OTA INSTALL
* 1. main system downloads OTA package to /cache/some-filename.zip
* 2. main system writes "--update_package=CACHE:some-filename.zip"
* 3. main system reboots into recovery
* 4. get_args() writes BCB with "boot-recovery" and "--update_package=..."
* -- after this, rebooting will attempt to reinstall the update --
* 5. install_package() attempts to install the update
* NOTE: the package install must itself be restartable from any point
* 6. finish_recovery() erases BCB
* -- after this, rebooting will (try to) restart the main system --
* 7. ** if install failed **
* 7a. prompt_and_wait() shows an error icon and waits for the user
* 7b; the user reboots (pulling the battery, etc) into the main system
* 8. main() calls maybe_install_firmware_update()
* ** if the update contained radio/hboot firmware **:
* 8a. m_i_f_u() writes BCB with "boot-recovery" and "--wipe_cache"
* -- after this, rebooting will reformat cache & restart main system --
* 8b. m_i_f_u() writes firmware image into raw cache partition
* 8c. m_i_f_u() writes BCB with "update-radio/hboot" and "--wipe_cache"
* -- after this, rebooting will attempt to reinstall firmware --
* 8d. bootloader tries to flash firmware
* 8e. bootloader writes BCB with "boot-recovery" (keeping "--wipe_cache")
* -- after this, rebooting will reformat cache & restart main system --
* 8f. erase_root() reformats /cache
* 8g. finish_recovery() erases BCB
* -- after this, rebooting will (try to) restart the main system --
* 9. main() calls reboot() to boot main system
*/ */
static const int MAX_ARG_LENGTH = 4096; static const int MAX_ARG_LENGTH = 4096;
@ -105,52 +148,64 @@ check_and_fclose(FILE *fp, const char *name) {
// - the contents of COMMAND_FILE (one per line) // - the contents of COMMAND_FILE (one per line)
static void static void
get_args(int *argc, char ***argv) { get_args(int *argc, char ***argv) {
if (*argc > 1) return; // actual command line arguments take priority
char *argv0 = (*argv)[0];
struct bootloader_message boot; struct bootloader_message boot;
if (!get_bootloader_message(&boot)) { memset(&boot, 0, sizeof(boot));
if (boot.command[0] != 0 && boot.command[0] != 255) { get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
}
if (boot.status[0] != 0 && boot.status[0] != 255) { if (boot.command[0] != 0 && boot.command[0] != 255) {
LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status); LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
} }
// Ensure that from here on, a reboot goes back into recovery if (boot.status[0] != 0 && boot.status[0] != 255) {
strcpy(boot.command, "boot-recovery"); LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
set_bootloader_message(&boot); }
// --- if arguments weren't supplied, look in the bootloader control block
if (*argc <= 1) {
boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
const char *arg = strtok(boot.recovery, "\n"); const char *arg = strtok(boot.recovery, "\n");
if (arg != NULL && !strcmp(arg, "recovery")) { if (arg != NULL && !strcmp(arg, "recovery")) {
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS); *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = argv0; (*argv)[0] = strdup(arg);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) { for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if ((arg = strtok(NULL, "\n")) == NULL) break; if ((arg = strtok(NULL, "\n")) == NULL) break;
(*argv)[*argc] = strdup(arg); (*argv)[*argc] = strdup(arg);
} }
LOGI("Got arguments from boot message\n"); LOGI("Got arguments from boot message\n");
return;
} else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) { } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery); LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
} }
} }
FILE *fp = fopen_root_path(COMMAND_FILE, "r"); // --- if that doesn't work, try the command file
if (fp == NULL) return; if (*argc <= 1) {
FILE *fp = fopen_root_path(COMMAND_FILE, "r");
if (fp != NULL) {
char *argv0 = (*argv)[0];
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
(*argv)[0] = argv0; // use the same program name
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS); char buf[MAX_ARG_LENGTH];
(*argv)[0] = argv0; // use the same program name for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
(*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
}
char buf[MAX_ARG_LENGTH]; check_and_fclose(fp, COMMAND_FILE);
for (*argc = 1; *argc < MAX_ARGS && fgets(buf, sizeof(buf), fp); ++*argc) { LOGI("Got arguments from %s\n", COMMAND_FILE);
(*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline. }
} }
check_and_fclose(fp, COMMAND_FILE); // --> write the arguments we have back into the bootloader control block
LOGI("Got arguments from %s\n", COMMAND_FILE); // always boot into recovery after this (until finish_recovery() is called)
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
int i;
for (i = 1; i < *argc; ++i) {
strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
set_bootloader_message(&boot);
} }