diff options
author | Yifan Hong <elsk@google.com> | 2020-08-13 13:59:54 -0700 |
---|---|---|
committer | Treehugger Robot <treehugger-gerrit@google.com> | 2020-08-19 18:42:31 +0000 |
commit | 8d6df9ac7a70f4b07ebb86f50fb3548b693acad5 (patch) | |
tree | 0173db33bc1bd984878ca8bd254a8f0b4e3b051d | |
parent | b753e0e9258170dce7c62733eed78e616b4a37b2 (diff) |
Check allocatable space correctly when sideloading on VAB
On a device with Virtual A/B, when sideloading and there's
not enough space in super partition to hold CoW, update_engine
falls back to overwriting all source partitions. In that case,
the allocatable space should be the whole super partition, not
a half of it.
Also update doc comments.
Test: unit test. RecoveryErrorShouldDeleteSource fails without the patch
but succeeds with the patch.
Bug: 163613538
Change-Id: I6bd6895a7eabeb4e8436e57b0ac6830c11d1e98f
-rw-r--r-- | dynamic_partition_control_android.cc | 12 | ||||
-rw-r--r-- | dynamic_partition_control_android.h | 7 | ||||
-rw-r--r-- | dynamic_partition_control_android_unittest.cc | 18 | ||||
-rw-r--r-- | dynamic_partition_test_utils.h | 6 |
4 files changed, 32 insertions, 11 deletions
diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc index aa0f393c..ccb99ba4 100644 --- a/dynamic_partition_control_android.cc +++ b/dynamic_partition_control_android.cc @@ -838,6 +838,11 @@ bool DynamicPartitionControlAndroid::UpdatePartitionMetadata( MetadataBuilder* builder, uint32_t target_slot, const DeltaArchiveManifest& manifest) { + // Check preconditions. + CHECK(!GetVirtualAbFeatureFlag().IsEnabled() || IsRecovery()) + << "UpdatePartitionMetadata is called on a Virtual A/B device " + "but source partitions is not deleted. This is not allowed."; + // If applying downgrade from Virtual A/B to non-Virtual A/B, the left-over // COW group needs to be deleted to ensure there are enough space to create // target partitions. @@ -853,7 +858,12 @@ bool DynamicPartitionControlAndroid::UpdatePartitionMetadata( std::string expr; uint64_t allocatable_space = builder->AllocatableSpace(); - if (!GetDynamicPartitionsFeatureFlag().IsRetrofit()) { + // On device retrofitting dynamic partitions, allocatable_space = super. + // On device launching dynamic partitions w/o VAB, + // allocatable_space = super / 2. + // On device launching dynamic partitions with VAB, allocatable_space = super. + if (!GetDynamicPartitionsFeatureFlag().IsRetrofit() && + !GetVirtualAbFeatureFlag().IsEnabled()) { allocatable_space /= 2; expr = "half of "; } diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h index 9ee85db6..49967f6c 100644 --- a/dynamic_partition_control_android.h +++ b/dynamic_partition_control_android.h @@ -203,8 +203,11 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface { bool force_writable, std::string* path); - // Update |builder| according to |partition_metadata|, assuming the device - // does not have Virtual A/B. + // Update |builder| according to |partition_metadata|. + // - In Android mode, this is only called when the device + // does not have Virtual A/B. + // - When sideloading, this maybe called as a fallback path if CoW cannot + // be created. bool UpdatePartitionMetadata(android::fs_mgr::MetadataBuilder* builder, uint32_t target_slot, const DeltaArchiveManifest& manifest); diff --git a/dynamic_partition_control_android_unittest.cc b/dynamic_partition_control_android_unittest.cc index 4154b36c..223e177d 100644 --- a/dynamic_partition_control_android_unittest.cc +++ b/dynamic_partition_control_android_unittest.cc @@ -113,21 +113,24 @@ class DynamicPartitionControlAndroidTest : public ::testing::Test { // |slot|. void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes, - uint32_t partition_attr = 0) { + uint32_t partition_attr = 0, + uint64_t super_size = kDefaultSuperSize) { EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(slot), slot)) .Times(AnyNumber()) - .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto) { + .WillRepeatedly(Invoke([=](auto, auto) { return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes), - partition_attr); + partition_attr, + super_size); })); EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(slot), slot, _)) .Times(AnyNumber()) - .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto, auto) { + .WillRepeatedly(Invoke([=](auto, auto, auto) { return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes), - partition_attr); + partition_attr, + super_size); })); } @@ -1006,8 +1009,11 @@ TEST_P(SnapshotPartitionTestP, RecoveryErrorShouldDeleteSource) { return dynamicControl().RealPrepareDynamicPartitionsForUpdate( source_slot, target_slot, manifest, delete_source); })); + // Only one slot of space in super + uint64_t super_size = kDefaultGroupSize + 1_MiB; // Expectation on PrepareDynamicPartitionsForUpdate - SetMetadata(source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}); + SetMetadata( + source(), {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}}, 0, super_size); ExpectUnmap({T("system"), T("vendor")}); // Expect that the source partitions aren't present in target super metadata. ExpectStoreMetadata({{T("system"), 3_GiB}, {T("vendor"), 1_GiB}}); diff --git a/dynamic_partition_test_utils.h b/dynamic_partition_test_utils.h index 70a176b5..d701dce8 100644 --- a/dynamic_partition_test_utils.h +++ b/dynamic_partition_test_utils.h @@ -175,9 +175,11 @@ inline DeltaArchiveManifest PartitionSizesToManifest( } inline std::unique_ptr<MetadataBuilder> NewFakeMetadata( - const DeltaArchiveManifest& manifest, uint32_t partition_attr = 0) { + const DeltaArchiveManifest& manifest, + uint32_t partition_attr = 0, + uint64_t super_size = kDefaultSuperSize) { auto builder = - MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots); + MetadataBuilder::New(super_size, kFakeMetadataSize, kMaxNumSlots); for (const auto& group : manifest.dynamic_partition_metadata().groups()) { EXPECT_TRUE(builder->AddGroup(group.name(), group.size())); for (const auto& partition_name : group.partition_names()) { |