Merge "RefBase: test for stack check"
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 762aebb..f850b94 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -17,6 +17,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <unordered_map>
 #include <unordered_set>
 
 #include <android-base/file.h>
@@ -165,27 +166,25 @@
     android::dm::IDeviceMapper& impl_;
 };
 
-class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
+class SnapshotTestPropertyFetcher : public android::fs_mgr::IPropertyFetcher {
   public:
-    SnapshotTestPropertyFetcher(const std::string& slot_suffix) {
-        using testing::Return;
-        ON_CALL(*this, GetProperty("ro.boot.slot_suffix", _)).WillByDefault(Return(slot_suffix));
-        ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions", _))
-                .WillByDefault(Return(true));
-        ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
-                .WillByDefault(Return(false));
-        ON_CALL(*this, GetBoolProperty("ro.virtual_ab.enabled", _)).WillByDefault(Return(true));
-    }
+    explicit SnapshotTestPropertyFetcher(const std::string& slot_suffix,
+                                         std::unordered_map<std::string, std::string>&& props = {});
+
+    std::string GetProperty(const std::string& key, const std::string& defaultValue) override;
+    bool GetBoolProperty(const std::string& key, bool defaultValue) override;
 
     static void SetUp(const std::string& slot_suffix = "_a") { Reset(slot_suffix); }
-
     static void TearDown() { Reset("_a"); }
 
   private:
     static void Reset(const std::string& slot_suffix) {
         IPropertyFetcher::OverrideForTesting(
-                std::make_unique<NiceMock<SnapshotTestPropertyFetcher>>(slot_suffix));
+                std::make_unique<SnapshotTestPropertyFetcher>(slot_suffix));
     }
+
+  private:
+    std::unordered_map<std::string, std::string> properties_;
 };
 
 // Helper for error-spam-free cleanup.
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index d242e60..91f31b0 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -53,9 +53,11 @@
 #include <libsnapshot/mock_device_info.h>
 #include <libsnapshot/mock_snapshot.h>
 
-DEFINE_string(force_config, "", "Force testing mode (dmsnap, vab, vabc) ignoring device config.");
+DEFINE_string(force_mode, "",
+              "Force testing older modes (vab-legacy, vabc-legacy) ignoring device config.");
 DEFINE_string(force_iouring_disable, "",
               "Force testing mode (iouring_disabled) - disable io_uring");
+DEFINE_string(compression_method, "gz", "Default compression algorithm.");
 
 namespace android {
 namespace snapshot {
@@ -90,7 +92,6 @@
 std::unique_ptr<SnapshotManager> sm;
 TestDeviceInfo* test_device = nullptr;
 std::string fake_super;
-bool gIsSnapuserdRequired;
 
 void MountMetadata();
 
@@ -108,7 +109,7 @@
     void SetUp() override {
         SKIP_IF_NON_VIRTUAL_AB();
 
-        SnapshotTestPropertyFetcher::SetUp();
+        SetupProperties();
         InitializeState();
         CleanupTestArtifacts();
         FormatFakeSuper();
@@ -116,6 +117,38 @@
         ASSERT_TRUE(sm->BeginUpdate());
     }
 
+    void SetupProperties() {
+        std::unordered_map<std::string, std::string> properties;
+
+        ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "0"))
+                << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
+        ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0"))
+                << "Failed to set property: snapuserd.test.io_uring.disabled";
+
+        if (FLAGS_force_mode == "vabc-legacy") {
+            ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "1"))
+                    << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
+            properties["ro.virtual_ab.compression.enabled"] = "true";
+            properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
+        } else if (FLAGS_force_mode == "vab-legacy") {
+            properties["ro.virtual_ab.compression.enabled"] = "false";
+            properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
+        }
+
+        if (FLAGS_force_iouring_disable == "iouring_disabled") {
+            ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1"))
+                    << "Failed to set property: snapuserd.test.io_uring.disabled";
+            properties["ro.virtual_ab.io_uring.enabled"] = "false";
+        }
+
+        auto fetcher = std::make_unique<SnapshotTestPropertyFetcher>("_a", std::move(properties));
+        IPropertyFetcher::OverrideForTesting(std::move(fetcher));
+
+        if (GetLegacyCompressionEnabledProperty() || CanUseUserspaceSnapshots()) {
+            snapuserd_required_ = true;
+        }
+    }
+
     void TearDown() override {
         RETURN_IF_NON_VIRTUAL_AB();
 
@@ -358,8 +391,11 @@
         DeltaArchiveManifest manifest;
 
         auto dynamic_partition_metadata = manifest.mutable_dynamic_partition_metadata();
-        dynamic_partition_metadata->set_vabc_enabled(gIsSnapuserdRequired);
+        dynamic_partition_metadata->set_vabc_enabled(snapuserd_required_);
         dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
+        if (snapuserd_required_) {
+            dynamic_partition_metadata->set_vabc_compression_param(FLAGS_compression_method);
+        }
 
         auto group = dynamic_partition_metadata->add_groups();
         group->set_name("group");
@@ -397,7 +433,7 @@
             if (!res) {
                 return res;
             }
-        } else if (!gIsSnapuserdRequired) {
+        } else if (!snapuserd_required_) {
             std::string ignore;
             if (!MapUpdateSnapshot("test_partition_b", &ignore)) {
                 return AssertionFailure() << "Failed to map test_partition_b";
@@ -450,15 +486,16 @@
     std::unique_ptr<SnapshotManager::LockedFile> lock_;
     android::fiemap::IImageManager* image_manager_ = nullptr;
     std::string fake_super_;
+    bool snapuserd_required_ = false;
 };
 
 TEST_F(SnapshotTest, CreateSnapshot) {
     ASSERT_TRUE(AcquireLock());
 
     PartitionCowCreator cow_creator;
-    cow_creator.using_snapuserd = gIsSnapuserdRequired;
+    cow_creator.using_snapuserd = snapuserd_required_;
     if (cow_creator.using_snapuserd) {
-        cow_creator.compression_algorithm = "gz";
+        cow_creator.compression_algorithm = FLAGS_compression_method;
     } else {
         cow_creator.compression_algorithm = "none";
     }
@@ -497,7 +534,7 @@
     ASSERT_TRUE(AcquireLock());
 
     PartitionCowCreator cow_creator;
-    cow_creator.using_snapuserd = gIsSnapuserdRequired;
+    cow_creator.using_snapuserd = snapuserd_required_;
 
     static const uint64_t kDeviceSize = 1024 * 1024;
     SnapshotStatus status;
@@ -624,10 +661,10 @@
     SnapshotStatus status;
     ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
     ASSERT_EQ(status.state(), SnapshotState::CREATED);
-    if (gIsSnapuserdRequired) {
-        ASSERT_EQ(status.compression_algorithm(), "gz");
+    if (snapuserd_required_) {
+        ASSERT_EQ(status.compression_algorithm(), FLAGS_compression_method);
     } else {
-        ASSERT_EQ(status.compression_algorithm(), "none");
+        ASSERT_EQ(status.compression_algorithm(), "");
     }
 
     DeviceMapper::TargetInfo target;
@@ -898,8 +935,11 @@
         opener_ = std::make_unique<TestPartitionOpener>(fake_super);
 
         auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata();
-        dynamic_partition_metadata->set_vabc_enabled(gIsSnapuserdRequired);
+        dynamic_partition_metadata->set_vabc_enabled(snapuserd_required_);
         dynamic_partition_metadata->set_cow_version(android::snapshot::kCowVersionMajor);
+        if (snapuserd_required_) {
+            dynamic_partition_metadata->set_vabc_compression_param(FLAGS_compression_method);
+        }
 
         // Create a fake update package metadata.
         // Not using full name "system", "vendor", "product" because these names collide with the
@@ -1031,7 +1071,7 @@
     }
 
     AssertionResult MapOneUpdateSnapshot(const std::string& name) {
-        if (gIsSnapuserdRequired) {
+        if (snapuserd_required_) {
             std::unique_ptr<ISnapshotWriter> writer;
             return MapUpdateSnapshot(name, &writer);
         } else {
@@ -1052,7 +1092,7 @@
 
     AssertionResult WriteSnapshotAndHash(PartitionUpdate* partition) {
         std::string name = partition->partition_name() + "_b";
-        if (gIsSnapuserdRequired) {
+        if (snapuserd_required_) {
             std::unique_ptr<ISnapshotWriter> writer;
             auto res = MapUpdateSnapshot(name, &writer);
             if (!res) {
@@ -1254,7 +1294,7 @@
 
     // Initiate the merge and wait for it to be completed.
     ASSERT_TRUE(init->InitiateMerge());
-    ASSERT_EQ(init->IsSnapuserdRequired(), gIsSnapuserdRequired);
+    ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
     {
         // We should have started in SECOND_PHASE since nothing shrinks.
         ASSERT_TRUE(AcquireLock());
@@ -1281,7 +1321,7 @@
 }
 
 TEST_F(SnapshotUpdateTest, DuplicateOps) {
-    if (!gIsSnapuserdRequired) {
+    if (!snapuserd_required_) {
         GTEST_SKIP() << "snapuserd-only test";
     }
 
@@ -1323,7 +1363,7 @@
 // Test that shrinking and growing partitions at the same time is handled
 // correctly in VABC.
 TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) {
-    if (!gIsSnapuserdRequired) {
+    if (!snapuserd_required_) {
         // b/179111359
         GTEST_SKIP() << "Skipping snapuserd test";
     }
@@ -1386,7 +1426,7 @@
 
     // Initiate the merge and wait for it to be completed.
     ASSERT_TRUE(init->InitiateMerge());
-    ASSERT_EQ(init->IsSnapuserdRequired(), gIsSnapuserdRequired);
+    ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
     {
         // Check that the merge phase is FIRST_PHASE until at least one call
         // to ProcessUpdateState() occurs.
@@ -1440,7 +1480,7 @@
 
 // Test that a transient merge consistency check failure can resume properly.
 TEST_F(SnapshotUpdateTest, ConsistencyCheckResume) {
-    if (!gIsSnapuserdRequired) {
+    if (!snapuserd_required_) {
         // b/179111359
         GTEST_SKIP() << "Skipping snapuserd test";
     }
@@ -1494,7 +1534,7 @@
 
     // Initiate the merge and wait for it to be completed.
     ASSERT_TRUE(init->InitiateMerge());
-    ASSERT_EQ(init->IsSnapuserdRequired(), gIsSnapuserdRequired);
+    ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
     {
         // Check that the merge phase is FIRST_PHASE until at least one call
         // to ProcessUpdateState() occurs.
@@ -2098,8 +2138,8 @@
         ASSERT_TRUE(AcquireLock());
 
         PartitionCowCreator cow_creator = {
-                .using_snapuserd = gIsSnapuserdRequired,
-                .compression_algorithm = gIsSnapuserdRequired ? "gz" : "",
+                .using_snapuserd = snapuserd_required_,
+                .compression_algorithm = snapuserd_required_ ? FLAGS_compression_method : "",
         };
         SnapshotStatus status;
         status.set_name("sys_a");
@@ -2195,7 +2235,7 @@
 
 // Test for overflow bit after update
 TEST_F(SnapshotUpdateTest, Overflow) {
-    if (gIsSnapuserdRequired) {
+    if (snapuserd_required_) {
         GTEST_SKIP() << "No overflow bit set for snapuserd COWs";
     }
 
@@ -2330,7 +2370,7 @@
 };
 
 TEST_F(SnapshotUpdateTest, DaemonTransition) {
-    if (!gIsSnapuserdRequired) {
+    if (!snapuserd_required_) {
         GTEST_SKIP() << "Skipping snapuserd test";
     }
 
@@ -2761,21 +2801,17 @@
     }
 }
 
-void SetGlobalConfigOptions() {
-    if (FLAGS_force_config == "dmsnap") {
-        ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "1"))
-                << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
+void KillSnapuserd() {
+    auto status = android::base::GetProperty("init.svc.snapuserd", "stopped");
+    if (status == "stopped") {
+        return;
     }
-
-    if (FLAGS_force_iouring_disable == "iouring_disabled") {
-        ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "1"))
-                << "Failed to disable property: snapuserd.test.io_uring.disabled";
+    auto snapuserd_client = SnapuserdClient::Connect(kSnapuserdSocket, 5s);
+    if (!snapuserd_client) {
+        return;
     }
-
-    if (FLAGS_force_config != "dmsnap" &&
-        (GetLegacyCompressionEnabledProperty() || CanUseUserspaceSnapshots())) {
-        gIsSnapuserdRequired = true;
-    }
+    snapuserd_client->DetachSnapuserd();
+    snapuserd_client->CloseConnection();
 }
 
 }  // namespace snapshot
@@ -2788,23 +2824,20 @@
 
     android::base::SetProperty("ctl.stop", "snapuserd");
 
-    std::unordered_set<std::string> configs = {"", "dmsnap", "vab", "vabc"};
-    if (configs.count(FLAGS_force_config) == 0) {
+    std::unordered_set<std::string> modes = {"", "vab-legacy", "vabc-legacy"};
+    if (modes.count(FLAGS_force_mode) == 0) {
         std::cerr << "Unexpected force_config argument\n";
         return 1;
     }
 
-    android::snapshot::SetGlobalConfigOptions();
+    // This is necessary if the configuration we're testing doesn't match the device.
+    android::snapshot::KillSnapuserd();
 
     int ret = RUN_ALL_TESTS();
 
-    if (FLAGS_force_config == "dmsnap") {
-        android::base::SetProperty("snapuserd.test.dm.snapshots", "0");
-    }
+    android::base::SetProperty("snapuserd.test.dm.snapshots", "0");
+    android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
 
-    if (FLAGS_force_iouring_disable == "iouring_disabled") {
-        android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
-    }
-
+    android::snapshot::KillSnapuserd();
     return ret;
 }
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index 3e889a0..b05123a 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -18,10 +18,12 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parsebool.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
+#include <liblp/property_fetcher.h>
 #include <openssl/sha.h>
 #include <payload_consumer/file_descriptor.h>
 
@@ -278,5 +280,38 @@
     return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
 }
 
+SnapshotTestPropertyFetcher::SnapshotTestPropertyFetcher(
+        const std::string& slot_suffix, std::unordered_map<std::string, std::string>&& props)
+    : properties_(std::move(props)) {
+    properties_["ro.boot.slot_suffix"] = slot_suffix;
+    properties_["ro.boot.dynamic_partitions"] = "true";
+    properties_["ro.boot.dynamic_partitions_retrofit"] = "false";
+    properties_["ro.virtual_ab.enabled"] = "true";
+}
+
+std::string SnapshotTestPropertyFetcher::GetProperty(const std::string& key,
+                                                     const std::string& defaultValue) {
+    auto iter = properties_.find(key);
+    if (iter == properties_.end()) {
+        return android::base::GetProperty(key, defaultValue);
+    }
+    return iter->second;
+}
+
+bool SnapshotTestPropertyFetcher::GetBoolProperty(const std::string& key, bool defaultValue) {
+    auto iter = properties_.find(key);
+    if (iter == properties_.end()) {
+        return android::base::GetBoolProperty(key, defaultValue);
+    }
+    switch (android::base::ParseBool(iter->second)) {
+        case android::base::ParseBoolResult::kTrue:
+            return true;
+        case android::base::ParseBoolResult::kFalse:
+            return false;
+        default:
+            return defaultValue;
+    }
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 08207be..0a1be0d 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -26,6 +26,7 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <fs_mgr/roots.h>
+#include <liblp/property_fetcher.h>
 
 using android::dm::kSectorSize;
 using android::fiemap::FiemapStatus;
@@ -33,6 +34,7 @@
 using android::fs_mgr::EnsurePathUnmounted;
 using android::fs_mgr::Fstab;
 using android::fs_mgr::GetEntryForPath;
+using android::fs_mgr::IPropertyFetcher;
 using android::fs_mgr::MetadataBuilder;
 using android::fs_mgr::Partition;
 using android::fs_mgr::ReadDefaultFstab;
@@ -185,11 +187,13 @@
 }
 
 bool GetLegacyCompressionEnabledProperty() {
-    return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
+    auto fetcher = IPropertyFetcher::GetInstance();
+    return fetcher->GetBoolProperty("ro.virtual_ab.compression.enabled", false);
 }
 
 bool GetUserspaceSnapshotsEnabledProperty() {
-    return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
+    auto fetcher = IPropertyFetcher::GetInstance();
+    return fetcher->GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
 }
 
 bool CanUseUserspaceSnapshots() {
@@ -197,9 +201,11 @@
         return false;
     }
 
+    auto fetcher = IPropertyFetcher::GetInstance();
+
     const std::string UNKNOWN = "unknown";
     const std::string vendor_release =
-            android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
+            fetcher->GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
 
     // No user-space snapshots if vendor partition is on Android 12
     if (vendor_release.find("12") != std::string::npos) {
@@ -217,11 +223,13 @@
 }
 
 bool GetIouringEnabledProperty() {
-    return android::base::GetBoolProperty("ro.virtual_ab.io_uring.enabled", false);
+    auto fetcher = IPropertyFetcher::GetInstance();
+    return fetcher->GetBoolProperty("ro.virtual_ab.io_uring.enabled", false);
 }
 
 bool GetXorCompressionEnabledProperty() {
-    return android::base::GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false);
+    auto fetcher = IPropertyFetcher::GetInstance();
+    return fetcher->GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false);
 }
 
 std::string GetOtherPartitionName(const std::string& name) {
@@ -233,7 +241,8 @@
 }
 
 bool IsDmSnapshotTestingEnabled() {
-    return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false);
+    auto fetcher = IPropertyFetcher::GetInstance();
+    return fetcher->GetBoolProperty("snapuserd.test.dm.snapshots", false);
 }
 
 }  // namespace snapshot
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 3a11547..ed5b2a9 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -797,6 +797,8 @@
 
 void RefBase::extendObjectLifetime(int32_t mode)
 {
+    check_not_on_stack(this);
+
     // Must be happens-before ordered with respect to construction or any
     // operation that could destroy the object.
     mRefs->mFlags.fetch_or(mode, std::memory_order_relaxed);