aboutsummaryrefslogtreecommitdiffstats
path: root/recovery.cpp
diff options
context:
space:
mode:
authorTom Marshall <tdm@cyngn.com>2014-11-24 16:02:04 -0800
committerTom Marshall <tdm@cyngn.com>2015-11-25 15:34:31 -0800
commit3f092f7778ed608d454df4c3dc3b3f7cb4afde3b (patch)
tree326444388672880e6ab3bf72f434e13e1d80c25e /recovery.cpp
parent383f723fdb0ebba5078ccc2aabf87f0516215bf9 (diff)
downloadbootable_recovery-3f092f7778ed608d454df4c3dc3b3f7cb4afde3b.zip
bootable_recovery-3f092f7778ed608d454df4c3dc3b3f7cb4afde3b.tar.gz
bootable_recovery-3f092f7778ed608d454df4c3dc3b3f7cb4afde3b.tar.bz2
recovery: Awakening of MiniVold
A minimal vold client for recovery. Change-Id: Id25d955dc1861a910e5f5fc27d9a19e245d66833
Diffstat (limited to 'recovery.cpp')
-rw-r--r--recovery.cpp220
1 files changed, 145 insertions, 75 deletions
diff --git a/recovery.cpp b/recovery.cpp
index b7641aa..9f45d9a 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -47,6 +47,9 @@
#include "ui.h"
#include "screen_ui.h"
#include "device.h"
+
+#include "voldclient.h"
+
#include "adb_install.h"
#include "adb.h"
#include "fuse_sideload.h"
@@ -81,7 +84,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";
@@ -94,6 +96,8 @@ char* stage = NULL;
char* reason = NULL;
bool modified_flash = false;
+#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
@@ -589,7 +593,7 @@ static bool erase_volume(const char* volume) {
return (result == 0);
}
-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
@@ -600,7 +604,7 @@ get_menu_selection(const char* const * headers, const char* const * items,
int selected = initial_selection;
int chosen_item = -1;
- while (chosen_item < 0 && chosen_item != Device::kGoBack) {
+ while (chosen_item < 0 && chosen_item != Device::kGoBack && chosen_item != Device::kRefresh) {
int key = ui->WaitKey();
int visible = ui->IsTextVisible();
@@ -615,6 +619,9 @@ get_menu_selection(const char* const * headers, const char* const * items,
} else if (key == -2) { // we are returning from ui_cancel_wait_key(): trigger a GO_BACK
return Device::kGoBack;
}
+ else if (key == -6) {
+ return Device::kRefresh;
+ }
int action = device->HandleMenuKey(key, visible);
@@ -634,6 +641,9 @@ get_menu_selection(const char* const * headers, const char* const * items,
case Device::kGoBack:
chosen_item = Device::kGoBack;
break;
+ case Device::kRefresh:
+ chosen_item = Device::kRefresh;
+ break;
}
} else if (!menu_only) {
chosen_item = action;
@@ -650,8 +660,6 @@ static int compare_string(const void* a, const void* b) {
// Returns a malloc'd path, or NULL.
static char* browse_directory(const char* path, Device* device) {
- ensure_path_mounted(path);
-
DIR* d = opendir(path);
if (d == NULL) {
LOGE("error opening %s: %s\n", path, strerror(errno));
@@ -716,15 +724,15 @@ static char* 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 "../"
+ 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);
@@ -842,30 +850,82 @@ static void choose_recovery_file(Device* device) {
}
}
-static int apply_from_sdcard(Device* device, bool* wipe_cache) {
+static int apply_from_storage(Device* device, const std::string& id, bool* wipe_cache) {
modified_flash = true;
- if (ensure_path_mounted(SDCARD_ROOT) != 0) {
- ui->Print("\n-- Couldn't mount %s.\n", SDCARD_ROOT);
+ int status;
+
+ if (!vdc->volumeMount(id)) {
return INSTALL_ERROR;
}
- char* path = browse_directory(SDCARD_ROOT, device);
+ VolumeInfo vi = vdc->getVolume(id);
+
+ char* path = browse_directory(vi.mInternalPath.c_str(), device);
if (path == NULL) {
ui->Print("\n-- No package file selected.\n");
- ensure_path_unmounted(SDCARD_ROOT);
- return INSTALL_ERROR;
+ vdc->volumeUnmount(vi.mId);
+ return INSTALL_NONE;
}
ui->Print("\n-- Install %s ...\n", path);
set_sdcard_update_bootloader_message();
void* token = start_sdcard_fuse(path);
- int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
+ vdc->volumeUnmount(vi.mId, true);
+
+ status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
TEMPORARY_INSTALL_FILE, false);
finish_sdcard_fuse(token);
- ensure_path_unmounted(SDCARD_ROOT);
+ free(path);
+ 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];
+ std::vector<VolumeInfo> volumes = vdc->getVolumes();
+
+ const int item_sideload = 0;
+ int n, i;
+ std::vector<VolumeInfo>::iterator vitr;
+
+refresh:
+ menu_items[item_sideload] = strdup("Apply from ADB");
+
+ n = item_sideload + 1;
+ for (vitr = volumes.begin(); vitr != volumes.end(); ++vitr) {
+ menu_items[n] = (char*)malloc(256);
+ sprintf(menu_items[n], "Choose from %s", vitr->mLabel.c_str());
+ ++n;
+ }
+ menu_items[n] = NULL;
+
+ bool wipe_cache;
+ int status = INSTALL_ERROR;
+
+ for (;;) {
+ int chosen = get_menu_selection(headers, menu_items, 0, 0, device);
+ for (i = 0; i < n; ++i) {
+ free(menu_items[i]);
+ }
+ if (chosen == Device::kRefresh) {
+ goto refresh;
+ }
+ if (chosen == Device::kGoBack) {
+ break;
+ }
+ if (chosen == item_sideload) {
+ status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE);
+ }
+ else {
+ std::string id = volumes[chosen - 1].mId;
+ status = apply_from_storage(device, id, &wipe_cache);
+ }
+ }
+
return status;
}
@@ -901,77 +961,79 @@ prompt_and_wait(Device* device, int status) {
Device::BuiltinAction chosen_action = device->InvokeMenuItem(chosen_item);
bool should_wipe_cache = false;
- switch (chosen_action) {
- case Device::NO_ACTION:
- break;
+ for (;;) {
+ switch (chosen_action) {
+ case Device::NO_ACTION:
+ break;
- case Device::REBOOT:
- case Device::SHUTDOWN:
- case Device::REBOOT_BOOTLOADER:
- return chosen_action;
+ 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_DATA:
+ wipe_data(ui->IsTextVisible(), device);
+ if (!ui->IsTextVisible()) return Device::NO_ACTION;
+ break;
- case Device::WIPE_CACHE:
- wipe_cache(ui->IsTextVisible(), device);
- if (!ui->IsTextVisible()) return Device::NO_ACTION;
- break;
+ case Device::WIPE_CACHE:
+ wipe_cache(ui->IsTextVisible(), device);
+ if (!ui->IsTextVisible()) return Device::NO_ACTION;
+ break;
- case Device::APPLY_ADB_SIDELOAD:
- case Device::APPLY_SDCARD:
- {
- bool adb = (chosen_action == Device::APPLY_ADB_SIDELOAD);
- if (adb) {
- status = apply_from_adb(ui, &should_wipe_cache, TEMPORARY_INSTALL_FILE);
- } else {
- status = apply_from_sdcard(device, &should_wipe_cache);
- }
+ case Device::APPLY_UPDATE:
+ {
+ status = show_apply_update_menu(device);
- if (status == INSTALL_SUCCESS && should_wipe_cache) {
- if (!wipe_cache(false, device)) {
- status = INSTALL_ERROR;
+ if (status == INSTALL_SUCCESS && should_wipe_cache) {
+ if (!wipe_cache(false, device)) {
+ status = INSTALL_ERROR;
+ }
}
- }
- 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 %s complete.\n", adb ? "ADB" : "SD card");
+ 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 complete.\n");
}
+ break;
}
- break;
+ break;
- case Device::VIEW_RECOVERY_LOGS:
- choose_recovery_file(device);
- break;
+ case Device::VIEW_RECOVERY_LOGS:
+ choose_recovery_file(device);
+ break;
- case Device::MOUNT_SYSTEM:
- char system_root_image[PROPERTY_VALUE_MAX];
- property_get("ro.build.system_root_image", system_root_image, "");
-
- // For a system image built with the root directory (i.e.
- // system_root_image == "true"), we mount it to /system_root, and symlink /system
- // to /system_root/system to make adb shell work (the symlink is created through
- // the build system).
- // Bug: 22855115
- if (strcmp(system_root_image, "true") == 0) {
- if (ensure_path_mounted_at("/", "/system_root") != -1) {
- ui->Print("Mounted /system.\n");
- }
- } else {
- if (ensure_path_mounted("/system") != -1) {
- ui->Print("Mounted /system.\n");
+ case Device::MOUNT_SYSTEM:
+ char system_root_image[PROPERTY_VALUE_MAX];
+ property_get("ro.build.system_root_image", system_root_image, "");
+
+ // For a system image built with the root directory (i.e.
+ // system_root_image == "true"), we mount it to /system_root, and symlink /system
+ // to /system_root/system to make adb shell work (the symlink is created through
+ // the build system).
+ // Bug: 22855115
+ if (strcmp(system_root_image, "true") == 0) {
+ if (ensure_path_mounted_at("/", "/system_root") != -1) {
+ ui->Print("Mounted /system.\n");
+ }
+ } else {
+ if (ensure_path_mounted("/system") != -1) {
+ ui->Print("Mounted /system.\n");
+ }
}
- }
- break;
+ break;
+ }
+ if (status == Device::kRefresh) {
+ status = 0;
+ continue;
+ }
+ break;
}
}
}
@@ -1159,6 +1221,9 @@ main(int argc, char **argv) {
ui = device->GetUI();
gCurrentUI = ui;
+ vdc = new VoldClient(device);
+ vdc->start();
+
ui->SetLocale(locale);
ui->Init();
@@ -1286,6 +1351,11 @@ main(int argc, char **argv) {
// Save logs and clean up before rebooting or shutting down.
finish_recovery(send_intent);
+ vdc->unmountAll();
+ vdc->stop();
+
+ sync();
+
switch (after) {
case Device::SHUTDOWN:
ui->Print("Shutting down...\n");