AU: block exit / reset update progress for non-idempotent ops as late as possible.

BUG=2390
TEST=unit tests, gmerged on device

Change-Id: I569dd1c2efc8056bd20b77e10d7ba50ddd2c55e6

Review URL: http://codereview.chromium.org/3603015
diff --git a/delta_performer.cc b/delta_performer.cc
index 8fc479b..3c24d5b 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -222,6 +222,7 @@
             next_operation_num_ - manifest_.install_operations_size());
     if (!CanPerformInstallOperation(op))
       break;
+    // Makes sure we unblock exit when this operation completes.
     ScopedTerminatorExitUnblocker exit_unblocker =
         ScopedTerminatorExitUnblocker();  // Avoids a compiler unused var bug.
     // Log every thousandth operation, and also the first and last ones
@@ -232,13 +233,6 @@
     }
     bool is_kernel_partition =
         (next_operation_num_ >= manifest_.install_operations_size());
-    // If about to start a non-idempotent operation, clear the update state so
-    // that if the operation gets interrupted, we don't try to resume the
-    // update.
-    if (!IsIdempotentOperation(op)) {
-      Terminator::set_exit_blocked(true);
-      ResetUpdateProgress(prefs_, true);
-    }
     if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
         op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
       if (!PerformReplaceOperation(op, is_kernel_partition)) {
@@ -371,6 +365,14 @@
     bytes_read += bytes_read_this_iteration;
   }
 
+  // If this is a non-idempotent operation, request a delayed exit and clear the
+  // update state in case the operation gets interrupted. Do this as late as
+  // possible.
+  if (!IsIdempotentOperation(operation)) {
+    Terminator::set_exit_blocked(true);
+    ResetUpdateProgress(prefs_, true);
+  }
+
   // Write bytes out.
   ssize_t bytes_written = 0;
   for (int i = 0; i < operation.dst_extents_size(); i++) {
@@ -446,6 +448,14 @@
   int fd = is_kernel_partition ? kernel_fd_ : fd_;
   const string& path = is_kernel_partition ? kernel_path_ : path_;
 
+  // If this is a non-idempotent operation, request a delayed exit and clear the
+  // update state in case the operation gets interrupted. Do this as late as
+  // possible.
+  if (!IsIdempotentOperation(operation)) {
+    Terminator::set_exit_blocked(true);
+    ResetUpdateProgress(prefs_, true);
+  }
+
   vector<string> cmd;
   cmd.push_back(kBspatchPath);
   cmd.push_back(path);