update_engine: Migrate update_engine_client to chrome DBus bindings.

chromeos-dbus-bindings now generates the proxy inteface that we can use
to interact with update_engine DBus daemon. This CL migrates
update_engine_client to use this proxy insterface instead of dbus-glib,
removing all glib dependencies from update_engine_client.

There's a small functionallity change in the --follow flag. With this patch,
instead of polling the status every 5 seconds, we use the signals sent by
update_engine (about once a second) to monitor the update status.

BUG=chromium:419827
TEST=deployed and tested manually most flags of update_engine_client and its interaction with update_engine. Specifically, the blocking functionality was also tested.

Change-Id: Id27922cb1cdcef750d623ce4f816fbc5ecbc2354
Reviewed-on: https://chromium-review.googlesource.com/280878
Trybot-Ready: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/update_engine_client.cc b/update_engine_client.cc
index 4678a83..01946e7 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -2,76 +2,176 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <inttypes.h>
+#include <sysexits.h>
+#include <unistd.h>
+
 #include <string>
 
+#include <base/bind.h>
 #include <base/command_line.h>
 #include <base/logging.h>
+#include <base/macros.h>
+#include <chromeos/daemons/dbus_daemon.h>
 #include <chromeos/dbus/service_constants.h>
 #include <chromeos/flag_helper.h>
-#include <dbus/dbus.h>
-#include <glib.h>
-#include <inttypes.h>
+#include <dbus/bus.h>
 
 #include "update_engine/dbus_constants.h"
-#include "update_engine/glib_utils.h"
+#include "update_engine/dbus_proxies.h"
 
-extern "C" {
-#include "update_engine/org.chromium.UpdateEngineInterface.dbusclient.h"
-}
-
-using chromeos_update_engine::AttemptUpdateFlags;
 using chromeos_update_engine::kAttemptUpdateFlagNonInteractive;
-using chromeos_update_engine::kUpdateEngineServiceInterface;
 using chromeos_update_engine::kUpdateEngineServiceName;
-using chromeos_update_engine::kUpdateEngineServicePath;
-using chromeos_update_engine::utils::GetAndFreeGError;
 using std::string;
 
 namespace {
 
-bool GetProxy(DBusGProxy** out_proxy) {
-  DBusGConnection* bus;
-  DBusGProxy* proxy = nullptr;
-  GError* error = nullptr;
-  const int kTries = 4;
-  const int kRetrySeconds = 10;
+// Constant to signal that we need to continue running the daemon after
+// initialization.
+const int kContinueRunning = -1;
 
-  bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
-  if (bus == nullptr) {
-    LOG(ERROR) << "Failed to get bus: " << GetAndFreeGError(&error);
-    exit(1);
-  }
-  for (int i = 0; !proxy && i < kTries; ++i) {
-    if (i > 0) {
-      LOG(INFO) << "Retrying to get dbus proxy. Try "
-                << (i + 1) << "/" << kTries;
-      g_usleep(kRetrySeconds * G_USEC_PER_SEC);
+class UpdateEngineClient : public chromeos::DBusDaemon {
+ public:
+  UpdateEngineClient(int argc, char** argv) : argc_(argc), argv_(argv) {}
+  ~UpdateEngineClient() override = default;
+
+ protected:
+  int OnInit() override {
+    int ret = DBusDaemon::OnInit();
+    if (ret != EX_OK)
+      return ret;
+    if (!InitProxy())
+      return 1;
+    ret = ProcessFlags();
+    if (ret != kContinueRunning) {
+      base::MessageLoop::current()->PostTask(
+          FROM_HERE,
+          base::Bind(&UpdateEngineClient::QuitWithExitCode,
+                     base::Unretained(this), ret));
     }
-    proxy = dbus_g_proxy_new_for_name_owner(bus,
-                                            kUpdateEngineServiceName,
-                                            kUpdateEngineServicePath,
-                                            kUpdateEngineServiceInterface,
-                                            &error);
-    LOG_IF(WARNING, !proxy) << "Error getting dbus proxy for "
-                            << kUpdateEngineServiceName << ": "
-                            << GetAndFreeGError(&error);
+    return EX_OK;
   }
-  if (proxy == nullptr) {
-    LOG(ERROR) << "Giving up -- unable to get dbus proxy for "
-               << kUpdateEngineServiceName;
-    exit(1);
+
+ private:
+  bool InitProxy();
+
+  // Callback called when a StatusUpdate signal is received.
+  void OnStatusUpdateSignal(int64_t last_checked_time,
+                            double progress,
+                            const string& current_operation,
+                            const string& new_version,
+                            int64_t new_size);
+  // Callback called when the OnStatusUpdateSignal() handler is registered.
+  void OnStatusUpdateSignalRegistration(const string& interface,
+                                        const string& signal_name,
+                                        bool success);
+
+  // Registers a callback that prints on stderr the received StatusUpdate
+  // signals.
+  // The daemon should continue running for this to work.
+  void WatchForUpdates();
+
+  void ResetStatus();
+
+  // Show the status of the update engine in stdout.
+  // Blocking call. Exits the program with error 1 in case of an error.
+  void ShowStatus();
+
+  // Return the current operation status, such as UPDATE_STATUS_IDLE.
+  // Blocking call. Exits the program with error 1 in case of an error.
+  string GetCurrentOperation();
+
+  void Rollback(bool rollback);
+  string GetRollbackPartition();
+  string GetKernelDevices();
+  void CheckForUpdates(const string& app_version,
+                       const string& omaha_url,
+                       bool interactive);
+
+  // Reboot the device if a reboot is needed.
+  // Blocking call. Ignores failures.
+  void RebootIfNeeded();
+
+  // Getter and setter for the target channel. If |get_current_channel| is true,
+  // the current channel instead of the target channel will be returned.
+  // Blocking call. Exits the program with error 1 in case of an error.
+  void SetTargetChannel(const string& target_channel, bool allow_powerwash);
+  string GetChannel(bool get_current_channel);
+
+  // Getter and setter for the updates over cellular connections.
+  // Blocking call. Exits the program with error 1 in case of an error.
+  void SetUpdateOverCellularPermission(bool allowed);
+  bool GetUpdateOverCellularPermission();
+
+  // Getter and setter for the updates from P2P permission.
+  // Blocking call. Exits the program with error 1 in case of an error.
+  void SetP2PUpdatePermission(bool enabled);
+  bool GetP2PUpdatePermission();
+
+  // This is similar to watching for updates but rather than registering
+  // a signal watch, actively poll the daemon just in case it stops
+  // sending notifications.
+  void WaitForUpdateComplete();
+  void OnUpdateCompleteCheck(int64_t last_checked_time,
+                             double progress,
+                             const string& current_operation,
+                             const string& new_version,
+                             int64_t new_size);
+
+  // Blocking call. Exits the program with error 1 in case of an error.
+  void ShowPrevVersion();
+
+  // Returns whether the current status is such that a reboot is needed.
+  // Blocking call. Exits the program with error 1 in case of an error.
+  bool GetIsRebootNeeded();
+
+  // Blocks until a reboot is needed. If the reboot is needed, exits the program
+  // with 0. Otherwise it exits the program with 1 if an error occurs before
+  // the reboot is needed.
+  void WaitForRebootNeeded();
+  void OnRebootNeededCheck(int64_t last_checked_time,
+                           double progress,
+                           const string& current_operation,
+                           const string& new_version,
+                           int64_t new_size);
+  // Callback called when the OnRebootNeededCheck() handler is registered. This
+  // is useful to check at this point if the reboot is needed, without loosing
+  // any StatusUpdate signals and avoiding the race condition.
+  void OnRebootNeededCheckRegistration(const string& interface,
+                                       const string& signal_name,
+                                       bool success);
+
+  // Main method that parses and triggers all the actions based on the passed
+  // flags.
+  int ProcessFlags();
+
+  // DBus Proxy to the update_engine daemon object used for all the calls.
+  std::unique_ptr<org::chromium::UpdateEngineInterfaceProxy> proxy_;
+
+  // Copy of argc and argv passed to main().
+  int argc_;
+  char** argv_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateEngineClient);
+};
+
+
+bool UpdateEngineClient::InitProxy() {
+  proxy_.reset(new org::chromium::UpdateEngineInterfaceProxy(bus_));
+
+  if (!proxy_->GetObjectProxy()) {
+    LOG(ERROR) << "Error getting dbus proxy for " << kUpdateEngineServiceName;
+    return false;
   }
-  *out_proxy = proxy;
   return true;
 }
 
-static void StatusUpdateSignalHandler(DBusGProxy* proxy,
-                                      int64_t last_checked_time,
-                                      double progress,
-                                      gchar* current_operation,
-                                      gchar* new_version,
-                                      int64_t new_size,
-                                      void* user_data) {
+void UpdateEngineClient::OnStatusUpdateSignal(
+    int64_t last_checked_time,
+    double progress,
+    const string& current_operation,
+    const string& new_version,
+    int64_t new_size) {
   LOG(INFO) << "Got status update:";
   LOG(INFO) << "  last_checked_time: " << last_checked_time;
   LOG(INFO) << "  progress: " << progress;
@@ -80,420 +180,217 @@
   LOG(INFO) << "  new_size: " << new_size;
 }
 
-bool ResetStatus() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean rc = update_engine_client_reset_status(proxy, &error);
-  return rc;
+void UpdateEngineClient::OnStatusUpdateSignalRegistration(
+    const string& interface,
+    const string& signal_name,
+    bool success) {
+  VLOG(1) << "OnStatusUpdateSignalRegistration(" << interface << ", "
+          << signal_name << ", " << success << ");";
+  if (!success) {
+    LOG(ERROR) << "Couldn't connect to the " << signal_name << " signal.";
+    exit(1);
+  }
 }
 
+void UpdateEngineClient::WatchForUpdates() {
+  proxy_->RegisterStatusUpdateSignalHandler(
+      base::Bind(&UpdateEngineClient::OnStatusUpdateSignal,
+                 base::Unretained(this)),
+      base::Bind(&UpdateEngineClient::OnStatusUpdateSignalRegistration,
+                 base::Unretained(this)));
+}
 
-// 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) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
+void UpdateEngineClient::ResetStatus() {
+  bool ret = proxy_->ResetStatus(nullptr);
+  CHECK(ret) << "ResetStatus() failed.";
+}
 
-  CHECK(GetProxy(&proxy));
+void UpdateEngineClient::ShowStatus() {
+  int64_t last_checked_time = 0;
+  double progress = 0.0;
+  string current_op;
+  string new_version;
+  int64_t new_size = 0;
 
-  gint64 last_checked_time = 0;
-  gdouble progress = 0.0;
-  char* current_op = nullptr;
-  char* new_version = nullptr;
-  gint64 new_size = 0;
-
-  gboolean rc = update_engine_client_get_status(proxy,
-                                                &last_checked_time,
-                                                &progress,
-                                                &current_op,
-                                                &new_version,
-                                                &new_size,
-                                                &error);
-  if (rc == FALSE) {
-    LOG(INFO) << "Error getting status: " << GetAndFreeGError(&error);
-  }
+  bool ret = proxy_->GetStatus(
+      &last_checked_time, &progress, &current_op, &new_version, &new_size,
+      nullptr);
+  CHECK(ret) << "GetStatus() failed";
   printf("LAST_CHECKED_TIME=%" PRIi64 "\nPROGRESS=%f\nCURRENT_OP=%s\n"
          "NEW_VERSION=%s\nNEW_SIZE=%" PRIi64 "\n",
          last_checked_time,
          progress,
-         current_op,
-         new_version,
+         current_op.c_str(),
+         new_version.c_str(),
          new_size);
-  if (op) {
-    *op = current_op ? current_op : "";
+}
+
+string UpdateEngineClient::GetCurrentOperation() {
+  int64_t last_checked_time = 0;
+  double progress = 0.0;
+  string current_op;
+  string new_version;
+  int64_t new_size = 0;
+
+  bool ret = proxy_->GetStatus(
+      &last_checked_time, &progress, &current_op, &new_version, &new_size,
+      nullptr);
+  CHECK(ret) << "GetStatus() failed";
+  return current_op;
+}
+
+void UpdateEngineClient::Rollback(bool rollback) {
+  bool ret = proxy_->AttemptRollback(rollback, nullptr);
+  CHECK(ret) << "Rollback request failed.";
+}
+
+string UpdateEngineClient::GetRollbackPartition() {
+  string rollback_partition;
+  bool ret = proxy_->GetRollbackPartition(&rollback_partition, nullptr);
+  CHECK(ret) << "Error while querying rollback partition availabilty.";
+  return rollback_partition;
+}
+
+string UpdateEngineClient::GetKernelDevices() {
+  string kernel_devices;
+  bool ret = proxy_->GetKernelDevices(&kernel_devices, nullptr);
+  CHECK(ret) << "Error while getting a list of kernel devices";
+  return kernel_devices;
+}
+
+void UpdateEngineClient::CheckForUpdates(const string& app_version,
+                                         const string& omaha_url,
+                                         bool interactive) {
+  int32_t flags = interactive ? 0 : kAttemptUpdateFlagNonInteractive;
+  bool ret = proxy_->AttemptUpdateWithFlags(app_version, omaha_url, flags,
+                                            nullptr);
+  CHECK(ret) << "Error checking for update.";
+}
+
+void UpdateEngineClient::RebootIfNeeded() {
+  bool ret = proxy_->RebootIfNeeded(nullptr);
+  if (!ret) {
+    // Reboot error code doesn't necessarily mean that a reboot
+    // failed. For example, D-Bus may be shutdown before we receive the
+    // result.
+    LOG(INFO) << "RebootIfNeeded() failure ignored.";
   }
-  return true;
 }
 
-// Should never return.
-void WatchForUpdates() {
-  DBusGProxy* proxy;
-
-  CHECK(GetProxy(&proxy));
-
-  // Register marshaller
-  dbus_g_object_register_marshaller(
-      g_cclosure_marshal_generic,
-      G_TYPE_NONE,
-      G_TYPE_INT64,
-      G_TYPE_DOUBLE,
-      G_TYPE_STRING,
-      G_TYPE_STRING,
-      G_TYPE_INT64,
-      G_TYPE_INVALID);
-
-  static const char kStatusUpdate[] = "StatusUpdate";
-  dbus_g_proxy_add_signal(proxy,
-                          kStatusUpdate,
-                          G_TYPE_INT64,
-                          G_TYPE_DOUBLE,
-                          G_TYPE_STRING,
-                          G_TYPE_STRING,
-                          G_TYPE_INT64,
-                          G_TYPE_INVALID);
-  GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
-  dbus_g_proxy_connect_signal(proxy,
-                              kStatusUpdate,
-                              G_CALLBACK(StatusUpdateSignalHandler),
-                              nullptr,
-                              nullptr);
-  g_main_loop_run(loop);
-  g_main_loop_unref(loop);
-}
-
-bool Rollback(bool rollback) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean rc = update_engine_client_attempt_rollback(proxy,
-                                                      rollback,
-                                                      &error);
-  CHECK_EQ(rc, TRUE) << "Error with rollback request: "
-                     << GetAndFreeGError(&error);
-  return true;
-}
-
-string GetRollbackPartition() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  char* rollback_partition = nullptr;
-  gboolean rc = update_engine_client_get_rollback_partition(proxy,
-                                                            &rollback_partition,
-                                                            &error);
-  CHECK_EQ(rc, TRUE) << "Error while querying rollback partition availabilty: "
-                     << GetAndFreeGError(&error);
-  string partition = rollback_partition;
-  g_free(rollback_partition);
-  return partition;
-}
-
-string GetKernelDevices() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  char* kernel_devices = nullptr;
-  gboolean rc = update_engine_client_get_kernel_devices(proxy,
-                                                        &kernel_devices,
-                                                        &error);
-  CHECK_EQ(rc, TRUE) << "Error while getting a list of kernel devices: "
-    << GetAndFreeGError(&error);
-  string devices = kernel_devices;
-  g_free(kernel_devices);
-  return devices;
-}
-
-bool CheckForUpdates(const string& app_version,
-                     const string& omaha_url,
-                     bool interactive) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  AttemptUpdateFlags flags = static_cast<AttemptUpdateFlags>(
-      interactive ? 0 : kAttemptUpdateFlagNonInteractive);
-  gboolean rc =
-      update_engine_client_attempt_update_with_flags(proxy,
-                                                     app_version.c_str(),
-                                                     omaha_url.c_str(),
-                                                     static_cast<gint>(flags),
-                                                     &error);
-  CHECK_EQ(rc, TRUE) << "Error checking for update: "
-                     << GetAndFreeGError(&error);
-  return true;
-}
-
-bool RebootIfNeeded() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean rc =
-      update_engine_client_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: " << GetAndFreeGError(&error);
-  return true;
-}
-
-void SetTargetChannel(const string& target_channel, bool allow_powerwash) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean rc = update_engine_client_set_channel(proxy,
-                                                 target_channel.c_str(),
-                                                 allow_powerwash,
-                                                 &error);
-  CHECK_EQ(rc, true) << "Error setting the channel: "
-                     << GetAndFreeGError(&error);
+void UpdateEngineClient::SetTargetChannel(const string& target_channel,
+                                          bool allow_powerwash) {
+  bool ret = proxy_->SetChannel(target_channel, allow_powerwash, nullptr);
+  CHECK(ret) << "Error setting the channel.";
   LOG(INFO) << "Channel permanently set to: " << target_channel;
 }
 
-string GetChannel(bool get_current_channel) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  char* channel = nullptr;
-  gboolean rc = update_engine_client_get_channel(proxy,
-                                                 get_current_channel,
-                                                 &channel,
-                                                 &error);
-  CHECK_EQ(rc, true) << "Error getting the channel: "
-                     << GetAndFreeGError(&error);
-  string output = channel;
-  g_free(channel);
-  return output;
+string UpdateEngineClient::GetChannel(bool get_current_channel) {
+  string channel;
+  bool ret = proxy_->GetChannel(get_current_channel, &channel, nullptr);
+  CHECK(ret) << "Error getting the channel.";
+  return channel;
 }
 
-void SetUpdateOverCellularPermission(gboolean allowed) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean rc = update_engine_client_set_update_over_cellular_permission(
-      proxy,
-      allowed,
-      &error);
-  CHECK_EQ(rc, true) << "Error setting the update over cellular setting: "
-                     << GetAndFreeGError(&error);
+void UpdateEngineClient::SetUpdateOverCellularPermission(bool allowed) {
+  bool ret = proxy_->SetUpdateOverCellularPermission(allowed, nullptr);
+  CHECK(ret) << "Error setting the update over cellular setting.";
 }
 
-bool GetUpdateOverCellularPermission() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean allowed;
-  gboolean rc = update_engine_client_get_update_over_cellular_permission(
-      proxy,
-      &allowed,
-      &error);
-  CHECK_EQ(rc, true) << "Error getting the update over cellular setting: "
-                     << GetAndFreeGError(&error);
+bool UpdateEngineClient::GetUpdateOverCellularPermission() {
+  bool allowed;
+  bool ret = proxy_->GetUpdateOverCellularPermission(&allowed, nullptr);
+  CHECK(ret) << "Error getting the update over cellular setting.";
   return allowed;
 }
 
-void SetP2PUpdatePermission(gboolean enabled) {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean rc = update_engine_client_set_p2p_update_permission(
-      proxy,
-      enabled,
-      &error);
-  CHECK_EQ(rc, true) << "Error setting the peer-to-peer update setting: "
-                     << GetAndFreeGError(&error);
+void UpdateEngineClient::SetP2PUpdatePermission(bool enabled) {
+  bool ret = proxy_->SetP2PUpdatePermission(enabled, nullptr);
+  CHECK(ret) << "Error setting the peer-to-peer update setting.";
 }
 
-bool GetP2PUpdatePermission() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
-
-  CHECK(GetProxy(&proxy));
-
-  gboolean enabled;
-  gboolean rc = update_engine_client_get_p2p_update_permission(
-      proxy,
-      &enabled,
-      &error);
-  CHECK_EQ(rc, true) << "Error getting the peer-to-peer update setting: "
-                     << GetAndFreeGError(&error);
+bool UpdateEngineClient::GetP2PUpdatePermission() {
+  bool enabled;
+  bool ret = proxy_->GetP2PUpdatePermission(&enabled, nullptr);
+  CHECK(ret) << "Error getting the peer-to-peer update setting.";
   return enabled;
 }
 
-static gboolean CompleteUpdateSource(gpointer data) {
-  string current_op;
-  if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
-    LOG(ERROR) << "Update failed.";
+void UpdateEngineClient::OnUpdateCompleteCheck(
+    int64_t /* last_checked_time */,
+    double /* progress */,
+    const string& current_operation,
+    const string& /* new_version */,
+    int64_t /* new_size */) {
+  if (current_operation == update_engine::kUpdateStatusIdle) {
+    LOG(ERROR) << "Update failed, current operations is " << current_operation;
     exit(1);
   }
-  if (current_op == "UPDATE_STATUS_UPDATED_NEED_REBOOT") {
+  if (current_operation == update_engine::kUpdateStatusUpdatedNeedReboot) {
     LOG(INFO) << "Update succeeded -- reboot needed.";
     exit(0);
   }
-  return TRUE;
 }
 
-// This is similar to watching for updates but rather than registering
-// a signal watch, actively poll the daemon just in case it stops
-// sending notifications.
-void CompleteUpdate() {
-  GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
-  g_timeout_add_seconds(5, CompleteUpdateSource, nullptr);
-  g_main_loop_run(loop);
-  g_main_loop_unref(loop);
+void UpdateEngineClient::WaitForUpdateComplete() {
+  proxy_->RegisterStatusUpdateSignalHandler(
+      base::Bind(&UpdateEngineClient::OnUpdateCompleteCheck,
+                 base::Unretained(this)),
+      base::Bind(&UpdateEngineClient::OnStatusUpdateSignalRegistration,
+                 base::Unretained(this)));
 }
 
-void ShowPrevVersion() {
-  DBusGProxy* proxy;
-  GError* error = nullptr;
+void UpdateEngineClient::ShowPrevVersion() {
+  string prev_version = nullptr;
 
-  CHECK(GetProxy(&proxy));
-
-  char* prev_version = nullptr;
-
-  gboolean rc = update_engine_client_get_prev_version(proxy,
-                                                      &prev_version,
-                                                      &error);
-  if (!rc) {
-    LOG(ERROR) << "Error getting previous version: "
-               << GetAndFreeGError(&error);
+  bool ret = proxy_->GetPrevVersion(&prev_version, nullptr);;
+  if (!ret) {
+    LOG(ERROR) << "Error getting previous version.";
   } else {
     LOG(INFO) << "Previous version = " << prev_version;
-    g_free(prev_version);
   }
 }
 
-bool CheckIfRebootIsNeeded(DBusGProxy *proxy, bool *out_reboot_needed) {
-  gint64 last_checked_time = 0;
-  gdouble progress = 0.0;
-  char* current_op = nullptr;
-  char* new_version = nullptr;
-  gint64 new_size = 0;
-  GError* error = nullptr;
-
-  if (!update_engine_client_get_status(proxy,
-                                       &last_checked_time,
-                                       &progress,
-                                       &current_op,
-                                       &new_version,
-                                       &new_size,
-                                       &error)) {
-    LOG(INFO) << "Error getting status: " << GetAndFreeGError(&error);
-    return false;
-  }
-  *out_reboot_needed =
-      (g_strcmp0(current_op,
-                 update_engine::kUpdateStatusUpdatedNeedReboot) == 0);
-  g_free(current_op);
-  g_free(new_version);
-  return true;
+bool UpdateEngineClient::GetIsRebootNeeded() {
+  return GetCurrentOperation() == update_engine::kUpdateStatusUpdatedNeedReboot;
 }
 
-// Determines if reboot is needed. The result is returned in
-// |out_reboot_needed|. Returns true if the check succeeded, false
-// otherwise.
-bool IsRebootNeeded(bool *out_reboot_needed) {
-  DBusGProxy* proxy = nullptr;
-  CHECK(GetProxy(&proxy));
-  bool ret = CheckIfRebootIsNeeded(proxy, out_reboot_needed);
-  g_object_unref(proxy);
-  return ret;
-}
-
-static void OnBlockUntilRebootStatusCallback(
-    DBusGProxy* proxy,
-    int64_t last_checked_time,
-    double progress,
-    const gchar* current_operation,
-    const gchar* new_version,
-    int64_t new_size,
-    void* user_data) {
-  GMainLoop *loop = reinterpret_cast<GMainLoop*>(user_data);
-  if (g_strcmp0(current_operation,
-                update_engine::kUpdateStatusUpdatedNeedReboot) == 0) {
-    g_main_loop_quit(loop);
+void UpdateEngineClient::OnRebootNeededCheck(
+    int64_t /* last_checked_time */,
+    double /* progress */,
+    const string& current_operation,
+    const string& /* new_version */,
+    int64_t /* new_size */) {
+  if (current_operation == update_engine::kUpdateStatusUpdatedNeedReboot) {
+    LOG(INFO) << "Reboot needed.";
+    exit(0);
   }
 }
 
-bool CheckRebootNeeded(DBusGProxy *proxy, GMainLoop *loop) {
-  bool reboot_needed;
-  if (!CheckIfRebootIsNeeded(proxy, &reboot_needed))
-    return false;
-  if (reboot_needed)
-    return true;
-  // This will block until OnBlockUntilRebootStatusCallback() calls
-  // g_main_loop_quit().
-  g_main_loop_run(loop);
-  return true;
+void UpdateEngineClient::OnRebootNeededCheckRegistration(
+    const string& interface,
+    const string& signal_name,
+    bool success) {
+  if (GetIsRebootNeeded())
+    exit(0);
+  if (!success) {
+    LOG(ERROR) << "Couldn't connect to the " << signal_name << " signal.";
+    exit(1);
+  }
 }
 
 // Blocks until a reboot is needed. Returns true if waiting succeeded,
 // false if an error occurred.
-bool BlockUntilRebootIsNeeded() {
-  // The basic idea is to get a proxy, listen to signals and only then
-  // check the status. If no reboot is needed, just sit and wait for
-  // the StatusUpdate signal to convey that a reboot is pending.
-  DBusGProxy* proxy = nullptr;
-  CHECK(GetProxy(&proxy));
-  dbus_g_object_register_marshaller(
-      g_cclosure_marshal_generic,
-      G_TYPE_NONE,
-      G_TYPE_INT64,
-      G_TYPE_DOUBLE,
-      G_TYPE_STRING,
-      G_TYPE_STRING,
-      G_TYPE_INT64,
-      G_TYPE_INVALID);
-  dbus_g_proxy_add_signal(proxy,
-                          update_engine::kStatusUpdate,  // Signal name.
-                          G_TYPE_INT64,
-                          G_TYPE_DOUBLE,
-                          G_TYPE_STRING,
-                          G_TYPE_STRING,
-                          G_TYPE_INT64,
-                          G_TYPE_INVALID);
-  GMainLoop* loop = g_main_loop_new(nullptr, TRUE);
-  dbus_g_proxy_connect_signal(proxy,
-                              update_engine::kStatusUpdate,
-                              G_CALLBACK(OnBlockUntilRebootStatusCallback),
-                              loop,
-                              nullptr);  // free_data_func.
-
-  bool ret = CheckRebootNeeded(proxy, loop);
-
-  dbus_g_proxy_disconnect_signal(proxy,
-                                 update_engine::kStatusUpdate,
-                                 G_CALLBACK(OnBlockUntilRebootStatusCallback),
-                                 loop);
-  g_main_loop_unref(loop);
-  g_object_unref(proxy);
-  return ret;
+void UpdateEngineClient::WaitForRebootNeeded() {
+  proxy_->RegisterStatusUpdateSignalHandler(
+      base::Bind(&UpdateEngineClient::OnUpdateCompleteCheck,
+                 base::Unretained(this)),
+      base::Bind(&UpdateEngineClient::OnStatusUpdateSignalRegistration,
+                 base::Unretained(this)));
+  if (GetIsRebootNeeded())
+    exit(0);
 }
 
-}  // namespace
-
-int main(int argc, char** argv) {
+int UpdateEngineClient::ProcessFlags() {
   DEFINE_string(app_version, "", "Force the current app version.");
   DEFINE_string(channel, "",
                 "Set the target channel. The device will be powerwashed if the "
@@ -539,9 +436,8 @@
               "whether each of them is bootable or not");
 
   // Boilerplate init commands.
-  g_type_init();
-  dbus_threads_init_default();
-  chromeos::FlagHelper::Init(argc, argv, "Chromium OS Update Engine Client");
+  base::CommandLine::Init(argc_, argv_);
+  chromeos::FlagHelper::Init(argc_, argv_, "Chromium OS Update Engine Client");
 
   // Ensure there are no positional arguments.
   const std::vector<string> positional_args =
@@ -556,10 +452,7 @@
   // 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;
-    }
+    ResetStatus();
     LOG(INFO) << "ResetStatus succeeded; to undo partition table changes run:\n"
                  "(D=$(rootdev -d) P=$(rootdev -s); cgpt p -i$(($(echo ${P#$D} "
                  "| sed 's/^[^0-9]*//')-1)) $D;)";
@@ -567,7 +460,7 @@
 
   // Changes the current update over cellular network setting.
   if (!FLAGS_update_over_cellular.empty()) {
-    gboolean allowed = FLAGS_update_over_cellular == "yes";
+    bool allowed = FLAGS_update_over_cellular == "yes";
     if (!allowed && FLAGS_update_over_cellular != "no") {
       LOG(ERROR) << "Unknown option: \"" << FLAGS_update_over_cellular
                  << "\". Please specify \"yes\" or \"no\".";
@@ -590,7 +483,7 @@
 
   // Change the P2P enabled setting.
   if (!FLAGS_p2p_update.empty()) {
-    gboolean enabled = FLAGS_p2p_update == "yes";
+    bool enabled = FLAGS_p2p_update == "yes";
     if (!enabled && FLAGS_p2p_update != "no") {
       LOG(ERROR) << "Unknown option: \"" << FLAGS_p2p_update
                  << "\". Please specify \"yes\" or \"no\".";
@@ -650,7 +543,7 @@
 
   if (FLAGS_rollback) {
     LOG(INFO) << "Requesting rollback.";
-    CHECK(Rollback(FLAGS_powerwash)) << "Request for rollback failed.";
+    Rollback(FLAGS_powerwash);
   }
 
   // Initiate an update check, if necessary.
@@ -662,8 +555,7 @@
       LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
     }
     LOG(INFO) << "Initiating update check and install.";
-    CHECK(CheckForUpdates(app_version, FLAGS_omaha_url, FLAGS_interactive))
-        << "Update check/initiate update failed.";
+    CheckForUpdates(app_version, FLAGS_omaha_url, FLAGS_interactive);
   }
 
   // These final options are all mutually exclusive with one another.
@@ -679,28 +571,25 @@
 
   if (FLAGS_status) {
     LOG(INFO) << "Querying Update Engine status...";
-    if (!GetStatus(nullptr)) {
-      LOG(ERROR) << "GetStatus failed.";
-      return 1;
-    }
+    ShowStatus();
     return 0;
   }
 
   if (FLAGS_follow) {
     LOG(INFO) << "Waiting for update to complete.";
-    CompleteUpdate();  // Should never return.
-    return 1;
+    WaitForUpdateComplete();
+    return kContinueRunning;
   }
 
   if (FLAGS_watch_for_updates) {
     LOG(INFO) << "Watching for status updates.";
-    WatchForUpdates();  // Should never return.
-    return 1;
+    WatchForUpdates();
+    return kContinueRunning;
   }
 
   if (FLAGS_reboot) {
     LOG(INFO) << "Requesting a reboot...";
-    CHECK(RebootIfNeeded());
+    RebootIfNeeded();
     return 0;
   }
 
@@ -714,18 +603,25 @@
   }
 
   if (FLAGS_is_reboot_needed) {
-    bool reboot_needed = false;
-    if (!IsRebootNeeded(&reboot_needed))
-      return 1;
-    else if (!reboot_needed)
+    // In case of error GetIsRebootNeeded() will exit with 1.
+    if (GetIsRebootNeeded()) {
+      return 0;
+    } else {
       return 2;
+    }
   }
 
   if (FLAGS_block_until_reboot_is_needed) {
-    if (!BlockUntilRebootIsNeeded())
-      return 1;
+    WaitForRebootNeeded();
+    return kContinueRunning;
   }
 
-  LOG(INFO) << "Done.";
   return 0;
 }
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  UpdateEngineClient client(argc, argv);
+  return client.Run();
+}