Loading fs_mgr/libsnapshot/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ cc_test { "libcutils", "libcrypto", "libfs_mgr", "libgmock", "liblp", "libsnapshot", ], Loading fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +1 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,7 @@ class SnapshotManager final { FRIEND_TEST(SnapshotTest, CreateSnapshot); FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback); FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge); FRIEND_TEST(SnapshotTest, FlashSuperDuringUpdate); FRIEND_TEST(SnapshotTest, MapPartialSnapshot); FRIEND_TEST(SnapshotTest, MapSnapshot); FRIEND_TEST(SnapshotTest, Merge); Loading fs_mgr/libsnapshot/snapshot.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -1041,6 +1041,12 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe continue; } if (!(partition.attributes & LP_PARTITION_ATTR_UPDATED)) { LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: " << partition_name; live_snapshots.erase(partition_name); } CreateLogicalPartitionParams params = { .block_device = super_device, .metadata = metadata.get(), Loading fs_mgr/libsnapshot/snapshot_test.cpp +86 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <libdm/dm.h> #include <libfiemap/image_manager.h> #include <liblp/builder.h> #include <liblp/mock_property_fetcher.h> #include "test_helpers.h" Loading @@ -43,7 +44,10 @@ using android::dm::DmDeviceState; using android::fiemap::IImageManager; using android::fs_mgr::BlockDeviceInfo; using android::fs_mgr::CreateLogicalPartitionParams; using android::fs_mgr::DestroyLogicalPartition; using android::fs_mgr::MetadataBuilder; using namespace ::testing; using namespace android::fs_mgr::testing; using namespace std::chrono_literals; using namespace std::string_literals; Loading @@ -67,6 +71,7 @@ class SnapshotTest : public ::testing::Test { protected: void SetUp() override { ResetMockPropertyFetcher(); InitializeState(); CleanupTestArtifacts(); FormatFakeSuper(); Loading @@ -78,6 +83,7 @@ class SnapshotTest : public ::testing::Test { lock_ = nullptr; CleanupTestArtifacts(); ResetMockPropertyFetcher(); } void InitializeState() { Loading @@ -95,7 +101,8 @@ class SnapshotTest : public ::testing::Test { // get an accurate list to remove. lock_ = nullptr; std::vector<std::string> snapshots = {"test-snapshot", "test_partition_b"}; std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a", "test_partition_b"}; for (const auto& snapshot : snapshots) { DeleteSnapshotDevice(snapshot); DeleteBackingImage(image_manager_, snapshot + "-cow"); Loading Loading @@ -154,11 +161,10 @@ class SnapshotTest : public ::testing::Test { return false; } // Update both slots for convenience. // Update the source slot. auto metadata = builder->Export(); if (!metadata) return false; if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0) || !UpdatePartitionTable(opener, "super", *metadata.get(), 1)) { if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) { return false; } Loading @@ -174,6 +180,35 @@ class SnapshotTest : public ::testing::Test { return CreateLogicalPartition(params, path); } bool MapUpdatePartitions() { TestPartitionOpener opener(fake_super); auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1); if (!builder) return false; auto metadata = builder->Export(); if (!metadata) return false; // Update the destination slot, mark it as updated. if (!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) { return false; } for (const auto& partition : metadata->partitions) { CreateLogicalPartitionParams params = { .block_device = fake_super, .metadata = metadata.get(), .partition = &partition, .force_writable = true, .timeout_ms = 10s, }; std::string ignore_path; if (!CreateLogicalPartition(params, &ignore_path)) { return false; } } return true; } void DeleteSnapshotDevice(const std::string& snapshot) { DeleteDevice(snapshot); DeleteDevice(snapshot + "-inner"); Loading Loading @@ -370,17 +405,22 @@ TEST_F(SnapshotTest, MergeCannotRemoveCow) { } TEST_F(SnapshotTest, FirstStageMountAndMerge) { ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _)) .WillByDefault(Return(true)); ASSERT_TRUE(AcquireLock()); static const uint64_t kDeviceSize = 1024 * 1024; ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize)); ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize)); ASSERT_TRUE(MapUpdatePartitions()); ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize, kDeviceSize)); // Simulate a reboot into the new slot. lock_ = nullptr; ASSERT_TRUE(sm->FinishedSnapshotWrites()); ASSERT_TRUE(DestroyLogicalPartition("test_partition_b")); auto rebooted = new TestDeviceInfo(fake_super); rebooted->set_slot_suffix("_b"); Loading @@ -403,6 +443,47 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) { ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot"); } TEST_F(SnapshotTest, FlashSuperDuringUpdate) { ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _)) .WillByDefault(Return(true)); ASSERT_TRUE(AcquireLock()); static const uint64_t kDeviceSize = 1024 * 1024; ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize)); ASSERT_TRUE(MapUpdatePartitions()); ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize, kDeviceSize)); // Simulate a reboot into the new slot. lock_ = nullptr; ASSERT_TRUE(sm->FinishedSnapshotWrites()); ASSERT_TRUE(DestroyLogicalPartition("test_partition_b")); // Reflash the super partition. FormatFakeSuper(); ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize)); auto rebooted = new TestDeviceInfo(fake_super); rebooted->set_slot_suffix("_b"); auto init = SnapshotManager::NewForFirstStageMount(rebooted); ASSERT_NE(init, nullptr); ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount()); ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super")); ASSERT_TRUE(AcquireLock()); SnapshotManager::SnapshotStatus status; ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status)); // We should not get a snapshot device now. DeviceMapper::TargetInfo target; auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status); ASSERT_FALSE(init->IsSnapshotDevice(dm_name, &target)); } } // namespace snapshot } // namespace android Loading Loading
fs_mgr/libsnapshot/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ cc_test { "libcutils", "libcrypto", "libfs_mgr", "libgmock", "liblp", "libsnapshot", ], Loading
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +1 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,7 @@ class SnapshotManager final { FRIEND_TEST(SnapshotTest, CreateSnapshot); FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback); FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge); FRIEND_TEST(SnapshotTest, FlashSuperDuringUpdate); FRIEND_TEST(SnapshotTest, MapPartialSnapshot); FRIEND_TEST(SnapshotTest, MapSnapshot); FRIEND_TEST(SnapshotTest, Merge); Loading
fs_mgr/libsnapshot/snapshot.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -1041,6 +1041,12 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe continue; } if (!(partition.attributes & LP_PARTITION_ATTR_UPDATED)) { LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: " << partition_name; live_snapshots.erase(partition_name); } CreateLogicalPartitionParams params = { .block_device = super_device, .metadata = metadata.get(), Loading
fs_mgr/libsnapshot/snapshot_test.cpp +86 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <libdm/dm.h> #include <libfiemap/image_manager.h> #include <liblp/builder.h> #include <liblp/mock_property_fetcher.h> #include "test_helpers.h" Loading @@ -43,7 +44,10 @@ using android::dm::DmDeviceState; using android::fiemap::IImageManager; using android::fs_mgr::BlockDeviceInfo; using android::fs_mgr::CreateLogicalPartitionParams; using android::fs_mgr::DestroyLogicalPartition; using android::fs_mgr::MetadataBuilder; using namespace ::testing; using namespace android::fs_mgr::testing; using namespace std::chrono_literals; using namespace std::string_literals; Loading @@ -67,6 +71,7 @@ class SnapshotTest : public ::testing::Test { protected: void SetUp() override { ResetMockPropertyFetcher(); InitializeState(); CleanupTestArtifacts(); FormatFakeSuper(); Loading @@ -78,6 +83,7 @@ class SnapshotTest : public ::testing::Test { lock_ = nullptr; CleanupTestArtifacts(); ResetMockPropertyFetcher(); } void InitializeState() { Loading @@ -95,7 +101,8 @@ class SnapshotTest : public ::testing::Test { // get an accurate list to remove. lock_ = nullptr; std::vector<std::string> snapshots = {"test-snapshot", "test_partition_b"}; std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a", "test_partition_b"}; for (const auto& snapshot : snapshots) { DeleteSnapshotDevice(snapshot); DeleteBackingImage(image_manager_, snapshot + "-cow"); Loading Loading @@ -154,11 +161,10 @@ class SnapshotTest : public ::testing::Test { return false; } // Update both slots for convenience. // Update the source slot. auto metadata = builder->Export(); if (!metadata) return false; if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0) || !UpdatePartitionTable(opener, "super", *metadata.get(), 1)) { if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) { return false; } Loading @@ -174,6 +180,35 @@ class SnapshotTest : public ::testing::Test { return CreateLogicalPartition(params, path); } bool MapUpdatePartitions() { TestPartitionOpener opener(fake_super); auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1); if (!builder) return false; auto metadata = builder->Export(); if (!metadata) return false; // Update the destination slot, mark it as updated. if (!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) { return false; } for (const auto& partition : metadata->partitions) { CreateLogicalPartitionParams params = { .block_device = fake_super, .metadata = metadata.get(), .partition = &partition, .force_writable = true, .timeout_ms = 10s, }; std::string ignore_path; if (!CreateLogicalPartition(params, &ignore_path)) { return false; } } return true; } void DeleteSnapshotDevice(const std::string& snapshot) { DeleteDevice(snapshot); DeleteDevice(snapshot + "-inner"); Loading Loading @@ -370,17 +405,22 @@ TEST_F(SnapshotTest, MergeCannotRemoveCow) { } TEST_F(SnapshotTest, FirstStageMountAndMerge) { ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _)) .WillByDefault(Return(true)); ASSERT_TRUE(AcquireLock()); static const uint64_t kDeviceSize = 1024 * 1024; ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize)); ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize)); ASSERT_TRUE(MapUpdatePartitions()); ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize, kDeviceSize)); // Simulate a reboot into the new slot. lock_ = nullptr; ASSERT_TRUE(sm->FinishedSnapshotWrites()); ASSERT_TRUE(DestroyLogicalPartition("test_partition_b")); auto rebooted = new TestDeviceInfo(fake_super); rebooted->set_slot_suffix("_b"); Loading @@ -403,6 +443,47 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) { ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot"); } TEST_F(SnapshotTest, FlashSuperDuringUpdate) { ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _)) .WillByDefault(Return(true)); ASSERT_TRUE(AcquireLock()); static const uint64_t kDeviceSize = 1024 * 1024; ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize)); ASSERT_TRUE(MapUpdatePartitions()); ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize, kDeviceSize)); // Simulate a reboot into the new slot. lock_ = nullptr; ASSERT_TRUE(sm->FinishedSnapshotWrites()); ASSERT_TRUE(DestroyLogicalPartition("test_partition_b")); // Reflash the super partition. FormatFakeSuper(); ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize)); auto rebooted = new TestDeviceInfo(fake_super); rebooted->set_slot_suffix("_b"); auto init = SnapshotManager::NewForFirstStageMount(rebooted); ASSERT_NE(init, nullptr); ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount()); ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super")); ASSERT_TRUE(AcquireLock()); SnapshotManager::SnapshotStatus status; ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status)); // We should not get a snapshot device now. DeviceMapper::TargetInfo target; auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status); ASSERT_FALSE(init->IsSnapshotDevice(dm_name, &target)); } } // namespace snapshot } // namespace android Loading