aboutsummaryrefslogtreecommitdiffstats
path: root/recovery.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'recovery.cpp')
-rw-r--r--recovery.cpp549
1 files changed, 442 insertions, 107 deletions
diff --git a/recovery.cpp b/recovery.cpp
index 575e287a..b75cb2f4 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -42,26 +42,66 @@
#include "ui.h"
#include "screen_ui.h"
#include "device.h"
+
+#include "voldclient/voldclient.h"
+
#include "adb_install.h"
extern "C" {
#include "minadbd/adb.h"
#include "fuse_sideload.h"
#include "fuse_sdcard_provider.h"
+#include "recovery_cmds.h"
}
struct selabel_handle *sehandle;
+#ifdef HAVE_OEMLOCK
+
+/*
+ * liboemlock must supply the following C symbols:
+ *
+ * - int oemlock_get()
+ *
+ * Returns the current state of the OEM lock, if available.
+ * -1: Not available and/or error
+ * 0: Unlocked
+ * 1: Locked
+ *
+ * - int oemlock_set(int lock)
+ *
+ * Sets the state of the OEM lock. The "lock" parameter will be set
+ * to 0 for unlock and 1 for lock.
+ *
+ * Returns 0 on success, -1 on error
+ */
+extern "C" {
+int oemlock_get();
+int oemlock_set(int lock);
+}
+
+enum OemLockOp {
+ OEM_LOCK_NONE,
+ OEM_LOCK_UNLOCK
+};
+
+static OemLockOp oem_lock = OEM_LOCK_NONE;
+
+#endif
+
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 's' },
{ "update_package", required_argument, NULL, 'u' },
+ { "headless", no_argument, NULL, 'h' },
{ "wipe_data", no_argument, NULL, 'w' },
{ "wipe_cache", no_argument, NULL, 'c' },
+ { "wipe_media", no_argument, NULL, 'm' },
{ "show_text", no_argument, NULL, 't' },
{ "just_exit", no_argument, NULL, 'x' },
{ "locale", required_argument, NULL, 'l' },
{ "stages", required_argument, NULL, 'g' },
{ "shutdown_after", no_argument, NULL, 'p' },
{ "reason", required_argument, NULL, 'r' },
+ { "sideload", no_argument, NULL, 'a' },
{ NULL, 0, NULL, 0 },
};
@@ -74,7 +114,6 @@ static const char *LOG_FILE = "/cache/recovery/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";
-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 *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
@@ -91,6 +130,8 @@ char recovery_version[PROPERTY_VALUE_MAX+1];
char* stage = NULL;
char* reason = NULL;
+#include "mtdutils/mounts.h"
+
/*
* The recovery tool communicates with the main system through /cache files.
* /cache/recovery/command - INPUT - command line for tool, one arg per line
@@ -104,6 +145,7 @@ char* reason = NULL;
* --wipe_cache - wipe cache (but not user data), then reboot
* --set_encrypted_filesystem=on|off - enables / diasables encrypted fs
* --just_exit - do nothing; exit and reboot
+ * --sideload - enter sideload mode
*
* After completing, we remove /cache/recovery/command and reboot.
* Arguments may also be supplied in the bootloader control block (BCB).
@@ -211,6 +253,14 @@ get_args(int *argc, char ***argv) {
(*argv)[0] = strdup(arg);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if ((arg = strtok(NULL, "\n")) == NULL) break;
+ // Arguments that may only be passed in BCB
+#ifdef HAVE_OEMLOCK
+ if (strcmp(arg, "--oemunlock") == 0) {
+ oem_lock = OEM_LOCK_UNLOCK;
+ --*argc;
+ continue;
+ }
+#endif
(*argv)[*argc] = strdup(arg);
}
LOGI("Got arguments from boot message\n");
@@ -414,15 +464,15 @@ typedef struct _saved_log_file {
} saved_log_file;
static int
-erase_volume(const char *volume) {
+erase_volume(const char *volume, bool force = false) {
bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
+ saved_log_file* head = NULL;
+
ui->SetBackground(RecoveryUI::ERASING);
ui->SetProgressType(RecoveryUI::INDETERMINATE);
- saved_log_file* head = NULL;
-
- if (is_cache) {
+ if (!force && is_cache) {
// If we're reformatting /cache, we load any
// "/cache/recovery/last*" files into memory, so we can restore
// them after the reformat.
@@ -468,10 +518,12 @@ erase_volume(const char *volume) {
ui->Print("Formatting %s...\n", volume);
- ensure_path_unmounted(volume);
- int result = format_volume(volume);
+ if (volume[0] == '/') {
+ ensure_path_unmounted(volume);
+ }
+ int result = format_volume(volume, force);
- if (is_cache) {
+ if (!force && is_cache) {
while (head) {
FILE* f = fopen_path(head->name, "wb");
if (f) {
@@ -507,7 +559,7 @@ prepend_title(const char* const* headers) {
const char** new_headers = (const char**)malloc((count+1) * sizeof(char*));
const char** h = new_headers;
- *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>";
+ *(h++) = "CyanogenMod Simple recovery <" EXPAND(RECOVERY_API_VERSION) "e>";
*(h++) = recovery_version;
*(h++) = "";
for (p = headers; *p; ++p, ++h) *h = *p;
@@ -516,18 +568,23 @@ prepend_title(const char* const* headers) {
return new_headers;
}
-static int
+int
get_menu_selection(const char* const * headers, const char* const * items,
int menu_only, int initial_selection, Device* device) {
// throw away keys pressed previously, so user doesn't
// accidentally trigger menu items.
ui->FlushKeys();
+ // Count items to detect valid values for absolute selection
+ int item_count = 0;
+ while (items[item_count] != NULL)
+ ++item_count;
+
ui->StartMenu(headers, items, initial_selection);
int selected = initial_selection;
int chosen_item = -1;
- while (chosen_item < 0) {
+ while (chosen_item < 0 && chosen_item != Device::kGoBack && chosen_item != Device::kRefresh) {
int key = ui->WaitKey();
int visible = ui->IsTextVisible();
@@ -539,10 +596,29 @@ get_menu_selection(const char* const * headers, const char* const * items,
ui->EndMenu();
return 0; // XXX fixme
}
+ } else if (key == -2) { // we are returning from ui_cancel_wait_key(): no action
+ return Device::kNoAction;
+ }
+ else if (key == -6) {
+ return Device::kRefresh;
}
int action = device->HandleMenuKey(key, visible);
+ if (action >= 0) {
+ if ((action & ~KEY_FLAG_ABS) >= item_count) {
+ action = Device::kNoAction;
+ }
+ else {
+ // Absolute selection. Update selected item and give some
+ // feedback in the UI by selecting the item for a short time.
+ selected = action & ~KEY_FLAG_ABS;
+ action = Device::kInvokeItem;
+ selected = ui->SelectMenu(selected, true);
+ usleep(50*1000);
+ }
+ }
+
if (action < 0) {
switch (action) {
case Device::kHighlightUp:
@@ -558,6 +634,12 @@ get_menu_selection(const char* const * headers, const char* const * items,
break;
case Device::kNoAction:
break;
+ case Device::kGoBack:
+ chosen_item = Device::kGoBack;
+ break;
+ case Device::kRefresh:
+ chosen_item = Device::kRefresh;
+ break;
}
} else if (!menu_only) {
chosen_item = action;
@@ -646,15 +728,16 @@ browse_directory(const char* path, Device* device) {
int chosen_item = 0;
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 "../"
+ // item 0 is always "../"
+ if (chosen_item == 0 || chosen_item == Device::kGoBack) {
// go up but continue browsing (if the caller is update_directory)
result = NULL;
break;
}
+ char* item = zips[chosen_item];
+ int item_len = strlen(item);
+
char new_path[PATH_MAX];
strlcpy(new_path, path, PATH_MAX);
strlcat(new_path, "/", PATH_MAX);
@@ -695,19 +778,12 @@ wipe_data(int confirm, Device* device) {
const char* items[] = { " No",
" No",
- " No",
- " No",
- " No",
- " No",
- " No",
" Yes -- delete all user data", // [7]
" No",
- " No",
- " No",
NULL };
int chosen_item = get_menu_selection(title_headers, items, 1, 0, device);
- if (chosen_item != 7) {
+ if (chosen_item != 2) {
return;
}
}
@@ -728,6 +804,7 @@ static void file_to_ui(const char* fn) {
char line[1024];
int ct = 0;
int key = 0;
+ ui->SetBackground(RecoveryUI::VIEWING_LOG);
redirect_stdio("/dev/null");
while(fgets(line, sizeof(line), fp) != NULL) {
ui->Print("%s", line);
@@ -736,7 +813,7 @@ static void file_to_ui(const char* fn) {
// give the user time to glance at the entries
key = ui->WaitKey();
- if (key == KEY_POWER) {
+ if (key == KEY_POWER || key == KEY_BACK) {
break;
}
@@ -762,11 +839,13 @@ static void file_to_ui(const char* fn) {
// If the user didn't abort, then give the user time to glance at
// the end of the log, sorry, no rewind here
- if (key != KEY_POWER) {
+ if (key != KEY_POWER && key != KEY_BACK) {
ui->Print("\n--END-- (press any key)\n");
ui->WaitKey();
}
+ ui->SetBackground(RecoveryUI::NONE);
+
redirect_stdio(TEMPORARY_LOG_FILE);
fclose(fp);
}
@@ -810,7 +889,7 @@ static void choose_recovery_file(Device* device) {
while(1) {
int chosen_item = get_menu_selection(title_headers, entries, 1, 0, device);
- if (chosen_item == 0) break;
+ if (chosen_item == 0 || chosen_item == Device::kGoBack) break;
file_to_ui(entries[chosen_item]);
}
@@ -819,6 +898,152 @@ static void choose_recovery_file(Device* device) {
}
}
+static void
+wipe_media(int confirm, Device* device) {
+ if (confirm) {
+ static const char** title_headers = NULL;
+
+ if (title_headers == NULL) {
+ const char* headers[] = { "Confirm wipe of all user media?",
+ " THIS CAN NOT BE UNDONE.",
+ "",
+ NULL };
+ title_headers = prepend_title((const char**)headers);
+ }
+
+ const char* items[] = { " No",
+ " No",
+ " Yes -- delete all user media", // [7]
+ " No",
+ NULL };
+
+ int chosen_item = get_menu_selection(title_headers, items, 1, 0, device);
+ if (chosen_item != 2) {
+ return;
+ }
+ }
+
+ ui->Print("\n-- Wiping media...\n");
+ device->WipeMedia();
+ erase_volume("media");
+ ui->Print("Media wipe complete.\n");
+}
+
+static int enter_sideload_mode(int* wipe_cache, Device* device) {
+
+ ensure_path_mounted(CACHE_ROOT);
+ start_sideload(ui, wipe_cache, TEMPORARY_INSTALL_FILE);
+
+ static const char* headers[] = { "ADB Sideload",
+ "",
+ NULL
+ };
+
+ static const char* list[] = { "Cancel sideload", NULL };
+
+ int status = INSTALL_NONE;
+ int item = get_menu_selection(headers, list, 0, 0, device);
+ if (item != Device::kNoAction) {
+ stop_sideload();
+ }
+ status = wait_sideload();
+
+ if (status >= 0 && status != INSTALL_NONE) {
+ if (status != INSTALL_SUCCESS) {
+ ui->SetBackground(RecoveryUI::ERROR);
+ ui->Print("Installation aborted.\n");
+ } else if (!ui->IsTextVisible()) {
+ return status; // reboot if logs aren't visible
+ } else {
+ ui->Print("\nInstall from ADB complete.\n");
+ }
+ }
+ return status;
+}
+
+static int
+show_apply_update_menu(Device* device) {
+ static const char* headers[] = { "Apply update", "", NULL };
+ char* menu_items[MAX_NUM_MANAGED_VOLUMES + 1 + 1];
+ storage_item* items = get_storage_items();
+
+ int item_sideload = 0;
+ menu_items[item_sideload] = strdup("Apply from ADB");
+
+ int n;
+ for (n = 0; items[n].label; ++n) {
+ menu_items[n+1] = (char*)malloc(256);
+ sprintf(menu_items[n+1], "Choose from %s", items[n].label);
+ }
+ menu_items[n+1] = NULL;
+
+ int wipe_cache;
+ int status = INSTALL_ERROR;
+
+ int chosen = get_menu_selection(headers, menu_items, 0, 0, device);
+ if (chosen == Device::kGoBack) {
+ status = INSTALL_NONE;
+ goto out;
+ }
+ if (chosen == item_sideload) {
+ status = enter_sideload_mode(&wipe_cache, device);
+ }
+ else {
+ storage_item* item = &items[chosen-1];
+ status = ensure_volume_mounted(item->vol);
+ if (status == 0) {
+ char* path = browse_directory(item->path, device);
+ if (path != NULL) {
+ ui->Print("\n-- Install %s ...\n", path);
+ ui->ClearLog();
+ ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
+ set_sdcard_update_bootloader_message();
+ void* token = start_sdcard_fuse(path);
+ status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, &wipe_cache,
+ TEMPORARY_INSTALL_FILE, false);
+ finish_sdcard_fuse(token);
+ if (status != INSTALL_SUCCESS) {
+ ui->DialogShowErrorLog("Install failed");
+ }
+ }
+ else {
+ ui->Print("\n-- No package file selected.\n", path);
+ status = INSTALL_NONE;
+ }
+ }
+ else {
+ status = INSTALL_ERROR;
+ }
+ ensure_volume_unmounted(item->vol);
+ }
+ if (status == INSTALL_SUCCESS && wipe_cache) {
+ ui->Print("\n-- Wiping cache (at package request)...\n");
+ ui->DialogShowInfo("Wiping cache ...");
+ if (erase_volume("/cache")) {
+ ui->Print("Cache wipe failed.\n");
+ } else {
+ ui->Print("Cache wipe complete.\n");
+ }
+ ui->DialogDismiss();
+ }
+ if (status >= 0 && status != INSTALL_NONE) {
+ if (status != INSTALL_SUCCESS) {
+ ui->SetBackground(RecoveryUI::ERROR);
+ ui->Print("Installation aborted.\n");
+ ui->DialogShowErrorLog("Install failed");
+ } else if (ui->IsTextVisible()) {
+ ui->Print("\nInstallation complete.\n");
+ }
+ }
+
+out:
+ free_storage_items(items);
+
+ return status;
+}
+
+int ui_root_menu = 0;
+
// 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.
@@ -828,12 +1053,12 @@ prompt_and_wait(Device* device, int status) {
for (;;) {
finish_recovery(NULL);
+ ui_root_menu = 1;
switch (status) {
case INSTALL_SUCCESS:
case INSTALL_NONE:
- ui->SetBackground(RecoveryUI::NO_COMMAND);
+ ui->SetBackground(RecoveryUI::NONE);
break;
-
case INSTALL_ERROR:
case INSTALL_CORRUPT:
ui->SetBackground(RecoveryUI::ERROR);
@@ -842,6 +1067,7 @@ prompt_and_wait(Device* device, int status) {
ui->SetProgressType(RecoveryUI::EMPTY);
int chosen_item = get_menu_selection(headers, device->GetMenuItems(), 0, 0, device);
+ ui_root_menu = 0;
// device-specific code may take some action here. It may
// return one of the core actions handled in the switch
@@ -849,89 +1075,50 @@ prompt_and_wait(Device* device, int status) {
Device::BuiltinAction chosen_action = device->InvokeMenuItem(chosen_item);
int wipe_cache = 0;
- switch (chosen_action) {
- case Device::NO_ACTION:
- break;
- case Device::REBOOT:
- case Device::SHUTDOWN:
- case Device::REBOOT_BOOTLOADER:
- return chosen_action;
-
- case Device::WIPE_DATA:
- wipe_data(ui->IsTextVisible(), device);
- 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 Device::NO_ACTION;
- break;
-
- 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);
+ for (;;) {
+ switch (chosen_action) {
+ case Device::NO_ACTION:
break;
- }
- ui->Print("\n-- Install %s ...\n", path);
- set_sdcard_update_bootloader_message();
- void* token = start_sdcard_fuse(path);
+ case Device::REBOOT:
+ case Device::SHUTDOWN:
+ case Device::REBOOT_BOOTLOADER:
+ return chosen_action;
- int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, &wipe_cache,
- TEMPORARY_INSTALL_FILE, false);
+ case Device::WIPE_DATA:
+ wipe_data(ui->IsTextVisible(), device);
+ if (!ui->IsTextVisible()) return Device::NO_ACTION;
+ break;
- finish_sdcard_fuse(token);
- ensure_path_unmounted(SDCARD_ROOT);
+ case Device::WIPE_CACHE:
+ ui->Print("\n-- Wiping cache...\n");
+ erase_volume("/cache");
+ ui->Print("Cache wipe complete.\n");
+ if (!ui->IsTextVisible()) return Device::NO_ACTION;
+ break;
- 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");
- }
- }
+ case Device::WIPE_MEDIA:
+ wipe_media(ui->IsTextVisible(), device);
+ if (!ui->IsTextVisible()) return Device::NO_ACTION;
+ break;
- if (status >= 0) {
- if (status != INSTALL_SUCCESS) {
- ui->SetBackground(RecoveryUI::ERROR);
- ui->Print("Installation aborted.\n");
- } else if (!ui->IsTextVisible()) {
+ case Device::APPLY_UPDATE:
+ status = show_apply_update_menu(device);
+ if (status == INSTALL_SUCCESS && !ui->IsTextVisible()) {
return Device::NO_ACTION; // reboot if logs aren't visible
- } else {
- ui->Print("\nInstall from sdcard complete.\n");
}
- }
- break;
- }
-
- case Device::APPLY_CACHE:
- ui->Print("\nAPPLY_CACHE is deprecated.\n");
- break;
-
- case Device::READ_RECOVERY_LASTLOG:
- choose_recovery_file(device);
- break;
+ break;
- case Device::APPLY_ADB_SIDELOAD:
- status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
- if (status >= 0) {
- if (status != INSTALL_SUCCESS) {
- ui->SetBackground(RecoveryUI::ERROR);
- ui->Print("Installation aborted.\n");
- copy_logs();
- } else if (!ui->IsTextVisible()) {
- return Device::NO_ACTION; // reboot if logs aren't visible
- } else {
- ui->Print("\nInstall from ADB complete.\n");
- }
- }
- break;
+ case Device::READ_RECOVERY_LASTLOG:
+ choose_recovery_file(device);
+ break;
+ }
+ if (status == Device::kRefresh) {
+ status = 0;
+ continue;
+ }
+ break;
}
}
}
@@ -960,6 +1147,39 @@ load_locale_from_cache() {
}
}
+static void
+setup_adbd() {
+ struct stat f;
+ const char *key_src = "/data/misc/adb/adb_keys";
+ const char *key_dest = "/adb_keys";
+
+ // Mount /data and copy adb_keys to root if it exists
+ ensure_path_mounted("/data");
+ if (stat(key_src, &f) == 0) {
+ FILE *file_src = fopen(key_src, "r");
+ if (file_src == NULL) {
+ LOGE("Can't open %s\n", key_src);
+ } else {
+ FILE *file_dest = fopen(key_dest, "w");
+ if (file_dest == NULL) {
+ LOGE("Can't open %s\n", key_dest);
+ } else {
+ char buf[4096];
+ while (fgets(buf, sizeof(buf), file_src)) fputs(buf, file_dest);
+ check_and_fclose(file_dest, key_dest);
+
+ // Enable secure adbd
+ property_set("ro.adb.secure", "1");
+ }
+ check_and_fclose(file_src, key_src);
+ }
+ }
+ ensure_path_unmounted("/data");
+
+ // Trigger (re)start of adb daemon
+ property_set("service.adb.root", "1");
+}
+
static RecoveryUI* gCurrentUI = NULL;
void
@@ -978,12 +1198,49 @@ ui_print(const char* format, ...) {
}
}
+static int write_file(const char *path, const char *value)
+{
+ int fd, ret, len;
+
+ fd = open(path, O_WRONLY|O_CREAT, 0622);
+ if (fd < 0)
+ return -errno;
+
+ len = strlen(value);
+
+ do {
+ ret = write(fd, value, len);
+ } while (ret < 0 && errno == EINTR);
+
+ close(fd);
+ if (ret < 0) {
+ return -errno;
+ } else {
+ return 0;
+ }
+}
+
+static int handle_volume_hotswap(char* label, char* path) {
+ ui->NotifyVolumesChanged();
+ return 0;
+}
+
+static int handle_volume_state_changed(char* label, char* path, int state) {
+ LOGV("%s: %s\n", path, volume_state_to_string(state));
+
+ return 0;
+}
+
+static struct vold_callbacks v_callbacks = {
+ .state_changed = handle_volume_state_changed,
+ .disk_added = handle_volume_hotswap,
+ .disk_removed = handle_volume_hotswap,
+};
+
int
main(int argc, char **argv) {
time_t start = time(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
// of a stripped-down version of adbd that only supports the
@@ -996,16 +1253,52 @@ main(int argc, char **argv) {
return 0;
}
+ // Handle alternative invocations
+ char* command = argv[0];
+ char* stripped = strrchr(argv[0], '/');
+ if (stripped)
+ command = stripped + 1;
+
+ if (strcmp(command, "recovery") != 0) {
+ struct recovery_cmd cmd = get_command(command);
+ if (cmd.name)
+ return cmd.main_func(argc, argv);
+
+ if (!strcmp(command, "setup_adbd")) {
+ load_volume_table();
+ setup_adbd();
+ return 0;
+ }
+ if (strstr(argv[0], "start")) {
+ property_set("ctl.start", argv[1]);
+ return 0;
+ }
+ if (strstr(argv[0], "stop")) {
+ property_set("ctl.stop", argv[1]);
+ return 0;
+ }
+ return busybox_driver(argc, argv);
+ }
+
+ // Clear umask for packages that copy files out to /tmp and then over
+ // to /system without properly setting all permissions (eg. gapps).
+ umask(0);
+
+ redirect_stdio(TEMPORARY_LOG_FILE);
+
printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
load_volume_table();
+ vold_client_start(&v_callbacks, 0);
+ vold_set_automount(1);
ensure_path_mounted(LAST_LOG_FILE);
rotate_last_logs(KEEP_LOG_COUNT);
get_args(&argc, &argv);
const char *send_intent = NULL;
const char *update_package = NULL;
- int wipe_data = 0, wipe_cache = 0, show_text = 0;
+ int wipe_data = 0, wipe_cache = 0, wipe_media = 0, show_text = 0, sideload = 0;
+ bool headless = false;
bool just_exit = false;
bool shutdown_after = false;
@@ -1014,7 +1307,9 @@ main(int argc, char **argv) {
switch (arg) {
case 's': send_intent = optarg; break;
case 'u': update_package = optarg; break;
+ case 'h': headless = true; break;
case 'w': wipe_data = wipe_cache = 1; break;
+ case 'm': wipe_media = 1; break;
case 'c': wipe_cache = 1; break;
case 't': show_text = 1; break;
case 'x': just_exit = true; break;
@@ -1029,6 +1324,7 @@ main(int argc, char **argv) {
}
case 'p': shutdown_after = true; break;
case 'r': reason = optarg; break;
+ case 'a': sideload = 1; break;
case '?':
LOGE("Invalid command argument\n");
continue;
@@ -1057,6 +1353,9 @@ main(int argc, char **argv) {
ui->SetBackground(RecoveryUI::NONE);
if (show_text) ui->ShowText(true);
+ /*enable the backlight*/
+ write_file("/sys/class/leds/lcd-backlight/brightness", "128");
+
struct selinux_opt seopts[] = {
{ SELABEL_OPT_PATH, "/file_contexts" }
};
@@ -1097,6 +1396,17 @@ main(int argc, char **argv) {
int status = INSTALL_SUCCESS;
+#ifdef HAVE_OEMLOCK
+ if (oem_lock == OEM_LOCK_UNLOCK) {
+ if (device->WipeData()) status = INSTALL_ERROR;
+ if (erase_volume("/data", true)) status = INSTALL_ERROR;
+ if (wipe_cache && erase_volume("/cache", true)) status = INSTALL_ERROR;
+ if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
+ if (oemlock_set(0)) status = INSTALL_ERROR;
+ // Force reboot regardless of actual status
+ status = INSTALL_SUCCESS;
+ } else
+#endif
if (update_package != NULL) {
status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE, true);
if (status == INSTALL_SUCCESS && wipe_cache) {
@@ -1119,15 +1429,19 @@ main(int argc, char **argv) {
}
} else if (wipe_data) {
if (device->WipeData()) status = INSTALL_ERROR;
- if (erase_volume("/data")) status = INSTALL_ERROR;
+ if (erase_volume("/data", wipe_media)) status = INSTALL_ERROR;
if (wipe_cache && erase_volume("/cache")) 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;
if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
+ } else if (wipe_media) {
+ if (erase_volume("media")) status = INSTALL_ERROR;
+ if (status != INSTALL_SUCCESS) ui->Print("Media wipe failed.\n");
+ } else if (sideload) {
+ status = enter_sideload_mode(&wipe_cache, device);
} else if (!just_exit) {
status = INSTALL_NONE; // No command specified
- ui->SetBackground(RecoveryUI::NO_COMMAND);
}
if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
@@ -1135,7 +1449,16 @@ main(int argc, char **argv) {
ui->SetBackground(RecoveryUI::ERROR);
}
Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT;
- if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
+ if (headless) {
+ ui->ShowText(true);
+ ui->SetHeadlessMode();
+ finish_recovery(NULL);
+ for (;;) {
+ pause();
+ }
+ }
+ else if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
+ ui->ShowText(true);
Device::BuiltinAction temp = prompt_and_wait(device, status);
if (temp != Device::NO_ACTION) after = temp;
}
@@ -1143,6 +1466,13 @@ main(int argc, char **argv) {
// Save logs and clean up before rebooting or shutting down.
finish_recovery(send_intent);
+ vold_unmount_all();
+
+ sync();
+
+ write_file("/sys/class/leds/lcd-backlight/brightness", "0");
+ gr_fb_blank(true);
+
switch (after) {
case Device::SHUTDOWN:
ui->Print("Shutting down...\n");
@@ -1150,8 +1480,13 @@ main(int argc, char **argv) {
break;
case Device::REBOOT_BOOTLOADER:
+#ifdef DOWNLOAD_MODE
+ ui->Print("Rebooting to download mode...\n");
+ property_set(ANDROID_RB_PROPERTY, "reboot,download");
+#else
ui->Print("Rebooting to bootloader...\n");
property_set(ANDROID_RB_PROPERTY, "reboot,bootloader");
+#endif
break;
default: