Support in update_engine for script for UI jank investigation.

We need to update image_to_live.sh to run in a loop to help investigate
the kernel behavior during AU. Since update_engine doesn't allow a
new update to be applied unless the device is rebooted after the previous
update, this CL adds an option to reset the state for testing purposes.

This CL does not cause any change in product code, since
update_engine_client will never be invoked with this option in product.

BUG=chromium-os:27954
TEST=Tested on ZGB.
Change-Id: I561e58893818a1b4990fdc131cd3bb64e473155e
Reviewed-on: https://gerrit.chromium.org/gerrit/29907
Commit-Ready: Jay Srinivasan <jaysri@chromium.org>
Reviewed-by: Jay Srinivasan <jaysri@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index 949e5bb..4c6cd1c 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -18,6 +18,9 @@
            send_member="AttemptUpdate"/>
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
+           send_member="ResetStatus"/>
+    <allow send_destination="org.chromium.UpdateEngine"
+           send_interface="org.chromium.UpdateEngineInterface"
            send_member="GetStatus"/>
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
diff --git a/dbus_service.cc b/dbus_service.cc
index ef68596..2d0f31b 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -100,6 +100,13 @@
   return TRUE;
 }
 
+gboolean update_engine_service_reset_status(UpdateEngineService* self,
+                                            GError **error) {
+  *error = NULL;
+  return self->update_attempter_->ResetStatus();
+}
+
+
 gboolean update_engine_service_get_status(UpdateEngineService* self,
                                           int64_t* last_checked_time,
                                           double* progress,
diff --git a/dbus_service.h b/dbus_service.h
index 4fe17e9..56e4ef3 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -51,6 +51,9 @@
                                               gchar* omaha_url,
                                               GError **error);
 
+gboolean update_engine_service_reset_status(UpdateEngineService* self,
+                                            GError **error);
+
 gboolean update_engine_service_get_status(UpdateEngineService* self,
                                           int64_t* last_checked_time,
                                           double* progress,
diff --git a/update_attempter.cc b/update_attempter.cc
index 4422e4c..6bef755 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -14,6 +14,7 @@
 #include <tr1/memory>
 #include <vector>
 
+#include <base/file_util.h>
 #include <base/rand_util.h>
 #include <glib.h>
 #include <metrics/metrics_library.h>
@@ -717,6 +718,32 @@
   }
 }
 
+bool UpdateAttempter::ResetStatus() {
+  LOG(INFO) << "Attempting to reset state from "
+            << UpdateStatusToString(status_) << " to UPDATE_STATUS_IDLE";
+
+  switch (status_) {
+    case UPDATE_STATUS_IDLE:
+      // no-op.
+      return true;
+
+    case UPDATE_STATUS_UPDATED_NEED_REBOOT:  {
+      status_ = UPDATE_STATUS_IDLE;
+      LOG(INFO) << "Reset Successful";
+
+      // also remove the reboot marker so that if the machine is rebooted
+      // after resetting to idle state, it doesn't go back to
+      // UPDATE_STATUS_UPDATED_NEED_REBOOT state.
+      const FilePath kUpdateCompletedMarkerPath(kUpdateCompletedMarker);
+      return file_util::Delete(kUpdateCompletedMarkerPath, false);
+    }
+
+    default:
+      LOG(ERROR) << "Reset not allowed in this state.";
+      return false;
+  }
+}
+
 bool UpdateAttempter::GetStatus(int64_t* last_checked_time,
                                 double* progress,
                                 string* current_operation,
diff --git a/update_attempter.h b/update_attempter.h
index 9109cec..89e8144 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -97,6 +97,13 @@
   // Try to resume from a previously Terminate()d update.
   void ResumeUpdating();
 
+  // Resets the current state to UPDATE_STATUS_IDLE.
+  // Used by update_engine_client for restarting a new update without
+  // having to reboot once the previous update has reached
+  // UPDATE_STATUS_UPDATED_NEED_REBOOT state. This is used only
+  // for testing purposes.
+  bool ResetStatus();
+
   // Returns the current status in the out params. Returns true on success.
   bool GetStatus(int64_t* last_checked_time,
                  double* progress,
diff --git a/update_engine.xml b/update_engine.xml
index 2008d2d..f226fa4 100644
--- a/update_engine.xml
+++ b/update_engine.xml
@@ -11,6 +11,8 @@
       <arg type="s" name="app_version" />
       <arg type="s" name="omaha_url" />
     </method>
+    <method name="ResetStatus">
+    </method>
     <method name="GetStatus">
       <arg type="x" name="last_checked_time" direction="out" />
       <arg type="d" name="progress" direction="out" />
diff --git a/update_engine_client.cc b/update_engine_client.cc
index db14fb6..f8396c9 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -28,6 +28,7 @@
 DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
 DEFINE_bool(show_track, false, "Show the update track.");
 DEFINE_bool(status, false, "Print the status to stdout.");
+DEFINE_bool(reset_status, false, "Sets the status in update_engine to idle.");
 DEFINE_string(track, "", "Permanently change the update track.");
 DEFINE_bool(update, false, "Forces an update and waits for its completion. "
             "Exit status is 0 if the update succeeded, and 1 otherwise.");
@@ -81,6 +82,18 @@
   LOG(INFO) << "  new_size: " << new_size;
 }
 
+bool ResetStatus() {
+  DBusGProxy* proxy;
+  GError* error = NULL;
+
+  CHECK(GetProxy(&proxy));
+
+  gboolean rc =
+      org_chromium_UpdateEngineInterface_reset_status(proxy, &error);
+  return rc;
+}
+
+
 // If |op| is non-NULL, sets it to the current operation string or an
 // empty string if unable to obtain the current status.
 bool GetStatus(string* op) {
@@ -251,6 +264,19 @@
   chromeos_update_engine::Subprocess::Init();
   google::ParseCommandLineFlags(&argc, &argv, true);
 
+  // Update the status if requested.
+  if (FLAGS_reset_status) {
+    LOG(INFO) << "Setting Update Engine status to idle ...";
+    if (!ResetStatus()) {
+      LOG(ERROR) << "ResetStatus failed.";
+      return 1;
+    }
+
+    LOG(INFO) << "ResetStatus succeeded.";
+    return 0;
+  }
+
+
   if (FLAGS_status) {
     LOG(INFO) << "Querying Update Engine status...";
     if (!GetStatus(NULL)) {