Loading fs_mgr/libsnapshot/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ cc_defaults { "libfs_mgr", "libfstab", "liblp", "update_metadata-protos", ], whole_static_libs: [ "libext2_uuid", Loading @@ -41,6 +42,9 @@ cc_defaults { header_libs: [ "libfiemap_headers", ], export_static_lib_headers: [ "update_metadata-protos", ], export_header_lib_headers: [ "libfiemap_headers", ], Loading @@ -51,6 +55,7 @@ filegroup { name: "libsnapshot_sources", srcs: [ "snapshot.cpp", "snapshot_metadata_updater.cpp", "partition_cow_creator.cpp", "utility.cpp", ], Loading Loading @@ -87,10 +92,12 @@ cc_test { srcs: [ "snapshot_test.cpp", "partition_cow_creator_test.cpp", "snapshot_metadata_updater_test.cpp", "test_helpers.cpp", ], shared_libs: [ "libbinder", "libprotobuf-cpp-lite", "libutils", ], static_libs: [ Loading fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +4 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <libfiemap/image_manager.h> #include <liblp/builder.h> #include <liblp/liblp.h> #include <update_engine/update_metadata.pb.h> #ifndef FRIEND_TEST #define FRIEND_TEST(test_set_name, individual_test) \ Loading Loading @@ -89,6 +90,7 @@ class SnapshotManager final { using IPartitionOpener = android::fs_mgr::IPartitionOpener; using LpMetadata = android::fs_mgr::LpMetadata; using MetadataBuilder = android::fs_mgr::MetadataBuilder; using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest; public: // Dependency injection for testing. Loading @@ -98,6 +100,7 @@ class SnapshotManager final { virtual std::string GetGsidDir() const = 0; virtual std::string GetMetadataDir() const = 0; virtual std::string GetSlotSuffix() const = 0; virtual std::string GetOtherSlotSuffix() const = 0; virtual std::string GetSuperDevice(uint32_t slot) const = 0; virtual const IPartitionOpener& GetPartitionOpener() const = 0; virtual bool IsOverlayfsSetup() const = 0; Loading Loading @@ -169,9 +172,7 @@ class SnapshotManager final { // Create necessary COW device / files for OTA clients. New logical partitions will be added to // group "cow" in target_metadata. Regions of partitions of current_metadata will be // "write-protected" and snapshotted. bool CreateUpdateSnapshots(MetadataBuilder* target_metadata, const std::string& target_suffix, MetadataBuilder* current_metadata, const std::string& current_suffix, const std::map<std::string, uint64_t>& cow_sizes); bool CreateUpdateSnapshots(const DeltaArchiveManifest& manifest); // Map a snapshotted partition for OTA clients to write to. Write-protected regions are // determined previously in CreateSnapshots. Loading fs_mgr/libsnapshot/partition_cow_creator.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ using android::fs_mgr::Extent; using android::fs_mgr::Interval; using android::fs_mgr::kDefaultBlockSize; using android::fs_mgr::Partition; using chromeos_update_engine::InstallOperation; template <typename T> using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>; namespace android { namespace snapshot { Loading Loading @@ -117,9 +120,15 @@ std::optional<uint64_t> PartitionCowCreator::GetSnapshotSize() { return snapshot_size; } std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { std::optional<uint64_t> PartitionCowCreator::GetCowSize(uint64_t snapshot_size) { // TODO: Use |operations|. to determine a minimum COW size. // kCowEstimateFactor is good for prototyping but we can't use that in production. static constexpr double kCowEstimateFactor = 1.05; auto cow_size = RoundUp(snapshot_size * kCowEstimateFactor, kDefaultBlockSize); return cow_size; } std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { CHECK(current_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME && target_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME); Loading @@ -135,13 +144,8 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { ret.snapshot_status.snapshot_size = *snapshot_size; // TODO: always read from cow_size when the COW size is written in // update package. kCowEstimateFactor is good for prototyping but // we can't use that in production. if (!cow_size.has_value()) { cow_size = RoundUp(ret.snapshot_status.snapshot_size * kCowEstimateFactor, kDefaultBlockSize); } auto cow_size = GetCowSize(*snapshot_size); if (!cow_size.has_value()) return std::nullopt; // Compute regions that are free in both current and target metadata. These are the regions // we can use for COW partition. Loading fs_mgr/libsnapshot/partition_cow_creator.h +9 −5 Original line number Diff line number Diff line Loading @@ -32,20 +32,23 @@ struct PartitionCowCreator { using Interval = android::fs_mgr::Interval; using MetadataBuilder = android::fs_mgr::MetadataBuilder; using Partition = android::fs_mgr::Partition; using InstallOperation = chromeos_update_engine::InstallOperation; template <typename T> using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>; // The metadata that will be written to target metadata slot. MetadataBuilder* target_metadata; MetadataBuilder* target_metadata = nullptr; // The suffix of the target slot. std::string target_suffix; // The partition in target_metadata that needs to be snapshotted. Partition* target_partition; Partition* target_partition = nullptr; // The metadata at the current slot (that would be used if the device boots // normally). This is used to determine which extents are being used. MetadataBuilder* current_metadata; MetadataBuilder* current_metadata = nullptr; // The suffix of the current slot. std::string current_suffix; // The COW size given by client code. std::optional<uint64_t> cow_size; // List of operations to be applied on the partition. const RepeatedPtrField<InstallOperation>* operations = nullptr; struct Return { SnapshotManager::SnapshotStatus snapshot_status; Loading @@ -57,6 +60,7 @@ struct PartitionCowCreator { private: bool HasExtent(Partition* p, Extent* e); std::optional<uint64_t> GetSnapshotSize(); std::optional<uint64_t> GetCowSize(uint64_t snapshot_size); }; } // namespace snapshot Loading fs_mgr/libsnapshot/partition_cow_creator_test.cpp +1 −4 Original line number Diff line number Diff line Loading @@ -76,14 +76,11 @@ TEST(PartitionCowCreator, IntersectSelf) { .target_suffix = "_b", .target_partition = system_b, .current_metadata = builder_a.get(), .current_suffix = "_a", .cow_size = 20 * 1024}; .current_suffix = "_a"}; auto ret = creator.Run(); ASSERT_TRUE(ret.has_value()); ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size); ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size); ASSERT_EQ(20 * 1024, ret->snapshot_status.cow_file_size + ret->snapshot_status.cow_partition_size); } } // namespace snapshot Loading Loading
fs_mgr/libsnapshot/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ cc_defaults { "libfs_mgr", "libfstab", "liblp", "update_metadata-protos", ], whole_static_libs: [ "libext2_uuid", Loading @@ -41,6 +42,9 @@ cc_defaults { header_libs: [ "libfiemap_headers", ], export_static_lib_headers: [ "update_metadata-protos", ], export_header_lib_headers: [ "libfiemap_headers", ], Loading @@ -51,6 +55,7 @@ filegroup { name: "libsnapshot_sources", srcs: [ "snapshot.cpp", "snapshot_metadata_updater.cpp", "partition_cow_creator.cpp", "utility.cpp", ], Loading Loading @@ -87,10 +92,12 @@ cc_test { srcs: [ "snapshot_test.cpp", "partition_cow_creator_test.cpp", "snapshot_metadata_updater_test.cpp", "test_helpers.cpp", ], shared_libs: [ "libbinder", "libprotobuf-cpp-lite", "libutils", ], static_libs: [ Loading
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +4 −3 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <libfiemap/image_manager.h> #include <liblp/builder.h> #include <liblp/liblp.h> #include <update_engine/update_metadata.pb.h> #ifndef FRIEND_TEST #define FRIEND_TEST(test_set_name, individual_test) \ Loading Loading @@ -89,6 +90,7 @@ class SnapshotManager final { using IPartitionOpener = android::fs_mgr::IPartitionOpener; using LpMetadata = android::fs_mgr::LpMetadata; using MetadataBuilder = android::fs_mgr::MetadataBuilder; using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest; public: // Dependency injection for testing. Loading @@ -98,6 +100,7 @@ class SnapshotManager final { virtual std::string GetGsidDir() const = 0; virtual std::string GetMetadataDir() const = 0; virtual std::string GetSlotSuffix() const = 0; virtual std::string GetOtherSlotSuffix() const = 0; virtual std::string GetSuperDevice(uint32_t slot) const = 0; virtual const IPartitionOpener& GetPartitionOpener() const = 0; virtual bool IsOverlayfsSetup() const = 0; Loading Loading @@ -169,9 +172,7 @@ class SnapshotManager final { // Create necessary COW device / files for OTA clients. New logical partitions will be added to // group "cow" in target_metadata. Regions of partitions of current_metadata will be // "write-protected" and snapshotted. bool CreateUpdateSnapshots(MetadataBuilder* target_metadata, const std::string& target_suffix, MetadataBuilder* current_metadata, const std::string& current_suffix, const std::map<std::string, uint64_t>& cow_sizes); bool CreateUpdateSnapshots(const DeltaArchiveManifest& manifest); // Map a snapshotted partition for OTA clients to write to. Write-protected regions are // determined previously in CreateSnapshots. Loading
fs_mgr/libsnapshot/partition_cow_creator.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ using android::fs_mgr::Extent; using android::fs_mgr::Interval; using android::fs_mgr::kDefaultBlockSize; using android::fs_mgr::Partition; using chromeos_update_engine::InstallOperation; template <typename T> using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>; namespace android { namespace snapshot { Loading Loading @@ -117,9 +120,15 @@ std::optional<uint64_t> PartitionCowCreator::GetSnapshotSize() { return snapshot_size; } std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { std::optional<uint64_t> PartitionCowCreator::GetCowSize(uint64_t snapshot_size) { // TODO: Use |operations|. to determine a minimum COW size. // kCowEstimateFactor is good for prototyping but we can't use that in production. static constexpr double kCowEstimateFactor = 1.05; auto cow_size = RoundUp(snapshot_size * kCowEstimateFactor, kDefaultBlockSize); return cow_size; } std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { CHECK(current_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME && target_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME); Loading @@ -135,13 +144,8 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { ret.snapshot_status.snapshot_size = *snapshot_size; // TODO: always read from cow_size when the COW size is written in // update package. kCowEstimateFactor is good for prototyping but // we can't use that in production. if (!cow_size.has_value()) { cow_size = RoundUp(ret.snapshot_status.snapshot_size * kCowEstimateFactor, kDefaultBlockSize); } auto cow_size = GetCowSize(*snapshot_size); if (!cow_size.has_value()) return std::nullopt; // Compute regions that are free in both current and target metadata. These are the regions // we can use for COW partition. Loading
fs_mgr/libsnapshot/partition_cow_creator.h +9 −5 Original line number Diff line number Diff line Loading @@ -32,20 +32,23 @@ struct PartitionCowCreator { using Interval = android::fs_mgr::Interval; using MetadataBuilder = android::fs_mgr::MetadataBuilder; using Partition = android::fs_mgr::Partition; using InstallOperation = chromeos_update_engine::InstallOperation; template <typename T> using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>; // The metadata that will be written to target metadata slot. MetadataBuilder* target_metadata; MetadataBuilder* target_metadata = nullptr; // The suffix of the target slot. std::string target_suffix; // The partition in target_metadata that needs to be snapshotted. Partition* target_partition; Partition* target_partition = nullptr; // The metadata at the current slot (that would be used if the device boots // normally). This is used to determine which extents are being used. MetadataBuilder* current_metadata; MetadataBuilder* current_metadata = nullptr; // The suffix of the current slot. std::string current_suffix; // The COW size given by client code. std::optional<uint64_t> cow_size; // List of operations to be applied on the partition. const RepeatedPtrField<InstallOperation>* operations = nullptr; struct Return { SnapshotManager::SnapshotStatus snapshot_status; Loading @@ -57,6 +60,7 @@ struct PartitionCowCreator { private: bool HasExtent(Partition* p, Extent* e); std::optional<uint64_t> GetSnapshotSize(); std::optional<uint64_t> GetCowSize(uint64_t snapshot_size); }; } // namespace snapshot Loading
fs_mgr/libsnapshot/partition_cow_creator_test.cpp +1 −4 Original line number Diff line number Diff line Loading @@ -76,14 +76,11 @@ TEST(PartitionCowCreator, IntersectSelf) { .target_suffix = "_b", .target_partition = system_b, .current_metadata = builder_a.get(), .current_suffix = "_a", .cow_size = 20 * 1024}; .current_suffix = "_a"}; auto ret = creator.Run(); ASSERT_TRUE(ret.has_value()); ASSERT_EQ(40 * 1024, ret->snapshot_status.device_size); ASSERT_EQ(40 * 1024, ret->snapshot_status.snapshot_size); ASSERT_EQ(20 * 1024, ret->snapshot_status.cow_file_size + ret->snapshot_status.cow_partition_size); } } // namespace snapshot Loading