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