diff options
author | Yifan Hong <elsk@google.com> | 2019-09-16 13:18:22 -0700 |
---|---|---|
committer | Yifan Hong <elsk@google.com> | 2019-09-23 19:38:27 -0700 |
commit | 13d41cb2accc1e2e1271b22a53f0dce6db0493f5 (patch) | |
tree | a3f1a02ee80743e96abdd8be437411402b02b16d | |
parent | 87ea73fe5a48c54ad56ba769375d180d1ce5c614 (diff) |
[REFACTOR] Pass DeltaArchiveManifest to DynamicPartitionControl
DynamicPartitionControl need the list of operations to calculate
COW sizes.
- Remove BootControlInterface::PartitionMetadata. Replace all references
with DeltaArchiveManifest. DeltaArchiveManifest has all information
that PartitionMetadata has.
- Rename all InitPartitionMetadata to PreparePartitionsForUpdate
- Change all PreparePartitionsForUpdate to use new signature
Bug: 138816109
Test: update_enigne_unittests --gtest_filter=*BootControl*:*Dynamic*
Change-Id: I4389ba2b1801addf8c3bc8395e2ea6a9a3ed27a0
-rw-r--r-- | boot_control_android.cc | 12 | ||||
-rw-r--r-- | boot_control_android.h | 8 | ||||
-rw-r--r-- | boot_control_android_unittest.cc | 22 | ||||
-rw-r--r-- | boot_control_chromeos.cc | 6 | ||||
-rw-r--r-- | boot_control_chromeos.h | 6 | ||||
-rw-r--r-- | common/boot_control_interface.h | 30 | ||||
-rw-r--r-- | common/boot_control_stub.cc | 6 | ||||
-rw-r--r-- | common/boot_control_stub.h | 6 | ||||
-rw-r--r-- | common/fake_boot_control.h | 6 | ||||
-rw-r--r-- | dynamic_partition_control_android.cc | 58 | ||||
-rw-r--r-- | dynamic_partition_control_android.h | 15 | ||||
-rw-r--r-- | dynamic_partition_control_android_unittest.cc | 159 | ||||
-rw-r--r-- | dynamic_partition_control_interface.h | 5 | ||||
-rw-r--r-- | dynamic_partition_test_utils.h | 149 | ||||
-rw-r--r-- | mock_dynamic_partition_control.h | 4 | ||||
-rw-r--r-- | payload_consumer/delta_performer.cc | 42 | ||||
-rw-r--r-- | payload_consumer/delta_performer.h | 2 |
17 files changed, 276 insertions, 260 deletions
diff --git a/boot_control_android.cc b/boot_control_android.cc index ce86666c..4c998b1b 100644 --- a/boot_control_android.cc +++ b/boot_control_android.cc @@ -39,8 +39,6 @@ using android::hardware::boot::V1_0::BoolResult; using android::hardware::boot::V1_0::CommandResult; using android::hardware::boot::V1_0::IBootControl; using Slot = chromeos_update_engine::BootControlInterface::Slot; -using PartitionMetadata = - chromeos_update_engine::BootControlInterface::PartitionMetadata; namespace { @@ -277,9 +275,9 @@ bool BootControlAndroid::MarkBootSuccessfulAsync( brillo::MessageLoop::kTaskIdNull; } -bool BootControlAndroid::InitPartitionMetadata( +bool BootControlAndroid::PreparePartitionsForUpdate( Slot target_slot, - const PartitionMetadata& partition_metadata, + const DeltaArchiveManifest& manifest, bool update_metadata) { if (fs_mgr_overlayfs_is_setup()) { // Non DAP devices can use overlayfs as well. @@ -294,14 +292,14 @@ bool BootControlAndroid::InitPartitionMetadata( auto source_slot = GetCurrentSlot(); if (target_slot == source_slot) { - LOG(ERROR) << "Cannot call InitPartitionMetadata on current slot."; + LOG(ERROR) << "Cannot call PreparePartitionsForUpdate on current slot."; return false; } // Although the current build supports dynamic partitions, the given payload // doesn't use it for target partitions. This could happen when applying a // retrofit update. Skip updating the partition metadata for the target slot. - is_target_dynamic_ = !partition_metadata.groups.empty(); + is_target_dynamic_ = !manifest.dynamic_partition_metadata().groups().empty(); if (!is_target_dynamic_) { return true; } @@ -311,7 +309,7 @@ bool BootControlAndroid::InitPartitionMetadata( } return dynamic_control_->PreparePartitionsForUpdate( - source_slot, target_slot, partition_metadata); + source_slot, target_slot, manifest); } } // namespace chromeos_update_engine diff --git a/boot_control_android.h b/boot_control_android.h index a6f33bed..65543ca2 100644 --- a/boot_control_android.h +++ b/boot_control_android.h @@ -51,9 +51,9 @@ class BootControlAndroid : public BootControlInterface { bool MarkSlotUnbootable(BootControlInterface::Slot slot) override; bool SetActiveBootSlot(BootControlInterface::Slot slot) override; bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override; - bool InitPartitionMetadata(Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) override; + bool PreparePartitionsForUpdate(Slot slot, + const DeltaArchiveManifest& manifest, + bool update_metadata) override; void Cleanup() override; private: @@ -84,7 +84,7 @@ class BootControlAndroid : public BootControlInterface { const std::string& partition_name_suffix) const; // Whether the target partitions should be loaded as dynamic partitions. Set - // by InitPartitionMetadata() per each update. + // by PreparePartitionsForUpdate() per each update. bool is_target_dynamic_{false}; DISALLOW_COPY_AND_ASSIGN(BootControlAndroid); diff --git a/boot_control_android_unittest.cc b/boot_control_android_unittest.cc index 3b921912..f090de2f 100644 --- a/boot_control_android_unittest.cc +++ b/boot_control_android_unittest.cc @@ -102,7 +102,7 @@ class BootControlAndroidTest : public ::testing::Test { LoadMetadataBuilder(GetSuperDevice(slot), slot)) .Times(AnyNumber()) .WillRepeatedly(Invoke([sizes](auto, auto) { - return NewFakeMetadata(PartitionSuffixSizesToMetadata(sizes)); + return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes)); })); } @@ -125,11 +125,11 @@ class BootControlAndroidTest : public ::testing::Test { })); } - bool InitPartitionMetadata(uint32_t slot, - PartitionSizes partition_sizes, - bool update_metadata = true) { - auto m = PartitionSizesToMetadata(partition_sizes); - return bootctl_.InitPartitionMetadata(slot, m, update_metadata); + bool PreparePartitionsForUpdate(uint32_t slot, + PartitionSizes partition_sizes, + bool update_metadata = true) { + auto m = PartitionSizesToManifest(partition_sizes); + return bootctl_.PreparePartitionsForUpdate(slot, m, update_metadata); } BootControlAndroid bootctl_; // BootControlAndroid under test. @@ -155,9 +155,9 @@ TEST_P(BootControlAndroidTestP, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}}); - // Not calling through BootControlAndroidTest::InitPartitionMetadata(), since - // we don't want any default group in the PartitionMetadata. - EXPECT_TRUE(bootctl_.InitPartitionMetadata(target(), {}, true)); + // Not calling through BootControlAndroidTest::PreparePartitionsForUpdate(), + // since we don't want any default group in the PartitionMetadata. + EXPECT_TRUE(bootctl_.PreparePartitionsForUpdate(target(), {}, true)); // Should use dynamic source partitions. EXPECT_CALL(dynamicControl(), GetState(S("system"))) @@ -197,7 +197,7 @@ TEST_P(BootControlAndroidTestP, GetPartitionDeviceWhenResumingUpdate) { {T("system"), 2_GiB}, {T("vendor"), 1_GiB}}); - EXPECT_TRUE(InitPartitionMetadata( + EXPECT_TRUE(PreparePartitionsForUpdate( target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}, false)); // Dynamic partition "system". @@ -240,7 +240,7 @@ INSTANTIATE_TEST_CASE_P(BootControlAndroidTest, TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) { SetSlots({1, 1}); - EXPECT_FALSE(InitPartitionMetadata(target(), {})) + EXPECT_FALSE(PreparePartitionsForUpdate(target(), {})) << "Should not be able to apply to current slot."; } diff --git a/boot_control_chromeos.cc b/boot_control_chromeos.cc index ccba316c..7e748d5e 100644 --- a/boot_control_chromeos.cc +++ b/boot_control_chromeos.cc @@ -326,10 +326,8 @@ int BootControlChromeOS::GetPartitionNumber( return -1; } -bool BootControlChromeOS::InitPartitionMetadata( - Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) { +bool BootControlChromeOS::PreparePartitionsForUpdate( + Slot slot, const DeltaArchiveManifest& manifest, bool update_metadata) { return true; } diff --git a/boot_control_chromeos.h b/boot_control_chromeos.h index f3682e9f..29841c91 100644 --- a/boot_control_chromeos.h +++ b/boot_control_chromeos.h @@ -50,9 +50,9 @@ class BootControlChromeOS : public BootControlInterface { bool MarkSlotUnbootable(BootControlInterface::Slot slot) override; bool SetActiveBootSlot(BootControlInterface::Slot slot) override; bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override; - bool InitPartitionMetadata(Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) override; + bool PreparePartitionsForUpdate(Slot slot, + const DeltaArchiveManifest& manifest, + bool update_metadata) override; void Cleanup() override; private: diff --git a/common/boot_control_interface.h b/common/boot_control_interface.h index 392d7851..9bf639a6 100644 --- a/common/boot_control_interface.h +++ b/common/boot_control_interface.h @@ -25,6 +25,8 @@ #include <base/callback.h> #include <base/macros.h> +#include "update_engine/update_metadata.pb.h" + namespace chromeos_update_engine { // The abstract boot control interface defines the interaction with the @@ -35,19 +37,6 @@ class BootControlInterface { public: using Slot = unsigned int; - struct PartitionMetadata { - struct Partition { - std::string name; - uint64_t size; - }; - struct Group { - std::string name; - uint64_t size; - std::vector<Partition> partitions; - }; - std::vector<Group> groups; - }; - static const Slot kInvalidSlot = UINT_MAX; virtual ~BootControlInterface() = default; @@ -67,9 +56,9 @@ class BootControlInterface { // The |slot| number must be between 0 and GetNumSlots() - 1 and the // |partition_name| is a platform-specific name that identifies a partition on // every slot. In order to access the dynamic partitions in the target slot, - // InitPartitionMetadata() must be called (once per payload) prior to calling - // this function. On success, returns true and stores the block device in - // |device|. + // PreparePartitionsForUpdate() must be called (once per payload) prior to + // calling this function. On success, returns true and stores the block device + // in |device|. virtual bool GetPartitionDevice(const std::string& partition_name, Slot slot, std::string* device) const = 0; @@ -96,12 +85,11 @@ class BootControlInterface { // Initializes the metadata of the underlying partitions for a given |slot| // and sets up the states for accessing dynamic partitions. - // |partition_metadata| will be written to the specified |slot| if + // Metadata will be written to the specified |slot| if // |update_metadata| is set. - virtual bool InitPartitionMetadata( - Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) = 0; + virtual bool PreparePartitionsForUpdate(Slot slot, + const DeltaArchiveManifest& manifest, + bool update_metadata) = 0; // Do necessary clean-up operations after the whole update. virtual void Cleanup() = 0; diff --git a/common/boot_control_stub.cc b/common/boot_control_stub.cc index 0fe8a989..b10e82f5 100644 --- a/common/boot_control_stub.cc +++ b/common/boot_control_stub.cc @@ -59,10 +59,8 @@ bool BootControlStub::MarkBootSuccessfulAsync( return false; } -bool BootControlStub::InitPartitionMetadata( - Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) { +bool BootControlStub::PreparePartitionsForUpdate( + Slot slot, const DeltaArchiveManifest& manifest, bool update_metadata) { LOG(ERROR) << __FUNCTION__ << " should never be called."; return false; } diff --git a/common/boot_control_stub.h b/common/boot_control_stub.h index 8dfaffc6..f2973a28 100644 --- a/common/boot_control_stub.h +++ b/common/boot_control_stub.h @@ -45,9 +45,9 @@ class BootControlStub : public BootControlInterface { bool MarkSlotUnbootable(BootControlInterface::Slot slot) override; bool SetActiveBootSlot(BootControlInterface::Slot slot) override; bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override; - bool InitPartitionMetadata(Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) override; + bool PreparePartitionsForUpdate(Slot slot, + const DeltaArchiveManifest& manifest, + bool update_metadata) override; void Cleanup() override; private: diff --git a/common/fake_boot_control.h b/common/fake_boot_control.h index 3d650758..11810d10 100644 --- a/common/fake_boot_control.h +++ b/common/fake_boot_control.h @@ -74,9 +74,9 @@ class FakeBootControl : public BootControlInterface { return true; } - bool InitPartitionMetadata(Slot slot, - const PartitionMetadata& partition_metadata, - bool update_metadata) override { + bool PreparePartitionsForUpdate(Slot slot, + const DeltaArchiveManifest& manifest, + bool update_metadata) override { return true; } diff --git a/dynamic_partition_control_android.cc b/dynamic_partition_control_android.cc index b9732322..e351dbdf 100644 --- a/dynamic_partition_control_android.cc +++ b/dynamic_partition_control_android.cc @@ -16,6 +16,7 @@ #include "update_engine/dynamic_partition_control_android.h" +#include <map> #include <memory> #include <set> #include <string> @@ -48,8 +49,6 @@ using android::fs_mgr::SlotSuffixForSlotNumber; namespace chromeos_update_engine { -using PartitionMetadata = BootControlInterface::PartitionMetadata; - constexpr char kUseDynamicPartitions[] = "ro.boot.dynamic_partitions"; constexpr char kRetrfoitDynamicPartitions[] = "ro.boot.dynamic_partitions_retrofit"; @@ -309,14 +308,14 @@ bool DynamicPartitionControlAndroid::GetDeviceDir(std::string* out) { bool DynamicPartitionControlAndroid::PreparePartitionsForUpdate( uint32_t source_slot, uint32_t target_slot, - const PartitionMetadata& partition_metadata) { + const DeltaArchiveManifest& manifest) { const std::string target_suffix = SlotSuffixForSlotNumber(target_slot); // Unmap all the target dynamic partitions because they would become // inconsistent with the new metadata. - for (const auto& group : partition_metadata.groups) { - for (const auto& partition : group.partitions) { - if (!UnmapPartitionOnDeviceMapper(partition.name + target_suffix)) { + for (const auto& group : manifest.dynamic_partition_metadata().groups()) { + for (const auto& partition_name : group.partition_names()) { + if (!UnmapPartitionOnDeviceMapper(partition_name + target_suffix)) { return false; } } @@ -337,8 +336,7 @@ bool DynamicPartitionControlAndroid::PreparePartitionsForUpdate( return false; } - if (!UpdatePartitionMetadata( - builder.get(), target_slot, partition_metadata)) { + if (!UpdatePartitionMetadata(builder.get(), target_slot, manifest)) { return false; } @@ -355,13 +353,13 @@ std::string DynamicPartitionControlAndroid::GetSuperPartitionName( bool DynamicPartitionControlAndroid::UpdatePartitionMetadata( MetadataBuilder* builder, uint32_t target_slot, - const PartitionMetadata& partition_metadata) { + const DeltaArchiveManifest& manifest) { const std::string target_suffix = SlotSuffixForSlotNumber(target_slot); DeleteGroupsWithSuffix(builder, target_suffix); uint64_t total_size = 0; - for (const auto& group : partition_metadata.groups) { - total_size += group.size; + for (const auto& group : manifest.dynamic_partition_metadata().groups()) { + total_size += group.size(); } std::string expr; @@ -378,18 +376,36 @@ bool DynamicPartitionControlAndroid::UpdatePartitionMetadata( return false; } - for (const auto& group : partition_metadata.groups) { - auto group_name_suffix = group.name + target_suffix; - if (!builder->AddGroup(group_name_suffix, group.size)) { + // name of partition(e.g. "system") -> size in bytes + std::map<std::string, uint64_t> partition_sizes; + for (const auto& partition : manifest.partitions()) { + partition_sizes.emplace(partition.partition_name(), + partition.new_partition_info().size()); + } + + for (const auto& group : manifest.dynamic_partition_metadata().groups()) { + auto group_name_suffix = group.name() + target_suffix; + if (!builder->AddGroup(group_name_suffix, group.size())) { LOG(ERROR) << "Cannot add group " << group_name_suffix << " with size " - << group.size; + << group.size(); return false; } LOG(INFO) << "Added group " << group_name_suffix << " with size " - << group.size; + << group.size(); + + for (const auto& partition_name : group.partition_names()) { + auto partition_sizes_it = partition_sizes.find(partition_name); + if (partition_sizes_it == partition_sizes.end()) { + // TODO(tbao): Support auto-filling partition info for framework-only + // OTA. + LOG(ERROR) << "dynamic_partition_metadata contains partition " + << partition_name << " but it is not part of the manifest. " + << "This is not supported."; + return false; + } + uint64_t partition_size = partition_sizes_it->second; - for (const auto& partition : group.partitions) { - auto partition_name_suffix = partition.name + target_suffix; + auto partition_name_suffix = partition_name + target_suffix; Partition* p = builder->AddPartition( partition_name_suffix, group_name_suffix, LP_PARTITION_ATTR_READONLY); if (!p) { @@ -397,13 +413,13 @@ bool DynamicPartitionControlAndroid::UpdatePartitionMetadata( << " to group " << group_name_suffix; return false; } - if (!builder->ResizePartition(p, partition.size)) { + if (!builder->ResizePartition(p, partition_size)) { LOG(ERROR) << "Cannot resize partition " << partition_name_suffix - << " to size " << partition.size << ". Not enough space?"; + << " to size " << partition_size << ". Not enough space?"; return false; } LOG(INFO) << "Added partition " << partition_name_suffix << " to group " - << group_name_suffix << " with size " << partition.size; + << group_name_suffix << " with size " << partition_size; } } diff --git a/dynamic_partition_control_android.h b/dynamic_partition_control_android.h index d743e6e5..0907236a 100644 --- a/dynamic_partition_control_android.h +++ b/dynamic_partition_control_android.h @@ -44,10 +44,10 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface { std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder( const std::string& super_device, uint32_t source_slot) override; - bool PreparePartitionsForUpdate(uint32_t source_slot, - uint32_t target_slot, - const BootControlInterface::PartitionMetadata& - partition_metadata) override; + bool PreparePartitionsForUpdate( + uint32_t source_slot, + uint32_t target_slot, + const DeltaArchiveManifest& manifest) override; bool GetDeviceDir(std::string* path) override; std::string GetSuperPartitionName(uint32_t slot) override; @@ -94,10 +94,9 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface { // Update |builder| according to |partition_metadata|, assuming the device // does not have Virtual A/B. - bool UpdatePartitionMetadata( - android::fs_mgr::MetadataBuilder* builder, - uint32_t target_slot, - const BootControlInterface::PartitionMetadata& partition_metadata); + bool UpdatePartitionMetadata(android::fs_mgr::MetadataBuilder* builder, + uint32_t target_slot, + const DeltaArchiveManifest& manifest); DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid); }; diff --git a/dynamic_partition_control_android_unittest.cc b/dynamic_partition_control_android_unittest.cc index 1a3f6647..552774e6 100644 --- a/dynamic_partition_control_android_unittest.cc +++ b/dynamic_partition_control_android_unittest.cc @@ -86,7 +86,7 @@ class DynamicPartitionControlAndroidTest : public ::testing::Test { LoadMetadataBuilder(GetSuperDevice(slot), slot, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke([sizes](auto, auto, auto) { - return NewFakeMetadata(PartitionSuffixSizesToMetadata(sizes)); + return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes)); })); } @@ -112,7 +112,7 @@ class DynamicPartitionControlAndroidTest : public ::testing::Test { } bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) { return dynamicControl().PreparePartitionsForUpdate( - source(), target(), PartitionSizesToMetadata(partition_sizes)); + source(), target(), PartitionSizesToManifest(partition_sizes)); } void SetSlots(const TestParam& slots) { slots_ = slots; } @@ -125,24 +125,24 @@ class DynamicPartitionControlAndroidTest : public ::testing::Test { const PartitionSizes& update_metadata, const PartitionSuffixSizes& expected) { return UpdatePartitionMetadata( - PartitionSuffixSizesToMetadata(source_metadata), - PartitionSizesToMetadata(update_metadata), - PartitionSuffixSizesToMetadata(expected)); + PartitionSuffixSizesToManifest(source_metadata), + PartitionSizesToManifest(update_metadata), + PartitionSuffixSizesToManifest(expected)); } testing::AssertionResult UpdatePartitionMetadata( - const PartitionMetadata& source_metadata, - const PartitionMetadata& update_metadata, - const PartitionMetadata& expected) { + const DeltaArchiveManifest& source_manifest, + const DeltaArchiveManifest& update_manifest, + const DeltaArchiveManifest& expected) { return UpdatePartitionMetadata( - source_metadata, update_metadata, MetadataMatches(expected)); + source_manifest, update_manifest, MetadataMatches(expected)); } testing::AssertionResult UpdatePartitionMetadata( - const PartitionMetadata& source_metadata, - const PartitionMetadata& update_metadata, + const DeltaArchiveManifest& source_manifest, + const DeltaArchiveManifest& update_manifest, const Matcher<MetadataBuilder*>& matcher) { - auto super_metadata = NewFakeMetadata(source_metadata); + auto super_metadata = NewFakeMetadata(source_manifest); if (!module_->UpdatePartitionMetadata( - super_metadata.get(), target(), update_metadata)) { + super_metadata.get(), target(), update_manifest)) { return testing::AssertionFailure() << "UpdatePartitionMetadataInternal failed"; } @@ -290,112 +290,115 @@ INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest, class DynamicPartitionControlAndroidGroupTestP : public DynamicPartitionControlAndroidTestP { public: - PartitionMetadata source_metadata; + DeltaArchiveManifest source_manifest; void SetUp() override { DynamicPartitionControlAndroidTestP::SetUp(); - source_metadata = { - .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB), - SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB), - SimpleGroup(T("android"), 3_GiB, T("system"), 0), - SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}}; + AddGroupAndPartition( + &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB); + AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB); + AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0); + AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0); } - // Return a simple group with only one partition. - PartitionMetadata::Group SimpleGroup(const string& group, - uint64_t group_size, - const string& partition, - uint64_t partition_size) { - return {.name = group, - .size = group_size, - .partitions = {{.name = partition, .size = partition_size}}}; + void AddGroupAndPartition(DeltaArchiveManifest* manifest, + const string& group, + uint64_t group_size, + const string& partition, + uint64_t partition_size) { + auto* g = AddGroup(manifest, group, group_size); + AddPartition(manifest, g, partition, partition_size); } }; // Allow to resize within group. TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) { - PartitionMetadata expected{ - .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB), - SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}}; + DeltaArchiveManifest expected; + AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB); + AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB); - PartitionMetadata update_metadata{ - .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB), - SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}; + DeltaArchiveManifest update_manifest; + AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB); + AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB); EXPECT_TRUE( - UpdatePartitionMetadata(source_metadata, update_metadata, expected)); + UpdatePartitionMetadata(source_manifest, update_manifest, expected)); } TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) { - PartitionMetadata update_metadata{ - .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB), - SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}; - EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {})) + DeltaArchiveManifest update_manifest; + AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB), + AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB); + EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {})) << "Should not be able to grow over maximum size of group"; } TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) { - PartitionMetadata update_metadata{ - .groups = {{.name = "android", .size = 3_GiB}, - {.name = "oem", .size = 3_GiB}}}; - EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {})) + DeltaArchiveManifest update_manifest; + AddGroup(&update_manifest, "android", 3_GiB); + AddGroup(&update_manifest, "oem", 3_GiB); + EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {})) << "Should not be able to grow over size of super / 2"; } TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) { - PartitionMetadata expected{ - .groups = {{.name = T("android"), - .size = 3_GiB, - .partitions = {{.name = T("system"), .size = 2_GiB}, - {.name = T("system_ext"), .size = 1_GiB}}}}}; - PartitionMetadata update_metadata{ - .groups = {{.name = "android", - .size = 3_GiB, - .partitions = {{.name = "system", .size = 2_GiB}, - {.name = "system_ext", .size = 1_GiB}}}, - SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}; + DeltaArchiveManifest expected; + auto* g = AddGroup(&expected, T("android"), 3_GiB); + AddPartition(&expected, g, T("system"), 2_GiB); + AddPartition(&expected, g, T("system_ext"), 1_GiB); + + DeltaArchiveManifest update_manifest; + g = AddGroup(&update_manifest, "android", 3_GiB); + AddPartition(&update_manifest, g, "system", 2_GiB); + AddPartition(&update_manifest, g, "system_ext", 1_GiB); + AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB); + EXPECT_TRUE( - UpdatePartitionMetadata(source_metadata, update_metadata, expected)); + UpdatePartitionMetadata(source_manifest, update_manifest, expected)); } TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) { - PartitionMetadata expected{ - .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}}; - PartitionMetadata update_metadata{ - .groups = {{.name = "android", .size = 3_GiB, .partitions = {}}, - SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}; + DeltaArchiveManifest expected; + AddGroup(&expected, T("android"), 3_GiB); + + DeltaArchiveManifest update_manifest; + AddGroup(&update_manifest, "android", 3_GiB); + AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB); + EXPECT_TRUE( - UpdatePartitionMetadata(source_metadata, update_metadata, expected)); + UpdatePartitionMetadata(source_manifest, update_manifest, expected)); } TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) { - PartitionMetadata expected{ - .groups = { - SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}}; - PartitionMetadata update_metadata{ - .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB), - SimpleGroup("oem", 1_GiB, "vendor", 1_GiB), - SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}; + DeltaArchiveManifest expected; + AddGroupAndPartition( + &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB); + + DeltaArchiveManifest update_manifest; + AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB); + AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB); + AddGroupAndPartition( + &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB); EXPECT_TRUE( - UpdatePartitionMetadata(source_metadata, update_metadata, expected)); + UpdatePartitionMetadata(source_manifest, update_manifest, expected)); } TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) { - PartitionMetadata update_metadata{ - .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}; + DeltaArchiveManifest update_manifest; + AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB); EXPECT_TRUE(UpdatePartitionMetadata( - source_metadata, update_metadata, Not(HasGroup(T("oem"))))); + source_manifest, update_manifest, Not(HasGroup(T("oem"))))); } TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) { - PartitionMetadata expected{ - .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB), - SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}}; - PartitionMetadata update_metadata{ - .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB), - SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}; + DeltaArchiveManifest expected; + AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB); + AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB); + DeltaArchiveManifest update_manifest; + AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB), + AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB); EXPECT_TRUE( - UpdatePartitionMetadata(source_metadata, update_metadata, expected)); + UpdatePartitionMetadata(source_manifest, update_manifest, expected)); } INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest, diff --git a/dynamic_partition_control_interface.h b/dynamic_partition_control_interface.h index 9c7b8d07..a4dc5765 100644 --- a/dynamic_partition_control_interface.h +++ b/dynamic_partition_control_interface.h @@ -27,6 +27,7 @@ #include <liblp/builder.h> #include "update_engine/common/boot_control_interface.h" +#include "update_engine/update_metadata.pb.h" namespace chromeos_update_engine { @@ -88,13 +89,13 @@ class DynamicPartitionControlInterface { virtual std::unique_ptr<android::fs_mgr::MetadataBuilder> LoadMetadataBuilder( const std::string& super_device, uint32_t source_slot) = 0; - // Prepare all partitions for an update specified in |partition_metadata|. + // Prepare all partitions for an update specified in |manifest|. // This is needed before calling MapPartitionOnDeviceMapper(), otherwise the // device would be mapped in an inconsistent way. virtual bool PreparePartitionsForUpdate( uint32_t source_slot, uint32_t target_slot, - const BootControlInterface::PartitionMetadata& partition_metadata) = 0; + const DeltaArchiveManifest& manifest) = 0; // Return a possible location for devices listed by name. virtual bool GetDeviceDir(std::string* path) = 0; diff --git a/dynamic_partition_test_utils.h b/dynamic_partition_test_utils.h index 61d8e0a3..346998fc 100644 --- a/dynamic_partition_test_utils.h +++ b/dynamic_partition_test_utils.h @@ -33,6 +33,7 @@ #include <storage_literals/storage_literals.h> #include "update_engine/common/boot_control_interface.h" +#include "update_engine/update_metadata.pb.h" namespace chromeos_update_engine { @@ -59,8 +60,6 @@ using PartitionSizes = std::map<std::string, uint64_t>; // "{name_a, size}" using PartitionSuffixSizes = std::map<std::string, uint64_t>; -using PartitionMetadata = BootControlInterface::PartitionMetadata; - constexpr uint64_t kDefaultGroupSize = 5_GiB; // Super device size. 1 MiB for metadata. constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB; @@ -78,8 +77,8 @@ inline std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) { return os << "}"; } -template <typename T> -inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) { +template <typename V> +inline void VectorToStream(std::ostream& os, const V& param) { os << "["; bool first = true; for (const auto& e : param) { @@ -88,21 +87,28 @@ inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) { os << e; first = false; } - return os << "]"; + os << "]"; } -inline std::ostream& operator<<(std::ostream& os, - const PartitionMetadata::Partition& p) { - return os << "{" << p.name << ", " << p.size << "}"; +inline std::ostream& operator<<(std::ostream& os, const PartitionUpdate& p) { + return os << "{" << p.partition_name() << ", " + << p.new_partition_info().size() << "}"; } inline std::ostream& operator<<(std::ostream& os, - const PartitionMetadata::Group& g) { - return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}"; + const DynamicPartitionGroup& g) { + os << "{" << g.name() << ", " << g.size() << ", "; + VectorToStream(os, g.partition_names()); + return os << "}"; } -inline std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) { - return os << m.groups; +inline std::ostream& operator<<(std::ostream& os, + const DeltaArchiveManifest& m) { + os << "{.groups = "; + VectorToStream(os, m.dynamic_partition_metadata().groups()); + os << ", .partitions = "; + VectorToStream(os, m.partitions()); + return os; } inline std::string GetDevice(const std::string& name) { @@ -113,90 +119,125 @@ inline std::string GetDmDevice(const std::string& name) { return kFakeDmDevicePath + name; } +inline DynamicPartitionGroup* AddGroup(DeltaArchiveManifest* manifest, + const std::string& group, + uint64_t group_size) { + auto* g = manifest->mutable_dynamic_partition_metadata()->add_groups(); + g->set_name(group); + g->set_size(group_size); + return g; +} + +inline void AddPartition(DeltaArchiveManifest* manifest, + DynamicPartitionGroup* group, + const std::string& partition, + uint64_t partition_size) { + group->add_partition_names(partition); + auto* p = manifest->add_partitions(); + p->set_partition_name(partition); + p->mutable_new_partition_info()->set_size(partition_size); +} + // To support legacy tests, auto-convert {name_a: size} map to -// PartitionMetadata. -inline PartitionMetadata PartitionSuffixSizesToMetadata( +// DeltaArchiveManifest. +inline DeltaArchiveManifest PartitionSuffixSizesToManifest( const PartitionSuffixSizes& partition_sizes) { - PartitionMetadata metadata; + DeltaArchiveManifest manifest; for (const char* suffix : kSlotSuffixes) { - metadata.groups.push_back( - {std::string(kDefaultGroup) + suffix, kDefaultGroupSize, {}}); + AddGroup(&manifest, std::string(kDefaultGroup) + suffix, kDefaultGroupSize); } for (const auto& pair : partition_sizes) { for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) { if (base::EndsWith(pair.first, kSlotSuffixes[suffix_idx], base::CompareCase::SENSITIVE)) { - metadata.groups[suffix_idx].partitions.push_back( - {pair.first, pair.second}); + AddPartition( + &manifest, + manifest.mutable_dynamic_partition_metadata()->mutable_groups( + suffix_idx), + pair.first, + pair.second); } } } - return metadata; + return manifest; } // To support legacy tests, auto-convert {name: size} map to PartitionMetadata. -inline PartitionMetadata PartitionSizesToMetadata( +inline DeltaArchiveManifest PartitionSizesToManifest( const PartitionSizes& partition_sizes) { - PartitionMetadata metadata; - metadata.groups.push_back( - {std::string{kDefaultGroup}, kDefaultGroupSize, {}}); + DeltaArchiveManifest manifest; + auto* g = AddGroup(&manifest, std::string(kDefaultGroup), kDefaultGroupSize); for (const auto& pair : partition_sizes) { - metadata.groups[0].partitions.push_back({pair.first, pair.second}); + AddPartition(&manifest, g, pair.first, pair.second); } - return metadata; + return manifest; } inline std::unique_ptr<MetadataBuilder> NewFakeMetadata( - const PartitionMetadata& metadata) { + const DeltaArchiveManifest& manifest) { auto builder = MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots); - EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2); - EXPECT_NE(nullptr, builder); - if (builder == nullptr) - return nullptr; - for (const auto& group : metadata.groups) { - EXPECT_TRUE(builder->AddGroup(group.name, group.size)); - for (const auto& partition : group.partitions) { - auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */); - EXPECT_TRUE(p && builder->ResizePartition(p, partition.size)); + 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()) { + EXPECT_NE( + nullptr, + builder->AddPartition(partition_name, group.name(), 0 /* attr */)); } } + for (const auto& partition : manifest.partitions()) { + auto p = builder->FindPartition(partition.partition_name()); + EXPECT_TRUE(p && builder->ResizePartition( + p, partition.new_partition_info().size())); + } return builder; } class MetadataMatcher : public MatcherInterface<MetadataBuilder*> { public: explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes) - : partition_metadata_(PartitionSuffixSizesToMetadata(partition_sizes)) {} - explicit MetadataMatcher(const PartitionMetadata& partition_metadata) - : partition_metadata_(partition_metadata) {} + : manifest_(PartitionSuffixSizesToManifest(partition_sizes)) {} + explicit MetadataMatcher(const DeltaArchiveManifest& manifest) + : manifest_(manifest) {} bool MatchAndExplain(MetadataBuilder* metadata, MatchResultListener* listener) const override { bool success = true; - for (const auto& group : partition_metadata_.groups) { - for (const auto& partition : group.partitions) { - auto p = metadata->FindPartition(partition.name); + for (const auto& group : manifest_.dynamic_partition_metadata().groups()) { + for (const auto& partition_name : group.partition_names()) { + auto p = metadata->FindPartition(partition_name); if (p == nullptr) { if (!success) *listener << "; "; - *listener << "No partition " << partition.name; + *listener << "No partition " << partition_name; + success = false; + continue; + } + const auto& partition_updates = manifest_.partitions(); + auto it = std::find_if(partition_updates.begin(), + partition_updates.end(), + [&](const auto& p) { + return p.partition_name() == partition_name; + }); + if (it == partition_updates.end()) { + *listener << "Can't find partition update " << partition_name; success = false; continue; } - if (p->size() != partition.size) { + auto partition_size = it->new_partition_info().size(); + if (p->size() != partition_size) { if (!success) *listener << "; "; - *listener << "Partition " << partition.name << " has size " - << p->size() << ", expected " << partition.size; + *listener << "Partition " << partition_name << " has size " + << p->size() << ", expected " << partition_size; success = false; } - if (p->group_name() != group.name) { + if (p->group_name() != group.name()) { if (!success) *listener << "; "; - *listener << "Partition " << partition.name << " has group " - << p->group_name() << ", expected " << group.name; + *listener << "Partition " << partition_name << " has group " + << p->group_name() << ", expected " << group.name(); success = false; } } @@ -205,15 +246,15 @@ class MetadataMatcher : public MatcherInterface<MetadataBuilder*> { } void DescribeTo(std::ostream* os) const override { - *os << "expect: " << partition_metadata_; + *os << "expect: " << manifest_; } void DescribeNegationTo(std::ostream* os) const override { - *os << "expect not: " << partition_metadata_; + *os << "expect not: " << manifest_; } private: - PartitionMetadata partition_metadata_; + DeltaArchiveManifest manifest_; }; inline Matcher<MetadataBuilder*> MetadataMatches( @@ -222,8 +263,8 @@ inline Matcher<MetadataBuilder*> MetadataMatches( } inline Matcher<MetadataBuilder*> MetadataMatches( - const PartitionMetadata& partition_metadata) { - return MakeMatcher(new MetadataMatcher(partition_metadata)); + const DeltaArchiveManifest& manifest) { + return MakeMatcher(new MetadataMatcher(manifest)); } MATCHER_P(HasGroup, group, " has group " + group) { diff --git a/mock_dynamic_partition_control.h b/mock_dynamic_partition_control.h index aab3c4d8..d96432b1 100644 --- a/mock_dynamic_partition_control.h +++ b/mock_dynamic_partition_control.h @@ -45,9 +45,7 @@ class MockDynamicPartitionControl : public DynamicPartitionControlInterface { MOCK_METHOD1(GetDeviceDir, bool(std::string*)); MOCK_METHOD0(GetDynamicPartitionsFeatureFlag, FeatureFlag()); MOCK_METHOD3(PreparePartitionsForUpdate, - bool(uint32_t, - uint32_t, - const BootControlInterface::PartitionMetadata&)); + bool(uint32_t, uint32_t, const DeltaArchiveManifest&)); MOCK_METHOD1(GetSuperPartitionName, std::string(uint32_t)); MOCK_METHOD0(GetVirtualAbFeatureFlag, FeatureFlag()); }; diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc index d76a959e..3ff98ca2 100644 --- a/payload_consumer/delta_performer.cc +++ b/payload_consumer/delta_performer.cc @@ -808,7 +808,6 @@ bool DeltaPerformer::ParseManifestPartitions(ErrorCode* error) { for (const PartitionUpdate& partition : manifest_.partitions()) { partitions_.push_back(partition); } - manifest_.clear_partitions(); } else if (major_payload_version_ == kChromeOSMajorPayloadVersion) { LOG(INFO) << "Converting update information from old format."; PartitionUpdate root_part; @@ -923,12 +922,16 @@ bool DeltaPerformer::ParseManifestPartitions(ErrorCode* error) { } if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) { - if (!InitPartitionMetadata()) { + if (!PreparePartitionsForUpdate()) { *error = ErrorCode::kInstallDeviceOpenError; return false; } } + if (major_payload_version_ == kBrilloMajorPayloadVersion) { + manifest_.clear_partitions(); + } + if (!install_plan_->LoadPartitionsFromSlots(boot_control_)) { LOG(ERROR) << "Unable to determine all the partition devices."; *error = ErrorCode::kInstallDeviceOpenError; @@ -938,45 +941,18 @@ bool DeltaPerformer::ParseManifestPartitions(ErrorCode* error) { return true; } -bool DeltaPerformer::InitPartitionMetadata() { - BootControlInterface::PartitionMetadata partition_metadata; - if (manifest_.has_dynamic_partition_metadata()) { - std::map<string, uint64_t> partition_sizes; - for (const auto& partition : install_plan_->partitions) { - partition_sizes.emplace(partition.name, partition.target_size); - } - for (const auto& group : manifest_.dynamic_partition_metadata().groups()) { - BootControlInterface::PartitionMetadata::Group e; - e.name = group.name(); - e.size = group.size(); - for (const auto& partition_name : group.partition_names()) { - auto it = partition_sizes.find(partition_name); - if (it == partition_sizes.end()) { - // TODO(tbao): Support auto-filling partition info for framework-only - // OTA. - LOG(ERROR) << "dynamic_partition_metadata contains partition " - << partition_name - << " but it is not part of the manifest. " - << "This is not supported."; - return false; - } - e.partitions.push_back({partition_name, it->second}); - } - partition_metadata.groups.push_back(std::move(e)); - } - } - +bool DeltaPerformer::PreparePartitionsForUpdate() { bool metadata_updated = false; prefs_->GetBoolean(kPrefsDynamicPartitionMetadataUpdated, &metadata_updated); - if (!boot_control_->InitPartitionMetadata( - install_plan_->target_slot, partition_metadata, !metadata_updated)) { + if (!boot_control_->PreparePartitionsForUpdate( + install_plan_->target_slot, manifest_, !metadata_updated)) { LOG(ERROR) << "Unable to initialize partition metadata for slot " << BootControlInterface::SlotName(install_plan_->target_slot); return false; } TEST_AND_RETURN_FALSE( prefs_->SetBoolean(kPrefsDynamicPartitionMetadataUpdated, true)); - LOG(INFO) << "InitPartitionMetadata done."; + LOG(INFO) << "PreparePartitionsForUpdate done."; return true; } diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h index 17cb5995..25c348c9 100644 --- a/payload_consumer/delta_performer.h +++ b/payload_consumer/delta_performer.h @@ -275,7 +275,7 @@ class DeltaPerformer : public FileWriter { // After install_plan_ is filled with partition names and sizes, initialize // metadata of partitions and map necessary devices before opening devices. - bool InitPartitionMetadata(); + bool PreparePartitionsForUpdate(); // Update Engine preference store. PrefsInterface* prefs_; |