libsnapshot: Do not map snapshots for partitions that were reflashed.
Bug: 139154795
Test: libsnapshot_test gtests
Change-Id: Ic4bb663d4286040adec4c0141373c66a487c91ff
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index b320db8..a54db58 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -86,6 +86,7 @@
"libcutils",
"libcrypto",
"libfs_mgr",
+ "libgmock",
"liblp",
"libsnapshot",
],
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 0c0355d..b982b4b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -158,6 +158,7 @@
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);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 87170a7..ab1157b 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1041,6 +1041,12 @@
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(),
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f4eb1ac..acffe8c 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -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"
@@ -43,7 +44,10 @@
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;
@@ -67,6 +71,7 @@
protected:
void SetUp() override {
+ ResetMockPropertyFetcher();
InitializeState();
CleanupTestArtifacts();
FormatFakeSuper();
@@ -78,6 +83,7 @@
lock_ = nullptr;
CleanupTestArtifacts();
+ ResetMockPropertyFetcher();
}
void InitializeState() {
@@ -95,7 +101,8 @@
// 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");
@@ -154,11 +161,10 @@
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;
}
@@ -174,6 +180,35 @@
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");
@@ -370,17 +405,22 @@
}
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");
@@ -403,6 +443,47 @@
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