bootloader_message: Add helpers for handling IBootControl MergeStatus.

Move merge_status from bootloader_control_ab, which is in vendor space,
to a new generic AOSP struct in system space. This will allow more
devices to share the same HAL implementation.

This patch also changes libboot_control to compensate for merge_status
moving out of vendor space. The reference HAL library now also provides
separate helper functions for managing the merge status, so devices
using a custom boot control HAL can still take advantage of the new misc
implementation.

Bug: 139156011
Test: manual test
Change-Id: I5cd824e25f9d07aad1476301def5cdc3f506b029
diff --git a/boot_control/libboot_control.cpp b/boot_control/libboot_control.cpp
index ff4eaab..7021839 100644
--- a/boot_control/libboot_control.cpp
+++ b/boot_control/libboot_control.cpp
@@ -232,6 +232,10 @@
     UpdateAndSaveBootloaderControl(device.c_str(), &boot_ctrl);
   }
 
+  if (!InitMiscVirtualAbMessageIfNeeded()) {
+    return false;
+  }
+
   num_slots_ = boot_ctrl.nb_slot;
   return true;
 }
@@ -335,18 +339,15 @@
 }
 
 bool BootControl::SetSnapshotMergeStatus(MergeStatus status) {
-  bootloader_control bootctrl;
-  if (!LoadBootloaderControl(misc_device_, &bootctrl)) return false;
-
-  bootctrl.merge_status = (unsigned int)status;
-  return UpdateAndSaveBootloaderControl(misc_device_, &bootctrl);
+  return SetMiscVirtualAbMergeStatus(current_slot_, status);
 }
 
 MergeStatus BootControl::GetSnapshotMergeStatus() {
-  bootloader_control bootctrl;
-  if (!LoadBootloaderControl(misc_device_, &bootctrl)) return MergeStatus::UNKNOWN;
-
-  return (MergeStatus)bootctrl.merge_status;
+  MergeStatus status;
+  if (!GetMiscVirtualAbMergeStatus(current_slot_, &status)) {
+    return MergeStatus::UNKNOWN;
+  }
+  return status;
 }
 
 const char* BootControl::GetSuffix(unsigned int slot) {
@@ -356,5 +357,66 @@
   return kSlotSuffixes[slot];
 }
 
+bool InitMiscVirtualAbMessageIfNeeded() {
+  std::string err;
+  misc_virtual_ab_message message;
+  if (!ReadMiscVirtualAbMessage(&message, &err)) {
+    LOG(ERROR) << "Could not read merge status: " << err;
+    return false;
+  }
+
+  if (message.version == MISC_VIRTUAL_AB_MESSAGE_VERSION) {
+    // Already initialized.
+    return true;
+  }
+
+  message = {};
+  message.version = MISC_VIRTUAL_AB_MESSAGE_VERSION;
+  if (!WriteMiscVirtualAbMessage(message, &err)) {
+    LOG(ERROR) << "Could not write merge status: " << err;
+    return false;
+  }
+  return true;
+}
+
+bool SetMiscVirtualAbMergeStatus(unsigned int current_slot,
+                                 android::hardware::boot::V1_1::MergeStatus status) {
+  std::string err;
+  misc_virtual_ab_message message;
+
+  if (!ReadMiscVirtualAbMessage(&message, &err)) {
+    LOG(ERROR) << "Could not read merge status: " << err;
+    return false;
+  }
+
+  message.merge_status = static_cast<uint8_t>(status);
+  message.source_slot = current_slot;
+  if (!WriteMiscVirtualAbMessage(message, &err)) {
+    LOG(ERROR) << "Could not write merge status: " << err;
+    return false;
+  }
+  return true;
+}
+
+bool GetMiscVirtualAbMergeStatus(unsigned int current_slot,
+                                 android::hardware::boot::V1_1::MergeStatus* status) {
+  std::string err;
+  misc_virtual_ab_message message;
+
+  if (!ReadMiscVirtualAbMessage(&message, &err)) {
+    LOG(ERROR) << "Could not read merge status: " << err;
+    return false;
+  }
+
+  // If the slot reverted after having created a snapshot, then the snapshot will
+  // be thrown away at boot. Thus we don't count this as being in a snapshotted
+  // state.
+  *status = static_cast<MergeStatus>(message.merge_status);
+  if (*status == MergeStatus::SNAPSHOTTED && current_slot == message.source_slot) {
+    *status = MergeStatus::NONE;
+  }
+  return true;
+}
+
 }  // namespace bootable
 }  // namespace android