Introduce status handlers and use them in client

We introduce a StatusUpdateHandler class which can be overridden to
provide a method with which to react to status updates. This replaces
manual dbus logic in several places in update_engine_client with a
consistent interface for asynchronously handling status updates.

Change-Id: Idca4229de82074fb7a87a315b45dd0292c1b1f16
Test: Confirmed --update blocks and resumes correctly
Bug: 26233663
diff --git a/client_library/client_impl.cc b/client_library/client_impl.cc
index 7b80025..247f8f0 100644
--- a/client_library/client_impl.cc
+++ b/client_library/client_impl.cc
@@ -40,10 +40,8 @@
                                            const string& in_omaha_url,
                                            bool at_user_request) {
   return proxy_->AttemptUpdateWithFlags(
-      in_app_version,
-      in_omaha_url,
-      (at_user_request) ? 0 : kAttemptUpdateFlagNonInteractive,
-      nullptr);
+      in_app_version, in_omaha_url,
+      (at_user_request) ? 0 : kAttemptUpdateFlagNonInteractive, nullptr);
 }
 
 bool UpdateEngineClientImpl::GetStatus(int64_t* out_last_checked_time,
@@ -52,13 +50,9 @@
                                        string* out_new_version,
                                        int64_t* out_new_size) {
   string status_as_string;
-  const bool success = proxy_->GetStatus(
-      out_last_checked_time,
-      out_progress,
-      &status_as_string,
-      out_new_version,
-      out_new_size,
-      nullptr);
+  const bool success =
+      proxy_->GetStatus(out_last_checked_time, out_progress, &status_as_string,
+                        out_new_version, out_new_size, nullptr);
   if (!success) {
     return false;
   }
@@ -70,7 +64,7 @@
   return proxy_->SetUpdateOverCellularPermission(allowed, nullptr);
 }
 
-bool UpdateEngineClientImpl::GetUpdateOverCellularPermission(bool *allowed) {
+bool UpdateEngineClientImpl::GetUpdateOverCellularPermission(bool* allowed) {
   return proxy_->GetUpdateOverCellularPermission(allowed, nullptr);
 }
 
@@ -108,26 +102,63 @@
   return proxy_->ResetStatus(nullptr);
 }
 
+void UpdateEngineClientImpl::StatusUpdateHandlerRegistered(
+    StatusUpdateHandler* handler, const std::string& interface,
+    const std::string& signal_name, bool success) {
+  if (!success) {
+    handler->IPCError("Could not connect to" + signal_name);
+    return;
+  }
+
+  int64_t last_checked_time;
+  double progress;
+  UpdateStatus update_status;
+  string new_version;
+  int64_t new_size;
+
+  if (GetStatus(&last_checked_time, &progress, &update_status, &new_version,
+                &new_size)) {
+    handler->HandleStatusUpdate(last_checked_time, progress, update_status,
+                                new_version, new_size);
+    return;
+  }
+
+  handler->IPCError("Could not query current status");
+}
+
+void UpdateEngineClientImpl::RunStatusUpdateHandler(
+    StatusUpdateHandler* h, int64_t last_checked_time, double progress,
+    const std::string& current_operation, const std::string& new_version,
+    int64_t new_size) {
+  UpdateStatus status;
+  StringToUpdateStatus(current_operation, &status);
+
+  h->HandleStatusUpdate(last_checked_time, progress, status, new_version,
+                        new_size);
+}
+
+void UpdateEngineClientImpl::RegisterStatusUpdateHandler(
+    StatusUpdateHandler* handler) {
+  proxy_->RegisterStatusUpdateSignalHandler(
+      base::Bind(&UpdateEngineClientImpl::RunStatusUpdateHandler,
+                 base::Unretained(this), base::Unretained(handler)),
+      base::Bind(&UpdateEngineClientImpl::StatusUpdateHandlerRegistered,
+                 base::Unretained(this), base::Unretained(handler)));
+}
+
 bool UpdateEngineClientImpl::SetTargetChannel(const string& in_target_channel,
                                               bool allow_powerwash) {
-  return proxy_->SetChannel(
-      in_target_channel,
-      allow_powerwash,
-      nullptr);
+  return proxy_->SetChannel(in_target_channel, allow_powerwash, nullptr);
 }
 
 bool UpdateEngineClientImpl::GetTargetChannel(string* out_channel) {
-  return proxy_->GetChannel(
-      false,  // Get the target channel.
-      out_channel,
-      nullptr);
+  return proxy_->GetChannel(false,  // Get the target channel.
+                            out_channel, nullptr);
 }
 
 bool UpdateEngineClientImpl::GetChannel(string* out_channel) {
-  return proxy_->GetChannel(
-      true,  // Get the current channel.
-      out_channel,
-      nullptr);
+  return proxy_->GetChannel(true,  // Get the current channel.
+                            out_channel, nullptr);
 }
 
 }  // namespace internal
diff --git a/client_library/client_impl.h b/client_library/client_impl.h
index 4886692..03c8f3c 100644
--- a/client_library/client_impl.h
+++ b/client_library/client_impl.h
@@ -67,9 +67,23 @@
 
   bool GetChannel(std::string* out_channel) override;
 
+  void RegisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
+
  private:
   std::unique_ptr<org::chromium::UpdateEngineInterfaceProxy> proxy_;
 
+  void StatusUpdateHandlerRegistered(StatusUpdateHandler* handler,
+                                     const std::string& interface,
+                                     const std::string& signal_name,
+                                     bool success);
+
+  void RunStatusUpdateHandler(StatusUpdateHandler* handler,
+                              int64_t last_checked_time,
+                              double progress,
+                              const std::string& current_operation,
+                              const std::string& new_version,
+                              int64_t new_size);
+
   DISALLOW_COPY_AND_ASSIGN(UpdateEngineClientImpl);
 };  // class UpdateEngineClientImpl
 
diff --git a/client_library/include/update_engine/client.h b/client_library/include/update_engine/client.h
index 604cc5a..4d264c8 100644
--- a/client_library/include/update_engine/client.h
+++ b/client_library/include/update_engine/client.h
@@ -21,6 +21,7 @@
 #include <memory>
 #include <string>
 
+#include "update_engine/status_update_handler.h"
 #include "update_engine/update_status.h"
 
 namespace update_engine {
@@ -100,6 +101,13 @@
   // Get the channel the device is currently on.
   virtual bool GetChannel(std::string* out_channel) = 0;
 
+  // Handle status updates. The handler must exist until the client is
+  // destroyed. Its IPCError method will be called if the handler could
+  // not be registered. Otherwise its HandleStatusUpdate method will be called
+  // every time update_engine's status changes. Will always report the status
+  // on registration to prevent race conditions.
+  virtual void RegisterStatusUpdateHandler(StatusUpdateHandler* handler) = 0;
+
  protected:
   // Use CreateInstance().
   UpdateEngineClient() = default;
diff --git a/client_library/include/update_engine/status_update_handler.h b/client_library/include/update_engine/status_update_handler.h
new file mode 100644
index 0000000..d5b8cdb
--- /dev/null
+++ b/client_library/include/update_engine/status_update_handler.h
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_CLIENT_LIBRARY_INCLUDE_STATUS_UPDATE_HANDLER_H_
+#define UPDATE_ENGINE_CLIENT_LIBRARY_INCLUDE_STATUS_UPDATE_HANDLER_H_
+
+#include <string>
+
+#include "update_engine/client.h"
+#include "update_engine/update_status.h"
+
+namespace update_engine {
+
+// Handles update_engine status changes. An instance of this class can be
+// registered with UpdateEngineClient and will respond to any update_engine
+// status changes.
+class StatusUpdateHandler {
+ public:
+  virtual ~StatusUpdateHandler() = default;
+
+  // Runs when we fail to register the handler due to an IPC error.
+  virtual void IPCError(const std::string& error) = 0;
+
+  // Runs every time update_engine reports a status change.
+  virtual void HandleStatusUpdate(int64_t last_checked_time,
+                                  double progress,
+                                  UpdateStatus current_operation,
+                                  const std::string& new_version,
+                                  int64_t new_size) = 0;
+};
+
+}  // namespace update_engine
+
+#endif  // UPDATE_ENGINE_CLIENT_LIBRARY_INCLUDE_STATUS_UPDATE_HANDLER_H_