Merge changes Ibffdd9c9,Ief5a16d1

* changes:
  libsnapshot: Add a test case for unexpected snapshots during data resets.
  libfiemap: Add some dependency injection.
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index c8516ab..31a57a8 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -224,8 +224,9 @@
     return false;
 }
 
-std::unique_ptr<IImageManager> IImageManager::Open(
-        const std::string& dir, const std::chrono::milliseconds& /*timeout_ms*/) {
+std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir,
+                                                   const std::chrono::milliseconds& /*timeout_ms*/,
+                                                   const DeviceInfo&) {
     android::sp<IGsiService> service = android::gsi::GetGsiService();
     android::sp<IImageService> manager;
 
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 44f659b..dcbbc54 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -55,7 +55,8 @@
 static constexpr char kTestImageMetadataDir[] = "/metadata/gsi/test";
 static constexpr char kOtaTestImageMetadataDir[] = "/metadata/gsi/ota/test";
 
-std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
+std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix,
+                                                 const DeviceInfo& device_info) {
     auto metadata_dir = "/metadata/gsi/" + dir_prefix;
     auto data_dir = "/data/gsi/" + dir_prefix;
     auto install_dir_file = gsi::DsuInstallDirFile(gsi::GetDsuSlot(dir_prefix));
@@ -63,17 +64,28 @@
     if (ReadFileToString(install_dir_file, &path)) {
         data_dir = path;
     }
-    return Open(metadata_dir, data_dir);
+    return Open(metadata_dir, data_dir, device_info);
 }
 
 std::unique_ptr<ImageManager> ImageManager::Open(const std::string& metadata_dir,
-                                                 const std::string& data_dir) {
-    return std::unique_ptr<ImageManager>(new ImageManager(metadata_dir, data_dir));
+                                                 const std::string& data_dir,
+                                                 const DeviceInfo& device_info) {
+    return std::unique_ptr<ImageManager>(new ImageManager(metadata_dir, data_dir, device_info));
 }
 
-ImageManager::ImageManager(const std::string& metadata_dir, const std::string& data_dir)
-    : metadata_dir_(metadata_dir), data_dir_(data_dir) {
+ImageManager::ImageManager(const std::string& metadata_dir, const std::string& data_dir,
+                           const DeviceInfo& device_info)
+    : metadata_dir_(metadata_dir), data_dir_(data_dir), device_info_(device_info) {
     partition_opener_ = std::make_unique<android::fs_mgr::PartitionOpener>();
+
+    // Allow overriding whether ImageManager thinks it's in recovery, for testing.
+#ifdef __ANDROID_RECOVERY__
+    device_info_.is_recovery = {true};
+#else
+    if (!device_info_.is_recovery.has_value()) {
+        device_info_.is_recovery = {false};
+    }
+#endif
 }
 
 std::string ImageManager::GetImageHeaderPath(const std::string& name) {
@@ -261,10 +273,11 @@
         return false;
     }
 
-#if defined __ANDROID_RECOVERY__
-    LOG(ERROR) << "Cannot remove images backed by /data in recovery";
-    return false;
-#else
+    if (device_info_.is_recovery.value()) {
+        LOG(ERROR) << "Cannot remove images backed by /data in recovery";
+        return false;
+    }
+
     std::string message;
     auto header_file = GetImageHeaderPath(name);
     if (!SplitFiemap::RemoveSplitFiles(header_file, &message)) {
@@ -278,7 +291,6 @@
         LOG(ERROR) << "Error removing " << status_file << ": " << message;
     }
     return RemoveImageMetadata(metadata_dir_, name);
-#endif
 }
 
 // Create a block device for an image file, using its extents in its
@@ -521,6 +533,9 @@
     // filesystem. This should only happen on devices with no encryption, or
     // devices with FBE and no metadata encryption. For these cases it suffices
     // to perform normal file writes to /data/gsi (which is unencrypted).
+    //
+    // Note: this is not gated on DeviceInfo, because the recovery-specific path
+    // must only be used in actual recovery.
     std::string block_device;
     bool can_use_devicemapper;
     if (!FiemapWriter::GetBlockDeviceForFile(image_header, &block_device, &can_use_devicemapper)) {
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index 7e30509..3c87000 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -21,6 +21,7 @@
 #include <chrono>
 #include <functional>
 #include <memory>
+#include <optional>
 #include <set>
 #include <string>
 
@@ -37,11 +38,17 @@
 
     virtual ~IImageManager() {}
 
+    // Helper for dependency injection.
+    struct DeviceInfo {
+        std::optional<bool> is_recovery;
+    };
+
     // When linking to libfiemap_binder, the Open() call will use binder.
     // Otherwise, the Open() call will use the ImageManager implementation
-    // below.
+    // below. In binder mode, device_info is ignored.
     static std::unique_ptr<IImageManager> Open(const std::string& dir_prefix,
-                                               const std::chrono::milliseconds& timeout_ms);
+                                               const std::chrono::milliseconds& timeout_ms,
+                                               const DeviceInfo& device_info = {});
 
     // Flags for CreateBackingImage().
     static constexpr int CREATE_IMAGE_DEFAULT = 0x0;
@@ -131,11 +138,13 @@
     // Return an ImageManager for the given metadata and data directories. Both
     // directories must already exist.
     static std::unique_ptr<ImageManager> Open(const std::string& metadata_dir,
-                                              const std::string& data_dir);
+                                              const std::string& data_dir,
+                                              const DeviceInfo& device_info = {});
 
     // Helper function that derives the metadata and data dirs given a single
     // prefix.
-    static std::unique_ptr<ImageManager> Open(const std::string& dir_prefix);
+    static std::unique_ptr<ImageManager> Open(const std::string& dir_prefix,
+                                              const DeviceInfo& device_info = {});
 
     // Methods that must be implemented from IImageManager.
     FiemapStatus CreateBackingImage(const std::string& name, uint64_t size, int flags,
@@ -166,7 +175,8 @@
     FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes);
 
   private:
-    ImageManager(const std::string& metadata_dir, const std::string& data_dir);
+    ImageManager(const std::string& metadata_dir, const std::string& data_dir,
+                 const DeviceInfo& device_info);
     std::string GetImageHeaderPath(const std::string& name);
     std::string GetStatusFilePath(const std::string& image_name);
     bool MapWithLoopDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
@@ -187,6 +197,7 @@
     std::string metadata_dir_;
     std::string data_dir_;
     std::unique_ptr<IPartitionOpener> partition_opener_;
+    DeviceInfo device_info_;
 };
 
 // RAII helper class for mapping and opening devices with an ImageManager.
diff --git a/fs_mgr/libfiemap/passthrough.cpp b/fs_mgr/libfiemap/passthrough.cpp
index 1ccd9a0..d521804 100644
--- a/fs_mgr/libfiemap/passthrough.cpp
+++ b/fs_mgr/libfiemap/passthrough.cpp
@@ -20,9 +20,10 @@
 namespace fiemap {
 
 std::unique_ptr<IImageManager> IImageManager::Open(const std::string& dir_prefix,
-                                                   const std::chrono::milliseconds& timeout_ms) {
+                                                   const std::chrono::milliseconds& timeout_ms,
+                                                   const DeviceInfo& device_info) {
     (void)timeout_ms;
-    return ImageManager::Open(dir_prefix);
+    return ImageManager::Open(dir_prefix, device_info);
 }
 
 }  // namespace fiemap
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 195b6f2..d2fdfd6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -392,6 +392,7 @@
     FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
     FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
     FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
+    FRIEND_TEST(SnapshotUpdateTest, DataWipeWithStaleSnapshots);
     FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
     FRIEND_TEST(SnapshotUpdateTest, MergeCannotRemoveCow);
     FRIEND_TEST(SnapshotUpdateTest, MergeInRecovery);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 8f3926a..245742e 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2583,7 +2583,11 @@
 }
 
 bool SnapshotManager::ForceLocalImageManager() {
-    images_ = android::fiemap::ImageManager::Open(gsid_dir_);
+    android::fiemap::ImageManager::DeviceInfo device_info = {
+            .is_recovery = {device_->IsRecovery()},
+    };
+
+    images_ = android::fiemap::ImageManager::Open(gsid_dir_, device_info);
     if (!images_) {
         LOG(ERROR) << "Could not open ImageManager";
         return false;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index f18f176..9226b7f 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1860,6 +1860,67 @@
     }
 }
 
+// Test update package that requests data wipe.
+TEST_F(SnapshotUpdateTest, DataWipeWithStaleSnapshots) {
+    AddOperationForPartitions();
+
+    // Execute the update.
+    ASSERT_TRUE(sm->BeginUpdate());
+    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+    // Write some data to target partitions.
+    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+        ASSERT_TRUE(WriteSnapshotAndHash(name)) << name;
+    }
+
+    // Create a stale snapshot that should not exist.
+    {
+        ASSERT_TRUE(AcquireLock());
+
+        PartitionCowCreator cow_creator = {
+                .compression_enabled = IsCompressionEnabled(),
+                .compression_algorithm = IsCompressionEnabled() ? "gz" : "none",
+        };
+        SnapshotStatus status;
+        status.set_name("sys_a");
+        status.set_device_size(1_MiB);
+        status.set_snapshot_size(2_MiB);
+        status.set_cow_partition_size(2_MiB);
+
+        ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), &cow_creator, &status));
+        lock_ = nullptr;
+
+        ASSERT_TRUE(sm->EnsureImageManager());
+        ASSERT_TRUE(sm->image_manager()->CreateBackingImage("sys_a", 1_MiB, 0));
+    }
+
+    ASSERT_TRUE(sm->FinishedSnapshotWrites(true /* wipe */));
+
+    // Simulate shutting down the device.
+    ASSERT_TRUE(UnmapAll());
+
+    // Simulate a reboot into recovery.
+    auto test_device = new TestDeviceInfo(fake_super, "_b");
+    test_device->set_recovery(true);
+    auto new_sm = NewManagerForFirstStageMount(test_device);
+
+    ASSERT_TRUE(new_sm->HandleImminentDataWipe());
+    // Manually mount metadata so that we can call GetUpdateState() below.
+    MountMetadata();
+    EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
+    ASSERT_FALSE(test_device->IsSlotUnbootable(1));
+    ASSERT_FALSE(test_device->IsSlotUnbootable(0));
+
+    // Now reboot into new slot.
+    test_device = new TestDeviceInfo(fake_super, "_b");
+    auto init = NewManagerForFirstStageMount(test_device);
+    ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+    // Verify that we are on the downgraded build.
+    for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+        ASSERT_TRUE(IsPartitionUnchanged(name)) << name;
+    }
+}
+
 TEST_F(SnapshotUpdateTest, Hashtree) {
     constexpr auto partition_size = 4_MiB;
     constexpr auto data_size = 3_MiB;