AU: Resume interrupted update attempts.

BUG=7390,7520
TEST=unit tests

Change-Id: I9baf72aa444dd855409f865f03fb665e91f8d03d

Review URL: http://codereview.chromium.org/3620013
diff --git a/delta_performer.cc b/delta_performer.cc
index 10031eb..0eccb09 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -198,7 +198,10 @@
                                       manifest_metadata_size_))
         << "Unable to save the manifest metadata size.";
     manifest_valid_ = true;
-    block_size_ = manifest_.block_size();
+    if (!PrimeUpdateState()) {
+      LOG(ERROR) << "Unable to prime the update state.";
+      return -EINVAL;
+    }
   }
   ssize_t total_operations = manifest_.install_operations_size() +
       manifest_.kernel_install_operations_size();
@@ -225,7 +228,7 @@
     // update.
     if (!IsIdempotentOperation(op)) {
       Terminator::set_exit_blocked(true);
-      ResetUpdateProgress(prefs_);
+      ResetUpdateProgress(prefs_, true);
     }
     if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
         op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
@@ -281,8 +284,8 @@
 
   // Since we delete data off the beginning of the buffer as we use it,
   // the data we need should be exactly at the beginning of the buffer.
-  CHECK_EQ(buffer_offset_, operation.data_offset());
-  CHECK_GE(buffer_.size(), operation.data_length());
+  TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
+  TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
 
   // Extract the signature message if it's in this operation.
   ExtractSignatureMessage(operation);
@@ -405,8 +408,8 @@
     bool is_kernel_partition) {
   // Since we delete data off the beginning of the buffer as we use it,
   // the data we need should be exactly at the beginning of the buffer.
-  CHECK_EQ(buffer_offset_, operation.data_offset());
-  CHECK_GE(buffer_.size(), operation.data_length());
+  TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
+  TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
 
   string input_positions;
   TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.src_extents(),
@@ -571,9 +574,16 @@
   return true;
 }
 
-bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs) {
+bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs, bool quick) {
   TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation,
                                         kUpdateStateOperationInvalid));
+  if (!quick) {
+    prefs->SetString(kPrefsUpdateCheckResponseHash, "");
+    prefs->SetInt64(kPrefsUpdateStateNextDataOffset, -1);
+    prefs->SetString(kPrefsUpdateStateSHA256Context, "");
+    prefs->SetString(kPrefsUpdateStateSignedSHA256Context, "");
+    prefs->SetInt64(kPrefsManifestMetadataSize, -1);
+  }
   return true;
 }
 
@@ -581,7 +591,7 @@
   Terminator::set_exit_blocked(true);
   if (last_updated_buffer_offset_ != buffer_offset_) {
     // Resets the progress in case we die in the middle of the state update.
-    ResetUpdateProgress(prefs_);
+    ResetUpdateProgress(prefs_, true);
     TEST_AND_RETURN_FALSE(
         prefs_->SetString(kPrefsUpdateStateSHA256Context,
                           hash_calculator_.GetContext()));
@@ -594,4 +604,43 @@
   return true;
 }
 
+bool DeltaPerformer::PrimeUpdateState() {
+  CHECK(manifest_valid_);
+  block_size_ = manifest_.block_size();
+
+  int64_t next_operation = kUpdateStateOperationInvalid;
+  if (!prefs_->GetInt64(kPrefsUpdateStateNextOperation, &next_operation) ||
+      next_operation == kUpdateStateOperationInvalid ||
+      next_operation <= 0) {
+    // Initiating a new update, no more state needs to be initialized.
+    return true;
+  }
+  next_operation_num_ = next_operation;
+
+  // Resuming an update -- load the rest of the update state.
+  int64_t next_data_offset = -1;
+  TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsUpdateStateNextDataOffset,
+                                         &next_data_offset) &&
+                        next_data_offset >= 0);
+  buffer_offset_ = next_data_offset;
+
+  // The signed hash context may be empty if the interrupted update didn't reach
+  // the signature blob.
+  prefs_->GetString(kPrefsUpdateStateSignedSHA256Context,
+                    &signed_hash_context_);
+
+  string hash_context;
+  TEST_AND_RETURN_FALSE(prefs_->GetString(kPrefsUpdateStateSHA256Context,
+                                          &hash_context) &&
+                        hash_calculator_.SetContext(hash_context));
+
+  int64_t manifest_metadata_size = 0;
+  TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsManifestMetadataSize,
+                                         &manifest_metadata_size) &&
+                        manifest_metadata_size > 0);
+  manifest_metadata_size_ = manifest_metadata_size;
+
+  return true;
+}
+
 }  // namespace chromeos_update_engine