Allow applying an OTA package manually from cache.

Change-Id: I8f78377555c658a992ca95cadf11b67ddc93fed8
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
index 7c4017e..d56164e 100644
--- a/default_recovery_ui.c
+++ b/default_recovery_ui.c
@@ -27,6 +27,7 @@
                        "apply update from external storage",
                        "wipe data/factory reset",
                        "wipe cache partition",
+                       "apply update from cache",
                        NULL };
 
 void device_ui_init(UIParameters* ui_parameters) {
diff --git a/recovery.c b/recovery.c
index 3a412d5..1e3eb5a 100644
--- a/recovery.c
+++ b/recovery.c
@@ -52,6 +52,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 *CACHE_ROOT = "/cache";
 static const char *SDCARD_ROOT = "/sdcard";
 static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
 static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
@@ -468,8 +469,8 @@
 }
 
 static int
-sdcard_directory(const char* path) {
-    ensure_path_mounted(SDCARD_ROOT);
+update_directory(const char* path, const char* unmount_when_done) {
+    ensure_path_mounted(path);
 
     const char* MENU_HEADERS[] = { "Choose a package to install:",
                                    path,
@@ -480,7 +481,9 @@
     d = opendir(path);
     if (d == NULL) {
         LOGE("error opening %s: %s\n", path, strerror(errno));
-        ensure_path_unmounted(SDCARD_ROOT);
+        if (unmount_when_done != NULL) {
+            ensure_path_unmounted(unmount_when_done);
+        }
         return 0;
     }
 
@@ -545,7 +548,7 @@
         char* item = zips[chosen_item];
         int item_len = strlen(item);
         if (chosen_item == 0) {          // item 0 is always "../"
-            // go up but continue browsing (if the caller is sdcard_directory)
+            // go up but continue browsing (if the caller is update_directory)
             result = -1;
             break;
         } else if (item[item_len-1] == '/') {
@@ -555,7 +558,7 @@
             strlcat(new_path, "/", PATH_MAX);
             strlcat(new_path, item, PATH_MAX);
             new_path[strlen(new_path)-1] = '\0';  // truncate the trailing '/'
-            result = sdcard_directory(new_path);
+            result = update_directory(new_path, unmount_when_done);
             if (result >= 0) break;
         } else {
             // selected a zip file:  attempt to install it, and return
@@ -568,7 +571,9 @@
             ui_print("\n-- Install %s ...\n", path);
             set_sdcard_update_bootloader_message();
             char* copy = copy_sideloaded_package(new_path);
-            ensure_path_unmounted(SDCARD_ROOT);
+            if (unmount_when_done != NULL) {
+                ensure_path_unmounted(unmount_when_done);
+            }
             if (copy) {
                 result = install_package(copy);
                 free(copy);
@@ -584,7 +589,9 @@
     free(zips);
     free(headers);
 
-    ensure_path_unmounted(SDCARD_ROOT);
+    if (unmount_when_done != NULL) {
+        ensure_path_unmounted(unmount_when_done);
+    }
     return result;
 }
 
@@ -642,6 +649,7 @@
         // statement below.
         chosen_item = device_perform_action(chosen_item);
 
+        int status;
         switch (chosen_item) {
             case ITEM_REBOOT:
                 return;
@@ -659,8 +667,7 @@
                 break;
 
             case ITEM_APPLY_SDCARD:
-                ;
-                int status = sdcard_directory(SDCARD_ROOT);
+                status = update_directory(SDCARD_ROOT, SDCARD_ROOT);
                 if (status >= 0) {
                     if (status != INSTALL_SUCCESS) {
                         ui_set_background(BACKGROUND_ICON_ERROR);
@@ -672,6 +679,21 @@
                     }
                 }
                 break;
+            case ITEM_APPLY_CACHE:
+                // Don't unmount cache at the end of this.
+                status = update_directory(CACHE_ROOT, NULL);
+                if (status >= 0) {
+                    if (status != INSTALL_SUCCESS) {
+                        ui_set_background(BACKGROUND_ICON_ERROR);
+                        ui_print("Installation aborted.\n");
+                    } else if (!ui_text_visible()) {
+                        return;  // reboot if logs aren't visible
+                    } else {
+                        ui_print("\nInstall from cache complete.\n");
+                    }
+                }
+                break;
+
         }
     }
 }
diff --git a/recovery_ui.h b/recovery_ui.h
index e56a24b..5f01770 100644
--- a/recovery_ui.h
+++ b/recovery_ui.h
@@ -76,6 +76,7 @@
 #define ITEM_APPLY_SDCARD    1  // historical synonym for ITEM_APPLY_EXT
 #define ITEM_WIPE_DATA       2
 #define ITEM_WIPE_CACHE      3
+#define ITEM_APPLY_CACHE     4
 
 // Header text to display above the main menu.
 extern char* MENU_HEADERS[];