Start action processing asynchronously in UpdateAttempter.

This is done so that we unblock the event loop on dbus calls.

BUG=chromium-os:12758
TEST=unit tests, tested updating the device

Change-Id: I38d9869afb392264a020fc6c653a20622fd38ada

Review URL: http://codereview.chromium.org/6624082
diff --git a/update_attempter.cc b/update_attempter.cc
index e49a551..c9ee712 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -248,7 +248,9 @@
               postinstall_runner_action.get());
 
   SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
-  processor_->StartProcessing();
+
+  // Start the processing asynchronously to unblock the event loop.
+  g_idle_add(&StaticStartProcessing, this);
 }
 
 void UpdateAttempter::CheckForUpdate(const std::string& app_version,
@@ -527,6 +529,11 @@
   return reinterpret_cast<UpdateAttempter*>(data)->ManagePriorityCallback();
 }
 
+gboolean UpdateAttempter::StaticStartProcessing(gpointer data) {
+  reinterpret_cast<UpdateAttempter*>(data)->processor_->StartProcessing();
+  return FALSE;  // Don't call this callback again.
+}
+
 bool UpdateAttempter::ManagePriorityCallback() {
   SetPriority(utils::kProcessPriorityNormal);
   manage_priority_source_ = NULL;
diff --git a/update_attempter.h b/update_attempter.h
index 0afe7f6..e41cab9 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -158,6 +158,9 @@
   static gboolean StaticManagePriorityCallback(gpointer data);
   bool ManagePriorityCallback();
 
+  // Callback to start the action processor.
+  static gboolean StaticStartProcessing(gpointer data);
+
   // Checks if a full update is needed and forces it by updating the Omaha
   // request params.
   void DisableDeltaUpdateIfNeeded();
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 76068fd..73addb5 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -39,7 +39,7 @@
 
 class UpdateAttempterTest : public ::testing::Test {
  protected:
-  UpdateAttempterTest() : attempter_(&dbus_) {}
+  UpdateAttempterTest() : attempter_(&dbus_), loop_(NULL) {}
   virtual void SetUp() {
     EXPECT_EQ(NULL, attempter_.dbus_service_);
     EXPECT_EQ(NULL, attempter_.prefs_);
@@ -60,10 +60,16 @@
     attempter_.prefs_ = &prefs_;
   }
 
+  void UpdateTestStart();
+  void UpdateTestVerify();
+  static gboolean StaticUpdateTestStart(gpointer data);
+  static gboolean StaticUpdateTestVerify(gpointer data);
+
   MockDbusGlib dbus_;
   UpdateAttempterUnderTest attempter_;
   ActionProcessorMock* processor_;
   NiceMock<PrefsMock> prefs_;
+  GMainLoop* loop_;
 };
 
 TEST_F(UpdateAttempterTest, ActionCompletedDownloadTest) {
@@ -227,22 +233,35 @@
                UpdateStatusToString(static_cast<UpdateStatus>(-1)));
 }
 
-TEST_F(UpdateAttempterTest, UpdateTest) {
+gboolean UpdateAttempterTest::StaticUpdateTestStart(gpointer data) {
+  reinterpret_cast<UpdateAttempterTest*>(data)->UpdateTestStart();
+  return FALSE;
+}
+
+gboolean UpdateAttempterTest::StaticUpdateTestVerify(gpointer data) {
+  reinterpret_cast<UpdateAttempterTest*>(data)->UpdateTestVerify();
+  return FALSE;
+}
+
+namespace {
+const string kActionTypes[] = {
+  OmahaRequestAction::StaticType(),
+  OmahaResponseHandlerAction::StaticType(),
+  FilesystemCopierAction::StaticType(),
+  FilesystemCopierAction::StaticType(),
+  OmahaRequestAction::StaticType(),
+  DownloadAction::StaticType(),
+  OmahaRequestAction::StaticType(),
+  FilesystemCopierAction::StaticType(),
+  FilesystemCopierAction::StaticType(),
+  PostinstallRunnerAction::StaticType(),
+  OmahaRequestAction::StaticType()
+};
+}  // namespace {}
+
+void UpdateAttempterTest::UpdateTestStart() {
   attempter_.set_http_response_code(200);
   InSequence s;
-  const string kActionTypes[] = {
-    OmahaRequestAction::StaticType(),
-    OmahaResponseHandlerAction::StaticType(),
-    FilesystemCopierAction::StaticType(),
-    FilesystemCopierAction::StaticType(),
-    OmahaRequestAction::StaticType(),
-    DownloadAction::StaticType(),
-    OmahaRequestAction::StaticType(),
-    FilesystemCopierAction::StaticType(),
-    FilesystemCopierAction::StaticType(),
-    PostinstallRunnerAction::StaticType(),
-    OmahaRequestAction::StaticType()
-  };
   for (size_t i = 0; i < arraysize(kActionTypes); ++i) {
     EXPECT_CALL(*processor_,
                 EnqueueAction(Property(&AbstractAction::Type,
@@ -251,7 +270,10 @@
   EXPECT_CALL(*processor_, StartProcessing()).Times(1);
 
   attempter_.Update("", "", false);
+  g_idle_add(&StaticUpdateTestVerify, this);
+}
 
+void UpdateAttempterTest::UpdateTestVerify() {
   EXPECT_EQ(0, attempter_.http_response_code());
   EXPECT_EQ(&attempter_, processor_->delegate());
   EXPECT_EQ(arraysize(kActionTypes), attempter_.actions_.size());
@@ -265,6 +287,15 @@
   ASSERT_TRUE(download_action != NULL);
   EXPECT_EQ(&attempter_, download_action->delegate());
   EXPECT_EQ(UPDATE_STATUS_CHECKING_FOR_UPDATE, attempter_.status());
+  g_main_loop_quit(loop_);
+}
+
+TEST_F(UpdateAttempterTest, UpdateTest) {
+  loop_ = g_main_loop_new(g_main_context_default(), FALSE);
+  g_idle_add(&StaticUpdateTestStart, this);
+  g_main_loop_run(loop_);
+  g_main_loop_unref(loop_);
+  loop_ = NULL;
 }
 
 }  // namespace chromeos_update_engine