recovery: Implement a volume manager

This is a copy of the pre-binderized vold which has been converted to
use direct calls instead of sockets and stripped down to only what is
needed to support recovery.

Includes:
  * recovery: volmgr: remove unused IsSupported

    Change-Id: If8206658fdfb6108221806c09c99bf0a30f4a586
    Signed-off-by: Jesse Chan <jc@lineageos.org>

  * recovery: volmgr: remove filesystem checks

    Those checks are not strictly necessary and we are
    not building fsck tools for recovery for now.

    Remove those checks so volmgr can be useful.

    Change-Id: I87756c61b933b6cdccd281c6276b686fbd36019f
    Signed-off-by: Jesse Chan <jc@lineageos.org>

  * recovery: fixup `EmulatedVolume creating`

    Avoid dangling pointer. Instead of pointing to FstabEntry create copy.

    Change-Id: I57f76006db09a6add2c173f43175f0f6b848d87b

  * recovery: fix volmgr cleaning up

    Don't reset pointer to netlink manager
    Delete disks in stop() rather then in ~VolumeManager
    Call destroy() before deleting disks cause delete expects the
      disk to be destroyed
    Clear the lists or we would read garbage data on the next scan

    Change-Id: Idadfa1f33b7cb5f2f3c780848a99344a6608420e

  * recovery: handle interrupts in apply update menu

    Change-Id: I1f78f9196634353b77986545332d7d52a5f0c161

Change-Id: Ic82d929e052b5ba70ecf7b475e0a223d77d9687e
diff --git a/recovery.cpp b/recovery.cpp
index c9108df..ff1b265 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -42,6 +42,7 @@
 #include <android-base/strings.h>
 #include <cutils/properties.h> /* for property_list */
 #include <fs_mgr/roots.h>
+#include <volume_manager/VolumeManager.h>
 #include <ziparchive/zip_archive.h>
 
 #include "bootloader_message/bootloader_message.h"
@@ -61,6 +62,10 @@
 #include "recovery_utils/battery_utils.h"
 #include "recovery_utils/logging.h"
 #include "recovery_utils/roots.h"
+#include "volclient.h"
+
+using android::volmgr::VolumeManager;
+using android::volmgr::VolumeInfo;
 
 static constexpr const char* COMMAND_FILE = "/cache/recovery/command";
 static constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
@@ -197,6 +202,47 @@
   return (chosen_item == 1);
 }
 
+static InstallResult apply_update_menu(Device* device, Device::BuiltinAction* reboot_action){
+  RecoveryUI* ui = device->GetUI();
+  std::vector<std::string> headers{ "Apply update" };
+  std::vector<std::string> items;
+
+  const int item_sideload = 0;
+  std::vector<VolumeInfo> volumes;
+
+  InstallResult status = INSTALL_NONE;
+
+  for (;;) {
+    items.clear();
+    items.push_back("Apply from ADB");
+    VolumeManager::Instance()->getVolumeInfo(volumes);
+    for (auto& vitr : volumes) {
+      items.push_back("Choose from " + vitr.mLabel);
+    }
+
+    int chosen = ui->ShowMenu(
+      headers, items, 0, false,
+      std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2),
+      true /* refreshable */);
+    if (chosen == Device::kRefresh) {
+      continue;
+    }
+    if (chosen == Device::kGoBack) {
+      break;
+    }
+    if (chosen == static_cast<size_t>(RecoveryUI::KeyError::INTERRUPTED)) {
+      return INSTALL_KEY_INTERRUPTED;
+    }
+
+    if (chosen == item_sideload) {
+      status = ApplyFromAdb(device, false /* rescue_mode */, reboot_action);
+    } else {
+      status = ApplyFromStorage(device, volumes[chosen - 1]);
+    }
+  }
+  return status;
+}
+
 static InstallResult prompt_and_wipe_data(Device* device) {
   // Use a single string and let ScreenRecoveryUI handles the wrapping.
   std::vector<std::string> wipe_data_menu_headers{
@@ -427,7 +473,6 @@
 
     switch (chosen_action) {
       case Device::MENU_BASE:
-      case Device::MENU_UPDATE:
       case Device::MENU_WIPE:
       case Device::MENU_ADVANCED:
         goto change_menu;
@@ -492,28 +537,22 @@
         break;
       }
 
-      case Device::APPLY_ADB_SIDELOAD:
-      case Device::APPLY_SDCARD:
+      case Device::APPLY_UPDATE:
       case Device::ENTER_RESCUE: {
         save_current_log = true;
 
         update_in_progress = true;
         WriteUpdateInProgress();
 
-        bool adb = true;
         Device::BuiltinAction reboot_action;
         if (chosen_action == Device::ENTER_RESCUE) {
           // Switch to graphics screen.
           ui->ShowText(false);
           status = ApplyFromAdb(device, true /* rescue_mode */, &reboot_action);
-        } else if (chosen_action == Device::APPLY_ADB_SIDELOAD) {
-          status = ApplyFromAdb(device, false /* rescue_mode */, &reboot_action);
-        } else {
-          adb = false;
-          status = ApplyFromSdcard(device);
+        } else if (chosen_action == Device::APPLY_UPDATE) {
+          status = apply_update_menu(device, &reboot_action);
         }
 
-        ui->Print("\nInstall from %s completed with status %d.\n", adb ? "ADB" : "SD card", status);
         if (status == INSTALL_REBOOT) {
           return reboot_action;
         }
@@ -521,6 +560,7 @@
           update_in_progress = false;
         }
 
+        ui->Print("\nInstall completed with status %d.\n", status);
         if (status == INSTALL_SUCCESS) {
           update_in_progress = false;
           if (!ui->IsTextVisible()) {
@@ -739,6 +779,12 @@
 
   auto ui = device->GetUI();
 
+  VolumeClient* volclient = new VolumeClient(device);
+  VolumeManager* volmgr = VolumeManager::Instance();
+  if (!volmgr->start(volclient)) {
+    printf("Failed to start volume manager\n");
+  }
+
   // Set background string to "installing security update" for security update,
   // otherwise set it to "installing system update".
   ui->SetSystemUpdateText(security_update);
@@ -926,5 +972,11 @@
   // Save logs and clean up before rebooting or shutting down.
   FinishRecovery(ui);
 
+  volmgr->unmountAll();
+  volmgr->stop();
+  delete volclient;
+
+  sync();
+
   return next_action;
 }