summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2020-08-13 13:59:54 -0700
committerTreehugger Robot <treehugger-gerrit@google.com>2020-08-19 18:42:31 +0000
commit8d6df9ac7a70f4b07ebb86f50fb3548b693acad5 (patch)
tree0173db33bc1bd984878ca8bd254a8f0b4e3b051d
parentb753e0e9258170dce7c62733eed78e616b4a37b2 (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.cc12
-rw-r--r--dynamic_partition_control_android.h7
-rw-r--r--dynamic_partition_control_android_unittest.cc18
-rw-r--r--dynamic_partition_test_utils.h6
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()) {