recovery: add support for changing slots

* reference: https://github.com/omnirom/android_bootable_recovery/commit/1b190166eb1295c6339f6100e4fbb92c81b81ea6

Change-Id: I848e003ca569dfaa572ce7641775f0ea9f2b5513
Signed-off-by: jhonboy121 <alfredmathew05@gmail.com>
Signed-off-by: Sipun Ku Mahanta <sipunkumar85@gmail.com>
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>

recovery: rewrite slot switch logic using bootcontrol APIs

Change-Id: I1eb136c81cc9246b0c9f5e52bcf6e7ba40fbc12d
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
diff --git a/recovery.cpp b/recovery.cpp
index 91be2b2..5745e12 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -42,6 +42,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
 #include <cutils/properties.h> /* for property_list */
 #include <fs_mgr/roots.h>
 #include <volume_manager/VolumeManager.h>
@@ -66,6 +67,10 @@
 #include "recovery_utils/roots.h"
 #include "volclient.h"
 
+using android::hardware::boot::V1_0::IBootControl;
+using android::hardware::boot::V1_0::CommandResult;
+using android::hardware::boot::V1_0::Slot;
+using android::sp;
 using android::volmgr::VolumeManager;
 using android::volmgr::VolumeInfo;
 
@@ -199,6 +204,37 @@
   }
 }
 
+std::string get_chosen_slot(Device* device) {
+  std::vector<std::string> headers{ "Choose which slot to boot into on next boot." };
+  std::vector<std::string> items{ "A", "B" };
+  size_t chosen_item = device->GetUI()->ShowMenu(
+      headers, items, 0, true,
+      std::bind(&Device::HandleMenuKey, device, std::placeholders::_1, std::placeholders::_2));
+  if (chosen_item < 0)
+    return "";
+  return items[chosen_item];
+}
+
+int set_slot(Device* device) {
+  std::string slot = get_chosen_slot(device);
+  CommandResult ret;
+  auto cb = [&ret](CommandResult result) { ret = result; };
+  Slot sslot = (slot == "A") ? 0 : 1;
+  sp<IBootControl> module = IBootControl::getService();
+  if (!module) {
+    device->GetUI()->Print("Error getting bootctrl module.\n");
+  } else {
+    auto result = module->setActiveBootSlot(sslot, cb);
+    if (result.isOk() && ret.success) {
+      device->GetUI()->Print("Switched slot to %s.\n", slot.c_str());
+      device->GoHome();
+    } else {
+      device->GetUI()->Print("Error changing bootloader boot slot to %s", slot.c_str());
+    }
+  }
+  return ret.success ? 0 : 1;
+}
+
 static bool ask_to_wipe_data(Device* device) {
   std::vector<std::string> headers{ "Format user data?", "This includes internal storage.", "THIS CANNOT BE UNDONE!" };
   std::vector<std::string> items{ " Cancel", " Format data" };
@@ -603,6 +639,10 @@
         ui->Print("Enabled ADB.\n");
         break;
 
+      case Device::SWAP_SLOT:
+        set_slot(device);
+        break;
+
       case Device::RUN_GRAPHICS_TEST:
         run_graphics_test(ui);
         break;
diff --git a/recovery_main.cpp b/recovery_main.cpp
index 7597418..e006acc 100644
--- a/recovery_main.cpp
+++ b/recovery_main.cpp
@@ -477,6 +477,8 @@
     // because ROMs are flashed to the inactive slot. Removing the menu option
     // prevents users from accidentally trashing a functioning ROM.
     device->RemoveMenuItemForAction(Device::WIPE_SYSTEM);
+  } else {
+    device->RemoveMenuItemForAction(Device::SWAP_SLOT);
   }
 
   if (!android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
diff --git a/recovery_ui/device.cpp b/recovery_ui/device.cpp
index e950ea6..9bca95f 100644
--- a/recovery_ui/device.cpp
+++ b/recovery_ui/device.cpp
@@ -45,6 +45,7 @@
   { "Mount/unmount system", Device::MOUNT_SYSTEM },
   { "View recovery logs", Device::VIEW_RECOVERY_LOGS },
   { "Enable ADB", Device::ENABLE_ADB },
+  { "Switch slot", Device::SWAP_SLOT },
   { "Run graphics test", Device::RUN_GRAPHICS_TEST },
   { "Run locale test", Device::RUN_LOCALE_TEST },
   { "Enter rescue", Device::ENTER_RESCUE },
diff --git a/recovery_ui/include/recovery_ui/device.h b/recovery_ui/include/recovery_ui/device.h
index c2fc38d..9a90210 100644
--- a/recovery_ui/include/recovery_ui/device.h
+++ b/recovery_ui/include/recovery_ui/device.h
@@ -71,6 +71,7 @@
     SHUTDOWN_FROM_FASTBOOT = 21,
     WIPE_SYSTEM = 100,
     ENABLE_ADB = 101,
+    SWAP_SLOT = 102,
     MENU_BASE = 200,
     MENU_WIPE = 202,
     MENU_ADVANCED = 203,