AU: Provide a reboot_if_needed D-Bus API.

This will reboot if the current state is UPDATED_REBOOT_NEEDED.
Also add -reboot option to the update_engine_client.

BUG=4250
TEST=unit tests,gmerged on device and tried reboot requests

Review URL: http://codereview.chromium.org/3034026
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index 05f0056..94aa5a5 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -22,6 +22,9 @@
     <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"
+           send_member="RebootIfNeeded"/>
   </policy>
   <policy context="default">
     <deny send_destination="org.chromium.UpdateEngine" />
diff --git a/dbus_service.cc b/dbus_service.cc
index 54dde41..4a05160 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -47,6 +47,24 @@
       g_object_new(UPDATE_ENGINE_TYPE_SERVICE, NULL));
 }
 
+gboolean update_engine_service_attempt_update(UpdateEngineService* self,
+                                              gchar* app_version,
+                                              gchar* omaha_url,
+                                              GError **error) {
+  const string update_app_version = app_version ? app_version : "";
+  const string update_omaha_url = omaha_url ? omaha_url : "";
+  LOG(INFO) << "Attempt update: app_version=\"" << update_app_version << "\" "
+            << "omaha_url=\"" << update_omaha_url << "\"";
+  self->update_attempter_->CheckForUpdate(app_version, omaha_url);
+  return TRUE;
+}
+
+gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+                                                GError **error) {
+  self->update_attempter_->CheckForUpdate("", "");
+  return TRUE;
+}
+
 gboolean update_engine_service_get_status(UpdateEngineService* self,
                                           int64_t* last_checked_time,
                                           double* progress,
@@ -68,21 +86,12 @@
   return TRUE;
 }
 
-gboolean update_engine_service_attempt_update(UpdateEngineService* self,
-                                              gchar* app_version,
-                                              gchar* omaha_url,
-                                              GError **error) {
-  const string update_app_version = app_version ? app_version : "";
-  const string update_omaha_url = omaha_url ? omaha_url : "";
-  LOG(INFO) << "Attempt update: app_version=\"" << update_app_version << "\" "
-            << "omaha_url=\"" << update_omaha_url << "\"";
-  self->update_attempter_->CheckForUpdate(app_version, omaha_url);
-  return TRUE;
-}
-
-gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+gboolean update_engine_service_reboot_if_needed(UpdateEngineService* self,
                                                 GError **error) {
-  self->update_attempter_->CheckForUpdate("", "");
+  if (!self->update_attempter_->RebootIfNeeded()) {
+    *error = NULL;
+    return FALSE;
+  }
   return TRUE;
 }
 
diff --git a/dbus_service.h b/dbus_service.h
index 4b760ce..12c9ed1 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -46,6 +46,14 @@
 
 // Methods
 
+gboolean update_engine_service_attempt_update(UpdateEngineService* self,
+                                              gchar* app_version,
+                                              gchar* omaha_url,
+                                              GError **error);
+
+gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+                                                GError **error);
+
 gboolean update_engine_service_get_status(UpdateEngineService* self,
                                           int64_t* last_checked_time,
                                           double* progress,
@@ -54,14 +62,9 @@
                                           int64_t* new_size,
                                           GError **error);
 
-gboolean update_engine_service_check_for_update(UpdateEngineService* self,
+gboolean update_engine_service_reboot_if_needed(UpdateEngineService* self,
                                                 GError **error);
 
-gboolean update_engine_service_attempt_update(UpdateEngineService* self,
-                                              gchar* app_version,
-                                              gchar* omaha_url,
-                                              GError **error);
-
 gboolean update_engine_service_emit_status_update(
     UpdateEngineService* self,
     gint64 last_checked_time,
diff --git a/update_attempter.cc b/update_attempter.cc
index 014f822..939e074 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -221,6 +221,16 @@
   Update(app_version, omaha_url);
 }
 
+bool UpdateAttempter::RebootIfNeeded() {
+  if (status_ != UPDATE_STATUS_UPDATED_NEED_REBOOT) {
+    LOG(INFO) << "Reboot requested, but status is "
+              << UpdateStatusToString(status_) << ", so not rebooting.";
+    return false;
+  }
+  TEST_AND_RETURN_FALSE(utils::Reboot());
+  return true;
+}
+
 // Delegate methods:
 void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
                                      ActionExitCode code) {
diff --git a/update_attempter.h b/update_attempter.h
index 3e47969..cd7f480 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -86,6 +86,10 @@
   void CheckForUpdate(const std::string& app_version,
                       const std::string& omaha_url);
 
+  // Initiates a reboot if the current state is
+  // UPDATED_NEED_REBOOT. Returns true on sucess, false otherwise.
+  bool RebootIfNeeded();
+
   // DownloadActionDelegate method
   void BytesReceived(uint64_t bytes_received, uint64_t total);
 
diff --git a/update_engine.xml b/update_engine.xml
index 9cd9d42..5f20751 100644
--- a/update_engine.xml
+++ b/update_engine.xml
@@ -7,6 +7,12 @@
   <interface name="org.chromium.UpdateEngineInterface">
     <annotation name="org.freedesktop.DBus.GLib.CSymbol"
                 value="update_engine_service"/>
+    <method name="AttemptUpdate">
+      <arg type="s" name="app_version" />
+      <arg type="s" name="omaha_url" />
+    </method>
+    <method name="CheckForUpdate">
+    </method>
     <method name="GetStatus">
       <arg type="x" name="last_checked_time" direction="out" />
       <arg type="d" name="progress" direction="out" />
@@ -14,11 +20,7 @@
       <arg type="s" name="new_version" direction="out" />
       <arg type="x" name="new_size" direction="out" />
     </method>
-    <method name="CheckForUpdate">
-    </method>
-    <method name="AttemptUpdate">
-      <arg type="s" name="app_version" />
-      <arg type="s" name="omaha_url" />
+    <method name="RebootIfNeeded">
     </method>
     <signal name="StatusUpdate">
       <arg type="x" name="last_checked_time" />
diff --git a/update_engine_client.cc b/update_engine_client.cc
index bb4beaa..c8dda07 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -22,14 +22,12 @@
 using chromeos_update_engine::utils::GetGErrorMessage;
 using std::string;
 
-DEFINE_string(app_version, "",
-              "Force the current app version.");
-DEFINE_bool(check_for_update, false,
-            "Initiate check for updates.");
+DEFINE_string(app_version, "", "Force the current app version.");
+DEFINE_bool(check_for_update, false, "Initiate check for updates.");
 DEFINE_bool(force_update, false,
             "Force an update, even over an expensive network.");
-DEFINE_string(omaha_url, "",
-              "The URL of the Omaha update server.");
+DEFINE_string(omaha_url, "", "The URL of the Omaha update server.");
+DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
 DEFINE_bool(status, false, "Print the status to stdout.");
 DEFINE_bool(watch_for_updates, false,
             "Listen for status updates and print them to the screen.");
@@ -158,6 +156,21 @@
   return true;
 }
 
+bool RebootIfNeeded() {
+  DBusGProxy* proxy;
+  GError* error = NULL;
+
+  CHECK(GetProxy(&proxy));
+
+  gboolean rc =
+      org_chromium_UpdateEngineInterface_reboot_if_needed(proxy, &error);
+  // Reboot error code doesn't necessarily mean that a reboot
+  // failed. For example, D-Bus may be shutdown before we receive the
+  // result.
+  LOG_IF(INFO, !rc) << "Reboot error message: " << GetGErrorMessage(error);
+  return true;
+}
+
 }  // namespace {}
 
 int main(int argc, char** argv) {
@@ -177,6 +190,7 @@
   }
   if (FLAGS_force_update || FLAGS_check_for_update ||
       !FLAGS_app_version.empty() || !FLAGS_omaha_url.empty()) {
+    LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
     LOG(INFO) << "Initiating update check and install.";
     if (FLAGS_force_update) {
       LOG(INFO) << "Will not abort due to being on expensive network.";
@@ -187,10 +201,16 @@
     return 0;
   }
   if (FLAGS_watch_for_updates) {
+    LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
     LOG(INFO) << "Watching for status updates.";
     WatchForUpdates();  // Should never return.
     return 1;
   }
+  if (FLAGS_reboot) {
+    LOG(INFO) << "Requesting a reboot...";
+    CHECK(RebootIfNeeded());
+    return 0;
+  }
 
   LOG(INFO) << "No flags specified. Exiting.";
   return 0;
diff --git a/utils.cc b/utils.cc
index b19e6fc..4c5a195 100644
--- a/utils.cc
+++ b/utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 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.
 
@@ -16,6 +16,7 @@
 #include <algorithm>
 #include "chromeos/obsolete_logging.h"
 #include "update_engine/file_writer.h"
+#include "update_engine/subprocess.h"
 
 using std::min;
 using std::string;
@@ -73,7 +74,7 @@
   }
   *out_bytes_read = bytes_read;
   return true;
-  
+
 }
 
 bool ReadFile(const std::string& path, std::vector<char>* out) {
@@ -282,7 +283,7 @@
   vector<char> buf(filename_template.size() + 1);
   memcpy(&buf[0], filename_template.data(), filename_template.size());
   buf[filename_template.size()] = '\0';
-  
+
   int mkstemp_fd = mkstemp(&buf[0]);
   TEST_AND_RETURN_FALSE_ERRNO(mkstemp_fd >= 0);
   if (filename) {
@@ -302,7 +303,7 @@
   vector<char> buf(dirname_template.size() + 1);
   memcpy(&buf[0], dirname_template.data(), dirname_template.size());
   buf[dirname_template.size()] = '\0';
-  
+
   char* return_code = mkdtemp(&buf[0]);
   TEST_AND_RETURN_FALSE_ERRNO(return_code != NULL);
   *dirname = &buf[0];
@@ -393,9 +394,19 @@
   return error->message;
 }
 
+bool Reboot() {
+  vector<string> command;
+  command.push_back("/sbin/shutdown");
+  command.push_back("-r");
+  command.push_back("now");
+  int rc = 0;
+  Subprocess::SynchronousExec(command, &rc);
+  TEST_AND_RETURN_FALSE(rc == 0);
+  return true;
+}
+
 const char* const kStatefulPartition = "/mnt/stateful_partition";
 
 }  // namespace utils
 
 }  // namespace chromeos_update_engine
-
diff --git a/utils.h b/utils.h
index 5a3efe9..9be2509 100644
--- a/utils.h
+++ b/utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
 
@@ -102,6 +102,9 @@
 // Returns the error message, if any, from a GError pointer.
 const char* GetGErrorMessage(const GError* error);
 
+// Initiates a system reboot. Returns true on success, false otherwise.
+bool Reboot();
+
 // Log a string in hex to LOG(INFO). Useful for debugging.
 void HexDumpArray(const unsigned char* const arr, const size_t length);
 inline void HexDumpString(const std::string& str) {