BootControl: is slot marked successful

Test: update_engine_unittests
Bug: 147696014

Change-Id: I316efda7a0936e2dee0f766efb5c18ff30790274
diff --git a/boot_control_android.cc b/boot_control_android.cc
index 429de6a..ec2ca0f 100644
--- a/boot_control_android.cc
+++ b/boot_control_android.cc
@@ -150,6 +150,22 @@
          brillo::MessageLoop::kTaskIdNull;
 }
 
+bool BootControlAndroid::IsSlotMarkedSuccessful(
+    BootControlInterface::Slot slot) const {
+  Return<BoolResult> ret = module_->isSlotMarkedSuccessful(slot);
+  CommandResult result;
+  if (!ret.isOk()) {
+    LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
+               << " is marked successful: " << ret.description();
+    return false;
+  }
+  if (ret == BoolResult::INVALID_SLOT) {
+    LOG(ERROR) << "Invalid slot: " << SlotName(slot);
+    return false;
+  }
+  return ret == BoolResult::TRUE;
+}
+
 DynamicPartitionControlInterface*
 BootControlAndroid::GetDynamicPartitionControl() {
   return dynamic_control_.get();
diff --git a/boot_control_android.h b/boot_control_android.h
index c909134..0b042e3 100644
--- a/boot_control_android.h
+++ b/boot_control_android.h
@@ -51,6 +51,7 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
+  bool IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const override;
   DynamicPartitionControlInterface* GetDynamicPartitionControl() override;
 
  private:
diff --git a/boot_control_chromeos.cc b/boot_control_chromeos.cc
index e972d41..0f47169 100644
--- a/boot_control_chromeos.cc
+++ b/boot_control_chromeos.cc
@@ -329,6 +329,11 @@
   return -1;
 }
 
+bool BootControlChromeOS::IsSlotMarkedSuccessful(Slot slot) const {
+  LOG(ERROR) << __func__ << " not supported.";
+  return false;
+}
+
 DynamicPartitionControlInterface*
 BootControlChromeOS::GetDynamicPartitionControl() {
   return dynamic_partition_control_.get();
diff --git a/boot_control_chromeos.h b/boot_control_chromeos.h
index 10454be..0209052 100644
--- a/boot_control_chromeos.h
+++ b/boot_control_chromeos.h
@@ -52,6 +52,7 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
+  bool IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const override;
   DynamicPartitionControlInterface* GetDynamicPartitionControl() override;
 
  private:
diff --git a/common/boot_control_interface.h b/common/boot_control_interface.h
index 41fe4ea..3906e2f 100644
--- a/common/boot_control_interface.h
+++ b/common/boot_control_interface.h
@@ -85,6 +85,9 @@
   // of the operation.
   virtual bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) = 0;
 
+  // Check if |slot| is marked boot successfully.
+  virtual bool IsSlotMarkedSuccessful(Slot slot) const = 0;
+
   // Return the dynamic partition control interface.
   virtual DynamicPartitionControlInterface* GetDynamicPartitionControl() = 0;
 
diff --git a/common/boot_control_stub.cc b/common/boot_control_stub.cc
index d198e9d..2eb9211 100644
--- a/common/boot_control_stub.cc
+++ b/common/boot_control_stub.cc
@@ -63,6 +63,11 @@
   return false;
 }
 
+bool BootControlStub::IsSlotMarkedSuccessful(Slot slot) const {
+  LOG(ERROR) << __FUNCTION__ << " should never be called.";
+  return false;
+}
+
 DynamicPartitionControlInterface*
 BootControlStub::GetDynamicPartitionControl() {
   return dynamic_partition_control_.get();
diff --git a/common/boot_control_stub.h b/common/boot_control_stub.h
index 1dfd08b..cc16190 100644
--- a/common/boot_control_stub.h
+++ b/common/boot_control_stub.h
@@ -47,6 +47,7 @@
   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
   bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
+  bool IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const override;
   DynamicPartitionControlInterface* GetDynamicPartitionControl() override;
 
  private:
diff --git a/common/fake_boot_control.h b/common/fake_boot_control.h
index e031fc6..bd9d9ca 100644
--- a/common/fake_boot_control.h
+++ b/common/fake_boot_control.h
@@ -74,14 +74,20 @@
   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override {
     // We run the callback directly from here to avoid having to setup a message
     // loop in the test environment.
+    is_marked_successful_[GetCurrentSlot()] = true;
     callback.Run(true);
     return true;
   }
 
+  bool IsSlotMarkedSuccessful(Slot slot) const override {
+    return slot < num_slots_ && is_marked_successful_[slot];
+  }
+
   // Setters
   void SetNumSlots(unsigned int num_slots) {
     num_slots_ = num_slots;
     is_bootable_.resize(num_slots_, false);
+    is_marked_successful_.resize(num_slots_, false);
     devices_.resize(num_slots_);
   }
 
@@ -108,6 +114,7 @@
   BootControlInterface::Slot current_slot_{0};
 
   std::vector<bool> is_bootable_;
+  std::vector<bool> is_marked_successful_;
   std::vector<std::map<std::string, std::string>> devices_;
 
   std::unique_ptr<DynamicPartitionControlInterface> dynamic_partition_control_;