AU: Split applied update verification into a separate step.

Use instances of FilesystemCopierAction to do applied update verification. This
speeds it up slightly because asynchronous reads happen in parallel with hash
calculation but, more importantly, makes update_engine be responsive to D-Bus
during that step.

BUG=9140
TEST=unit tests, tested on device

Change-Id: I3ec9445de5e8258a63433a61f1a476aef4434f6c

Review URL: http://codereview.chromium.org/5516009
diff --git a/filesystem_copier_action_unittest.cc b/filesystem_copier_action_unittest.cc
index 032a24d..2ce3cc4 100644
--- a/filesystem_copier_action_unittest.cc
+++ b/filesystem_copier_action_unittest.cc
@@ -27,9 +27,12 @@
 
 class FilesystemCopierActionTest : public ::testing::Test {
  protected:
+  // |verify_hash|: 0 - no hash verification, 1 -- successful hash verification,
+  // 2 -- hash verification failure.
   void DoTest(bool run_out_of_space,
               bool terminate_early,
-              bool use_kernel_partition);
+              bool use_kernel_partition,
+              int verify_hash);
   void SetUp() {
   }
   void TearDown() {
@@ -90,13 +93,14 @@
 
 TEST_F(FilesystemCopierActionTest, RunAsRootSimpleTest) {
   ASSERT_EQ(0, getuid());
-  DoTest(false, false, false);
-
-  DoTest(false, false, true);
+  DoTest(false, false, false, 0);
+  DoTest(false, false, true, 0);
 }
+
 void FilesystemCopierActionTest::DoTest(bool run_out_of_space,
                                         bool terminate_early,
-                                        bool use_kernel_partition) {
+                                        bool use_kernel_partition,
+                                        int verify_hash) {
   GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
 
   string a_loop_file;
@@ -142,10 +146,29 @@
   // Set up the action objects
   InstallPlan install_plan;
   install_plan.is_full_update = false;
-  if (use_kernel_partition)
-    install_plan.kernel_install_path = b_dev;
-  else
-    install_plan.install_path = b_dev;
+  if (verify_hash) {
+    if (use_kernel_partition) {
+      install_plan.kernel_install_path = a_dev;
+      install_plan.kernel_size =
+          kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
+      EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
+          a_loop_data,
+          &install_plan.kernel_hash));
+    } else {
+      install_plan.install_path = a_dev;
+      install_plan.rootfs_size =
+          kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
+      EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
+          a_loop_data,
+          &install_plan.rootfs_hash));
+    }
+  } else {
+    if (use_kernel_partition) {
+      install_plan.kernel_install_path = b_dev;
+    } else {
+      install_plan.install_path = b_dev;
+    }
+  }
 
   ActionProcessor processor;
   FilesystemCopierActionTestDelegate delegate;
@@ -153,7 +176,8 @@
   processor.set_delegate(&delegate);
 
   ObjectFeederAction<InstallPlan> feeder_action;
-  FilesystemCopierAction copier_action(use_kernel_partition);
+  FilesystemCopierAction copier_action(use_kernel_partition,
+                                       verify_hash != 0);
   ObjectCollectorAction<InstallPlan> collector_action;
 
   BondActions(&feeder_action, &copier_action);
@@ -163,7 +187,9 @@
   processor.EnqueueAction(&copier_action);
   processor.EnqueueAction(&collector_action);
 
-  copier_action.set_copy_source(a_dev);
+  if (!verify_hash) {
+    copier_action.set_copy_source(a_dev);
+  }
   feeder_action.set_obj(install_plan);
 
   StartProcessorCallbackArgs start_callback_args;
@@ -181,21 +207,26 @@
     EXPECT_EQ(kActionCodeError, delegate.code());
     return;
   }
+  if (verify_hash == 2) {
+    EXPECT_EQ(use_kernel_partition ?
+              kActionCodeNewKernelVerificationError :
+              kActionCodeNewRootfsVerificationError,
+              delegate.code());
+    return;
+  }
   EXPECT_EQ(kActionCodeSuccess, delegate.code());
 
   // Make sure everything in the out_image is there
   vector<char> a_out;
-  vector<char> b_out;
   EXPECT_TRUE(utils::ReadFile(a_dev, &a_out));
-  EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
-  EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
+  if (!verify_hash) {
+    vector<char> b_out;
+    EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
+    EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
+  }
   EXPECT_TRUE(ExpectVectorsEq(a_loop_data, a_out));
 
   EXPECT_TRUE(collector_action.object() == install_plan);
-  if (terminate_early) {
-    // sleep so OS can clean up
-    sleep(1);
-  }
 }
 
 class FilesystemCopierActionTest2Delegate : public ActionProcessorDelegate {
@@ -219,7 +250,7 @@
 
   processor.set_delegate(&delegate);
 
-  FilesystemCopierAction copier_action(false);
+  FilesystemCopierAction copier_action(false, false);
   ObjectCollectorAction<InstallPlan> collector_action;
 
   BondActions(&copier_action, &collector_action);
@@ -242,7 +273,7 @@
   const char* kUrl = "http://some/url";
   InstallPlan install_plan(true, false, kUrl, 0, "", "", "");
   feeder_action.set_obj(install_plan);
-  FilesystemCopierAction copier_action(false);
+  FilesystemCopierAction copier_action(false, false);
   ObjectCollectorAction<InstallPlan> collector_action;
 
   BondActions(&feeder_action, &copier_action);
@@ -268,7 +299,7 @@
   const char* kUrl = "http://some/url";
   InstallPlan install_plan(false, true, kUrl, 0, "", "", "");
   feeder_action.set_obj(install_plan);
-  FilesystemCopierAction copier_action(false);
+  FilesystemCopierAction copier_action(false, false);
   ObjectCollectorAction<InstallPlan> collector_action;
 
   BondActions(&feeder_action, &copier_action);
@@ -299,7 +330,7 @@
                            "/no/such/file",
                            "/no/such/file");
   feeder_action.set_obj(install_plan);
-  FilesystemCopierAction copier_action(false);
+  FilesystemCopierAction copier_action(false, false);
   ObjectCollectorAction<InstallPlan> collector_action;
 
   BondActions(&copier_action, &collector_action);
@@ -313,14 +344,26 @@
   EXPECT_EQ(kActionCodeError, delegate.code_);
 }
 
+TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashTest) {
+  ASSERT_EQ(0, getuid());
+  DoTest(false, false, false, 1);
+  DoTest(false, false, true, 1);
+}
+
+TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashFailTest) {
+  ASSERT_EQ(0, getuid());
+  DoTest(false, false, false, 2);
+  DoTest(false, false, true, 2);
+}
+
 TEST_F(FilesystemCopierActionTest, RunAsRootNoSpaceTest) {
   ASSERT_EQ(0, getuid());
-  DoTest(true, false, false);
+  DoTest(true, false, false, 0);
 }
 
 TEST_F(FilesystemCopierActionTest, RunAsRootTerminateEarlyTest) {
   ASSERT_EQ(0, getuid());
-  DoTest(false, true, false);
+  DoTest(false, true, false, 0);
 }
 
 TEST_F(FilesystemCopierActionTest, RunAsRootDetermineFilesystemSizeTest) {
@@ -336,7 +379,7 @@
 
   for (int i = 0; i < 2; ++i) {
     bool is_kernel = i == 1;
-    FilesystemCopierAction action(is_kernel);
+    FilesystemCopierAction action(is_kernel, false);
     EXPECT_EQ(kint64max, action.filesystem_size_);
     {
       int fd = HANDLE_EINTR(open(img.c_str(), O_RDONLY));