AU: Execute postinst asynchronously so that the D-Bus service is not blocked.

This CL also cleans up Subprocess memory handling a bit and extends it to
capture the output of asynchronous subprocesses. Also adds a scoped temp mount
unmounter utility class.

BUG=8937
TEST=unit tests, tested on the device -- making sure no D-Bus calls timeou
during postinstall.

Change-Id: I219dda3dc98d875ff05050f1a32ffcc925db1d53

Review URL: http://codereview.chromium.org/4690006
diff --git a/postinstall_runner_action_unittest.cc b/postinstall_runner_action_unittest.cc
index 55fe79f..7f4e65c 100644
--- a/postinstall_runner_action_unittest.cc
+++ b/postinstall_runner_action_unittest.cc
@@ -17,6 +17,14 @@
 
 namespace chromeos_update_engine {
 
+namespace {
+gboolean StartProcessorInRunLoop(gpointer data) {
+  ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
+  processor->StartProcessing();
+  return FALSE;
+}
+}  // namespace
+
 class PostinstallRunnerActionTest : public ::testing::Test {
  public:
   void DoTest(bool do_losetup, bool do_err_script);
@@ -25,8 +33,14 @@
 class PostinstActionProcessorDelegate : public ActionProcessorDelegate {
  public:
   PostinstActionProcessorDelegate()
-      : code_(kActionCodeError),
+      : loop_(NULL),
+        code_(kActionCodeError),
         code_set_(false) {}
+  void ProcessingDone(const ActionProcessor* processor,
+                      ActionExitCode code) {
+    ASSERT_TRUE(loop_);
+    g_main_loop_quit(loop_);
+  }
   void ActionCompleted(ActionProcessor* processor,
                        AbstractAction* action,
                        ActionExitCode code) {
@@ -35,6 +49,7 @@
       code_set_ = true;
     }
   }
+  GMainLoop* loop_;
   ActionExitCode code_;
   bool code_set_;
 };
@@ -125,9 +140,13 @@
   processor.EnqueueAction(&runner_action);
   processor.EnqueueAction(&collector_action);
   processor.set_delegate(&delegate);
-  processor.StartProcessing();
-  ASSERT_FALSE(processor.IsRunning())
-      << "Update test to handle non-asynch actions";
+
+  GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
+  delegate.loop_ = loop;
+  g_timeout_add(0, &StartProcessorInRunLoop, &processor);
+  g_main_loop_run(loop);
+  g_main_loop_unref(loop);
+  ASSERT_FALSE(processor.IsRunning());
 
   EXPECT_TRUE(delegate.code_set_);
   EXPECT_EQ(do_losetup && !do_err_script, delegate.code_ == kActionCodeSuccess);