AU: do not copy filesystem during full updates

The filesystem copying stage is redundant during full updates, where the
partition is being entirely overwritten regardless of its previous
content. It is also a very wasteful step, causing intensive I/O and
kernel buffer pressure, and known to (sometimes) cause jank and
otherwise have detrimental effects on our user experience.

This CL eliminates filesystem copying for full updates:

1) The decision is based on whether the Omaha response indicates that
   this is a full update.

2) To be safe, we also ensure that the payload manifest does not contain
   old partition hashes, which is indicative of a delta update.

Note that it is generally desirable to base the decision solely on #2
above (and ignore #1 altogether). However, this will require more
extensive re-engineering of the update flow, as filesystem copying
currently happens prior to the manifest being downloaded.

BUG=chromium:189855
TEST=Full and delta updates run correctly on x86-alex

Change-Id: Ic0dc6e32913cfb96019606624ec6b87c2e5b3ebb
Reviewed-on: https://gerrit.chromium.org/gerrit/43665
Commit-Queue: Gilad Arnold <garnold@chromium.org>
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/delta_performer.cc b/delta_performer.cc
index 360272f..5615801 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -383,6 +383,11 @@
     if (result == kMetadataParseInsufficientData) {
       return true;
     }
+
+    // Checks the integrity of the payload manifest.
+    if ((*error = ValidateManifest()) != kErrorCodeSuccess)
+      return false;
+
     // Remove protobuf and header info from buffer_, so buffer_ contains
     // just data blobs
     DiscardBufferHeadBytes(manifest_metadata_size_);
@@ -831,6 +836,30 @@
   return kErrorCodeSuccess;
 }
 
+ErrorCode DeltaPerformer::ValidateManifest() {
+  // Ensure that a full update does not contain old partition hashes, which is
+  // indicative of a delta.
+  //
+  // TODO(garnold) in general, the presence of an old partition hash should be
+  // the sole indicator for a delta update, as we would generally like update
+  // payloads to be self contained and not assume an Omaha response to tell us
+  // that. However, since this requires some massive reengineering of the update
+  // flow (making filesystem copying happen conditionally only *after*
+  // downloading and parsing of the update manifest) we'll put it off for now.
+  // See chromium-os:7597 for further discussion.
+  if (install_plan_->is_full_update &&
+      (manifest_.has_old_kernel_info() || manifest_.has_old_rootfs_info())) {
+    LOG(ERROR) << "Purported full payload contains old partition "
+                  "hash(es), aborting update";
+    return kErrorCodePayloadMismatchedType;
+  }
+
+  // TODO(garnold) we should be adding more and more manifest checks, such as
+  // partition boundaries etc (see chromium-os:37661).
+
+  return kErrorCodeSuccess;
+}
+
 ErrorCode DeltaPerformer::ValidateOperationHash(
     const DeltaArchiveManifest_InstallOperation& operation) {