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;
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index 4c64dfa..6dbd3b8 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -179,6 +179,24 @@
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.
+ // - Same payload: not make any persistent modifications (not write to disk)
+ // - Different payload: make persistent modifications (write to disk)
+ // In both cases, in-memory flags are updated. This function must be called
+ // on the payload at least once (to update in-memory flags) before writing
+ // (applying) the payload.
+ // If error due to insufficient space, |required_size| is set to the required
+ // size on the device to apply the payload.
+ static bool PreparePartitionsForUpdate(
+ PrefsInterface* prefs,
+ BootControlInterface* boot_control,
+ BootControlInterface::Slot target_slot,
+ const DeltaArchiveManifest& manifest,
+ const std::string& update_check_response_hash,
+ uint64_t* required_size);
+
private:
friend class DeltaPerformerTest;
friend class DeltaPerformerIntegrationTest;
@@ -289,7 +307,8 @@
// After install_plan_ is filled with partition names and sizes, initialize
// metadata of partitions and map necessary devices before opening devices.
- bool PreparePartitionsForUpdate();
+ // Also see comment for the static PreparePartitionsForUpdate().
+ bool PreparePartitionsForUpdate(uint64_t* required_size);
// Update Engine preference store.
PrefsInterface* prefs_;
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index a2ad77b..4797137 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -728,7 +728,7 @@
.WillRepeatedly(Return(true));
EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignedSHA256Context, _))
.WillRepeatedly(Return(true));
- EXPECT_CALL(prefs, SetBoolean(kPrefsDynamicPartitionMetadataUpdated, _))
+ EXPECT_CALL(prefs, SetString(kPrefsDynamicPartitionMetadataUpdated, _))
.WillRepeatedly(Return(true));
if (op_hash_test == kValidOperationData && signature_test != kSignatureNone) {
EXPECT_CALL(prefs, SetString(kPrefsUpdateStateSignatureBlob, _))