Implement a new resetStatus() method in Android interface.

When an alredy applied update is deleted from the server (normally
because is was detected to be a bad update), we need to go back to
the idle state and remove the update to prevent it from breaking
more devices.

This patch allows the application side to reset the applied update
back to idle.

Bug: 27081760
TEST=Deployed on a non-Brillo device, sent resetStatus.

Change-Id: I1bf5a141388250d225515e40f13bc3564fa5d957
diff --git a/Android.mk b/Android.mk
index 65ae2de..0b30720 100644
--- a/Android.mk
+++ b/Android.mk
@@ -380,6 +380,10 @@
 LOCAL_CPPFLAGS := $(ue_common_cppflags)
 LOCAL_LDFLAGS := $(ue_common_ldflags)
 LOCAL_C_INCLUDES :=  $(ue_common_c_includes)
+#TODO(deymo): Remove external/cros/system_api/dbus once the strings are moved
+# out of the DBus interface.
+LOCAL_C_INCLUDES += \
+    external/cros/system_api/dbus
 LOCAL_STATIC_LIBRARIES := \
     $(ue_libupdate_engine_android_exported_static_libraries:-host=)
 LOCAL_SHARED_LIBRARIES += \
@@ -395,7 +399,8 @@
     daemon_state_android.cc \
     hardware_android.cc \
     proxy_resolver.cc \
-    update_attempter_android.cc
+    update_attempter_android.cc \
+    update_status_utils.cc
 include $(BUILD_STATIC_LIBRARY)
 
 endif  # !defined(BRILLO)
diff --git a/binder_bindings/android/os/IUpdateEngine.aidl b/binder_bindings/android/os/IUpdateEngine.aidl
index 4245254..4c60eed 100644
--- a/binder_bindings/android/os/IUpdateEngine.aidl
+++ b/binder_bindings/android/os/IUpdateEngine.aidl
@@ -27,4 +27,5 @@
   void suspend();
   void resume();
   void cancel();
+  void resetStatus();
 }
diff --git a/binder_service_android.cc b/binder_service_android.cc
index e275319..872f64c 100644
--- a/binder_service_android.cc
+++ b/binder_service_android.cc
@@ -121,6 +121,13 @@
   return Status::ok();
 }
 
+Status BinderUpdateEngineAndroidService::resetStatus() {
+  brillo::ErrorPtr error;
+  if (!service_delegate_->ResetStatus(&error))
+    return ErrorPtrToStatus(error);
+  return Status::ok();
+}
+
 void BinderUpdateEngineAndroidService::UnbindCallback(
     IUpdateEngineCallback* callback) {
   auto it =
diff --git a/binder_service_android.h b/binder_service_android.h
index 0a82b82..47e76a7 100644
--- a/binder_service_android.h
+++ b/binder_service_android.h
@@ -67,6 +67,7 @@
   android::binder::Status suspend() override;
   android::binder::Status resume() override;
   android::binder::Status cancel() override;
+  android::binder::Status resetStatus() override;
 
  private:
   // Remove the passed |callback| from the list of registered callbacks. Called
diff --git a/service_delegate_android_interface.h b/service_delegate_android_interface.h
index 62e6540..7dae40f 100644
--- a/service_delegate_android_interface.h
+++ b/service_delegate_android_interface.h
@@ -64,6 +64,12 @@
   // sets |error| accordingly.
   virtual bool CancelUpdate(brillo::ErrorPtr* error) = 0;
 
+  // Reset the already applied update back to an idle state. This method can
+  // only be called when no update attempt is going on, and it will reset the
+  // status back to idle, deleting the currently applied update if any. In case
+  // of error, returns false and sets |error| accordingly.
+  virtual bool ResetStatus(brillo::ErrorPtr* error) = 0;
+
  protected:
   ServiceDelegateAndroidInterface() = default;
 };
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index f7bcab1..90501fb 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -35,6 +35,7 @@
 #include "update_engine/payload_consumer/download_action.h"
 #include "update_engine/payload_consumer/filesystem_verifier_action.h"
 #include "update_engine/payload_consumer/postinstall_runner_action.h"
+#include "update_engine/update_status_utils.h"
 
 using base::Bind;
 using base::TimeDelta;
@@ -199,6 +200,44 @@
   return LogAndSetError(error, FROM_HERE, "Cancel not implemented");
 }
 
+bool UpdateAttempterAndroid::ResetStatus(brillo::ErrorPtr* error) {
+  LOG(INFO) << "Attempting to reset state from "
+            << UpdateStatusToString(status_) << " to UpdateStatus::IDLE";
+
+  switch (status_) {
+    case UpdateStatus::IDLE:
+      return true;
+
+    case UpdateStatus::UPDATED_NEED_REBOOT:  {
+      // Remove the reboot marker so that if the machine is rebooted
+      // after resetting to idle state, it doesn't go back to
+      // UpdateStatus::UPDATED_NEED_REBOOT state.
+      bool ret_value = prefs_->Delete(kPrefsUpdateCompletedOnBootId);
+
+      // Update the boot flags so the current slot has higher priority.
+      if (!boot_control_->SetActiveBootSlot(boot_control_->GetCurrentSlot()))
+        ret_value = false;
+
+      if (!ret_value) {
+        return LogAndSetError(
+            error,
+            FROM_HERE,
+            "Failed to reset the status to ");
+      }
+
+      SetStatusAndNotify(UpdateStatus::IDLE);
+      LOG(INFO) << "Reset status successful";
+      return true;
+    }
+
+    default:
+      return LogAndSetError(
+          error,
+          FROM_HERE,
+          "Reset not allowed in this state. Cancel the ongoing update first");
+  }
+}
+
 void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor,
                                             ErrorCode code) {
   LOG(INFO) << "Processing Done.";
diff --git a/update_attempter_android.h b/update_attempter_android.h
index 96b584c..0d74d56 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -63,6 +63,7 @@
   bool SuspendUpdate(brillo::ErrorPtr* error) override;
   bool ResumeUpdate(brillo::ErrorPtr* error) override;
   bool CancelUpdate(brillo::ErrorPtr* error) override;
+  bool ResetStatus(brillo::ErrorPtr* error) override;
 
   // ActionProcessorDelegate methods:
   void ProcessingDone(const ActionProcessor* processor,
diff --git a/update_engine_client_android.cc b/update_engine_client_android.cc
index 3006a6f..989a97e 100644
--- a/update_engine_client_android.cc
+++ b/update_engine_client_android.cc
@@ -124,6 +124,7 @@
   DEFINE_bool(suspend, false, "Suspend an ongoing update and exit.");
   DEFINE_bool(resume, false, "Resume a suspended update.");
   DEFINE_bool(cancel, false, "Cancel the ongoing update and exit.");
+  DEFINE_bool(reset_status, false, "Reset an already applied update and exit.");
   DEFINE_bool(follow,
               false,
               "Follow status update changes until a final state is reached. "
@@ -174,6 +175,10 @@
     return ExitWhenIdle(service_->cancel());
   }
 
+  if (FLAGS_reset_status) {
+    return ExitWhenIdle(service_->resetStatus());
+  }
+
   if (FLAGS_follow) {
     // Register a callback object with the service.
     callback_ = new UECallback(this);