DeltaPerformer: add static PreparePartitionsForUpdate

Expose a static PreparePartitionsForUpdate for
implementation of AllocateSpaceForPayload.

- If this function is called multiple times with the same
'update_check_response_hash', calls after the first call
has no effect.

- If this function is called again with a different
'update_check_response_hash', space is re-allocated.

- DeltaPerformer::ResetUpdateProgress deletes the stored hash
and cause the next PreparePartitionsForUpdate to always re-allocate
space.

- DeltaPerformer::ParseManifestPartitions now set error code to
kNotEnoughSpace when appropriate.

Test: apply an OTA manually
Bug: 138808058
Change-Id: I6fb60016088a3133af3fc961196f63e7d079ae93
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 8cec076..bb7c98c 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -925,8 +925,13 @@
   }
 
   if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) {
-    if (!PreparePartitionsForUpdate()) {
-      *error = ErrorCode::kInstallDeviceOpenError;
+    uint64_t required_size = 0;
+    if (!PreparePartitionsForUpdate(&required_size)) {
+      if (required_size > 0) {
+        *error = ErrorCode::kNotEnoughSpace;
+      } else {
+        *error = ErrorCode::kInstallDeviceOpenError;
+      }
       return false;
     }
   }
@@ -944,21 +949,56 @@
   return true;
 }
 
-bool DeltaPerformer::PreparePartitionsForUpdate() {
-  bool metadata_updated = false;
-  prefs_->GetBoolean(kPrefsDynamicPartitionMetadataUpdated, &metadata_updated);
-  if (!boot_control_->GetDynamicPartitionControl()->PreparePartitionsForUpdate(
-          boot_control_->GetCurrentSlot(),
-          install_plan_->target_slot,
-          manifest_,
-          !metadata_updated,
-          nullptr /* required_size */)) {
+bool DeltaPerformer::PreparePartitionsForUpdate(uint64_t* required_size) {
+  // Call static PreparePartitionsForUpdate with hash from
+  // kPrefsUpdateCheckResponseHash to ensure hash of payload that space is
+  // preallocated for is the same as the hash of payload being applied.
+  string update_check_response_hash;
+  ignore_result(prefs_->GetString(kPrefsUpdateCheckResponseHash,
+                                  &update_check_response_hash));
+  return PreparePartitionsForUpdate(prefs_,
+                                    boot_control_,
+                                    install_plan_->target_slot,
+                                    manifest_,
+                                    update_check_response_hash,
+                                    required_size);
+}
+
+bool DeltaPerformer::PreparePartitionsForUpdate(
+    PrefsInterface* prefs,
+    BootControlInterface* boot_control,
+    BootControlInterface::Slot target_slot,
+    const DeltaArchiveManifest& manifest,
+    const std::string& update_check_response_hash,
+    uint64_t* required_size) {
+  string last_hash;
+  ignore_result(
+      prefs->GetString(kPrefsDynamicPartitionMetadataUpdated, &last_hash));
+
+  bool is_resume = !update_check_response_hash.empty() &&
+                   last_hash == update_check_response_hash;
+
+  if (is_resume) {
+    LOG(INFO) << "Using previously prepared partitions for update. hash = "
+              << last_hash;
+  } else {
+    LOG(INFO) << "Preparing partitions for new update. last hash = "
+              << last_hash << ", new hash = " << update_check_response_hash;
+  }
+
+  if (!boot_control->GetDynamicPartitionControl()->PreparePartitionsForUpdate(
+          boot_control->GetCurrentSlot(),
+          target_slot,
+          manifest,
+          !is_resume /* should update */,
+          required_size)) {
     LOG(ERROR) << "Unable to initialize partition metadata for slot "
-               << BootControlInterface::SlotName(install_plan_->target_slot);
+               << BootControlInterface::SlotName(target_slot);
     return false;
   }
-  TEST_AND_RETURN_FALSE(
-      prefs_->SetBoolean(kPrefsDynamicPartitionMetadataUpdated, true));
+
+  TEST_AND_RETURN_FALSE(prefs->SetString(kPrefsDynamicPartitionMetadataUpdated,
+                                         update_check_response_hash));
   LOG(INFO) << "PreparePartitionsForUpdate done.";
 
   return true;