[automerger skipped] Add ramdisk_available to init_first_stage's deps am: 7729c21a47 -s ours

am skip reason: Merged-In I0a9ba90f0ae6f0b551e73d0a4361b8cf5d2c1e85 with SHA-1 3cce62a6b4 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/system/update_engine/+/15067039

Change-Id: Ib43aad1e226d0842c11192e3229101070356027a
diff --git a/Android.bp b/Android.bp
index d89255d..c519280 100644
--- a/Android.bp
+++ b/Android.bp
@@ -233,6 +233,7 @@
         "payload_consumer/file_descriptor_utils.cc",
         "payload_consumer/file_writer.cc",
         "payload_consumer/filesystem_verifier_action.cc",
+        "payload_consumer/install_operation_executor.cc",
         "payload_consumer/install_plan.cc",
         "payload_consumer/mount_history.cc",
         "payload_consumer/payload_constants.cc",
@@ -243,6 +244,7 @@
         "payload_consumer/vabc_partition_writer.cc",
         "payload_consumer/snapshot_extent_writer.cc",
         "payload_consumer/postinstall_runner_action.cc",
+        "payload_consumer/verified_source_fd.cc",
         "payload_consumer/verity_writer_android.cc",
         "payload_consumer/xz_extent_writer.cc",
         "payload_consumer/fec_file_descriptor.cc",
@@ -806,6 +808,7 @@
         "payload_consumer/file_writer_unittest.cc",
         "payload_consumer/filesystem_verifier_action_unittest.cc",
         "payload_consumer/install_plan_unittest.cc",
+        "payload_consumer/install_operation_executor_unittest.cc",
         "payload_consumer/partition_update_generator_android_unittest.cc",
         "payload_consumer/postinstall_runner_action_unittest.cc",
         "payload_consumer/verity_writer_android_unittest.cc",
diff --git a/aosp/cleanup_previous_update_action.cc b/aosp/cleanup_previous_update_action.cc
index dde6b89..51bb083 100644
--- a/aosp/cleanup_previous_update_action.cc
+++ b/aosp/cleanup_previous_update_action.cc
@@ -276,7 +276,17 @@
 void CleanupPreviousUpdateAction::WaitForMergeOrSchedule() {
   AcknowledgeTaskExecuted();
   TEST_AND_RETURN(running_);
+
   auto update_uses_compression = snapshot_->UpdateUsesCompression();
+
+  // Propagate the merge failure code to the merge stats. If we wait until
+  // after ProcessUpdateState, then a successful merge could overwrite the
+  // state of the previous failure.
+  auto failure_code = snapshot_->ReadMergeFailureCode();
+  if (failure_code != android::snapshot::MergeFailureCode::Ok) {
+    merge_stats_->set_merge_failure_code(failure_code);
+  }
+
   auto state = snapshot_->ProcessUpdateState(
       std::bind(&CleanupPreviousUpdateAction::OnMergePercentageUpdate, this),
       std::bind(&CleanupPreviousUpdateAction::BeforeCancel, this));
diff --git a/aosp/update_attempter_android.cc b/aosp/update_attempter_android.cc
index 4636c43..bcae3aa 100644
--- a/aosp/update_attempter_android.cc
+++ b/aosp/update_attempter_android.cc
@@ -152,6 +152,17 @@
   processor_->set_delegate(nullptr);
 }
 
+[[nodiscard]] static bool DidSystemReboot(PrefsInterface* prefs) {
+  string boot_id;
+  TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
+  string old_boot_id;
+  // If no previous boot id found, treat as a reboot and write boot ID.
+  if (!prefs->GetString(kPrefsBootId, &old_boot_id)) {
+    return true;
+  }
+  return old_boot_id != boot_id;
+}
+
 void UpdateAttempterAndroid::Init() {
   // In case of update_engine restart without a reboot we need to restore the
   // reboot needed state.
@@ -159,7 +170,10 @@
     SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
   } else {
     SetStatusAndNotify(UpdateStatus::IDLE);
-    UpdatePrefsAndReportUpdateMetricsOnReboot();
+    if (DidSystemReboot(prefs_)) {
+      UpdateStateAfterReboot();
+    }
+
 #ifdef _UE_SIDELOAD
     LOG(INFO) << "Skip ScheduleCleanupPreviousUpdate in sideload because "
               << "ApplyPayload will call it later.";
@@ -883,22 +897,24 @@
   }
 }
 
-void UpdateAttempterAndroid::UpdatePrefsAndReportUpdateMetricsOnReboot() {
-  string current_boot_id;
-  TEST_AND_RETURN(utils::GetBootId(&current_boot_id));
+void UpdateAttempterAndroid::UpdateStateAfterReboot() {
   // Example: [ro.build.version.incremental]: [4292972]
   string current_version =
       android::base::GetProperty("ro.build.version.incremental", "");
   TEST_AND_RETURN(!current_version.empty());
   const auto current_slot = boot_control_->GetCurrentSlot();
 
+  // |InitAfterReboot()| is only called after system reboot, so record boot id
+  // unconditionally
+  string current_boot_id;
+  TEST_AND_RETURN(utils::GetBootId(&current_boot_id));
+  prefs_->SetString(kPrefsBootId, current_boot_id);
+
   // If there's no record of previous version (e.g. due to a data wipe), we
   // save the info of current boot and skip the metrics report.
   if (!prefs_->Exists(kPrefsPreviousVersion)) {
-    prefs_->SetString(kPrefsBootId, current_boot_id);
     prefs_->SetString(kPrefsPreviousVersion, current_version);
-    prefs_->SetInt64(std::string{kPrefsPreviousSlot},
-                     boot_control_->GetCurrentSlot());
+    prefs_->SetInt64(kPrefsPreviousSlot, boot_control_->GetCurrentSlot());
     ClearMetricsPrefs();
     return;
   }
@@ -909,14 +925,9 @@
   // TODO(xunchang) identify and report rollback by checking UpdateMarker.
   if (prefs_->GetString(kPrefsPreviousVersion, &previous_version) &&
       previous_version == current_version && previous_slot == current_slot) {
-    string last_boot_id;
-    bool is_reboot = prefs_->Exists(kPrefsBootId) &&
-                     (prefs_->GetString(kPrefsBootId, &last_boot_id) &&
-                      last_boot_id != current_boot_id);
     // Increment the reboot number if |kPrefsNumReboots| exists. That pref is
     // set when we start a new update.
-    if (is_reboot && prefs_->Exists(kPrefsNumReboots)) {
-      prefs_->SetString(kPrefsBootId, current_boot_id);
+    if (prefs_->Exists(kPrefsNumReboots)) {
       int64_t reboot_count =
           metrics_utils::GetPersistedValue(kPrefsNumReboots, prefs_);
       metrics_utils::SetNumReboots(reboot_count + 1, prefs_);
@@ -926,10 +937,8 @@
 
   // Now that the build version changes, report the update metrics.
   // TODO(xunchang) check the build version is larger than the previous one.
-  prefs_->SetString(kPrefsBootId, current_boot_id);
   prefs_->SetString(kPrefsPreviousVersion, current_version);
-  prefs_->SetInt64(std::string{kPrefsPreviousSlot},
-                   boot_control_->GetCurrentSlot());
+  prefs_->SetInt64(kPrefsPreviousSlot, boot_control_->GetCurrentSlot());
 
   bool previous_attempt_exists = prefs_->Exists(kPrefsPayloadAttemptNumber);
   // |kPrefsPayloadAttemptNumber| should be cleared upon successful update.
diff --git a/aosp/update_attempter_android.h b/aosp/update_attempter_android.h
index 70938bc..7a5a635 100644
--- a/aosp/update_attempter_android.h
+++ b/aosp/update_attempter_android.h
@@ -162,12 +162,16 @@
   //   |kPrefsSystemUpdatedMarker|
   void CollectAndReportUpdateMetricsOnUpdateFinished(ErrorCode error_code);
 
+  // This function is called after update_engine is started after device
+  // reboots. If update_engine is restarted w/o device reboot, this function
+  // would not be called.
+
   // Metrics report function to call:
   //   |ReportAbnormallyTerminatedUpdateAttemptMetrics|
   //   |ReportTimeToRebootMetrics|
   // Prefs to update:
   //   |kPrefsBootId|, |kPrefsPreviousVersion|
-  void UpdatePrefsAndReportUpdateMetricsOnReboot();
+  void UpdateStateAfterReboot();
 
   // Prefs to update:
   //   |kPrefsPayloadAttemptNumber|, |kPrefsUpdateTimestampStart|,
diff --git a/common/constants.cc b/common/constants.cc
index 0677e66..ff46755 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -16,133 +16,4 @@
 
 #include "update_engine/common/constants.h"
 
-namespace chromeos_update_engine {
-
-const char kExclusionPrefsSubDir[] = "exclusion";
-
-const char kDlcPrefsSubDir[] = "dlc";
-
-const char kPowerwashSafePrefsSubDirectory[] = "update_engine/prefs";
-
-const char kPrefsSubDirectory[] = "prefs";
-
-const char kStatefulPartition[] = "/mnt/stateful_partition";
-
-const char kPostinstallDefaultScript[] = "postinst";
-
-// Constants defining keys for the persisted state of update engine.
-const char kPrefsAttemptInProgress[] = "attempt-in-progress";
-const char kPrefsBackoffExpiryTime[] = "backoff-expiry-time";
-const char kPrefsBootId[] = "boot-id";
-const char kPrefsCurrentBytesDownloaded[] = "current-bytes-downloaded";
-const char kPrefsCurrentResponseSignature[] = "current-response-signature";
-const char kPrefsCurrentUrlFailureCount[] = "current-url-failure-count";
-const char kPrefsCurrentUrlIndex[] = "current-url-index";
-const char kPrefsDailyMetricsLastReportedAt[] =
-    "daily-metrics-last-reported-at";
-const char kPrefsDeltaUpdateFailures[] = "delta-update-failures";
-const char kPrefsDynamicPartitionMetadataUpdated[] =
-    "dynamic-partition-metadata-updated";
-const char kPrefsFullPayloadAttemptNumber[] = "full-payload-attempt-number";
-const char kPrefsInstallDateDays[] = "install-date-days";
-const char kPrefsLastActivePingDay[] = "last-active-ping-day";
-const char kPrefsLastRollCallPingDay[] = "last-roll-call-ping-day";
-const char kPrefsManifestMetadataSize[] = "manifest-metadata-size";
-const char kPrefsManifestSignatureSize[] = "manifest-signature-size";
-const char kPrefsMetricsAttemptLastReportingTime[] =
-    "metrics-attempt-last-reporting-time";
-const char kPrefsMetricsCheckLastReportingTime[] =
-    "metrics-check-last-reporting-time";
-const char kPrefsNoIgnoreBackoff[] = "no-ignore-backoff";
-const char kPrefsNumReboots[] = "num-reboots";
-const char kPrefsNumResponsesSeen[] = "num-responses-seen";
-const char kPrefsOmahaCohort[] = "omaha-cohort";
-const char kPrefsOmahaCohortHint[] = "omaha-cohort-hint";
-const char kPrefsOmahaCohortName[] = "omaha-cohort-name";
-const char kPrefsOmahaEolDate[] = "omaha-eol-date";
-const char kPrefsP2PEnabled[] = "p2p-enabled";
-const char kPrefsP2PFirstAttemptTimestamp[] = "p2p-first-attempt-timestamp";
-const char kPrefsP2PNumAttempts[] = "p2p-num-attempts";
-const char kPrefsPayloadAttemptNumber[] = "payload-attempt-number";
-const char kPrefsTestUpdateCheckIntervalTimeout[] =
-    "test-update-check-interval-timeout";
-// Keep |kPrefsPingActive| in sync with |kDlcMetadataFilePingActive| in
-// dlcservice.
-const char kPrefsPingActive[] = "active";
-const char kPrefsPingLastActive[] = "date_last_active";
-const char kPrefsPingLastRollcall[] = "date_last_rollcall";
-const char kPrefsLastFp[] = "last-fp";
-const char kPrefsPostInstallSucceeded[] = "post-install-succeeded";
-const char kPrefsPreviousVersion[] = "previous-version";
-const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
-const char kPrefsRollbackHappened[] = "rollback-happened";
-const char kPrefsRollbackVersion[] = "rollback-version";
-const char kPrefsChannelOnSlotPrefix[] = "channel-on-slot-";
-const char kPrefsSystemUpdatedMarker[] = "system-updated-marker";
-const char kPrefsTargetVersionAttempt[] = "target-version-attempt";
-const char kPrefsTargetVersionInstalledFrom[] = "target-version-installed-from";
-const char kPrefsTargetVersionUniqueId[] = "target-version-unique-id";
-const char kPrefsTotalBytesDownloaded[] = "total-bytes-downloaded";
-const char kPrefsUpdateCheckCount[] = "update-check-count";
-const char kPrefsUpdateCheckResponseHash[] = "update-check-response-hash";
-const char kPrefsUpdateCompletedBootTime[] = "update-completed-boot-time";
-const char kPrefsUpdateCompletedOnBootId[] = "update-completed-on-boot-id";
-const char kPrefsUpdateDurationUptime[] = "update-duration-uptime";
-const char kPrefsUpdateFirstSeenAt[] = "update-first-seen-at";
-const char kPrefsUpdateOverCellularPermission[] =
-    "update-over-cellular-permission";
-const char kPrefsUpdateOverCellularTargetVersion[] =
-    "update-over-cellular-target-version";
-const char kPrefsUpdateOverCellularTargetSize[] =
-    "update-over-cellular-target-size";
-const char kPrefsUpdateServerCertificate[] = "update-server-cert";
-const char kPrefsUpdateStateNextDataLength[] = "update-state-next-data-length";
-const char kPrefsUpdateStateNextDataOffset[] = "update-state-next-data-offset";
-const char kPrefsUpdateStateNextOperation[] = "update-state-next-operation";
-const char kPrefsUpdateStatePayloadIndex[] = "update-state-payload-index";
-const char kPrefsUpdateStateSHA256Context[] = "update-state-sha-256-context";
-const char kPrefsUpdateStateSignatureBlob[] = "update-state-signature-blob";
-const char kPrefsUpdateStateSignedSHA256Context[] =
-    "update-state-signed-sha-256-context";
-const char kPrefsUpdateBootTimestampStart[] = "update-boot-timestamp-start";
-const char kPrefsUpdateTimestampStart[] = "update-timestamp-start";
-const char kPrefsUrlSwitchCount[] = "url-switch-count";
-const char kPrefsVerityWritten[] = "verity-written";
-const char kPrefsWallClockScatteringWaitPeriod[] = "wall-clock-wait-period";
-const char kPrefsWallClockStagingWaitPeriod[] =
-    "wall-clock-staging-wait-period";
-const char kPrefsManifestBytes[] = "manifest-bytes";
-const char kPrefsPreviousSlot[] = "previous-slot";
-
-// These four fields are generated by scripts/brillo_update_payload.
-const char kPayloadPropertyFileSize[] = "FILE_SIZE";
-const char kPayloadPropertyFileHash[] = "FILE_HASH";
-const char kPayloadPropertyMetadataSize[] = "METADATA_SIZE";
-const char kPayloadPropertyMetadataHash[] = "METADATA_HASH";
-// The Authorization: HTTP header to be sent when downloading the payload.
-const char kPayloadPropertyAuthorization[] = "AUTHORIZATION";
-// The User-Agent HTTP header to be sent when downloading the payload.
-const char kPayloadPropertyUserAgent[] = "USER_AGENT";
-// Set "POWERWASH=1" to powerwash (factory data reset) the device after
-// applying the update.
-const char kPayloadPropertyPowerwash[] = "POWERWASH";
-// The network id to pass to android_setprocnetwork before downloading.
-// This can be used to zero-rate OTA traffic by sending it over the correct
-// network.
-const char kPayloadPropertyNetworkId[] = "NETWORK_ID";
-// Set "SWITCH_SLOT_ON_REBOOT=0" to skip marking the updated partitions active.
-// The default is 1 (always switch slot if update succeeded).
-const char kPayloadPropertySwitchSlotOnReboot[] = "SWITCH_SLOT_ON_REBOOT";
-// Set "RUN_POST_INSTALL=0" to skip running optional post install.
-// The default is 1 (always run post install).
-const char kPayloadPropertyRunPostInstall[] = "RUN_POST_INSTALL";
-
-const char kOmahaUpdaterVersion[] = "0.1.0.0";
-
-// X-Goog-Update headers.
-const char kXGoogleUpdateInteractivity[] = "X-Goog-Update-Interactivity";
-const char kXGoogleUpdateAppId[] = "X-Goog-Update-AppId";
-const char kXGoogleUpdateUpdater[] = "X-Goog-Update-Updater";
-const char kXGoogleUpdateSessionId[] = "X-Goog-SessionId";
-
-}  // namespace chromeos_update_engine
+namespace chromeos_update_engine {}  // namespace chromeos_update_engine
diff --git a/common/constants.h b/common/constants.h
index 68f720d..8c07fcf 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -20,116 +20,176 @@
 #include <cstdint>
 
 namespace chromeos_update_engine {
-
 // The root path of all exclusion prefs.
-extern const char kExclusionPrefsSubDir[];
+static constexpr const auto& kExclusionPrefsSubDir = "exclusion";
 
 // The root path of all DLC metadata.
-extern const char kDlcPrefsSubDir[];
+static constexpr const auto& kDlcPrefsSubDir = "dlc";
 
 // Directory for AU prefs that are preserved across powerwash.
-extern const char kPowerwashSafePrefsSubDirectory[];
+static constexpr const auto& kPowerwashSafePrefsSubDirectory =
+    "update_engine/prefs";
 
 // The location where we store the AU preferences (state etc).
-extern const char kPrefsSubDirectory[];
-
-// Path to the post install command, relative to the partition.
-extern const char kPostinstallDefaultScript[];
+static constexpr const auto& kPrefsSubDirectory = "prefs";
 
 // Path to the stateful partition on the root filesystem.
-extern const char kStatefulPartition[];
+static constexpr const auto& kStatefulPartition = "/mnt/stateful_partition";
+
+// Path to the post install command, relative to the partition.
+static constexpr const auto& kPostinstallDefaultScript = "postinst";
 
 // Constants related to preferences.
-extern const char kPrefsAttemptInProgress[];
-extern const char kPrefsBackoffExpiryTime[];
-extern const char kPrefsBootId[];
-extern const char kPrefsCurrentBytesDownloaded[];
-extern const char kPrefsCurrentResponseSignature[];
-extern const char kPrefsCurrentUrlFailureCount[];
-extern const char kPrefsCurrentUrlIndex[];
-extern const char kPrefsDailyMetricsLastReportedAt[];
-extern const char kPrefsDeltaUpdateFailures[];
-extern const char kPrefsDynamicPartitionMetadataUpdated[];
-extern const char kPrefsFullPayloadAttemptNumber[];
-extern const char kPrefsInstallDateDays[];
-extern const char kPrefsLastActivePingDay[];
-extern const char kPrefsLastRollCallPingDay[];
-extern const char kPrefsManifestMetadataSize[];
-extern const char kPrefsManifestSignatureSize[];
-extern const char kPrefsMetricsAttemptLastReportingTime[];
-extern const char kPrefsMetricsCheckLastReportingTime[];
-extern const char kPrefsNoIgnoreBackoff[];
-extern const char kPrefsNumReboots[];
-extern const char kPrefsNumResponsesSeen[];
-extern const char kPrefsOmahaCohort[];
-extern const char kPrefsOmahaCohortHint[];
-extern const char kPrefsOmahaCohortName[];
-extern const char kPrefsOmahaEolDate[];
-extern const char kPrefsP2PEnabled[];
-extern const char kPrefsP2PFirstAttemptTimestamp[];
-extern const char kPrefsP2PNumAttempts[];
-extern const char kPrefsPayloadAttemptNumber[];
-extern const char kPrefsTestUpdateCheckIntervalTimeout[];
-extern const char kPrefsPingActive[];
-extern const char kPrefsPingLastActive[];
-extern const char kPrefsPingLastRollcall[];
-extern const char kPrefsLastFp[];
-extern const char kPrefsPostInstallSucceeded[];
-extern const char kPrefsPreviousVersion[];
-extern const char kPrefsPreviousSlot[];
-extern const char kPrefsResumedUpdateFailures[];
-extern const char kPrefsRollbackHappened[];
-extern const char kPrefsRollbackVersion[];
-extern const char kPrefsChannelOnSlotPrefix[];
-extern const char kPrefsSystemUpdatedMarker[];
-extern const char kPrefsTargetVersionAttempt[];
-extern const char kPrefsTargetVersionInstalledFrom[];
-extern const char kPrefsTargetVersionUniqueId[];
-extern const char kPrefsTotalBytesDownloaded[];
-extern const char kPrefsUpdateCheckCount[];
-extern const char kPrefsUpdateCheckResponseHash[];
-extern const char kPrefsUpdateCompletedBootTime[];
-extern const char kPrefsUpdateCompletedOnBootId[];
-extern const char kPrefsUpdateDurationUptime[];
-extern const char kPrefsUpdateFirstSeenAt[];
-extern const char kPrefsUpdateOverCellularPermission[];
-extern const char kPrefsUpdateOverCellularTargetVersion[];
-extern const char kPrefsUpdateOverCellularTargetSize[];
-extern const char kPrefsUpdateServerCertificate[];
-extern const char kPrefsUpdateStateNextDataLength[];
-extern const char kPrefsUpdateStateNextDataOffset[];
-extern const char kPrefsUpdateStateNextOperation[];
-extern const char kPrefsUpdateStatePayloadIndex[];
-extern const char kPrefsUpdateStateSHA256Context[];
-extern const char kPrefsUpdateStateSignatureBlob[];
-extern const char kPrefsUpdateStateSignedSHA256Context[];
-extern const char kPrefsUpdateBootTimestampStart[];
-extern const char kPrefsUpdateTimestampStart[];
-extern const char kPrefsUrlSwitchCount[];
-extern const char kPrefsVerityWritten[];
-extern const char kPrefsWallClockScatteringWaitPeriod[];
-extern const char kPrefsWallClockStagingWaitPeriod[];
-extern const char kPrefsManifestBytes[];
+// Constants defining keys for the persisted state of update engine.
+static constexpr const auto& kPrefsAttemptInProgress = "attempt-in-progress";
+static constexpr const auto& kPrefsBackoffExpiryTime = "backoff-expiry-time";
+static constexpr const auto& kPrefsBootId = "boot-id";
+static constexpr const auto& kPrefsCurrentBytesDownloaded =
+    "current-bytes-downloaded";
+static constexpr const auto& kPrefsCurrentResponseSignature =
+    "current-response-signature";
+static constexpr const auto& kPrefsCurrentUrlFailureCount =
+    "current-url-failure-count";
+static constexpr const auto& kPrefsCurrentUrlIndex = "current-url-index";
+static constexpr const auto& kPrefsDailyMetricsLastReportedAt =
+    "daily-metrics-last-reported-at";
+static constexpr const auto& kPrefsDeltaUpdateFailures =
+    "delta-update-failures";
+static constexpr const auto& kPrefsDynamicPartitionMetadataUpdated =
+    "dynamic-partition-metadata-updated";
+static constexpr const auto& kPrefsFullPayloadAttemptNumber =
+    "full-payload-attempt-number";
+static constexpr const auto& kPrefsInstallDateDays = "install-date-days";
+static constexpr const auto& kPrefsLastActivePingDay = "last-active-ping-day";
+static constexpr const auto& kPrefsLastRollCallPingDay =
+    "last-roll-call-ping-day";
+static constexpr const auto& kPrefsManifestMetadataSize =
+    "manifest-metadata-size";
+static constexpr const auto& kPrefsManifestSignatureSize =
+    "manifest-signature-size";
+static constexpr const auto& kPrefsMetricsAttemptLastReportingTime =
+    "metrics-attempt-last-reporting-time";
+static constexpr const auto& kPrefsMetricsCheckLastReportingTime =
+    "metrics-check-last-reporting-time";
+static constexpr const auto& kPrefsNoIgnoreBackoff = "no-ignore-backoff";
+static constexpr const auto& kPrefsNumReboots = "num-reboots";
+static constexpr const auto& kPrefsNumResponsesSeen = "num-responses-seen";
+static constexpr const auto& kPrefsOmahaCohort = "omaha-cohort";
+static constexpr const auto& kPrefsOmahaCohortHint = "omaha-cohort-hint";
+static constexpr const auto& kPrefsOmahaCohortName = "omaha-cohort-name";
+static constexpr const auto& kPrefsOmahaEolDate = "omaha-eol-date";
+static constexpr const auto& kPrefsP2PEnabled = "p2p-enabled";
+static constexpr const auto& kPrefsP2PFirstAttemptTimestamp =
+    "p2p-first-attempt-timestamp";
+static constexpr const auto& kPrefsP2PNumAttempts = "p2p-num-attempts";
+static constexpr const auto& kPrefsPayloadAttemptNumber =
+    "payload-attempt-number";
+static constexpr const auto& kPrefsTestUpdateCheckIntervalTimeout =
+    "test-update-check-interval-timeout";
+// Keep |kPrefsPingActive| in sync with |kDlcMetadataFilePingActive| in
+// dlcservice.
+static constexpr const auto& kPrefsPingActive = "active";
+static constexpr const auto& kPrefsPingLastActive = "date_last_active";
+static constexpr const auto& kPrefsPingLastRollcall = "date_last_rollcall";
+static constexpr const auto& kPrefsLastFp = "last-fp";
+static constexpr const auto& kPrefsPostInstallSucceeded =
+    "post-install-succeeded";
+static constexpr const auto& kPrefsPreviousVersion = "previous-version";
+static constexpr const auto& kPrefsResumedUpdateFailures =
+    "resumed-update-failures";
+static constexpr const auto& kPrefsRollbackHappened = "rollback-happened";
+static constexpr const auto& kPrefsRollbackVersion = "rollback-version";
+static constexpr const auto& kPrefsChannelOnSlotPrefix = "channel-on-slot-";
+static constexpr const auto& kPrefsSystemUpdatedMarker =
+    "system-updated-marker";
+static constexpr const auto& kPrefsTargetVersionAttempt =
+    "target-version-attempt";
+static constexpr const auto& kPrefsTargetVersionInstalledFrom =
+    "target-version-installed-from";
+static constexpr const auto& kPrefsTargetVersionUniqueId =
+    "target-version-unique-id";
+static constexpr const auto& kPrefsTotalBytesDownloaded =
+    "total-bytes-downloaded";
+static constexpr const auto& kPrefsUpdateCheckCount = "update-check-count";
+static constexpr const auto& kPrefsUpdateCheckResponseHash =
+    "update-check-response-hash";
+static constexpr const auto& kPrefsUpdateCompletedBootTime =
+    "update-completed-boot-time";
+static constexpr const auto& kPrefsUpdateCompletedOnBootId =
+    "update-completed-on-boot-id";
+static constexpr const auto& kPrefsUpdateDurationUptime =
+    "update-duration-uptime";
+static constexpr const auto& kPrefsUpdateFirstSeenAt = "update-first-seen-at";
+static constexpr const auto& kPrefsUpdateOverCellularPermission =
+    "update-over-cellular-permission";
+static constexpr const auto& kPrefsUpdateOverCellularTargetVersion =
+    "update-over-cellular-target-version";
+static constexpr const auto& kPrefsUpdateOverCellularTargetSize =
+    "update-over-cellular-target-size";
+static constexpr const auto& kPrefsUpdateServerCertificate =
+    "update-server-cert";
+static constexpr const auto& kPrefsUpdateStateNextDataLength =
+    "update-state-next-data-length";
+static constexpr const auto& kPrefsUpdateStateNextDataOffset =
+    "update-state-next-data-offset";
+static constexpr const auto& kPrefsUpdateStateNextOperation =
+    "update-state-next-operation";
+static constexpr const auto& kPrefsUpdateStatePayloadIndex =
+    "update-state-payload-index";
+static constexpr const auto& kPrefsUpdateStateSHA256Context =
+    "update-state-sha-256-context";
+static constexpr const auto& kPrefsUpdateStateSignatureBlob =
+    "update-state-signature-blob";
+static constexpr const auto& kPrefsUpdateStateSignedSHA256Context =
+    "update-state-signed-sha-256-context";
+static constexpr const auto& kPrefsUpdateBootTimestampStart =
+    "update-boot-timestamp-start";
+static constexpr const auto& kPrefsUpdateTimestampStart =
+    "update-timestamp-start";
+static constexpr const auto& kPrefsUrlSwitchCount = "url-switch-count";
+static constexpr const auto& kPrefsVerityWritten = "verity-written";
+static constexpr const auto& kPrefsWallClockScatteringWaitPeriod =
+    "wall-clock-wait-period";
+static constexpr const auto& kPrefsWallClockStagingWaitPeriod =
+    "wall-clock-staging-wait-period";
+static constexpr const auto& kPrefsManifestBytes = "manifest-bytes";
+static constexpr const auto& kPrefsPreviousSlot = "previous-slot";
 
 // Keys used when storing and loading payload properties.
-extern const char kPayloadPropertyFileSize[];
-extern const char kPayloadPropertyFileHash[];
-extern const char kPayloadPropertyMetadataSize[];
-extern const char kPayloadPropertyMetadataHash[];
-extern const char kPayloadPropertyAuthorization[];
-extern const char kPayloadPropertyUserAgent[];
-extern const char kPayloadPropertyPowerwash[];
-extern const char kPayloadPropertyNetworkId[];
-extern const char kPayloadPropertySwitchSlotOnReboot[];
-extern const char kPayloadPropertyRunPostInstall[];
+// These four fields are generated by scripts/brillo_update_payload.
+static constexpr const auto& kPayloadPropertyFileSize = "FILE_SIZE";
+static constexpr const auto& kPayloadPropertyFileHash = "FILE_HASH";
+static constexpr const auto& kPayloadPropertyMetadataSize = "METADATA_SIZE";
+static constexpr const auto& kPayloadPropertyMetadataHash = "METADATA_HASH";
+// The Authorization: HTTP header to be sent when downloading the payload.
+static constexpr const auto& kPayloadPropertyAuthorization = "AUTHORIZATION";
+// The User-Agent HTTP header to be sent when downloading the payload.
+static constexpr const auto& kPayloadPropertyUserAgent = "USER_AGENT";
+// Set "POWERWASH=1" to powerwash (factory data reset) the device after
+// applying the update.
+static constexpr const auto& kPayloadPropertyPowerwash = "POWERWASH";
+// The network id to pass to android_setprocnetwork before downloading.
+// This can be used to zero-rate OTA traffic by sending it over the correct
+// network.
+static constexpr const auto& kPayloadPropertyNetworkId = "NETWORK_ID";
+// Set "SWITCH_SLOT_ON_REBOOT=0" to skip marking the updated partitions active.
+// The default is 1 (always switch slot if update succeeded).
+static constexpr const auto& kPayloadPropertySwitchSlotOnReboot =
+    "SWITCH_SLOT_ON_REBOOT";
+// Set "RUN_POST_INSTALL=0" to skip running optional post install.
+// The default is 1 (always run post install).
+static constexpr const auto& kPayloadPropertyRunPostInstall =
+    "RUN_POST_INSTALL";
 
-extern const char kOmahaUpdaterVersion[];
+static constexpr const auto& kOmahaUpdaterVersion = "0.1.0.0";
 
 // X-Goog-Update headers.
-extern const char kXGoogleUpdateInteractivity[];
-extern const char kXGoogleUpdateAppId[];
-extern const char kXGoogleUpdateUpdater[];
-extern const char kXGoogleUpdateSessionId[];
+// X-Goog-Update headers.
+static constexpr const auto& kXGoogleUpdateInteractivity =
+    "X-Goog-Update-Interactivity";
+static constexpr const auto& kXGoogleUpdateAppId = "X-Goog-Update-AppId";
+static constexpr const auto& kXGoogleUpdateUpdater = "X-Goog-Update-Updater";
+static constexpr const auto& kXGoogleUpdateSessionId = "X-Goog-SessionId";
 
 // A download source is any combination of protocol and server (that's of
 // interest to us when looking at UMA metrics) using which we may download
diff --git a/common/fake_prefs.cc b/common/fake_prefs.cc
index ea6ea60..e87e0ec 100644
--- a/common/fake_prefs.cc
+++ b/common/fake_prefs.cc
@@ -28,7 +28,7 @@
 
 namespace {
 
-void CheckNotNull(const string& key, void* ptr) {
+void CheckNotNull(std::string_view key, void* ptr) {
   EXPECT_NE(nullptr, ptr) << "Called Get*() for key \"" << key
                           << "\" with a null parameter.";
 }
@@ -63,41 +63,41 @@
 bool FakePrefs::PrefValue::*const FakePrefs::PrefConsts<bool>::member =
     &FakePrefs::PrefValue::as_bool;
 
-bool FakePrefs::GetString(const string& key, string* value) const {
+bool FakePrefs::GetString(std::string_view key, string* value) const {
   return GetValue(key, value);
 }
 
-bool FakePrefs::SetString(const string& key, std::string_view value) {
+bool FakePrefs::SetString(std::string_view key, std::string_view value) {
   SetValue(key, std::string(value));
   return true;
 }
 
-bool FakePrefs::GetInt64(const string& key, int64_t* value) const {
+bool FakePrefs::GetInt64(std::string_view key, int64_t* value) const {
   return GetValue(key, value);
 }
 
-bool FakePrefs::SetInt64(const string& key, const int64_t value) {
+bool FakePrefs::SetInt64(std::string_view key, const int64_t value) {
   SetValue(key, value);
   return true;
 }
 
-bool FakePrefs::GetBoolean(const string& key, bool* value) const {
+bool FakePrefs::GetBoolean(std::string_view key, bool* value) const {
   return GetValue(key, value);
 }
 
-bool FakePrefs::SetBoolean(const string& key, const bool value) {
+bool FakePrefs::SetBoolean(std::string_view key, const bool value) {
   SetValue(key, value);
   return true;
 }
 
-bool FakePrefs::Exists(const string& key) const {
+bool FakePrefs::Exists(std::string_view key) const {
   return values_.find(key) != values_.end();
 }
 
-bool FakePrefs::Delete(const string& key) {
+bool FakePrefs::Delete(std::string_view key) {
   if (values_.find(key) == values_.end())
     return false;
-  values_.erase(key);
+  values_.erase(std::string{key});
   const auto observers_for_key = observers_.find(key);
   if (observers_for_key != observers_.end()) {
     std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
@@ -107,7 +107,7 @@
   return true;
 }
 
-bool FakePrefs::Delete(const string& key, const vector<string>& nss) {
+bool FakePrefs::Delete(std::string_view key, const vector<string>& nss) {
   bool success = Delete(key);
   for (const auto& ns : nss) {
     vector<string> ns_keys;
@@ -123,7 +123,7 @@
   return success;
 }
 
-bool FakePrefs::GetSubKeys(const string& ns, vector<string>* keys) const {
+bool FakePrefs::GetSubKeys(std::string_view ns, vector<string>* keys) const {
   for (const auto& pr : values_)
     if (pr.first.compare(0, ns.length(), ns) == 0)
       keys->push_back(pr.first);
@@ -142,7 +142,7 @@
   return "Unknown";
 }
 
-void FakePrefs::CheckKeyType(const string& key, PrefType type) const {
+void FakePrefs::CheckKeyType(std::string_view key, PrefType type) const {
   auto it = values_.find(key);
   EXPECT_TRUE(it == values_.end() || it->second.type == type)
       << "Key \"" << key << "\" if defined as " << GetTypeName(it->second.type)
@@ -150,10 +150,11 @@
 }
 
 template <typename T>
-void FakePrefs::SetValue(const string& key, T value) {
+void FakePrefs::SetValue(std::string_view key, T value) {
+  std::string str_key{key};
   CheckKeyType(key, PrefConsts<T>::type);
-  values_[key].type = PrefConsts<T>::type;
-  values_[key].value.*(PrefConsts<T>::member) = std::move(value);
+  values_[str_key].type = PrefConsts<T>::type;
+  values_[str_key].value.*(PrefConsts<T>::member) = std::move(value);
   const auto observers_for_key = observers_.find(key);
   if (observers_for_key != observers_.end()) {
     std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
@@ -163,7 +164,7 @@
 }
 
 template <typename T>
-bool FakePrefs::GetValue(const string& key, T* value) const {
+bool FakePrefs::GetValue(std::string_view key, T* value) const {
   CheckKeyType(key, PrefConsts<T>::type);
   auto it = values_.find(key);
   if (it == values_.end())
@@ -173,12 +174,14 @@
   return true;
 }
 
-void FakePrefs::AddObserver(const string& key, ObserverInterface* observer) {
-  observers_[key].push_back(observer);
+void FakePrefs::AddObserver(std::string_view key, ObserverInterface* observer) {
+  observers_[string{key}].push_back(observer);
 }
 
-void FakePrefs::RemoveObserver(const string& key, ObserverInterface* observer) {
-  std::vector<ObserverInterface*>& observers_for_key = observers_[key];
+void FakePrefs::RemoveObserver(std::string_view key,
+                               ObserverInterface* observer) {
+  string str_key{key};
+  std::vector<ObserverInterface*>& observers_for_key = observers_[str_key];
   auto observer_it =
       std::find(observers_for_key.begin(), observers_for_key.end(), observer);
   EXPECT_NE(observer_it, observers_for_key.end())
@@ -186,7 +189,7 @@
   if (observer_it != observers_for_key.end())
     observers_for_key.erase(observer_it);
   if (observers_for_key.empty())
-    observers_.erase(key);
+    observers_.erase(str_key);
 }
 
 }  // namespace chromeos_update_engine
diff --git a/common/fake_prefs.h b/common/fake_prefs.h
index 430c291..7ae9fb9 100644
--- a/common/fake_prefs.h
+++ b/common/fake_prefs.h
@@ -17,6 +17,7 @@
 #ifndef UPDATE_ENGINE_COMMON_FAKE_PREFS_H_
 #define UPDATE_ENGINE_COMMON_FAKE_PREFS_H_
 
+#include <functional>
 #include <map>
 #include <string>
 #include <string_view>
@@ -40,24 +41,23 @@
   ~FakePrefs();
 
   // PrefsInterface methods.
-  bool GetString(const std::string& key, std::string* value) const override;
-  bool SetString(const std::string& key, std::string_view value) override;
-  bool GetInt64(const std::string& key, int64_t* value) const override;
-  bool SetInt64(const std::string& key, const int64_t value) override;
-  bool GetBoolean(const std::string& key, bool* value) const override;
-  bool SetBoolean(const std::string& key, const bool value) override;
+  bool GetString(std::string_view key, std::string* value) const override;
+  bool SetString(std::string_view key, std::string_view value) override;
+  bool GetInt64(std::string_view key, int64_t* value) const override;
+  bool SetInt64(std::string_view key, const int64_t value) override;
+  bool GetBoolean(std::string_view key, bool* value) const override;
+  bool SetBoolean(std::string_view key, const bool value) override;
 
-  bool Exists(const std::string& key) const override;
-  bool Delete(const std::string& key) override;
-  bool Delete(const std::string& key,
+  bool Exists(std::string_view key) const override;
+  bool Delete(std::string_view key) override;
+  bool Delete(std::string_view key,
               const std::vector<std::string>& nss) override;
 
-  bool GetSubKeys(const std::string& ns,
+  bool GetSubKeys(std::string_view ns,
                   std::vector<std::string>* keys) const override;
 
-  void AddObserver(const std::string& key,
-                   ObserverInterface* observer) override;
-  void RemoveObserver(const std::string& key,
+  void AddObserver(std::string_view key, ObserverInterface* observer) override;
+  void RemoveObserver(std::string_view key,
                       ObserverInterface* observer) override;
 
  private:
@@ -92,24 +92,25 @@
   static std::string GetTypeName(PrefType type);
 
   // Checks that the |key| is either not present or has the given |type|.
-  void CheckKeyType(const std::string& key, PrefType type) const;
+  void CheckKeyType(std::string_view key, PrefType type) const;
 
   // Helper function to set a value of the passed |key|. It sets the type based
   // on the template parameter T.
   template <typename T>
-  void SetValue(const std::string& key, T value);
+  void SetValue(std::string_view key, T value);
 
   // Helper function to get a value from the map checking for invalid calls.
   // The function fails the test if you attempt to read a value  defined as a
   // different type. Returns whether the get succeeded.
   template <typename T>
-  bool GetValue(const std::string& key, T* value) const;
+  bool GetValue(std::string_view key, T* value) const;
 
   // Container for all the key/value pairs.
-  std::map<std::string, PrefTypeValue> values_;
+  std::map<std::string, PrefTypeValue, std::less<>> values_;
 
   // The registered observers watching for changes.
-  std::map<std::string, std::vector<ObserverInterface*>> observers_;
+  std::map<std::string, std::vector<ObserverInterface*>, std::less<>>
+      observers_;
 
   DISALLOW_COPY_AND_ASSIGN(FakePrefs);
 };
diff --git a/common/mock_prefs.h b/common/mock_prefs.h
index 49431fb..f308074 100644
--- a/common/mock_prefs.h
+++ b/common/mock_prefs.h
@@ -29,27 +29,24 @@
 
 class MockPrefs : public PrefsInterface {
  public:
-  MOCK_CONST_METHOD2(GetString,
-                     bool(const std::string& key, std::string* value));
-  MOCK_METHOD2(SetString, bool(const std::string& key, std::string_view value));
-  MOCK_CONST_METHOD2(GetInt64, bool(const std::string& key, int64_t* value));
-  MOCK_METHOD2(SetInt64, bool(const std::string& key, const int64_t value));
+  MOCK_CONST_METHOD2(GetString, bool(std::string_view key, std::string* value));
+  MOCK_METHOD2(SetString, bool(std::string_view key, std::string_view value));
+  MOCK_CONST_METHOD2(GetInt64, bool(std::string_view key, int64_t* value));
+  MOCK_METHOD2(SetInt64, bool(std::string_view key, const int64_t value));
 
-  MOCK_CONST_METHOD2(GetBoolean, bool(const std::string& key, bool* value));
-  MOCK_METHOD2(SetBoolean, bool(const std::string& key, const bool value));
+  MOCK_CONST_METHOD2(GetBoolean, bool(std::string_view key, bool* value));
+  MOCK_METHOD2(SetBoolean, bool(std::string_view key, const bool value));
 
-  MOCK_CONST_METHOD1(Exists, bool(const std::string& key));
-  MOCK_METHOD1(Delete, bool(const std::string& key));
+  MOCK_CONST_METHOD1(Exists, bool(std::string_view key));
+  MOCK_METHOD1(Delete, bool(std::string_view key));
   MOCK_METHOD2(Delete,
-               bool(const std::string& key,
-                    const std::vector<std::string>& nss));
+               bool(std::string_view key, const std::vector<std::string>& nss));
 
   MOCK_CONST_METHOD2(GetSubKeys,
-                     bool(const std::string&, std::vector<std::string>*));
+                     bool(std::string_view, std::vector<std::string>*));
 
-  MOCK_METHOD2(AddObserver, void(const std::string& key, ObserverInterface*));
-  MOCK_METHOD2(RemoveObserver,
-               void(const std::string& key, ObserverInterface*));
+  MOCK_METHOD2(AddObserver, void(std::string_view key, ObserverInterface*));
+  MOCK_METHOD2(RemoveObserver, void(std::string_view key, ObserverInterface*));
 };
 
 }  // namespace chromeos_update_engine
diff --git a/common/prefs.cc b/common/prefs.cc
index 1e06be4..f33a8a9 100644
--- a/common/prefs.cc
+++ b/common/prefs.cc
@@ -51,11 +51,11 @@
 
 }  // namespace
 
-bool PrefsBase::GetString(const string& key, string* value) const {
+bool PrefsBase::GetString(const std::string_view key, string* value) const {
   return storage_->GetKey(key, value);
 }
 
-bool PrefsBase::SetString(const string& key, std::string_view value) {
+bool PrefsBase::SetString(std::string_view key, std::string_view value) {
   TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
   const auto observers_for_key = observers_.find(key);
   if (observers_for_key != observers_.end()) {
@@ -66,7 +66,7 @@
   return true;
 }
 
-bool PrefsBase::GetInt64(const string& key, int64_t* value) const {
+bool PrefsBase::GetInt64(const std::string_view key, int64_t* value) const {
   string str_value;
   if (!GetString(key, &str_value))
     return false;
@@ -75,11 +75,11 @@
   return true;
 }
 
-bool PrefsBase::SetInt64(const string& key, const int64_t value) {
+bool PrefsBase::SetInt64(std::string_view key, const int64_t value) {
   return SetString(key, base::NumberToString(value));
 }
 
-bool PrefsBase::GetBoolean(const string& key, bool* value) const {
+bool PrefsBase::GetBoolean(std::string_view key, bool* value) const {
   string str_value;
   if (!GetString(key, &str_value))
     return false;
@@ -95,15 +95,15 @@
   return false;
 }
 
-bool PrefsBase::SetBoolean(const string& key, const bool value) {
+bool PrefsBase::SetBoolean(std::string_view key, const bool value) {
   return SetString(key, value ? "true" : "false");
 }
 
-bool PrefsBase::Exists(const string& key) const {
+bool PrefsBase::Exists(std::string_view key) const {
   return storage_->KeyExists(key);
 }
 
-bool PrefsBase::Delete(const string& key) {
+bool PrefsBase::Delete(std::string_view key) {
   TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
   const auto observers_for_key = observers_.find(key);
   if (observers_for_key != observers_.end()) {
@@ -114,7 +114,7 @@
   return true;
 }
 
-bool PrefsBase::Delete(const string& pref_key, const vector<string>& nss) {
+bool PrefsBase::Delete(std::string_view pref_key, const vector<string>& nss) {
   // Delete pref key for platform.
   bool success = Delete(pref_key);
   // Delete pref key in each namespace.
@@ -132,16 +132,18 @@
   return success;
 }
 
-bool PrefsBase::GetSubKeys(const string& ns, vector<string>* keys) const {
+bool PrefsBase::GetSubKeys(std::string_view ns, vector<string>* keys) const {
   return storage_->GetSubKeys(ns, keys);
 }
 
-void PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
-  observers_[key].push_back(observer);
+void PrefsBase::AddObserver(std::string_view key, ObserverInterface* observer) {
+  observers_[std::string{key}].push_back(observer);
 }
 
-void PrefsBase::RemoveObserver(const string& key, ObserverInterface* observer) {
-  std::vector<ObserverInterface*>& observers_for_key = observers_[key];
+void PrefsBase::RemoveObserver(std::string_view key,
+                               ObserverInterface* observer) {
+  std::vector<ObserverInterface*>& observers_for_key =
+      observers_[std::string{key}];
   auto observer_it =
       std::find(observers_for_key.begin(), observers_for_key.end(), observer);
   if (observer_it != observers_for_key.end())
@@ -165,7 +167,7 @@
   return true;
 }
 
-bool Prefs::FileStorage::GetKey(const string& key, string* value) const {
+bool Prefs::FileStorage::GetKey(std::string_view key, string* value) const {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
   if (!base::ReadFileToString(filename, value)) {
@@ -174,7 +176,7 @@
   return true;
 }
 
-bool Prefs::FileStorage::GetSubKeys(const string& ns,
+bool Prefs::FileStorage::GetSubKeys(std::string_view ns,
                                     vector<string>* keys) const {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(ns, &filename));
@@ -192,7 +194,7 @@
   return true;
 }
 
-bool Prefs::FileStorage::SetKey(const string& key, std::string_view value) {
+bool Prefs::FileStorage::SetKey(std::string_view key, std::string_view value) {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
   if (!base::DirectoryExists(filename.DirName())) {
@@ -205,13 +207,13 @@
   return true;
 }
 
-bool Prefs::FileStorage::KeyExists(const string& key) const {
+bool Prefs::FileStorage::KeyExists(std::string_view key) const {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
   return base::PathExists(filename);
 }
 
-bool Prefs::FileStorage::DeleteKey(const string& key) {
+bool Prefs::FileStorage::DeleteKey(std::string_view key) {
   base::FilePath filename;
   TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
 #if BASE_VER < 800000
@@ -222,20 +224,21 @@
   return true;
 }
 
-bool Prefs::FileStorage::GetFileNameForKey(const string& key,
+bool Prefs::FileStorage::GetFileNameForKey(std::string_view key,
                                            base::FilePath* filename) const {
   // Allows only non-empty keys containing [A-Za-z0-9_-/].
   TEST_AND_RETURN_FALSE(!key.empty());
   for (char c : key)
     TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
                           c == '_' || c == '-' || c == kKeySeparator);
-  *filename = prefs_dir_.Append(key);
+  *filename = prefs_dir_.Append(
+      base::FilePath::StringPieceType(key.data(), key.size()));
   return true;
 }
 
 // MemoryPrefs
 
-bool MemoryPrefs::MemoryStorage::GetKey(const string& key,
+bool MemoryPrefs::MemoryStorage::GetKey(std::string_view key,
                                         string* value) const {
   auto it = values_.find(key);
   if (it == values_.end())
@@ -244,15 +247,13 @@
   return true;
 }
 
-bool MemoryPrefs::MemoryStorage::GetSubKeys(const string& ns,
+bool MemoryPrefs::MemoryStorage::GetSubKeys(std::string_view ns,
                                             vector<string>* keys) const {
-  using value_type = decltype(values_)::value_type;
-  using key_type = decltype(values_)::key_type;
-  auto lower_comp = [](const value_type& pr, const key_type& ns) {
-    return pr.first.substr(0, ns.length()) < ns;
+  auto lower_comp = [](const auto& pr, const auto& ns) {
+    return std::string_view{pr.first.data(), ns.length()} < ns;
   };
-  auto upper_comp = [](const key_type& ns, const value_type& pr) {
-    return ns < pr.first.substr(0, ns.length());
+  auto upper_comp = [](const auto& ns, const auto& pr) {
+    return ns < std::string_view{pr.first.data(), ns.length()};
   };
   auto lower_it =
       std::lower_bound(begin(values_), end(values_), ns, lower_comp);
@@ -262,17 +263,17 @@
   return true;
 }
 
-bool MemoryPrefs::MemoryStorage::SetKey(const string& key,
+bool MemoryPrefs::MemoryStorage::SetKey(std::string_view key,
                                         std::string_view value) {
-  values_[key] = value;
+  values_[std::string{key}] = value;
   return true;
 }
 
-bool MemoryPrefs::MemoryStorage::KeyExists(const string& key) const {
+bool MemoryPrefs::MemoryStorage::KeyExists(std::string_view key) const {
   return values_.find(key) != values_.end();
 }
 
-bool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
+bool MemoryPrefs::MemoryStorage::DeleteKey(std::string_view key) {
   auto it = values_.find(key);
   if (it != values_.end())
     values_.erase(it);
diff --git a/common/prefs.h b/common/prefs.h
index 93477dd..c3105c6 100644
--- a/common/prefs.h
+++ b/common/prefs.h
@@ -17,6 +17,7 @@
 #ifndef UPDATE_ENGINE_COMMON_PREFS_H_
 #define UPDATE_ENGINE_COMMON_PREFS_H_
 
+#include <functional>
 #include <map>
 #include <string>
 #include <string_view>
@@ -41,23 +42,23 @@
 
     // Get the key named |key| and store its value in the referenced |value|.
     // Returns whether the operation succeeded.
-    virtual bool GetKey(const std::string& key, std::string* value) const = 0;
+    virtual bool GetKey(std::string_view key, std::string* value) const = 0;
 
     // Get the keys stored within the namespace. If there are no keys in the
     // namespace, |keys| will be empty. Returns whether the operation succeeded.
-    virtual bool GetSubKeys(const std::string& ns,
+    virtual bool GetSubKeys(std::string_view ns,
                             std::vector<std::string>* keys) const = 0;
 
     // Set the value of the key named |key| to |value| regardless of the
     // previous value. Returns whether the operation succeeded.
-    virtual bool SetKey(const std::string& key, std::string_view value) = 0;
+    virtual bool SetKey(std::string_view key, std::string_view value) = 0;
 
     // Returns whether the key named |key| exists.
-    virtual bool KeyExists(const std::string& key) const = 0;
+    virtual bool KeyExists(std::string_view key) const = 0;
 
     // Deletes the value associated with the key name |key|. Returns whether the
     // key was deleted.
-    virtual bool DeleteKey(const std::string& key) = 0;
+    virtual bool DeleteKey(std::string_view key) = 0;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(StorageInterface);
@@ -66,29 +67,29 @@
   explicit PrefsBase(StorageInterface* storage) : storage_(storage) {}
 
   // PrefsInterface methods.
-  bool GetString(const std::string& key, std::string* value) const override;
-  bool SetString(const std::string& key, std::string_view value) override;
-  bool GetInt64(const std::string& key, int64_t* value) const override;
-  bool SetInt64(const std::string& key, const int64_t value) override;
-  bool GetBoolean(const std::string& key, bool* value) const override;
-  bool SetBoolean(const std::string& key, const bool value) override;
+  bool GetString(std::string_view key, std::string* value) const override;
+  bool SetString(std::string_view key, std::string_view value) override;
+  bool GetInt64(std::string_view key, int64_t* value) const override;
+  bool SetInt64(std::string_view key, const int64_t value) override;
+  bool GetBoolean(std::string_view key, bool* value) const override;
+  bool SetBoolean(std::string_view key, const bool value) override;
 
-  bool Exists(const std::string& key) const override;
-  bool Delete(const std::string& key) override;
-  bool Delete(const std::string& pref_key,
+  bool Exists(std::string_view key) const override;
+  bool Delete(std::string_view key) override;
+  bool Delete(std::string_view pref_key,
               const std::vector<std::string>& nss) override;
 
-  bool GetSubKeys(const std::string& ns,
+  bool GetSubKeys(std::string_view ns,
                   std::vector<std::string>* keys) const override;
 
-  void AddObserver(const std::string& key,
-                   ObserverInterface* observer) override;
-  void RemoveObserver(const std::string& key,
+  void AddObserver(std::string_view key, ObserverInterface* observer) override;
+  void RemoveObserver(std::string_view key,
                       ObserverInterface* observer) override;
 
  private:
   // The registered observers watching for changes.
-  std::map<std::string, std::vector<ObserverInterface*>> observers_;
+  std::map<std::string, std::vector<ObserverInterface*>, std::less<>>
+      observers_;
 
   // The concrete implementation of the storage used for the keys.
   StorageInterface* storage_;
@@ -121,12 +122,12 @@
     bool Init(const base::FilePath& prefs_dir);
 
     // PrefsBase::StorageInterface overrides.
-    bool GetKey(const std::string& key, std::string* value) const override;
-    bool GetSubKeys(const std::string& ns,
+    bool GetKey(std::string_view key, std::string* value) const override;
+    bool GetSubKeys(std::string_view ns,
                     std::vector<std::string>* keys) const override;
-    bool SetKey(const std::string& key, std::string_view value) override;
-    bool KeyExists(const std::string& key) const override;
-    bool DeleteKey(const std::string& key) override;
+    bool SetKey(std::string_view key, std::string_view value) override;
+    bool KeyExists(std::string_view key) const override;
+    bool DeleteKey(std::string_view key) override;
 
    private:
     FRIEND_TEST(PrefsTest, GetFileNameForKey);
@@ -135,7 +136,7 @@
 
     // Sets |filename| to the full path to the file containing the data
     // associated with |key|. Returns true on success, false otherwise.
-    bool GetFileNameForKey(const std::string& key,
+    bool GetFileNameForKey(std::string_view key,
                            base::FilePath* filename) const;
 
     // Preference store directory.
@@ -161,16 +162,16 @@
     MemoryStorage() = default;
 
     // PrefsBase::StorageInterface overrides.
-    bool GetKey(const std::string& key, std::string* value) const override;
-    bool GetSubKeys(const std::string& ns,
+    bool GetKey(std::string_view, std::string* value) const override;
+    bool GetSubKeys(std::string_view ns,
                     std::vector<std::string>* keys) const override;
-    bool SetKey(const std::string& key, std::string_view value) override;
-    bool KeyExists(const std::string& key) const override;
-    bool DeleteKey(const std::string& key) override;
+    bool SetKey(std::string_view key, std::string_view value) override;
+    bool KeyExists(std::string_view key) const override;
+    bool DeleteKey(std::string_view key) override;
 
    private:
     // The std::map holding the values in memory.
-    std::map<std::string, std::string> values_;
+    std::map<std::string, std::string, std::less<>> values_;
   };
 
   // The concrete memory storage implementation.
diff --git a/common/prefs_interface.h b/common/prefs_interface.h
index e773a35..69ccf68 100644
--- a/common/prefs_interface.h
+++ b/common/prefs_interface.h
@@ -37,10 +37,10 @@
     virtual ~ObserverInterface() = default;
 
     // Called when the value is set for the observed |key|.
-    virtual void OnPrefSet(const std::string& key) = 0;
+    virtual void OnPrefSet(std::string_view key) = 0;
 
     // Called when the observed |key| is deleted.
-    virtual void OnPrefDeleted(const std::string& key) = 0;
+    virtual void OnPrefDeleted(std::string_view key) = 0;
   };
 
   virtual ~PrefsInterface() = default;
@@ -48,61 +48,61 @@
   // Gets a string |value| associated with |key|. Returns true on
   // success, false on failure (including when the |key| is not
   // present in the store).
-  virtual bool GetString(const std::string& key, std::string* value) const = 0;
+  virtual bool GetString(std::string_view key, std::string* value) const = 0;
 
   // Associates |key| with a string |value|. Returns true on success,
   // false otherwise.
-  virtual bool SetString(const std::string& key, std::string_view value) = 0;
+  virtual bool SetString(std::string_view key, std::string_view value) = 0;
 
   // Gets an int64_t |value| associated with |key|. Returns true on
   // success, false on failure (including when the |key| is not
   // present in the store).
-  virtual bool GetInt64(const std::string& key, int64_t* value) const = 0;
+  virtual bool GetInt64(std::string_view key, int64_t* value) const = 0;
 
   // Associates |key| with an int64_t |value|. Returns true on success,
   // false otherwise.
-  virtual bool SetInt64(const std::string& key, const int64_t value) = 0;
+  virtual bool SetInt64(std::string_view key, const int64_t value) = 0;
 
   // Gets a boolean |value| associated with |key|. Returns true on
   // success, false on failure (including when the |key| is not
   // present in the store).
-  virtual bool GetBoolean(const std::string& key, bool* value) const = 0;
+  virtual bool GetBoolean(std::string_view key, bool* value) const = 0;
 
   // Associates |key| with a boolean |value|. Returns true on success,
   // false otherwise.
-  virtual bool SetBoolean(const std::string& key, const bool value) = 0;
+  virtual bool SetBoolean(std::string_view key, const bool value) = 0;
 
   // Returns true if the setting exists (i.e. a file with the given key
   // exists in the prefs directory)
-  virtual bool Exists(const std::string& key) const = 0;
+  virtual bool Exists(std::string_view key) const = 0;
 
   // Returns true if successfully deleted the file corresponding to
   // this key. Calling with non-existent keys does nothing.
-  virtual bool Delete(const std::string& key) = 0;
+  virtual bool Delete(std::string_view key) = 0;
 
   // Deletes the pref key from platform and given namespace subdirectories.
   // Keys are matched against end of pref keys in each namespace.
   // Returns true if all deletes were successful.
-  virtual bool Delete(const std::string& pref_key,
+  virtual bool Delete(std::string_view pref_key,
                       const std::vector<std::string>& nss) = 0;
 
   // Creates a key which is part of a sub preference.
   static std::string CreateSubKey(const std::vector<std::string>& ns_with_key);
 
   // Returns a list of keys within the namespace.
-  virtual bool GetSubKeys(const std::string& ns,
+  virtual bool GetSubKeys(std::string_view ns,
                           std::vector<std::string>* keys) const = 0;
 
   // Add an observer to watch whenever the given |key| is modified. The
   // OnPrefSet() and OnPrefDelete() methods will be called whenever any of the
   // Set*() methods or the Delete() method are called on the given key,
   // respectively.
-  virtual void AddObserver(const std::string& key,
+  virtual void AddObserver(std::string_view key,
                            ObserverInterface* observer) = 0;
 
   // Remove an observer added with AddObserver(). The observer won't be called
   // anymore for future Set*() and Delete() method calls.
-  virtual void RemoveObserver(const std::string& key,
+  virtual void RemoveObserver(std::string_view key,
                               ObserverInterface* observer) = 0;
 
  protected:
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc
index a5f46e5..cef6d44 100644
--- a/common/prefs_unittest.cc
+++ b/common/prefs_unittest.cc
@@ -507,8 +507,8 @@
 
 class MockPrefsObserver : public PrefsInterface::ObserverInterface {
  public:
-  MOCK_METHOD1(OnPrefSet, void(const string&));
-  MOCK_METHOD1(OnPrefDeleted, void(const string& key));
+  MOCK_METHOD1(OnPrefSet, void(std::string_view));
+  MOCK_METHOD1(OnPrefDeleted, void(std::string_view));
 };
 
 TEST_F(PrefsTest, ObserversCalled) {
diff --git a/metrics_utils.cc b/metrics_utils.cc
index 34da5a1..ade024a 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -294,7 +294,7 @@
   return metrics::ConnectionType::kUnknown;
 }
 
-int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) {
+int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs) {
   CHECK(prefs);
   if (!prefs->Exists(key))
     return 0;
diff --git a/metrics_utils.h b/metrics_utils.h
index 3aac4e5..16e9eec 100644
--- a/metrics_utils.h
+++ b/metrics_utils.h
@@ -50,7 +50,7 @@
 
 // Returns the persisted value from prefs for the given key. It also
 // validates that the value returned is non-negative.
-int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs);
+int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs);
 
 // Persists the reboot count of the update attempt to |kPrefsNumReboots|.
 void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs);
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index a57169b..7c07f1d 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -32,8 +32,6 @@
 #include <base/format_macros.h>
 #include <base/metrics/histogram_macros.h>
 #include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
 #include <base/time/time.h>
 #include <brillo/data_encoding.h>
 #include <bsdiff/bspatch.h>
@@ -873,44 +871,6 @@
   return partition_writer_->PerformZeroOrDiscardOperation(operation);
 }
 
-bool PartitionWriter::ValidateSourceHash(const brillo::Blob& calculated_hash,
-                                         const InstallOperation& operation,
-                                         const FileDescriptorPtr source_fd,
-                                         ErrorCode* error) {
-  brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
-                                    operation.src_sha256_hash().end());
-  if (calculated_hash != expected_source_hash) {
-    LOG(ERROR) << "The hash of the source data on disk for this operation "
-               << "doesn't match the expected value. This could mean that the "
-               << "delta update payload was targeted for another version, or "
-               << "that the source partition was modified after it was "
-               << "installed, for example, by mounting a filesystem.";
-    LOG(ERROR) << "Expected:   sha256|hex = "
-               << base::HexEncode(expected_source_hash.data(),
-                                  expected_source_hash.size());
-    LOG(ERROR) << "Calculated: sha256|hex = "
-               << base::HexEncode(calculated_hash.data(),
-                                  calculated_hash.size());
-
-    vector<string> source_extents;
-    for (const Extent& ext : operation.src_extents()) {
-      source_extents.push_back(
-          base::StringPrintf("%" PRIu64 ":%" PRIu64,
-                             static_cast<uint64_t>(ext.start_block()),
-                             static_cast<uint64_t>(ext.num_blocks())));
-    }
-    LOG(ERROR) << "Operation source (offset:size) in blocks: "
-               << base::JoinString(source_extents, ",");
-
-    // Log remount history if this device is an ext4 partition.
-    LogMountHistory(source_fd);
-
-    *error = ErrorCode::kDownloadStateInitializationError;
-    return false;
-  }
-  return true;
-}
-
 bool DeltaPerformer::PerformSourceCopyOperation(
     const InstallOperation& operation, ErrorCode* error) {
   if (operation.has_src_length())
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index c54316b..1d95e1e 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -176,14 +176,6 @@
   // Exposed for testing purposes.
   bool CheckpointUpdateProgress(bool force);
 
-  // Compare |calculated_hash| with source hash in |operation|, return false and
-  // dump hash and set |error| if don't match.
-  // |source_fd| is the file descriptor of the source partition.
-  static bool ValidateSourceHash(const brillo::Blob& calculated_hash,
-                                 const InstallOperation& operation,
-                                 const FileDescriptorPtr source_fd,
-                                 ErrorCode* error);
-
   // Initialize partitions and allocate required space for an update with the
   // given |manifest|. |update_check_response_hash| is used to check if the
   // previous call to this function corresponds to the same payload.
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index 4fab975..a72b8ae 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -156,7 +156,7 @@
     performer.manifest_.CopyFrom(manifest);
     performer.major_payload_version_ = major_version;
 
-    EXPECT_EQ(expected, performer.ValidateManifest());
+    ASSERT_EQ(expected, performer.ValidateManifest());
   }
   void AddPartition(DeltaArchiveManifest* manifest,
                     string name,
@@ -171,19 +171,19 @@
 static void CompareFilesByBlock(const string& a_file,
                                 const string& b_file,
                                 size_t image_size) {
-  EXPECT_EQ(0U, image_size % kBlockSize);
+  ASSERT_EQ(0U, image_size % kBlockSize);
 
   brillo::Blob a_data, b_data;
-  EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
-  EXPECT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
+  ASSERT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
+  ASSERT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
 
   EXPECT_GE(a_data.size(), image_size);
   EXPECT_GE(b_data.size(), image_size);
   for (size_t i = 0; i < image_size; i += kBlockSize) {
-    EXPECT_EQ(0U, i % kBlockSize);
+    ASSERT_EQ(0U, i % kBlockSize);
     brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
     brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
-    EXPECT_TRUE(a_sub == b_sub) << "Block " << (i / kBlockSize) << " differs";
+    ASSERT_EQ(a_sub, b_sub) << "Block " << (i / kBlockSize) << " differs";
   }
   if (::testing::Test::HasNonfatalFailure()) {
     LOG(INFO) << "Compared filesystems with size " << image_size
@@ -207,8 +207,7 @@
   int fd = open(path.c_str(), O_CREAT | O_WRONLY, 0644);
   TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
   ScopedFdCloser fd_closer(&fd);
-  EXPECT_TRUE(utils::PWriteAll(fd, "\0", 1, offset));
-  return true;
+  return utils::PWriteAll(fd, "\0", 1, offset);
 }
 
 static bool InsertSignaturePlaceholder(size_t signature_size,
@@ -245,7 +244,7 @@
                                                    {metadata_signature},
                                                    payload_path,
                                                    out_metadata_size));
-  EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
+  ASSERT_TRUE(PayloadSigner::VerifySignedPayload(
       payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
 }
 
@@ -359,12 +358,12 @@
     // openssl genrsa -out <private_key_path> 2048
     RSA* rsa = RSA_new();
     BIGNUM* e = BN_new();
-    EXPECT_EQ(1, BN_set_word(e, RSA_F4));
-    EXPECT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
+    ASSERT_EQ(1, BN_set_word(e, RSA_F4));
+    ASSERT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
     BN_free(e);
     FILE* fprikey = fopen(private_key_path.c_str(), "w");
     EXPECT_NE(nullptr, fprikey);
-    EXPECT_EQ(1,
+    ASSERT_EQ(1,
               PEM_write_RSAPrivateKey(
                   fprikey, rsa, nullptr, nullptr, 0, nullptr, nullptr));
     fclose(fprikey);
@@ -405,7 +404,7 @@
   // in-place on A, we apply it to a new image, result_img.
   state->result_img.reset(new ScopedTempFile("result_img.XXXXXX"));
 
-  EXPECT_TRUE(
+  ASSERT_TRUE(
       base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
                      base::FilePath(state->a_img->path())));
 
@@ -422,28 +421,28 @@
                             std::begin(kRandomString),
                             std::end(kRandomString));
     }
-    EXPECT_TRUE(utils::WriteFile(
+    ASSERT_TRUE(utils::WriteFile(
         base::StringPrintf("%s/hardtocompress", a_mnt.c_str()).c_str(),
         hardtocompress.data(),
         hardtocompress.size()));
 
     brillo::Blob zeros(16 * 1024, 0);
-    EXPECT_EQ(static_cast<int>(zeros.size()),
+    ASSERT_EQ(static_cast<int>(zeros.size()),
               base::WriteFile(base::FilePath(base::StringPrintf(
                                   "%s/move-to-sparse", a_mnt.c_str())),
                               reinterpret_cast<const char*>(zeros.data()),
                               zeros.size()));
 
-    EXPECT_TRUE(WriteSparseFile(
+    ASSERT_TRUE(WriteSparseFile(
         base::StringPrintf("%s/move-from-sparse", a_mnt.c_str()), 16 * 1024));
 
-    EXPECT_TRUE(WriteByteAtOffset(
+    ASSERT_TRUE(WriteByteAtOffset(
         base::StringPrintf("%s/move-semi-sparse", a_mnt.c_str()), 4096));
 
     // Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
     // patch fails to zero out the final block.
     brillo::Blob ones(1024 * 1024, 0xff);
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         utils::WriteFile(base::StringPrintf("%s/ones", a_mnt.c_str()).c_str(),
                          ones.data(),
                          ones.size()));
@@ -451,12 +450,12 @@
 
   // Create a result image with image_size bytes of garbage.
   brillo::Blob ones(state->image_size, 0xff);
-  EXPECT_TRUE(utils::WriteFile(
+  ASSERT_TRUE(utils::WriteFile(
       state->result_img->path().c_str(), ones.data(), ones.size()));
-  EXPECT_EQ(utils::FileSize(state->a_img->path()),
+  ASSERT_EQ(utils::FileSize(state->a_img->path()),
             utils::FileSize(state->result_img->path()));
 
-  EXPECT_TRUE(
+  ASSERT_TRUE(
       base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
                      base::FilePath(state->b_img->path())));
   {
@@ -465,45 +464,45 @@
     ScopedLoopMounter b_mounter(state->b_img->path(), &b_mnt, 0);
     base::FilePath mnt_path(b_mnt);
 
-    EXPECT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
+    ASSERT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
                                mnt_path.Append("regular-small2")));
 #if BASE_VER < 800000
-    EXPECT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
+    ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
 #else
-    EXPECT_TRUE(base::DeleteFile(mnt_path.Append("regular-small")));
+    ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small")));
 #endif
-    EXPECT_TRUE(base::Move(mnt_path.Append("regular-small2"),
+    ASSERT_TRUE(base::Move(mnt_path.Append("regular-small2"),
                            mnt_path.Append("regular-small")));
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         test_utils::WriteFileString(mnt_path.Append("foo").value(), "foo"));
-    EXPECT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
+    ASSERT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
 
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         WriteSparseFile(mnt_path.Append("fullsparse").value(), 1024 * 1024));
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         WriteSparseFile(mnt_path.Append("move-to-sparse").value(), 16 * 1024));
 
     brillo::Blob zeros(16 * 1024, 0);
-    EXPECT_EQ(static_cast<int>(zeros.size()),
+    ASSERT_EQ(static_cast<int>(zeros.size()),
               base::WriteFile(mnt_path.Append("move-from-sparse"),
                               reinterpret_cast<const char*>(zeros.data()),
                               zeros.size()));
 
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         WriteByteAtOffset(mnt_path.Append("move-semi-sparse").value(), 4096));
-    EXPECT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
+    ASSERT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
 
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         base::CopyFile(mnt_path.Append("regular-16k"), mnt_path.Append("tmp")));
-    EXPECT_TRUE(base::Move(mnt_path.Append("tmp"),
+    ASSERT_TRUE(base::Move(mnt_path.Append("tmp"),
                            mnt_path.Append("link-hard-regular-16k")));
 
 #if BASE_VER < 800000
-    EXPECT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
+    ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
 #else
-    EXPECT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink")));
+    ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink")));
 #endif
-    EXPECT_TRUE(test_utils::WriteFileString(
+    ASSERT_TRUE(test_utils::WriteFileString(
         mnt_path.Append("link-short_symlink").value(), "foobar"));
 
     brillo::Blob hardtocompress;
@@ -512,7 +511,7 @@
                             std::begin(kRandomString),
                             std::end(kRandomString));
     }
-    EXPECT_TRUE(utils::WriteFile(
+    ASSERT_TRUE(utils::WriteFile(
         base::StringPrintf("%s/hardtocompress", b_mnt.c_str()).c_str(),
         hardtocompress.data(),
         hardtocompress.size()));
@@ -534,13 +533,13 @@
       std::begin(kNewData), std::end(kNewData), state->new_kernel_data.begin());
 
   // Write kernels to disk
-  EXPECT_TRUE(utils::WriteFile(state->old_kernel->path().c_str(),
+  ASSERT_TRUE(utils::WriteFile(state->old_kernel->path().c_str(),
                                state->old_kernel_data.data(),
                                state->old_kernel_data.size()));
-  EXPECT_TRUE(utils::WriteFile(state->new_kernel->path().c_str(),
+  ASSERT_TRUE(utils::WriteFile(state->new_kernel->path().c_str(),
                                state->new_kernel_data.data(),
                                state->new_kernel_data.size()));
-  EXPECT_TRUE(utils::WriteFile(state->result_kernel->path().c_str(),
+  ASSERT_TRUE(utils::WriteFile(state->result_kernel->path().c_str(),
                                state->result_kernel_data.data(),
                                state->result_kernel_data.size()));
 
@@ -564,9 +563,9 @@
       if (!full_kernel)
         payload_config.source.partitions.back().path =
             state->old_kernel->path();
-      EXPECT_TRUE(payload_config.source.LoadImageSize());
+      ASSERT_TRUE(payload_config.source.LoadImageSize());
       for (PartitionConfig& part : payload_config.source.partitions)
-        EXPECT_TRUE(part.OpenFilesystem());
+        ASSERT_TRUE(part.OpenFilesystem());
     } else {
       if (payload_config.hard_chunk_size == -1)
         // Use 1 MiB chunk size for the full unittests.
@@ -576,26 +575,26 @@
     payload_config.target.partitions.back().path = state->b_img->path();
     payload_config.target.partitions.emplace_back(kPartitionNameKernel);
     payload_config.target.partitions.back().path = state->new_kernel->path();
-    EXPECT_TRUE(payload_config.target.LoadImageSize());
+    ASSERT_TRUE(payload_config.target.LoadImageSize());
     for (PartitionConfig& part : payload_config.target.partitions)
-      EXPECT_TRUE(part.OpenFilesystem());
+      ASSERT_TRUE(part.OpenFilesystem());
 
-    EXPECT_TRUE(payload_config.Validate());
-    EXPECT_TRUE(GenerateUpdatePayloadFile(payload_config,
+    ASSERT_TRUE(payload_config.Validate());
+    ASSERT_TRUE(GenerateUpdatePayloadFile(payload_config,
                                           state->delta_file->path(),
                                           private_key,
                                           &state->metadata_size));
   }
   // Extend the "partitions" holding the file system a bit.
-  EXPECT_EQ(0,
+  ASSERT_EQ(0,
             HANDLE_EINTR(truncate(state->a_img->path().c_str(),
                                   state->image_size + 1024 * 1024)));
-  EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
+  ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
             utils::FileSize(state->a_img->path()));
-  EXPECT_EQ(0,
+  ASSERT_EQ(0,
             HANDLE_EINTR(truncate(state->b_img->path().c_str(),
                                   state->image_size + 1024 * 1024)));
-  EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
+  ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
             utils::FileSize(state->b_img->path()));
 
   if (signature_test == kSignatureGeneratedPlaceholder ||
@@ -643,9 +642,9 @@
                            uint32_t minor_version) {
   // Check the metadata.
   {
-    EXPECT_TRUE(utils::ReadFile(state->delta_file->path(), &state->delta));
+    ASSERT_TRUE(utils::ReadFile(state->delta_file->path(), &state->delta));
     PayloadMetadata payload_metadata;
-    EXPECT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
+    ASSERT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
     state->metadata_size = payload_metadata.GetMetadataSize();
     LOG(INFO) << "Metadata size: " << state->metadata_size;
     state->metadata_signature_size =
@@ -653,23 +652,23 @@
     LOG(INFO) << "Metadata signature size: " << state->metadata_signature_size;
 
     DeltaArchiveManifest manifest;
-    EXPECT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
+    ASSERT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
     if (signature_test == kSignatureNone) {
-      EXPECT_FALSE(manifest.has_signatures_offset());
-      EXPECT_FALSE(manifest.has_signatures_size());
+      ASSERT_FALSE(manifest.has_signatures_offset());
+      ASSERT_FALSE(manifest.has_signatures_size());
     } else {
-      EXPECT_TRUE(manifest.has_signatures_offset());
-      EXPECT_TRUE(manifest.has_signatures_size());
+      ASSERT_TRUE(manifest.has_signatures_offset());
+      ASSERT_TRUE(manifest.has_signatures_size());
       Signatures sigs_message;
-      EXPECT_TRUE(sigs_message.ParseFromArray(
+      ASSERT_TRUE(sigs_message.ParseFromArray(
           &state->delta[state->metadata_size + state->metadata_signature_size +
                         manifest.signatures_offset()],
           manifest.signatures_size()));
       if (signature_test == kSignatureGeneratedShellRotateCl1 ||
           signature_test == kSignatureGeneratedShellRotateCl2)
-        EXPECT_EQ(2, sigs_message.signatures_size());
+        ASSERT_EQ(2, sigs_message.signatures_size());
       else
-        EXPECT_EQ(1, sigs_message.signatures_size());
+        ASSERT_EQ(1, sigs_message.signatures_size());
       const Signatures::Signature& signature = sigs_message.signatures(0);
 
       vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
@@ -680,10 +679,10 @@
         key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
       }
       uint64_t expected_sig_data_length = 0;
-      EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
+      ASSERT_TRUE(PayloadSigner::SignatureBlobLength(
           key_paths, &expected_sig_data_length));
-      EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
-      EXPECT_FALSE(signature.data().empty());
+      ASSERT_EQ(expected_sig_data_length, manifest.signatures_size());
+      ASSERT_FALSE(signature.data().empty());
     }
 
     // TODO(ahassani): Make |DeltaState| into a partition list kind of struct
@@ -696,15 +695,15 @@
           return partition.partition_name() == kPartitionNameKernel;
         });
     if (full_kernel) {
-      EXPECT_FALSE(kernel_part.has_old_partition_info());
+      ASSERT_FALSE(kernel_part.has_old_partition_info());
     } else {
-      EXPECT_EQ(state->old_kernel_data.size(),
+      ASSERT_EQ(state->old_kernel_data.size(),
                 kernel_part.old_partition_info().size());
-      EXPECT_FALSE(kernel_part.old_partition_info().hash().empty());
+      ASSERT_FALSE(kernel_part.old_partition_info().hash().empty());
     }
-    EXPECT_EQ(state->new_kernel_data.size(),
+    ASSERT_EQ(state->new_kernel_data.size(),
               kernel_part.new_partition_info().size());
-    EXPECT_FALSE(kernel_part.new_partition_info().hash().empty());
+    ASSERT_FALSE(kernel_part.new_partition_info().hash().empty());
 
     const auto& rootfs_part =
         *std::find_if(manifest.partitions().begin(),
@@ -713,11 +712,11 @@
                         return partition.partition_name() == kPartitionNameRoot;
                       });
     if (full_rootfs) {
-      EXPECT_FALSE(rootfs_part.has_old_partition_info());
+      ASSERT_FALSE(rootfs_part.has_old_partition_info());
     } else {
-      EXPECT_FALSE(rootfs_part.old_partition_info().hash().empty());
+      ASSERT_FALSE(rootfs_part.old_partition_info().hash().empty());
     }
-    EXPECT_FALSE(rootfs_part.new_partition_info().hash().empty());
+    ASSERT_FALSE(rootfs_part.new_partition_info().hash().empty());
   }
 
   NiceMock<MockPrefs> prefs;
@@ -798,7 +797,7 @@
           ? GetBuildArtifactsPath(kUnittestPrivateKeyECPath)
           : GetBuildArtifactsPath(kUnittestPrivateKeyPath),
       &install_plan->payloads[0].metadata_signature));
-  EXPECT_FALSE(install_plan->payloads[0].metadata_signature.empty());
+  ASSERT_FALSE(install_plan->payloads[0].metadata_signature.empty());
 
   *performer = new DeltaPerformer(&prefs,
                                   &state->fake_boot_control_,
@@ -810,15 +809,15 @@
   string public_key_path = signature_test == kSignatureGeneratedShellECKey
                                ? GetBuildArtifactsPath(kUnittestPublicKeyECPath)
                                : GetBuildArtifactsPath(kUnittestPublicKeyPath);
-  EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
+  ASSERT_TRUE(utils::FileExists(public_key_path.c_str()));
   (*performer)->set_public_key_path(public_key_path);
   (*performer)->set_update_certificates_path("");
 
-  EXPECT_EQ(
+  ASSERT_EQ(
       static_cast<off_t>(state->image_size),
       HashCalculator::RawHashOfFile(
           state->a_img->path(), state->image_size, &root_part.source_hash));
-  EXPECT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
+  ASSERT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
                                             &kernel_part.source_hash));
 
   // The partitions should be empty before DeltaPerformer.
@@ -872,23 +871,23 @@
     // we cannot proceed applying the delta.
     if (!write_succeeded) {
       LOG(INFO) << "Write failed. Checking if it failed with expected error";
-      EXPECT_EQ(expected_error, actual_error);
+      ASSERT_EQ(expected_error, actual_error);
       if (!continue_writing) {
         LOG(INFO) << "Cannot continue writing. Bailing out.";
         break;
       }
     }
 
-    EXPECT_EQ(ErrorCode::kSuccess, actual_error);
+    ASSERT_EQ(ErrorCode::kSuccess, actual_error);
   }
 
   // If we had continued all the way through, Close should succeed.
   // Otherwise, it should fail. Check appropriately.
   bool close_result = (*performer)->Close();
   if (continue_writing)
-    EXPECT_EQ(0, close_result);
+    ASSERT_EQ(0, close_result);
   else
-    EXPECT_LE(0, close_result);
+    ASSERT_LE(0, close_result);
 }
 
 void VerifyPayloadResult(DeltaPerformer* performer,
@@ -896,14 +895,14 @@
                          ErrorCode expected_result,
                          uint32_t minor_version) {
   if (!performer) {
-    EXPECT_TRUE(!"Skipping payload verification since performer is null.");
+    ASSERT_TRUE(!"Skipping payload verification since performer is null.");
     return;
   }
 
   LOG(INFO) << "Verifying payload for expected result " << expected_result;
   brillo::Blob expected_hash;
   HashCalculator::RawHashOfData(state->delta, &expected_hash);
-  EXPECT_EQ(expected_result,
+  ASSERT_EQ(expected_result,
             performer->VerifyPayload(expected_hash, state->delta.size()));
   LOG(INFO) << "Verified payload.";
 
@@ -919,31 +918,31 @@
       state->result_img->path(), state->b_img->path(), state->image_size);
 
   brillo::Blob updated_kernel_partition;
-  EXPECT_TRUE(
+  ASSERT_TRUE(
       utils::ReadFile(state->result_kernel->path(), &updated_kernel_partition));
   ASSERT_GE(updated_kernel_partition.size(), base::size(kNewData));
-  EXPECT_TRUE(std::equal(std::begin(kNewData),
+  ASSERT_TRUE(std::equal(std::begin(kNewData),
                          std::end(kNewData),
                          updated_kernel_partition.begin()));
 
   const auto& partitions = state->install_plan.partitions;
-  EXPECT_EQ(2U, partitions.size());
-  EXPECT_EQ(kPartitionNameRoot, partitions[0].name);
-  EXPECT_EQ(kPartitionNameKernel, partitions[1].name);
+  ASSERT_EQ(2U, partitions.size());
+  ASSERT_EQ(kPartitionNameRoot, partitions[0].name);
+  ASSERT_EQ(kPartitionNameKernel, partitions[1].name);
 
-  EXPECT_EQ(kDefaultKernelSize, partitions[1].target_size);
+  ASSERT_EQ(kDefaultKernelSize, partitions[1].target_size);
   brillo::Blob expected_new_kernel_hash;
-  EXPECT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
+  ASSERT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
                                             &expected_new_kernel_hash));
-  EXPECT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
+  ASSERT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
 
-  EXPECT_EQ(state->image_size, partitions[0].target_size);
+  ASSERT_EQ(state->image_size, partitions[0].target_size);
   brillo::Blob expected_new_rootfs_hash;
-  EXPECT_EQ(
+  ASSERT_EQ(
       static_cast<off_t>(state->image_size),
       HashCalculator::RawHashOfFile(
           state->b_img->path(), state->image_size, &expected_new_rootfs_hash));
-  EXPECT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
+  ASSERT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
 }
 
 void VerifyPayload(DeltaPerformer* performer,
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index 840ecf6..27f846e 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -654,7 +654,9 @@
   brillo::Blob payload_data =
       GeneratePayload(brillo::Blob(), {aop}, false, &old_part);
 
-  EXPECT_EQ(actual_data, ApplyPayload(payload_data, source.path(), false));
+  // When source hash mismatches, PartitionWriter will refuse to write anything.
+  // Therefore we should expect an empty blob.
+  EXPECT_EQ(brillo::Blob{}, ApplyPayload(payload_data, source.path(), false));
 }
 
 TEST_F(DeltaPerformerTest, ExtentsToByteStringTest) {
diff --git a/payload_consumer/file_descriptor_utils.cc b/payload_consumer/file_descriptor_utils.cc
index 9a6a601..91b5673 100644
--- a/payload_consumer/file_descriptor_utils.cc
+++ b/payload_consumer/file_descriptor_utils.cc
@@ -35,9 +35,12 @@
 // Size of the buffer used to copy blocks.
 const uint64_t kMaxCopyBufferSize = 1024 * 1024;
 
+}  // namespace
+namespace fd_utils {
+
 bool CommonHashExtents(FileDescriptorPtr source,
                        const RepeatedPtrField<Extent>& src_extents,
-                       DirectExtentWriter* writer,
+                       ExtentWriter* writer,
                        uint64_t block_size,
                        brillo::Blob* hash_out) {
   auto total_blocks = utils::BlocksInExtents(src_extents);
@@ -72,10 +75,6 @@
   return true;
 }
 
-}  // namespace
-
-namespace fd_utils {
-
 bool CopyAndHashExtents(FileDescriptorPtr source,
                         const RepeatedPtrField<Extent>& src_extents,
                         FileDescriptorPtr target,
diff --git a/payload_consumer/file_descriptor_utils.h b/payload_consumer/file_descriptor_utils.h
index 68fb001..3a4027d 100644
--- a/payload_consumer/file_descriptor_utils.h
+++ b/payload_consumer/file_descriptor_utils.h
@@ -19,12 +19,20 @@
 
 #include <brillo/secure_blob.h>
 
+#include "update_engine/payload_consumer/extent_writer.h"
 #include "update_engine/payload_consumer/file_descriptor.h"
 #include "update_engine/update_metadata.pb.h"
 
 namespace chromeos_update_engine {
 namespace fd_utils {
 
+bool CommonHashExtents(
+    FileDescriptorPtr source,
+    const google::protobuf::RepeatedPtrField<Extent>& src_extents,
+    ExtentWriter* writer,
+    uint64_t block_size,
+    brillo::Blob* hash_out);
+
 // Copy blocks from the |source| file to the |target| file and hashes the
 // contents. The blocks to copy from the |source| to the |target| files are
 // specified by the |src_extents| and |tgt_extents| list of Extents, which
diff --git a/payload_consumer/install_operation_executor.cc b/payload_consumer/install_operation_executor.cc
new file mode 100644
index 0000000..4bfcb5d
--- /dev/null
+++ b/payload_consumer/install_operation_executor.cc
@@ -0,0 +1,316 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/payload_consumer/install_operation_executor.h"
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <fcntl.h>
+#include <glob.h>
+#include <linux/fs.h>
+
+#include <base/files/memory_mapped_file.h>
+#include <bsdiff/bspatch.h>
+#include <puffin/puffpatch.h>
+#include <sys/mman.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/bzip_extent_writer.h"
+#include "update_engine/payload_consumer/cached_file_descriptor.h"
+#include "update_engine/payload_consumer/extent_reader.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/xz_extent_writer.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+class BsdiffExtentFile : public bsdiff::FileInterface {
+ public:
+  BsdiffExtentFile(std::unique_ptr<ExtentReader> reader, size_t size)
+      : BsdiffExtentFile(std::move(reader), nullptr, size) {}
+  BsdiffExtentFile(std::unique_ptr<ExtentWriter> writer, size_t size)
+      : BsdiffExtentFile(nullptr, std::move(writer), size) {}
+
+  ~BsdiffExtentFile() override = default;
+
+  bool Read(void* buf, size_t count, size_t* bytes_read) override {
+    TEST_AND_RETURN_FALSE(reader_->Read(buf, count));
+    *bytes_read = count;
+    offset_ += count;
+    return true;
+  }
+
+  bool Write(const void* buf, size_t count, size_t* bytes_written) override {
+    TEST_AND_RETURN_FALSE(writer_->Write(buf, count));
+    *bytes_written = count;
+    offset_ += count;
+    return true;
+  }
+
+  bool Seek(off_t pos) override {
+    if (reader_ != nullptr) {
+      TEST_AND_RETURN_FALSE(reader_->Seek(pos));
+      offset_ = pos;
+    } else {
+      // For writes technically there should be no change of position, or it
+      // should be equivalent of current offset.
+      TEST_AND_RETURN_FALSE(offset_ == static_cast<uint64_t>(pos));
+    }
+    return true;
+  }
+
+  bool Close() override { return true; }
+
+  bool GetSize(uint64_t* size) override {
+    *size = size_;
+    return true;
+  }
+
+ private:
+  BsdiffExtentFile(std::unique_ptr<ExtentReader> reader,
+                   std::unique_ptr<ExtentWriter> writer,
+                   size_t size)
+      : reader_(std::move(reader)),
+        writer_(std::move(writer)),
+        size_(size),
+        offset_(0) {}
+
+  std::unique_ptr<ExtentReader> reader_;
+  std::unique_ptr<ExtentWriter> writer_;
+  uint64_t size_;
+  uint64_t offset_;
+
+  DISALLOW_COPY_AND_ASSIGN(BsdiffExtentFile);
+};
+// A class to be passed to |puffpatch| for reading from |source_fd_| and writing
+// into |target_fd_|.
+class PuffinExtentStream : public puffin::StreamInterface {
+ public:
+  // Constructor for creating a stream for reading from an |ExtentReader|.
+  PuffinExtentStream(std::unique_ptr<ExtentReader> reader, uint64_t size)
+      : PuffinExtentStream(std::move(reader), nullptr, size) {}
+
+  // Constructor for creating a stream for writing to an |ExtentWriter|.
+  PuffinExtentStream(std::unique_ptr<ExtentWriter> writer, uint64_t size)
+      : PuffinExtentStream(nullptr, std::move(writer), size) {}
+
+  ~PuffinExtentStream() override = default;
+
+  bool GetSize(uint64_t* size) const override {
+    *size = size_;
+    return true;
+  }
+
+  bool GetOffset(uint64_t* offset) const override {
+    *offset = offset_;
+    return true;
+  }
+
+  bool Seek(uint64_t offset) override {
+    if (is_read_) {
+      TEST_AND_RETURN_FALSE(reader_->Seek(offset));
+      offset_ = offset;
+    } else {
+      // For writes technically there should be no change of position, or it
+      // should equivalent of current offset.
+      TEST_AND_RETURN_FALSE(offset_ == offset);
+    }
+    return true;
+  }
+
+  bool Read(void* buffer, size_t count) override {
+    TEST_AND_RETURN_FALSE(is_read_);
+    TEST_AND_RETURN_FALSE(reader_->Read(buffer, count));
+    offset_ += count;
+    return true;
+  }
+
+  bool Write(const void* buffer, size_t count) override {
+    TEST_AND_RETURN_FALSE(!is_read_);
+    TEST_AND_RETURN_FALSE(writer_->Write(buffer, count));
+    offset_ += count;
+    return true;
+  }
+
+  bool Close() override { return true; }
+
+ private:
+  PuffinExtentStream(std::unique_ptr<ExtentReader> reader,
+                     std::unique_ptr<ExtentWriter> writer,
+                     uint64_t size)
+      : reader_(std::move(reader)),
+        writer_(std::move(writer)),
+        size_(size),
+        offset_(0),
+        is_read_(reader_ ? true : false) {}
+
+  std::unique_ptr<ExtentReader> reader_;
+  std::unique_ptr<ExtentWriter> writer_;
+  uint64_t size_;
+  uint64_t offset_;
+  bool is_read_;
+
+  DISALLOW_COPY_AND_ASSIGN(PuffinExtentStream);
+};
+
+bool InstallOperationExecutor::ExecuteInstallOp(
+    const InstallOperation& op,
+    std::unique_ptr<ExtentWriter> writer,
+    FileDescriptorPtr source_fd,
+    const void* data,
+    size_t size) {
+  switch (op.type()) {
+    case InstallOperation::REPLACE:
+    case InstallOperation::REPLACE_BZ:
+    case InstallOperation::REPLACE_XZ:
+      return ExecuteReplaceOperation(op, std::move(writer), data, size);
+    case InstallOperation::ZERO:
+    case InstallOperation::DISCARD:
+      return ExecuteZeroOrDiscardOperation(op, writer.get());
+    case InstallOperation::SOURCE_COPY:
+      return ExecuteSourceCopyOperation(op, writer.get(), source_fd);
+    case InstallOperation::SOURCE_BSDIFF:
+    case InstallOperation::BROTLI_BSDIFF:
+      return ExecuteSourceBsdiffOperation(
+          op, std::move(writer), source_fd, data, size);
+    case InstallOperation::PUFFDIFF:
+      return ExecutePuffDiffOperation(
+          op, std::move(writer), source_fd, data, size);
+      break;
+    default:
+      return false;
+  }
+  return false;
+}
+
+bool InstallOperationExecutor::ExecuteReplaceOperation(
+    const InstallOperation& operation,
+    std::unique_ptr<ExtentWriter> writer,
+    const void* data,
+    size_t count) {
+  TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::REPLACE ||
+                        operation.type() == InstallOperation::REPLACE_BZ ||
+                        operation.type() == InstallOperation::REPLACE_XZ);
+  // Setup the ExtentWriter stack based on the operation type.
+  if (operation.type() == InstallOperation::REPLACE_BZ) {
+    writer.reset(new BzipExtentWriter(std::move(writer)));
+  } else if (operation.type() == InstallOperation::REPLACE_XZ) {
+    writer.reset(new XzExtentWriter(std::move(writer)));
+  }
+  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+  TEST_AND_RETURN_FALSE(writer->Write(data, operation.data_length()));
+
+  return true;
+}
+
+bool InstallOperationExecutor::ExecuteZeroOrDiscardOperation(
+    const InstallOperation& operation, ExtentWriter* writer) {
+  TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::ZERO ||
+                        operation.type() == InstallOperation::DISCARD);
+  using base::MemoryMappedFile;
+  using Access = base::MemoryMappedFile::Access;
+  using Region = base::MemoryMappedFile::Region;
+  writer->Init(operation.dst_extents(), block_size_);
+  for (const auto& extent : operation.dst_extents()) {
+    // Mmap a region of /dev/zero, as we don't need any actual memory to store
+    // these 0s, so mmap a region of "free memory".
+    base::File dev_zero(base::FilePath("/dev/zero"),
+                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+    MemoryMappedFile buffer;
+    TEST_AND_RETURN_FALSE_ERRNO(buffer.Initialize(
+        std::move(dev_zero),
+        Region{0, static_cast<size_t>(extent.num_blocks() * block_size_)},
+        Access::READ_ONLY));
+    writer->Write(buffer.data(), buffer.length());
+  }
+  return true;
+}
+
+bool InstallOperationExecutor::ExecuteSourceCopyOperation(
+    const InstallOperation& operation,
+    ExtentWriter* writer,
+    FileDescriptorPtr source_fd) {
+  TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::SOURCE_COPY);
+  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+  return fd_utils::CommonHashExtents(
+      source_fd, operation.src_extents(), writer, block_size_, nullptr);
+}
+
+bool InstallOperationExecutor::ExecuteSourceBsdiffOperation(
+    const InstallOperation& operation,
+    std::unique_ptr<ExtentWriter> writer,
+    FileDescriptorPtr source_fd,
+    const void* data,
+    size_t count) {
+  TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::SOURCE_BSDIFF ||
+                        operation.type() == InstallOperation::BROTLI_BSDIFF ||
+                        operation.type() == InstallOperation::BSDIFF);
+  TEST_AND_RETURN_FALSE(source_fd != nullptr);
+
+  auto reader = std::make_unique<DirectExtentReader>();
+  TEST_AND_RETURN_FALSE(
+      reader->Init(source_fd, operation.src_extents(), block_size_));
+  auto src_file = std::make_unique<BsdiffExtentFile>(
+      std::move(reader),
+      utils::BlocksInExtents(operation.src_extents()) * block_size_);
+
+  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+  auto dst_file = std::make_unique<BsdiffExtentFile>(
+      std::move(writer),
+      utils::BlocksInExtents(operation.dst_extents()) * block_size_);
+
+  TEST_AND_RETURN_FALSE(bsdiff::bspatch(std::move(src_file),
+                                        std::move(dst_file),
+                                        reinterpret_cast<const uint8_t*>(data),
+                                        count) == 0);
+  return true;
+}
+
+bool InstallOperationExecutor::ExecutePuffDiffOperation(
+    const InstallOperation& operation,
+    std::unique_ptr<ExtentWriter> writer,
+    FileDescriptorPtr source_fd,
+    const void* data,
+    size_t count) {
+  TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::PUFFDIFF);
+  TEST_AND_RETURN_FALSE(source_fd != nullptr);
+
+  auto reader = std::make_unique<DirectExtentReader>();
+  TEST_AND_RETURN_FALSE(
+      reader->Init(source_fd, operation.src_extents(), block_size_));
+  puffin::UniqueStreamPtr src_stream(new PuffinExtentStream(
+      std::move(reader),
+      utils::BlocksInExtents(operation.src_extents()) * block_size_));
+
+  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+  puffin::UniqueStreamPtr dst_stream(new PuffinExtentStream(
+      std::move(writer),
+      utils::BlocksInExtents(operation.dst_extents()) * block_size_));
+
+  constexpr size_t kMaxCacheSize = 5 * 1024 * 1024;  // Total 5MB cache.
+  TEST_AND_RETURN_FALSE(
+      puffin::PuffPatch(std::move(src_stream),
+                        std::move(dst_stream),
+                        reinterpret_cast<const uint8_t*>(data),
+                        count,
+                        kMaxCacheSize));
+  return true;
+}
+}  // namespace chromeos_update_engine
diff --git a/payload_consumer/install_operation_executor.h b/payload_consumer/install_operation_executor.h
new file mode 100644
index 0000000..a43139b
--- /dev/null
+++ b/payload_consumer/install_operation_executor.h
@@ -0,0 +1,64 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_INSTALL_OPERATION_EXECUTOR_H
+#define UPDATE_ENGINE_INSTALL_OPERATION_EXECUTOR_H
+
+#include <memory>
+
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+class InstallOperationExecutor {
+ public:
+  explicit InstallOperationExecutor(size_t block_size)
+      : block_size_(block_size) {}
+
+  bool ExecuteInstallOp(const InstallOperation& op,
+                        std::unique_ptr<ExtentWriter> writer,
+                        FileDescriptorPtr source_fd,
+                        const void* data,
+                        size_t size);
+  bool ExecuteReplaceOperation(const InstallOperation& operation,
+                               std::unique_ptr<ExtentWriter> writer,
+                               const void* data,
+                               size_t count);
+  bool ExecuteZeroOrDiscardOperation(const InstallOperation& operation,
+                                     ExtentWriter* writer);
+  bool ExecuteSourceCopyOperation(const InstallOperation& operation,
+                                  ExtentWriter* writer,
+                                  FileDescriptorPtr source_fd);
+  bool ExecuteSourceBsdiffOperation(const InstallOperation& operation,
+                                    std::unique_ptr<ExtentWriter> writer,
+                                    FileDescriptorPtr source_fd,
+                                    const void* data,
+                                    size_t count);
+  bool ExecutePuffDiffOperation(const InstallOperation& operation,
+                                std::unique_ptr<ExtentWriter> writer,
+                                FileDescriptorPtr source_fd,
+                                const void* data,
+                                size_t count);
+
+ private:
+  size_t block_size_;
+};
+
+}  // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/install_operation_executor_unittest.cc b/payload_consumer/install_operation_executor_unittest.cc
new file mode 100644
index 0000000..c90b28d
--- /dev/null
+++ b/payload_consumer/install_operation_executor_unittest.cc
@@ -0,0 +1,221 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/payload_consumer/install_operation_executor.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <array>
+#include <cstring>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include <brillo/secure_blob.h>
+#include <gtest/gtest.h>
+#include <update_engine/update_metadata.pb.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+namespace chromeos_update_engine {
+
+std::ostream& operator<<(std::ostream& out,
+                         const chromeos_update_engine::InstallOperation& op) {
+  out << InstallOperationTypeName(op.type())
+      << " SRC: " << ExtentsToString(op.src_extents())
+      << " DST: " << ExtentsToString(op.dst_extents());
+  return out;
+}
+
+namespace {
+template <typename Container>
+size_t GetNthBlock(const Container& extents, const size_t n) {
+  size_t cur_block_count = 0;
+  for (const auto& extent : extents) {
+    if (cur_block_count + extent.num_blocks() >= n) {
+      return extent.start_block() + (n - cur_block_count);
+    }
+    cur_block_count += extent.num_blocks();
+  }
+  return std::numeric_limits<size_t>::max();
+}
+
+}  // namespace
+
+class InstallOperationExecutorTest : public ::testing::Test {
+ public:
+  static constexpr size_t NUM_BLOCKS = 10;
+  static constexpr size_t BLOCK_SIZE = 4096;
+  void SetUp() override {
+    // Fill source partition with arbitrary data.
+    std::array<uint8_t, BLOCK_SIZE> buffer{};
+    for (size_t i = 0; i < NUM_BLOCKS; i++) {
+      // Fill block with arbitrary data. We don't care about what data is being
+      // written to source partition, so as long as each block is slightly
+      // different.
+      std::fill(buffer.begin(), buffer.end(), i);
+      ASSERT_TRUE(utils::WriteAll(source_.fd(), buffer.data(), buffer.size()))
+          << "Failed to write to source partition file: " << strerror(errno);
+      std::fill(buffer.begin(), buffer.end(), NUM_BLOCKS + i);
+      ASSERT_TRUE(utils::WriteAll(target_.fd(), buffer.data(), buffer.size()))
+          << "Failed to write to target partition file: " << strerror(errno);
+    }
+    fsync(source_.fd());
+    fsync(target_.fd());
+
+    // set target partition to have same size as source partition.
+    // update_engine mostly assumes that target partition have the desired
+    // size, so we mock that.
+    ASSERT_GE(ftruncate64(target_.fd(), NUM_BLOCKS * BLOCK_SIZE), 0)
+        << strerror(errno) << " failed to set target partition size to "
+        << NUM_BLOCKS * BLOCK_SIZE;
+
+    source_fd_->Open(source_.path().c_str(), O_RDONLY);
+    target_fd_->Open(target_.path().c_str(), O_RDWR);
+  }
+
+  void VerityUntouchedExtents(const InstallOperation& op) {
+    ExtentRanges extent_set;
+    extent_set.AddExtent(ExtentForRange(0, 10));
+    extent_set.SubtractRepeatedExtents(op.dst_extents());
+    std::vector<Extent> untouched_extents{extent_set.extent_set().begin(),
+                                          extent_set.extent_set().end()};
+    brillo::Blob actual_data;
+    ASSERT_TRUE(utils::ReadExtents(target_.path(),
+                                   untouched_extents,
+                                   &actual_data,
+                                   extent_set.blocks() * BLOCK_SIZE,
+                                   BLOCK_SIZE));
+    const auto untouched_blocks = ExpandExtents(untouched_extents);
+    for (size_t i = 0; i < actual_data.size(); i++) {
+      const auto block_offset = i / BLOCK_SIZE;
+      const auto offset = i % BLOCK_SIZE;
+      ASSERT_EQ(
+          actual_data[i],
+          static_cast<uint8_t>(NUM_BLOCKS + untouched_blocks[block_offset]))
+          << "After performing op " << op << ", offset " << offset
+          << " in block " << GetNthBlock(untouched_extents, block_offset)
+          << " is modified but it shouldn't.";
+    }
+  }
+  ScopedTempFile source_{"source_partition.XXXXXXXX", true};
+  ScopedTempFile target_{"target_partition.XXXXXXXX", true};
+  FileDescriptorPtr source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+  FileDescriptorPtr target_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+  InstallOperationExecutor executor_{BLOCK_SIZE};
+};
+
+TEST_F(InstallOperationExecutorTest, ReplaceOpTest) {
+  InstallOperation op;
+  op.set_type(InstallOperation::REPLACE);
+  *op.mutable_dst_extents()->Add() = ExtentForRange(2, 2);
+  *op.mutable_dst_extents()->Add() = ExtentForRange(6, 2);
+  op.set_data_length(BLOCK_SIZE * 4);
+  brillo::Blob expected_data;
+  expected_data.resize(BLOCK_SIZE * 4);
+  // Fill buffer with arbitrary data. Doesn't matter what it is. Each block
+  // needs to be different so that we can ensure the InstallOperationExecutor
+  // is reading data from the correct offset.
+  for (int i = 0; i < 4; i++) {
+    std::fill(&expected_data[i * BLOCK_SIZE],
+              &expected_data[(i + 1) * BLOCK_SIZE],
+              i + 99);
+  }
+  auto writer = std::make_unique<DirectExtentWriter>(target_fd_);
+  ASSERT_TRUE(executor_.ExecuteReplaceOperation(
+      op, std::move(writer), expected_data.data(), expected_data.size()));
+
+  brillo::Blob actual_data;
+  utils::ReadExtents(
+      target_.path(),
+      std::vector<Extent>{op.dst_extents().begin(), op.dst_extents().end()},
+      &actual_data,
+      BLOCK_SIZE * 4,
+      BLOCK_SIZE);
+  ASSERT_EQ(actual_data, expected_data);
+  VerityUntouchedExtents(op);
+}
+
+TEST_F(InstallOperationExecutorTest, ZeroOrDiscardeOpTest) {
+  InstallOperation op;
+  op.set_type(InstallOperation::ZERO);
+  *op.mutable_dst_extents()->Add() = ExtentForRange(2, 2);
+  *op.mutable_dst_extents()->Add() = ExtentForRange(6, 2);
+  auto writer = std::make_unique<DirectExtentWriter>(target_fd_);
+  ASSERT_TRUE(executor_.ExecuteZeroOrDiscardOperation(op, writer.get()));
+  brillo::Blob actual_data;
+  utils::ReadExtents(
+      target_.path(),
+      std::vector<Extent>{op.dst_extents().begin(), op.dst_extents().end()},
+      &actual_data,
+      BLOCK_SIZE * 4,
+      BLOCK_SIZE);
+  for (size_t i = 0; i < actual_data.size(); i++) {
+    ASSERT_EQ(actual_data[i], 0U) << "position " << i << " isn't zeroed!";
+  }
+  VerityUntouchedExtents(op);
+}
+
+TEST_F(InstallOperationExecutorTest, SourceCopyOpTest) {
+  InstallOperation op;
+  op.set_type(InstallOperation::SOURCE_COPY);
+  *op.mutable_src_extents()->Add() = ExtentForRange(1, 2);
+  *op.mutable_src_extents()->Add() = ExtentForRange(5, 1);
+  *op.mutable_src_extents()->Add() = ExtentForRange(7, 1);
+
+  *op.mutable_dst_extents()->Add() = ExtentForRange(2, 2);
+  *op.mutable_dst_extents()->Add() = ExtentForRange(6, 2);
+
+  auto writer = std::make_unique<DirectExtentWriter>(target_fd_);
+  ASSERT_TRUE(
+      executor_.ExecuteSourceCopyOperation(op, writer.get(), source_fd_));
+  brillo::Blob actual_data;
+  utils::ReadExtents(
+      target_.path(),
+      std::vector<Extent>{op.dst_extents().begin(), op.dst_extents().end()},
+      &actual_data,
+      BLOCK_SIZE * 4,
+      BLOCK_SIZE);
+  brillo::Blob expected_data;
+  utils::ReadExtents(
+      source_.path(),
+      std::vector<Extent>{op.src_extents().begin(), op.src_extents().end()},
+      &expected_data,
+      BLOCK_SIZE * 4,
+      BLOCK_SIZE);
+
+  ASSERT_EQ(expected_data.size(), actual_data.size());
+  for (size_t i = 0; i < actual_data.size(); i++) {
+    const auto block_offset = i / BLOCK_SIZE;
+    const auto offset = i % BLOCK_SIZE;
+    ASSERT_EQ(actual_data[i], expected_data[i])
+        << "After performing op " << op << ", offset " << offset << " in  ["
+        << GetNthBlock(op.src_extents(), block_offset) << " -> "
+        << GetNthBlock(op.dst_extents(), block_offset) << "]"
+        << " is not copied correctly";
+  }
+  VerityUntouchedExtents(op);
+}
+}  // namespace chromeos_update_engine
diff --git a/payload_consumer/partition_writer.cc b/payload_consumer/partition_writer.cc
index 6f98ba3..9db7ae0 100644
--- a/payload_consumer/partition_writer.cc
+++ b/payload_consumer/partition_writer.cc
@@ -17,18 +17,20 @@
 
 #include <fcntl.h>
 #include <linux/fs.h>
+#include <sys/mman.h>
+
+#include <inttypes.h>
 
 #include <algorithm>
 #include <initializer_list>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
 #include <base/strings/string_number_conversions.h>
-#include <bsdiff/bspatch.h>
-#include <puffin/puffpatch.h>
-#include <bsdiff/file_interface.h>
-#include <puffin/stream.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
 
 #include "update_engine/common/terminator.h"
 #include "update_engine/common/utils.h"
@@ -36,12 +38,12 @@
 #include "update_engine/payload_consumer/cached_file_descriptor.h"
 #include "update_engine/payload_consumer/extent_reader.h"
 #include "update_engine/payload_consumer/extent_writer.h"
-#include "update_engine/payload_consumer/fec_file_descriptor.h"
 #include "update_engine/payload_consumer/file_descriptor_utils.h"
 #include "update_engine/payload_consumer/install_plan.h"
 #include "update_engine/payload_consumer/mount_history.h"
 #include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/payload_consumer/xz_extent_writer.h"
+#include "update_engine/payload_generator/extent_utils.h"
 
 namespace chromeos_update_engine {
 
@@ -83,6 +85,8 @@
 
 }  // namespace
 
+using google::protobuf::RepeatedPtrField;
+
 // Opens path for read/write. On success returns an open FileDescriptor
 // and sets *err to 0. On failure, sets *err to errno and returns nullptr.
 FileDescriptorPtr OpenFile(const char* path,
@@ -108,135 +112,6 @@
   return fd;
 }
 
-class BsdiffExtentFile : public bsdiff::FileInterface {
- public:
-  BsdiffExtentFile(std::unique_ptr<ExtentReader> reader, size_t size)
-      : BsdiffExtentFile(std::move(reader), nullptr, size) {}
-  BsdiffExtentFile(std::unique_ptr<ExtentWriter> writer, size_t size)
-      : BsdiffExtentFile(nullptr, std::move(writer), size) {}
-
-  ~BsdiffExtentFile() override = default;
-
-  bool Read(void* buf, size_t count, size_t* bytes_read) override {
-    TEST_AND_RETURN_FALSE(reader_->Read(buf, count));
-    *bytes_read = count;
-    offset_ += count;
-    return true;
-  }
-
-  bool Write(const void* buf, size_t count, size_t* bytes_written) override {
-    TEST_AND_RETURN_FALSE(writer_->Write(buf, count));
-    *bytes_written = count;
-    offset_ += count;
-    return true;
-  }
-
-  bool Seek(off_t pos) override {
-    if (reader_ != nullptr) {
-      TEST_AND_RETURN_FALSE(reader_->Seek(pos));
-      offset_ = pos;
-    } else {
-      // For writes technically there should be no change of position, or it
-      // should be equivalent of current offset.
-      TEST_AND_RETURN_FALSE(offset_ == static_cast<uint64_t>(pos));
-    }
-    return true;
-  }
-
-  bool Close() override { return true; }
-
-  bool GetSize(uint64_t* size) override {
-    *size = size_;
-    return true;
-  }
-
- private:
-  BsdiffExtentFile(std::unique_ptr<ExtentReader> reader,
-                   std::unique_ptr<ExtentWriter> writer,
-                   size_t size)
-      : reader_(std::move(reader)),
-        writer_(std::move(writer)),
-        size_(size),
-        offset_(0) {}
-
-  std::unique_ptr<ExtentReader> reader_;
-  std::unique_ptr<ExtentWriter> writer_;
-  uint64_t size_;
-  uint64_t offset_;
-
-  DISALLOW_COPY_AND_ASSIGN(BsdiffExtentFile);
-};
-// A class to be passed to |puffpatch| for reading from |source_fd_| and writing
-// into |target_fd_|.
-class PuffinExtentStream : public puffin::StreamInterface {
- public:
-  // Constructor for creating a stream for reading from an |ExtentReader|.
-  PuffinExtentStream(std::unique_ptr<ExtentReader> reader, uint64_t size)
-      : PuffinExtentStream(std::move(reader), nullptr, size) {}
-
-  // Constructor for creating a stream for writing to an |ExtentWriter|.
-  PuffinExtentStream(std::unique_ptr<ExtentWriter> writer, uint64_t size)
-      : PuffinExtentStream(nullptr, std::move(writer), size) {}
-
-  ~PuffinExtentStream() override = default;
-
-  bool GetSize(uint64_t* size) const override {
-    *size = size_;
-    return true;
-  }
-
-  bool GetOffset(uint64_t* offset) const override {
-    *offset = offset_;
-    return true;
-  }
-
-  bool Seek(uint64_t offset) override {
-    if (is_read_) {
-      TEST_AND_RETURN_FALSE(reader_->Seek(offset));
-      offset_ = offset;
-    } else {
-      // For writes technically there should be no change of position, or it
-      // should equivalent of current offset.
-      TEST_AND_RETURN_FALSE(offset_ == offset);
-    }
-    return true;
-  }
-
-  bool Read(void* buffer, size_t count) override {
-    TEST_AND_RETURN_FALSE(is_read_);
-    TEST_AND_RETURN_FALSE(reader_->Read(buffer, count));
-    offset_ += count;
-    return true;
-  }
-
-  bool Write(const void* buffer, size_t count) override {
-    TEST_AND_RETURN_FALSE(!is_read_);
-    TEST_AND_RETURN_FALSE(writer_->Write(buffer, count));
-    offset_ += count;
-    return true;
-  }
-
-  bool Close() override { return true; }
-
- private:
-  PuffinExtentStream(std::unique_ptr<ExtentReader> reader,
-                     std::unique_ptr<ExtentWriter> writer,
-                     uint64_t size)
-      : reader_(std::move(reader)),
-        writer_(std::move(writer)),
-        size_(size),
-        offset_(0),
-        is_read_(reader_ ? true : false) {}
-
-  std::unique_ptr<ExtentReader> reader_;
-  std::unique_ptr<ExtentWriter> writer_;
-  uint64_t size_;
-  uint64_t offset_;
-  bool is_read_;
-
-  DISALLOW_COPY_AND_ASSIGN(PuffinExtentStream);
-};
-
 PartitionWriter::PartitionWriter(
     const PartitionUpdate& partition_update,
     const InstallPlan::Partition& install_part,
@@ -246,8 +121,10 @@
     : partition_update_(partition_update),
       install_part_(install_part),
       dynamic_control_(dynamic_control),
+      verified_source_fd_(block_size, install_part.source_path),
       interactive_(is_interactive),
-      block_size_(block_size) {}
+      block_size_(block_size),
+      install_op_executor_(block_size) {}
 
 PartitionWriter::~PartitionWriter() {
   Close();
@@ -261,9 +138,7 @@
   }
   if (install_part_.source_size > 0 && !install_part_.source_path.empty()) {
     source_path_ = install_part_.source_path;
-    int err;
-    source_fd_ = OpenFile(source_path_.c_str(), O_RDONLY, false, &err);
-    if (source_fd_ == nullptr) {
+    if (!verified_source_fd_.Open()) {
       LOG(ERROR) << "Unable to open source partition " << install_part_.name
                  << " on slot " << BootControlInterface::SlotName(source_slot)
                  << ", file " << source_path_;
@@ -319,161 +194,84 @@
                                               size_t count) {
   // Setup the ExtentWriter stack based on the operation type.
   std::unique_ptr<ExtentWriter> writer = CreateBaseExtentWriter();
-
-  if (operation.type() == InstallOperation::REPLACE_BZ) {
-    writer.reset(new BzipExtentWriter(std::move(writer)));
-  } else if (operation.type() == InstallOperation::REPLACE_XZ) {
-    writer.reset(new XzExtentWriter(std::move(writer)));
-  }
-
-  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
-  TEST_AND_RETURN_FALSE(writer->Write(data, operation.data_length()));
-
-  return true;
+  writer->Init(operation.dst_extents(), block_size_);
+  return install_op_executor_.ExecuteReplaceOperation(
+      operation, std::move(writer), data, count);
 }
 
 bool PartitionWriter::PerformZeroOrDiscardOperation(
     const InstallOperation& operation) {
 #ifdef BLKZEROOUT
-  bool attempt_ioctl = true;
   int request =
       (operation.type() == InstallOperation::ZERO ? BLKZEROOUT : BLKDISCARD);
 #else   // !defined(BLKZEROOUT)
-  bool attempt_ioctl = false;
-  int request = 0;
+  auto writer = CreateBaseExtentWriter();
+  return install_op_executor_.ExecuteZeroOrDiscardOperation(operation,
+                                                            writer.get());
 #endif  // !defined(BLKZEROOUT)
 
-  brillo::Blob zeros;
   for (const Extent& extent : operation.dst_extents()) {
     const uint64_t start = extent.start_block() * block_size_;
     const uint64_t length = extent.num_blocks() * block_size_;
-    if (attempt_ioctl) {
-      int result = 0;
-      if (target_fd_->BlkIoctl(request, start, length, &result) && result == 0)
-        continue;
-      attempt_ioctl = false;
+    int result = 0;
+    if (target_fd_->BlkIoctl(request, start, length, &result) && result == 0) {
+      continue;
     }
-    // In case of failure, we fall back to writing 0 to the selected region.
-    zeros.resize(16 * block_size_);
-    for (uint64_t offset = 0; offset < length; offset += zeros.size()) {
-      uint64_t chunk_length =
-          std::min(length - offset, static_cast<uint64_t>(zeros.size()));
-      TEST_AND_RETURN_FALSE(utils::WriteAll(
-          target_fd_, zeros.data(), chunk_length, start + offset));
-    }
+    // In case of failure, we fall back to writing 0 for the entire operation.
+    PLOG(WARNING) << "BlkIoctl failed. Falling back to write 0s for remainder "
+                     "of this operation.";
+    auto writer = CreateBaseExtentWriter();
+    writer->Init(operation.dst_extents(), block_size_);
+    return install_op_executor_.ExecuteZeroOrDiscardOperation(operation,
+                                                              writer.get());
   }
   return true;
 }
 
+std::ostream& operator<<(std::ostream& out,
+                         const RepeatedPtrField<Extent>& extents) {
+  if (extents.size() == 0) {
+    out << "[]";
+    return out;
+  }
+  out << "[";
+  auto begin = extents.begin();
+  out << *begin;
+  for (int i = 1; i < extents.size(); i++) {
+    ++begin;
+    out << ", " << *begin;
+  }
+  out << "]";
+  return out;
+}
+
 bool PartitionWriter::PerformSourceCopyOperation(
     const InstallOperation& operation, ErrorCode* error) {
-  TEST_AND_RETURN_FALSE(source_fd_ != nullptr);
-
   // The device may optimize the SOURCE_COPY operation.
   // Being this a device-specific optimization let DynamicPartitionController
   // decide it the operation should be skipped.
   const PartitionUpdate& partition = partition_update_;
-  const auto& partition_control = dynamic_control_;
 
   InstallOperation buf;
-  const bool should_optimize = partition_control->OptimizeOperation(
+  const bool should_optimize = dynamic_control_->OptimizeOperation(
       partition.partition_name(), operation, &buf);
   const InstallOperation& optimized = should_optimize ? buf : operation;
 
-  if (operation.has_src_sha256_hash()) {
-    bool read_ok;
-    brillo::Blob source_hash;
-    brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
-                                      operation.src_sha256_hash().end());
-
-    // We fall back to use the error corrected device if the hash of the raw
-    // device doesn't match or there was an error reading the source partition.
-    // Note that this code will also fall back if writing the target partition
-    // fails.
-    if (should_optimize) {
-      // Hash operation.src_extents(), then copy optimized.src_extents to
-      // optimized.dst_extents.
-      read_ok =
-          fd_utils::ReadAndHashExtents(
-              source_fd_, operation.src_extents(), block_size_, &source_hash) &&
-          fd_utils::CopyAndHashExtents(source_fd_,
-                                       optimized.src_extents(),
-                                       target_fd_,
-                                       optimized.dst_extents(),
-                                       block_size_,
-                                       nullptr /* skip hashing */);
-    } else {
-      read_ok = fd_utils::CopyAndHashExtents(source_fd_,
-                                             operation.src_extents(),
-                                             target_fd_,
-                                             operation.dst_extents(),
-                                             block_size_,
-                                             &source_hash);
-    }
-    if (read_ok && expected_source_hash == source_hash)
-      return true;
-    LOG(WARNING) << "Source hash from RAW device mismatched, attempting to "
-                    "correct using ECC";
-    if (!OpenCurrentECCPartition()) {
-      // The following function call will return false since the source hash
-      // mismatches, but we still want to call it so it prints the appropriate
-      // log message.
-      return ValidateSourceHash(source_hash, operation, source_fd_, error);
-    }
-
-    LOG(WARNING) << "Source hash from RAW device mismatched: found "
-                 << base::HexEncode(source_hash.data(), source_hash.size())
-                 << ", expected "
-                 << base::HexEncode(expected_source_hash.data(),
-                                    expected_source_hash.size());
-    if (should_optimize) {
-      TEST_AND_RETURN_FALSE(fd_utils::ReadAndHashExtents(
-          source_ecc_fd_, operation.src_extents(), block_size_, &source_hash));
-      TEST_AND_RETURN_FALSE(
-          fd_utils::CopyAndHashExtents(source_ecc_fd_,
-                                       optimized.src_extents(),
-                                       target_fd_,
-                                       optimized.dst_extents(),
-                                       block_size_,
-                                       nullptr /* skip hashing */));
-    } else {
-      TEST_AND_RETURN_FALSE(
-          fd_utils::CopyAndHashExtents(source_ecc_fd_,
-                                       operation.src_extents(),
-                                       target_fd_,
-                                       operation.dst_extents(),
-                                       block_size_,
-                                       &source_hash));
-    }
-    TEST_AND_RETURN_FALSE(
-        ValidateSourceHash(source_hash, operation, source_ecc_fd_, error));
-    // At this point reading from the error corrected device worked, but
-    // reading from the raw device failed, so this is considered a recovered
-    // failure.
-    source_ecc_recovered_failures_++;
-  } else {
-    // When the operation doesn't include a source hash, we attempt the error
-    // corrected device first since we can't verify the block in the raw device
-    // at this point, but we fall back to the raw device since the error
-    // corrected device can be shorter or not available.
-
-    if (OpenCurrentECCPartition() &&
-        fd_utils::CopyAndHashExtents(source_ecc_fd_,
-                                     optimized.src_extents(),
-                                     target_fd_,
-                                     optimized.dst_extents(),
-                                     block_size_,
-                                     nullptr)) {
-      return true;
-    }
-    TEST_AND_RETURN_FALSE(fd_utils::CopyAndHashExtents(source_fd_,
-                                                       optimized.src_extents(),
-                                                       target_fd_,
-                                                       optimized.dst_extents(),
-                                                       block_size_,
-                                                       nullptr));
+  // Invoke ChooseSourceFD with original operation, so that it can properly
+  // verify source hashes. Optimized operation might contain a smaller set of
+  // extents, or completely empty.
+  auto source_fd = ChooseSourceFD(operation, error);
+  if (source_fd == nullptr) {
+    LOG(ERROR) << "Unrecoverable source hash mismatch found on partition "
+               << partition.partition_name()
+               << " extents: " << operation.src_extents();
+    return false;
   }
-  return true;
+
+  auto writer = CreateBaseExtentWriter();
+  writer->Init(optimized.dst_extents(), block_size_);
+  return install_op_executor_.ExecuteSourceCopyOperation(
+      optimized, writer.get(), source_fd);
 }
 
 bool PartitionWriter::PerformSourceBsdiffOperation(
@@ -484,24 +282,10 @@
   FileDescriptorPtr source_fd = ChooseSourceFD(operation, error);
   TEST_AND_RETURN_FALSE(source_fd != nullptr);
 
-  auto reader = std::make_unique<DirectExtentReader>();
-  TEST_AND_RETURN_FALSE(
-      reader->Init(source_fd, operation.src_extents(), block_size_));
-  auto src_file = std::make_unique<BsdiffExtentFile>(
-      std::move(reader),
-      utils::BlocksInExtents(operation.src_extents()) * block_size_);
-
   auto writer = CreateBaseExtentWriter();
-  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
-  auto dst_file = std::make_unique<BsdiffExtentFile>(
-      std::move(writer),
-      utils::BlocksInExtents(operation.dst_extents()) * block_size_);
-
-  TEST_AND_RETURN_FALSE(bsdiff::bspatch(std::move(src_file),
-                                        std::move(dst_file),
-                                        reinterpret_cast<const uint8_t*>(data),
-                                        count) == 0);
-  return true;
+  writer->Init(operation.dst_extents(), block_size_);
+  return install_op_executor_.ExecuteSourceBsdiffOperation(
+      operation, std::move(writer), source_fd, data, count);
 }
 
 bool PartitionWriter::PerformPuffDiffOperation(
@@ -512,122 +296,20 @@
   FileDescriptorPtr source_fd = ChooseSourceFD(operation, error);
   TEST_AND_RETURN_FALSE(source_fd != nullptr);
 
-  auto reader = std::make_unique<DirectExtentReader>();
-  TEST_AND_RETURN_FALSE(
-      reader->Init(source_fd, operation.src_extents(), block_size_));
-  puffin::UniqueStreamPtr src_stream(new PuffinExtentStream(
-      std::move(reader),
-      utils::BlocksInExtents(operation.src_extents()) * block_size_));
-
   auto writer = CreateBaseExtentWriter();
-  TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
-  puffin::UniqueStreamPtr dst_stream(new PuffinExtentStream(
-      std::move(writer),
-      utils::BlocksInExtents(operation.dst_extents()) * block_size_));
-
-  constexpr size_t kMaxCacheSize = 5 * 1024 * 1024;  // Total 5MB cache.
-  TEST_AND_RETURN_FALSE(
-      puffin::PuffPatch(std::move(src_stream),
-                        std::move(dst_stream),
-                        reinterpret_cast<const uint8_t*>(data),
-                        count,
-                        kMaxCacheSize));
-  return true;
+  writer->Init(operation.dst_extents(), block_size_);
+  return install_op_executor_.ExecutePuffDiffOperation(
+      operation, std::move(writer), source_fd, data, count);
 }
 
 FileDescriptorPtr PartitionWriter::ChooseSourceFD(
     const InstallOperation& operation, ErrorCode* error) {
-  if (source_fd_ == nullptr) {
-    LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
-    return nullptr;
-  }
-
-  if (!operation.has_src_sha256_hash()) {
-    // When the operation doesn't include a source hash, we attempt the error
-    // corrected device first since we can't verify the block in the raw device
-    // at this point, but we first need to make sure all extents are readable
-    // since the error corrected device can be shorter or not available.
-    if (OpenCurrentECCPartition() &&
-        fd_utils::ReadAndHashExtents(
-            source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
-      return source_ecc_fd_;
-    }
-    return source_fd_;
-  }
-
-  brillo::Blob source_hash;
-  brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
-                                    operation.src_sha256_hash().end());
-  if (fd_utils::ReadAndHashExtents(
-          source_fd_, operation.src_extents(), block_size_, &source_hash) &&
-      source_hash == expected_source_hash) {
-    return source_fd_;
-  }
-  // We fall back to use the error corrected device if the hash of the raw
-  // device doesn't match or there was an error reading the source partition.
-  if (!OpenCurrentECCPartition()) {
-    // The following function call will return false since the source hash
-    // mismatches, but we still want to call it so it prints the appropriate
-    // log message.
-    ValidateSourceHash(source_hash, operation, source_fd_, error);
-    return nullptr;
-  }
-  LOG(WARNING) << "Source hash from RAW device mismatched: found "
-               << base::HexEncode(source_hash.data(), source_hash.size())
-               << ", expected "
-               << base::HexEncode(expected_source_hash.data(),
-                                  expected_source_hash.size());
-
-  if (fd_utils::ReadAndHashExtents(
-          source_ecc_fd_, operation.src_extents(), block_size_, &source_hash) &&
-      ValidateSourceHash(source_hash, operation, source_ecc_fd_, error)) {
-    // At this point reading from the error corrected device worked, but
-    // reading from the raw device failed, so this is considered a recovered
-    // failure.
-    source_ecc_recovered_failures_++;
-    return source_ecc_fd_;
-  }
-  return nullptr;
-}
-
-bool PartitionWriter::OpenCurrentECCPartition() {
-  // No support for ECC for full payloads.
-  // Full payload should not have any opeartion that requires ECC partitions.
-  if (source_ecc_fd_)
-    return true;
-
-  if (source_ecc_open_failure_)
-    return false;
-
-#if USE_FEC
-  const PartitionUpdate& partition = partition_update_;
-  const InstallPlan::Partition& install_part = install_part_;
-  std::string path = install_part.source_path;
-  FileDescriptorPtr fd(new FecFileDescriptor());
-  if (!fd->Open(path.c_str(), O_RDONLY, 0)) {
-    PLOG(ERROR) << "Unable to open ECC source partition "
-                << partition.partition_name() << ", file " << path;
-    source_ecc_open_failure_ = true;
-    return false;
-  }
-  source_ecc_fd_ = fd;
-#else
-  // No support for ECC compiled.
-  source_ecc_open_failure_ = true;
-#endif  // USE_FEC
-
-  return !source_ecc_open_failure_;
+  return verified_source_fd_.ChooseSourceFD(operation, error);
 }
 
 int PartitionWriter::Close() {
   int err = 0;
-  if (source_fd_ && !source_fd_->Close()) {
-    err = errno;
-    PLOG(ERROR) << "Error closing source partition";
-    if (!err)
-      err = 1;
-  }
-  source_fd_.reset();
+
   source_path_.clear();
 
   if (target_fd_ && !target_fd_->Close()) {
@@ -639,14 +321,6 @@
   target_fd_.reset();
   target_path_.clear();
 
-  if (source_ecc_fd_ && !source_ecc_fd_->Close()) {
-    err = errno;
-    PLOG(ERROR) << "Error closing ECC source partition";
-    if (!err)
-      err = 1;
-  }
-  source_ecc_fd_.reset();
-  source_ecc_open_failure_ = false;
   return -err;
 }
 
@@ -658,4 +332,44 @@
   return std::make_unique<DirectExtentWriter>(target_fd_);
 }
 
+bool PartitionWriter::ValidateSourceHash(const brillo::Blob& calculated_hash,
+                                         const InstallOperation& operation,
+                                         const FileDescriptorPtr source_fd,
+                                         ErrorCode* error) {
+  using std::string;
+  using std::vector;
+  brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
+                                    operation.src_sha256_hash().end());
+  if (calculated_hash != expected_source_hash) {
+    LOG(ERROR) << "The hash of the source data on disk for this operation "
+               << "doesn't match the expected value. This could mean that the "
+               << "delta update payload was targeted for another version, or "
+               << "that the source partition was modified after it was "
+               << "installed, for example, by mounting a filesystem.";
+    LOG(ERROR) << "Expected:   sha256|hex = "
+               << base::HexEncode(expected_source_hash.data(),
+                                  expected_source_hash.size());
+    LOG(ERROR) << "Calculated: sha256|hex = "
+               << base::HexEncode(calculated_hash.data(),
+                                  calculated_hash.size());
+
+    vector<string> source_extents;
+    for (const Extent& ext : operation.src_extents()) {
+      source_extents.push_back(
+          base::StringPrintf("%" PRIu64 ":%" PRIu64,
+                             static_cast<uint64_t>(ext.start_block()),
+                             static_cast<uint64_t>(ext.num_blocks())));
+    }
+    LOG(ERROR) << "Operation source (offset:size) in blocks: "
+               << base::JoinString(source_extents, ",");
+
+    // Log remount history if this device is an ext4 partition.
+    LogMountHistory(source_fd);
+
+    *error = ErrorCode::kDownloadStateInitializationError;
+    return false;
+  }
+  return true;
+}
+
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/partition_writer.h b/payload_consumer/partition_writer.h
index 82e557a..14bd18a 100644
--- a/payload_consumer/partition_writer.h
+++ b/payload_consumer/partition_writer.h
@@ -27,10 +27,13 @@
 #include "update_engine/common/dynamic_partition_control_interface.h"
 #include "update_engine/payload_consumer/extent_writer.h"
 #include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/install_operation_executor.h"
 #include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/verified_source_fd.h"
 #include "update_engine/update_metadata.pb.h"
 
 namespace chromeos_update_engine {
+
 class PartitionWriter {
  public:
   PartitionWriter(const PartitionUpdate& partition_update,
@@ -92,7 +95,8 @@
   friend class PartitionWriterTest;
   FRIEND_TEST(PartitionWriterTest, ChooseSourceFDTest);
 
-  bool OpenSourcePartition(uint32_t source_slot, bool source_may_exist);
+  [[nodiscard]] bool OpenSourcePartition(uint32_t source_slot,
+                                         bool source_may_exist);
 
   bool OpenCurrentECCPartition();
   // For a given operation, choose the source fd to be used (raw device or error
@@ -108,27 +112,17 @@
   DynamicPartitionControlInterface* dynamic_control_;
   // Path to source partition
   std::string source_path_;
+  VerifiedSourceFd verified_source_fd_;
   // Path to target partition
   std::string target_path_;
-  FileDescriptorPtr source_fd_;
   FileDescriptorPtr target_fd_;
   const bool interactive_;
   const size_t block_size_;
-  // File descriptor of the error corrected source partition. Only set while
-  // updating partition using a delta payload for a partition where error
-  // correction is available. The size of the error corrected device is smaller
-  // than the underlying raw device, since it doesn't include the error
-  // correction blocks.
-  FileDescriptorPtr source_ecc_fd_{nullptr};
 
-  // The total number of operations that failed source hash verification but
-  // passed after falling back to the error-corrected |source_ecc_fd_| device.
-  uint64_t source_ecc_recovered_failures_{0};
-
-  // Whether opening the current partition as an error-corrected device failed.
-  // Used to avoid re-opening the same source partition if it is not actually
-  // error corrected.
-  bool source_ecc_open_failure_{false};
+  // This instance handles decompression/bsdfif/puffdiff. It's responsible for
+  // constructing data which should be written to target partition, actual
+  // "writing" is handled by |PartitionWriter|
+  InstallOperationExecutor install_op_executor_;
 };
 
 namespace partition_writer {
diff --git a/payload_consumer/partition_writer_unittest.cc b/payload_consumer/partition_writer_unittest.cc
index 263f338..331a061 100644
--- a/payload_consumer/partition_writer_unittest.cc
+++ b/payload_consumer/partition_writer_unittest.cc
@@ -46,18 +46,19 @@
   // Helper function to pretend that the ECC file descriptor was already opened.
   // Returns a pointer to the created file descriptor.
   FakeFileDescriptor* SetFakeECCFile(size_t size) {
-    EXPECT_FALSE(writer_.source_ecc_fd_) << "source_ecc_fd_ already open.";
+    EXPECT_FALSE(writer_.verified_source_fd_.source_ecc_fd_)
+        << "source_ecc_fdb already open.";
     FakeFileDescriptor* ret = new FakeFileDescriptor();
     fake_ecc_fd_.reset(ret);
     // Call open to simulate it was already opened.
     ret->Open("", 0);
     ret->SetFileSize(size);
-    writer_.source_ecc_fd_ = fake_ecc_fd_;
+    writer_.verified_source_fd_.source_ecc_fd_ = fake_ecc_fd_;
     return ret;
   }
 
   uint64_t GetSourceEccRecoveredFailures() const {
-    return writer_.source_ecc_recovered_failures_;
+    return writer_.verified_source_fd_.source_ecc_recovered_failures_;
   }
 
   AnnotatedOperation GenerateSourceCopyOp(const brillo::Blob& copied_data,
@@ -81,22 +82,31 @@
 
   brillo::Blob PerformSourceCopyOp(const InstallOperation& op,
                                    const brillo::Blob blob_data) {
-    ScopedTempFile source_partition("Blob-XXXXXX");
+    LOG(INFO) << "Using source part " << source_partition.path();
     FileDescriptorPtr fd(new EintrSafeFileDescriptor());
     DirectExtentWriter extent_writer{fd};
     EXPECT_TRUE(fd->Open(source_partition.path().c_str(), O_RDWR));
+    if (HasFailure()) {
+      return {};
+    }
     EXPECT_TRUE(extent_writer.Init(op.src_extents(), kBlockSize));
+    if (HasFailure()) {
+      return {};
+    }
     EXPECT_TRUE(extent_writer.Write(blob_data.data(), blob_data.size()));
+    if (HasFailure()) {
+      return {};
+    }
+    fd->Flush();
 
-    ScopedTempFile target_partition("Blob-XXXXXX");
-
-    install_part_.source_path = source_partition.path();
-    install_part_.target_path = target_partition.path();
     install_part_.source_size = blob_data.size();
     install_part_.target_size = blob_data.size();
 
     ErrorCode error;
     EXPECT_TRUE(writer_.Init(&install_plan_, true, 0));
+    if (HasFailure()) {
+      return {};
+    }
     EXPECT_TRUE(writer_.PerformSourceCopyOperation(op, &error));
     writer_.CheckpointUpdateProgress(1);
 
@@ -111,8 +121,11 @@
   DynamicPartitionControlStub dynamic_control_{};
   FileDescriptorPtr fake_ecc_fd_{};
   DeltaArchiveManifest manifest_{};
+  ScopedTempFile source_partition{"source-part-XXXXXX"};
+  ScopedTempFile target_partition{"target-part-XXXXXX"};
+  InstallPlan::Partition install_part_{.source_path = source_partition.path(),
+                                       .target_path = target_partition.path()};
   PartitionUpdate partition_update_{};
-  InstallPlan::Partition install_part_{};
   PartitionWriter writer_{
       partition_update_, install_part_, &dynamic_control_, kBlockSize, false};
 };
@@ -124,7 +137,7 @@
   ScopedTempFile source("Source-XXXXXX");
   // Setup the source path with the right expected data.
   brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
-  EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
+  ASSERT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
 
   // Setup the fec file descriptor as the fake stream, with smaller data than
   // the expected.
@@ -136,17 +149,18 @@
 
   // The payload operation doesn't include an operation hash.
   auto source_copy_op = GenerateSourceCopyOp(expected_data, false, &old_part);
-
+  ASSERT_NO_FATAL_FAILURE();
   auto output_data = PerformSourceCopyOp(source_copy_op.op, expected_data);
+  ASSERT_NO_FATAL_FAILURE();
   ASSERT_EQ(output_data, expected_data);
 
   // Verify that the fake_fec was attempted to be used. Since the file
   // descriptor is shorter it can actually do more than one read to realize it
   // reached the EOF.
-  EXPECT_LE(1U, fake_fec->GetReadOps().size());
+  ASSERT_LE(1U, fake_fec->GetReadOps().size());
   // This fallback doesn't count as an error-corrected operation since the
   // operation hash was not available.
-  EXPECT_EQ(0U, GetSourceEccRecoveredFailures());
+  ASSERT_EQ(0U, GetSourceEccRecoveredFailures());
 }
 
 // Test that the error-corrected file descriptor is used to read the partition
@@ -163,11 +177,13 @@
   brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
 
   auto source_copy_op = GenerateSourceCopyOp(expected_data, true);
+  ASSERT_NO_FATAL_FAILURE();
   auto output_data = PerformSourceCopyOp(source_copy_op.op, invalid_data);
+  ASSERT_NO_FATAL_FAILURE();
   ASSERT_EQ(output_data, expected_data);
 
   // Verify that the fake_fec was actually used.
-  EXPECT_EQ(1U, fake_fec->GetReadOps().size());
+  EXPECT_GE(fake_fec->GetReadOps().size(), 1U);
   EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
 }
 
@@ -177,10 +193,11 @@
   // Write invalid data to the source image, which doesn't match the expected
   // hash.
   brillo::Blob invalid_data(kSourceSize, 0x55);
-  EXPECT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
+  ASSERT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
 
-  writer_.source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
-  writer_.source_fd_->Open(source.path().c_str(), O_RDONLY);
+  writer_.verified_source_fd_.source_fd_ =
+      std::make_shared<EintrSafeFileDescriptor>();
+  writer_.verified_source_fd_.source_fd_->Open(source.path().c_str(), O_RDONLY);
 
   // Setup the fec file descriptor as the fake stream, which matches
   // |expected_data|.
@@ -190,15 +207,16 @@
   InstallOperation op;
   *(op.add_src_extents()) = ExtentForRange(0, kSourceSize / 4096);
   brillo::Blob src_hash;
-  EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
+  ASSERT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
   op.set_src_sha256_hash(src_hash.data(), src_hash.size());
 
   ErrorCode error = ErrorCode::kSuccess;
-  EXPECT_EQ(writer_.source_ecc_fd_, writer_.ChooseSourceFD(op, &error));
-  EXPECT_EQ(ErrorCode::kSuccess, error);
+  ASSERT_EQ(writer_.verified_source_fd_.source_ecc_fd_,
+            writer_.ChooseSourceFD(op, &error));
+  ASSERT_EQ(ErrorCode::kSuccess, error);
   // Verify that the fake_fec was actually used.
-  EXPECT_EQ(1U, fake_fec->GetReadOps().size());
-  EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
+  ASSERT_EQ(1U, fake_fec->GetReadOps().size());
+  ASSERT_EQ(1U, GetSourceEccRecoveredFailures());
 }
 
 }  // namespace chromeos_update_engine
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
index 0843fff..a27847c 100644
--- a/payload_consumer/vabc_partition_writer.cc
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -90,7 +90,15 @@
   auto converted = ConvertToCowOperations(partition_update_.operations(),
                                           partition_update_.merge_operations());
 
-  WriteAllCowOps(block_size_, converted, cow_writer_.get(), source_fd_);
+  if (!converted.empty()) {
+    // Use source fd directly. Ideally we want to verify all extents used in
+    // source copy, but then what do we do if some extents contain correct
+    // hashes and some don't?
+    auto source_fd = std::make_shared<EintrSafeFileDescriptor>();
+    TEST_AND_RETURN_FALSE_ERRNO(
+        source_fd->Open(install_part_.source_path.c_str(), O_RDONLY));
+    WriteAllCowOps(block_size_, converted, cow_writer_.get(), source_fd);
+  }
   return true;
 }
 
diff --git a/payload_consumer/verified_source_fd.cc b/payload_consumer/verified_source_fd.cc
new file mode 100644
index 0000000..002bd07
--- /dev/null
+++ b/payload_consumer/verified_source_fd.cc
@@ -0,0 +1,124 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limi
+
+#include "update_engine/payload_consumer/verified_source_fd.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/fec_file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/mount_history.h"
+#include "update_engine/payload_consumer/partition_writer.h"
+
+namespace chromeos_update_engine {
+using std::string;
+
+bool VerifiedSourceFd::OpenCurrentECCPartition() {
+  // No support for ECC for full payloads.
+  // Full payload should not have any opeartion that requires ECC partitions.
+  if (source_ecc_fd_)
+    return true;
+
+  if (source_ecc_open_failure_)
+    return false;
+
+#if USE_FEC
+  FileDescriptorPtr fd(new FecFileDescriptor());
+  if (!fd->Open(source_path_.c_str(), O_RDONLY, 0)) {
+    PLOG(ERROR) << "Unable to open ECC source partition " << source_path_;
+    source_ecc_open_failure_ = true;
+    return false;
+  }
+  source_ecc_fd_ = fd;
+#else
+  // No support for ECC compiled.
+  source_ecc_open_failure_ = true;
+#endif  // USE_FEC
+
+  return !source_ecc_open_failure_;
+}
+
+FileDescriptorPtr VerifiedSourceFd::ChooseSourceFD(
+    const InstallOperation& operation, ErrorCode* error) {
+  if (source_fd_ == nullptr) {
+    LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
+    return nullptr;
+  }
+  if (!operation.has_src_sha256_hash()) {
+    // When the operation doesn't include a source hash, we attempt the error
+    // corrected device first since we can't verify the block in the raw device
+    // at this point, but we first need to make sure all extents are readable
+    // since the error corrected device can be shorter or not available.
+    if (OpenCurrentECCPartition() &&
+        fd_utils::ReadAndHashExtents(
+            source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
+      return source_ecc_fd_;
+    }
+    return source_fd_;
+  }
+
+  brillo::Blob source_hash;
+  brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
+                                    operation.src_sha256_hash().end());
+  if (fd_utils::ReadAndHashExtents(
+          source_fd_, operation.src_extents(), block_size_, &source_hash) &&
+      source_hash == expected_source_hash) {
+    return source_fd_;
+  }
+  // We fall back to use the error corrected device if the hash of the raw
+  // device doesn't match or there was an error reading the source partition.
+  if (!OpenCurrentECCPartition()) {
+    // The following function call will return false since the source hash
+    // mismatches, but we still want to call it so it prints the appropriate
+    // log message.
+    PartitionWriter::ValidateSourceHash(
+        source_hash, operation, source_fd_, error);
+    return nullptr;
+  }
+  LOG(WARNING) << "Source hash from RAW device mismatched: found "
+               << base::HexEncode(source_hash.data(), source_hash.size())
+               << ", expected "
+               << base::HexEncode(expected_source_hash.data(),
+                                  expected_source_hash.size());
+
+  if (fd_utils::ReadAndHashExtents(
+          source_ecc_fd_, operation.src_extents(), block_size_, &source_hash) &&
+      PartitionWriter::ValidateSourceHash(
+          source_hash, operation, source_ecc_fd_, error)) {
+    source_ecc_recovered_failures_++;
+    return source_ecc_fd_;
+  }
+  return nullptr;
+}
+
+bool VerifiedSourceFd::Open() {
+  source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+  if (source_fd_ == nullptr)
+    return false;
+  TEST_AND_RETURN_FALSE_ERRNO(source_fd_->Open(source_path_.c_str(), O_RDONLY));
+  return true;
+}
+
+}  // namespace chromeos_update_engine
diff --git a/payload_consumer/verified_source_fd.h b/payload_consumer/verified_source_fd.h
new file mode 100644
index 0000000..f7d0620
--- /dev/null
+++ b/payload_consumer/verified_source_fd.h
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limi
+
+#ifndef UPDATE_ENGINE_VERIFIED_SOURCE_FD_H__
+#define UPDATE_ENGINE_VERIFIED_SOURCE_FD_H__
+
+#include <cstddef>
+
+#include <string>
+#include <utility>
+
+#include <gtest/gtest_prod.h>
+#include <update_engine/update_metadata.pb.h>
+
+#include "update_engine/common/error_code.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+
+namespace chromeos_update_engine {
+
+class VerifiedSourceFd {
+ public:
+  explicit VerifiedSourceFd(size_t block_size, std::string source_path)
+      : block_size_(block_size), source_path_(std::move(source_path)) {}
+  FileDescriptorPtr ChooseSourceFD(const InstallOperation& operation,
+                                   ErrorCode* error);
+
+  [[nodiscard]] bool Open();
+
+ private:
+  bool OpenCurrentECCPartition();
+  const size_t block_size_;
+  const std::string source_path_;
+  FileDescriptorPtr source_ecc_fd_;
+  FileDescriptorPtr source_fd_;
+
+  friend class PartitionWriterTest;
+  FRIEND_TEST(PartitionWriterTest, ChooseSourceFDTest);
+  // The total number of operations that failed source hash verification but
+  // passed after falling back to the error-corrected |source_ecc_fd_| device.
+  uint64_t source_ecc_recovered_failures_{0};
+
+  // Whether opening the current partition as an error-corrected device failed.
+  // Used to avoid re-opening the same source partition if it is not actually
+  // error corrected.
+  bool source_ecc_open_failure_{false};
+};
+}  // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_generator/extent_utils.cc b/payload_generator/extent_utils.cc
index 2efef12..f4a9ff0 100644
--- a/payload_generator/extent_utils.cc
+++ b/payload_generator/extent_utils.cc
@@ -87,7 +87,8 @@
   }
 }
 
-string ExtentsToString(const vector<Extent>& extents) {
+template <typename Container>
+string ExtentsToStringTemplate(const Container& extents) {
   string ext_str;
   for (const Extent& e : extents)
     ext_str += base::StringPrintf("[%" PRIu64 ", %" PRIu64 "] ",
@@ -96,6 +97,15 @@
   return ext_str;
 }
 
+std::string ExtentsToString(const std::vector<Extent>& extents) {
+  return ExtentsToStringTemplate(extents);
+}
+
+std::string ExtentsToString(
+    const google::protobuf::RepeatedPtrField<Extent>& extents) {
+  return ExtentsToStringTemplate(extents);
+}
+
 void NormalizeExtents(vector<Extent>* extents) {
   vector<Extent> new_extents;
   for (const Extent& curr_ext : *extents) {
diff --git a/payload_generator/extent_utils.h b/payload_generator/extent_utils.h
index 7aa614a..e9afa98 100644
--- a/payload_generator/extent_utils.h
+++ b/payload_generator/extent_utils.h
@@ -22,6 +22,7 @@
 
 #include <base/logging.h>
 
+#include "google/protobuf/repeated_field.h"
 #include "update_engine/payload_consumer/payload_constants.h"
 #include "update_engine/update_metadata.pb.h"
 
@@ -63,6 +64,8 @@
 
 // Returns a string representing all extents in |extents|.
 std::string ExtentsToString(const std::vector<Extent>& extents);
+std::string ExtentsToString(
+    const google::protobuf::RepeatedPtrField<Extent>& extents);
 
 // Takes a pointer to extents |extents| and extents |extents_to_add|, and
 // merges them by adding |extents_to_add| to |extents| and normalizing.