Merge changes Ifddb5cb8,I8735ef6c,Ifd33c28e into main

* changes:
  snapuserd: Factor setpriority/settid calls into a helper.
  snapuserd: Add a harness to run tests without dm-user specific code.
  snapuserd: Add an IBlockServerFactory abstraction.
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 40dcc2a..6251e5a 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -72,6 +72,7 @@
         "user-space-merge/snapuserd_transitions.cpp",
         "user-space-merge/snapuserd_verify.cpp",
         "user-space-merge/worker.cpp",
+        "utility.cpp",
     ],
     static_libs: [
         "libbase",
@@ -219,6 +220,7 @@
         "libsnapshot_cow_defaults",
     ],
     srcs: [
+        "testing/dm_user_harness.cpp",
         "user-space-merge/snapuserd_test.cpp",
     ],
     shared_libs: [
diff --git a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
index b5fef47..e988335 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm_user_block_server.cpp
@@ -142,5 +142,11 @@
     return std::make_unique<DmUserBlockServer>(misc_name_, std::move(fd), delegate, buffer_size);
 }
 
+std::shared_ptr<IBlockServerOpener> DmUserBlockServerFactory::CreateOpener(
+        const std::string& misc_name) {
+    auto dm_path = "/dev/dm-user/" + misc_name;
+    return std::make_shared<DmUserBlockServerOpener>(misc_name, dm_path);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h
index 72b73fc..406bf11 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/block_server.h
@@ -83,5 +83,13 @@
                                                size_t buffer_size) = 0;
 };
 
+class IBlockServerFactory {
+  public:
+    virtual ~IBlockServerFactory() {}
+
+    // Return a new IBlockServerOpener given a unique device name.
+    virtual std::shared_ptr<IBlockServerOpener> CreateOpener(const std::string& misc_name) = 0;
+};
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
index 6aecf50..f1f8da1 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/dm_user_block_server.h
@@ -59,5 +59,10 @@
     std::string dm_user_path_;
 };
 
+class DmUserBlockServerFactory : public IBlockServerFactory {
+  public:
+    std::shared_ptr<IBlockServerOpener> CreateOpener(const std::string& misc_name) override;
+};
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp
new file mode 100644
index 0000000..7cadf25
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dm_user_harness.h"
+
+#include <fcntl.h>
+
+#include <android-base/file.h>
+#include <fs_mgr/file_wait.h>
+#include <libdm/dm.h>
+#include <snapuserd/dm_user_block_server.h>
+
+namespace android {
+namespace snapshot {
+
+using namespace std::chrono_literals;
+using android::base::unique_fd;
+
+DmUserDevice::DmUserDevice(std::unique_ptr<Tempdevice>&& dev) : dev_(std::move(dev)) {}
+
+const std::string& DmUserDevice::GetPath() {
+    return dev_->path();
+}
+
+bool DmUserDevice::Destroy() {
+    return dev_->Destroy();
+}
+
+DmUserTestHarness::DmUserTestHarness() {
+    block_server_factory_ = std::make_unique<DmUserBlockServerFactory>();
+}
+
+std::unique_ptr<IUserDevice> DmUserTestHarness::CreateUserDevice(const std::string& dev_name,
+                                                                 const std::string& misc_name,
+                                                                 uint64_t num_sectors) {
+    android::dm::DmTable dmuser_table;
+    dmuser_table.Emplace<android::dm::DmTargetUser>(0, num_sectors, misc_name);
+    auto dev = std::make_unique<Tempdevice>(dev_name, dmuser_table);
+    if (!dev->valid()) {
+        return nullptr;
+    }
+
+    auto misc_device = "/dev/dm-user/" + misc_name;
+    if (!android::fs_mgr::WaitForFile(misc_device, 10s)) {
+        return nullptr;
+    }
+
+    return std::make_unique<DmUserDevice>(std::move(dev));
+}
+
+IBlockServerFactory* DmUserTestHarness::GetBlockServerFactory() {
+    return block_server_factory_.get();
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h
new file mode 100644
index 0000000..cf26bed
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/testing/dm_user_harness.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include "harness.h"
+#include "temp_device.h"
+
+namespace android {
+namespace snapshot {
+
+using android::base::unique_fd;
+
+class DmUserBlockServerFactory;
+
+class DmUserDevice final : public IUserDevice {
+  public:
+    explicit DmUserDevice(std::unique_ptr<Tempdevice>&& dev);
+    const std::string& GetPath() override;
+    bool Destroy() override;
+
+  private:
+    std::unique_ptr<Tempdevice> dev_;
+};
+
+class DmUserTestHarness final : public ITestHarness {
+  public:
+    DmUserTestHarness();
+
+    std::unique_ptr<IUserDevice> CreateUserDevice(const std::string& dev_name,
+                                                  const std::string& misc_name,
+                                                  uint64_t num_sectors) override;
+    IBlockServerFactory* GetBlockServerFactory() override;
+    bool HasUserDevice() override { return true; }
+
+  private:
+    std::unique_ptr<DmUserBlockServerFactory> block_server_factory_;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/testing/harness.h b/fs_mgr/libsnapshot/snapuserd/testing/harness.h
new file mode 100644
index 0000000..c0d528f
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/testing/harness.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <memory>
+
+#include <android-base/unique_fd.h>
+#include <snapuserd/block_server.h>
+
+namespace android {
+namespace snapshot {
+
+// Interface for a "block driver in userspace" device.
+class IUserDevice {
+  public:
+    virtual ~IUserDevice() {}
+    virtual const std::string& GetPath() = 0;
+    virtual bool Destroy() = 0;
+};
+
+class ITestHarness {
+  public:
+    virtual ~ITestHarness() {}
+    virtual std::unique_ptr<IUserDevice> CreateUserDevice(const std::string& dev_name,
+                                                          const std::string& misc_name,
+                                                          uint64_t num_sectors) = 0;
+    virtual IBlockServerFactory* GetBlockServerFactory() = 0;
+    virtual bool HasUserDevice() = 0;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
index 041e516..fd41cd4 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
@@ -50,9 +50,10 @@
 std::shared_ptr<HandlerThread> SnapshotHandlerManager::AddHandler(
         const std::string& misc_name, const std::string& cow_device_path,
         const std::string& backing_device, const std::string& base_path_merge,
-        int num_worker_threads, bool use_iouring, bool perform_verification) {
+        std::shared_ptr<IBlockServerOpener> opener, int num_worker_threads, bool use_iouring,
+        bool perform_verification) {
     auto snapuserd = std::make_shared<SnapshotHandler>(misc_name, cow_device_path, backing_device,
-                                                       base_path_merge, num_worker_threads,
+                                                       base_path_merge, opener, num_worker_threads,
                                                        use_iouring, perform_verification);
     if (!snapuserd->InitCowDevice()) {
         LOG(ERROR) << "Failed to initialize Snapuserd";
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
index b7ddac1..2a6da96 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include <android-base/unique_fd.h>
+#include <snapuserd/block_server.h>
 
 namespace android {
 namespace snapshot {
@@ -55,6 +56,7 @@
                                                       const std::string& cow_device_path,
                                                       const std::string& backing_device,
                                                       const std::string& base_path_merge,
+                                                      std::shared_ptr<IBlockServerOpener> opener,
                                                       int num_worker_threads, bool use_iouring,
                                                       bool perform_verification) = 0;
 
@@ -91,6 +93,7 @@
                                               const std::string& cow_device_path,
                                               const std::string& backing_device,
                                               const std::string& base_path_merge,
+                                              std::shared_ptr<IBlockServerOpener> opener,
                                               int num_worker_threads, bool use_iouring,
                                               bool perform_verification) override;
     bool StartHandler(const std::string& misc_name) override;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
index a83cab8..2d69721 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
@@ -16,6 +16,7 @@
 #include "merge_worker.h"
 
 #include "snapuserd_core.h"
+#include "utility.h"
 
 namespace android {
 namespace snapshot {
@@ -550,8 +551,8 @@
         return true;
     }
 
-    if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) {
-        SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid();
+    if (!SetThreadPriority(kNiceValueForMergeThreads)) {
+        SNAP_PLOG(ERROR) << "Failed to set thread priority";
     }
 
     SNAP_LOG(INFO) << "Merge starting..";
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
index ce4be43..e2c292b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
@@ -17,6 +17,7 @@
 #include "read_worker.h"
 
 #include "snapuserd_core.h"
+#include "utility.h"
 
 namespace android {
 namespace snapshot {
@@ -208,8 +209,8 @@
 bool ReadWorker::Run() {
     SNAP_LOG(INFO) << "Processing snapshot I/O requests....";
 
-    if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) {
-        SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid();
+    if (!SetThreadPriority(kNiceValueForMergeThreads)) {
+        SNAP_PLOG(ERROR) << "Failed to set thread priority";
     }
 
     // Start serving IO
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 6d3d5c7..5a82ca1 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -36,12 +36,12 @@
 
 SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device,
                                  std::string backing_device, std::string base_path_merge,
-                                 int num_worker_threads, bool use_iouring,
-                                 bool perform_verification) {
+                                 std::shared_ptr<IBlockServerOpener> opener, int num_worker_threads,
+                                 bool use_iouring, bool perform_verification) {
     misc_name_ = std::move(misc_name);
     cow_device_ = std::move(cow_device);
     backing_store_device_ = std::move(backing_device);
-    control_device_ = "/dev/dm-user/" + misc_name_;
+    block_server_opener_ = std::move(opener);
     base_path_merge_ = std::move(base_path_merge);
     num_worker_threads_ = num_worker_threads;
     is_io_uring_enabled_ = use_iouring;
@@ -49,10 +49,10 @@
 }
 
 bool SnapshotHandler::InitializeWorkers() {
-    auto opener = std::make_shared<DmUserBlockServerOpener>(misc_name_, control_device_);
     for (int i = 0; i < num_worker_threads_; i++) {
         auto wt = std::make_unique<ReadWorker>(cow_device_, backing_store_device_, misc_name_,
-                                               base_path_merge_, GetSharedPtr(), opener);
+                                               base_path_merge_, GetSharedPtr(),
+                                               block_server_opener_);
         if (!wt->Init()) {
             SNAP_LOG(ERROR) << "Thread initialization failed";
             return false;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index 5fe0a70..a45e0bc 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -43,6 +43,7 @@
 #include <libsnapshot/cow_reader.h>
 #include <libsnapshot/cow_writer.h>
 #include <liburing.h>
+#include <snapuserd/block_server.h>
 #include <snapuserd/snapuserd_buffer.h>
 #include <snapuserd/snapuserd_kernel.h>
 #include <storage_literals/storage_literals.h>
@@ -102,8 +103,8 @@
 class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
   public:
     SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device,
-                    std::string base_path_merge, int num_workers, bool use_iouring,
-                    bool perform_verification);
+                    std::string base_path_merge, std::shared_ptr<IBlockServerOpener> opener,
+                    int num_workers, bool use_iouring, bool perform_verification);
     bool InitCowDevice();
     bool Start();
 
@@ -242,6 +243,7 @@
 
     std::unique_ptr<struct io_uring> ring_;
     std::unique_ptr<UpdateVerify> update_verify_;
+    std::shared_ptr<IBlockServerOpener> block_server_opener_;
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
index 8755820..8b799ea 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -17,6 +17,7 @@
 #include "snapuserd_readahead.h"
 
 #include "snapuserd_core.h"
+#include "utility.h"
 
 namespace android {
 namespace snapshot {
@@ -765,8 +766,8 @@
 
     InitializeIouring();
 
-    if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) {
-        SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid();
+    if (!SetThreadPriority(kNiceValueForMergeThreads)) {
+        SNAP_PLOG(ERROR) << "Failed to set thread priority";
     }
 
     while (!RAIterDone()) {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index f2585ea..13b9a00 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -31,6 +31,7 @@
 #include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <fs_mgr/file_wait.h>
+#include <snapuserd/dm_user_block_server.h>
 #include <snapuserd/snapuserd_client.h>
 #include "snapuserd_server.h"
 
@@ -48,6 +49,7 @@
 UserSnapshotServer::UserSnapshotServer() {
     terminating_ = false;
     handlers_ = std::make_unique<SnapshotHandlerManager>();
+    block_server_factory_ = std::make_unique<DmUserBlockServerFactory>();
 }
 
 UserSnapshotServer::~UserSnapshotServer() {
@@ -363,8 +365,11 @@
         perform_verification = false;
     }
 
+    auto opener = block_server_factory_->CreateOpener(misc_name);
+
     return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge,
-                                 num_worker_threads, io_uring_enabled_, perform_verification);
+                                 opener, num_worker_threads, io_uring_enabled_,
+                                 perform_verification);
 }
 
 bool UserSnapshotServer::WaitForSocket() {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
index 988c01a..be28541 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
@@ -31,6 +31,7 @@
 #include <vector>
 
 #include <android-base/unique_fd.h>
+#include <snapuserd/block_server.h>
 #include "handler_manager.h"
 #include "snapuserd_core.h"
 
@@ -50,6 +51,7 @@
     bool is_server_running_ = false;
     bool io_uring_enabled_ = false;
     std::unique_ptr<ISnapshotHandlerManager> handlers_;
+    std::unique_ptr<IBlockServerFactory> block_server_factory_;
 
     std::mutex lock_;
 
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index 16f9ed8..c407834 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -37,11 +37,13 @@
 #include <libdm/dm.h>
 #include <libdm/loop_control.h>
 #include <libsnapshot/cow_writer.h>
+#include <snapuserd/dm_user_block_server.h>
 #include <storage_literals/storage_literals.h>
-
 #include "handler_manager.h"
 #include "snapuserd_core.h"
+#include "testing/dm_user_harness.h"
 #include "testing/temp_device.h"
+#include "utility.h"
 
 DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
 
@@ -75,10 +77,9 @@
     static const uint64_t kSectorSize = 512;
 
   protected:
-    void SetUp() override {}
+    void SetUp() override;
     void TearDown() override { Shutdown(); }
 
-  private:
     void SetupImpl();
 
     void SimulateDaemonRestart();
@@ -94,10 +95,10 @@
     void InitCowDevice();
     void SetDeviceControlName();
     void InitDaemon();
-    void CreateDmUserDevice();
+    void CreateUserDevice();
 
     unique_ptr<LoopDevice> base_loop_;
-    unique_ptr<Tempdevice> dmuser_dev_;
+    unique_ptr<IUserDevice> dmuser_dev_;
 
     std::string system_device_ctrl_name_;
     std::string system_device_name_;
@@ -112,6 +113,7 @@
     size_t size_ = 100_MiB;
     int cow_num_sectors_;
     int total_base_size_;
+    std::unique_ptr<ITestHarness> harness_;
 };
 
 static unique_fd CreateTempFile(const std::string& name, size_t size) {
@@ -132,6 +134,10 @@
     return fd;
 }
 
+void SnapuserdTest::SetUp() {
+    harness_ = std::make_unique<DmUserTestHarness>();
+}
+
 void SnapuserdTest::Shutdown() {
     ASSERT_TRUE(dmuser_dev_->Destroy());
 
@@ -173,7 +179,7 @@
 bool SnapuserdTest::SetupDaemon() {
     SetDeviceControlName();
 
-    CreateDmUserDevice();
+    CreateUserDevice();
     InitCowDevice();
     InitDaemon();
 
@@ -206,7 +212,7 @@
 }
 
 void SnapuserdTest::ReadSnapshotDeviceAndValidate() {
-    unique_fd fd(open(dmuser_dev_->path().c_str(), O_RDONLY));
+    unique_fd fd(open(dmuser_dev_->GetPath().c_str(), O_RDONLY));
     ASSERT_GE(fd, 0);
     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
 
@@ -535,9 +541,11 @@
         use_iouring = false;
     }
 
+    auto factory = harness_->GetBlockServerFactory();
+    auto opener = factory->CreateOpener(system_device_ctrl_name_);
     auto handler =
             handlers_.AddHandler(system_device_ctrl_name_, cow_system_->path, base_loop_->device(),
-                                 base_loop_->device(), 1, use_iouring, false);
+                                 base_loop_->device(), opener, 1, use_iouring, false);
     ASSERT_NE(handler, nullptr);
     ASSERT_NE(handler->snapuserd(), nullptr);
 #ifdef __ANDROID__
@@ -557,7 +565,7 @@
     system_device_ctrl_name_ = system_device_name_ + "-ctrl";
 }
 
-void SnapuserdTest::CreateDmUserDevice() {
+void SnapuserdTest::CreateUserDevice() {
     unique_fd fd(TEMP_FAILURE_RETRY(open(base_loop_->device().c_str(), O_RDONLY | O_CLOEXEC)));
     ASSERT_TRUE(fd > 0);
 
@@ -566,17 +574,9 @@
 
     cow_num_sectors_ = dev_sz >> 9;
 
-    DmTable dmuser_table;
-    ASSERT_TRUE(dmuser_table.AddTarget(
-            std::make_unique<DmTargetUser>(0, cow_num_sectors_, system_device_ctrl_name_)));
-    ASSERT_TRUE(dmuser_table.valid());
-
-    dmuser_dev_ = std::make_unique<Tempdevice>(system_device_name_, dmuser_table);
-    ASSERT_TRUE(dmuser_dev_->valid());
-    ASSERT_FALSE(dmuser_dev_->path().empty());
-
-    auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
-    ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
+    dmuser_dev_ = harness_->CreateUserDevice(system_device_name_, system_device_ctrl_name_,
+                                             cow_num_sectors_);
+    ASSERT_NE(dmuser_dev_, nullptr);
 }
 
 void SnapuserdTest::InitDaemon() {
@@ -600,7 +600,7 @@
 
     SetDeviceControlName();
 
-    CreateDmUserDevice();
+    CreateUserDevice();
     InitCowDevice();
     InitDaemon();
 
@@ -629,7 +629,7 @@
     Shutdown();
     std::this_thread::sleep_for(500ms);
     SetDeviceControlName();
-    CreateDmUserDevice();
+    CreateUserDevice();
     InitCowDevice();
     InitDaemon();
 }
@@ -692,6 +692,9 @@
 }
 
 TEST_F(SnapuserdTest, Snapshot_IO_TEST) {
+    if (!harness_->HasUserDevice()) {
+        GTEST_SKIP() << "Skipping snapshot read; not supported";
+    }
     ASSERT_TRUE(SetupDefault());
     // I/O before merge
     ReadSnapshotDeviceAndValidate();
@@ -704,6 +707,9 @@
 }
 
 TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) {
+    if (!harness_->HasUserDevice()) {
+        GTEST_SKIP() << "Skipping snapshot read; not supported";
+    }
     ASSERT_TRUE(SetupDefault());
     // Issue I/O before merge begins
     std::async(std::launch::async, &SnapuserdTest::ReadSnapshotDeviceAndValidate, this);
@@ -714,6 +720,9 @@
 }
 
 TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) {
+    if (!harness_->HasUserDevice()) {
+        GTEST_SKIP() << "Skipping snapshot read; not supported";
+    }
     ASSERT_TRUE(SetupDefault());
     // Start the merge
     StartMerge();
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.cpp b/fs_mgr/libsnapshot/snapuserd/utility.cpp
new file mode 100644
index 0000000..a84a7c1
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/utility.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "utility.h"
+
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+
+namespace android {
+namespace snapshot {
+
+using android::base::unique_fd;
+
+bool SetThreadPriority([[maybe_unused]] int priority) {
+#ifdef __ANDROID__
+    return setpriority(PRIO_PROCESS, gettid(), priority) != -1;
+#else
+    return true;
+#endif
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.h b/fs_mgr/libsnapshot/snapuserd/utility.h
new file mode 100644
index 0000000..58ec3e6
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/utility.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+namespace android {
+namespace snapshot {
+
+bool SetThreadPriority(int priority);
+
+}  // namespace snapshot
+}  // namespace android