snapuserd: Test both async and sync paths.

Rather than split this into two binaries as we did for libsnapshot, this
uses test parameterization. I went this route because even for async
builds, the sync path must always work as a fallback.

Bug: N/A
Test: snapuserd_test
Change-Id: Ib68c8fd831c345f41a4e14a99fd0a0b8b1d47b6d
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 e886ec3..474ba7d 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -16,8 +16,6 @@
 
 #include "snapuserd_core.h"
 
-#include <sys/utsname.h>
-
 #include <android-base/chrono_utils.h>
 #include <android-base/properties.h>
 #include <android-base/scopeguard.h>
@@ -26,6 +24,7 @@
 
 #include "merge_worker.h"
 #include "read_worker.h"
+#include "utility.h"
 
 namespace android {
 namespace snapshot {
@@ -417,22 +416,7 @@
 }
 
 bool SnapshotHandler::IsIouringSupported() {
-    struct utsname uts;
-    unsigned int major, minor;
-
-    if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
-        SNAP_LOG(ERROR) << "Could not parse the kernel version from uname. "
-                        << " io_uring not supported";
-        return false;
-    }
-
-    // We will only support kernels from 5.6 onwards as IOSQE_ASYNC flag and
-    // IO_URING_OP_READ/WRITE opcodes were introduced only on 5.6 kernel
-    if (major >= 5) {
-        if (major == 5 && minor < 6) {
-            return false;
-        }
-    } else {
+    if (!KernelSupportsIoUring()) {
         return false;
     }
 
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 65f31cf..bed71cf 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -47,8 +47,6 @@
 #include "testing/temp_device.h"
 #include "utility.h"
 
-DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
-
 namespace android {
 namespace snapshot {
 
@@ -62,7 +60,7 @@
 using testing::AssertionResult;
 using testing::AssertionSuccess;
 
-class SnapuserdTestBase : public ::testing::Test {
+class SnapuserdTestBase : public ::testing::TestWithParam<bool> {
   protected:
     void SetUp() override;
     void TearDown() override;
@@ -627,16 +625,11 @@
 }
 
 void SnapuserdTest::InitCowDevice() {
-    bool use_iouring = true;
-    if (FLAGS_force_config == "iouring_disabled") {
-        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_dev_->GetPath(),
-                                  base_dev_->GetPath(), opener, 1, use_iouring, false);
+                                  base_dev_->GetPath(), opener, 1, GetParam(), false);
     ASSERT_NE(handler, nullptr);
     ASSERT_NE(handler->snapuserd(), nullptr);
 #ifdef __ANDROID__
@@ -780,7 +773,7 @@
     ASSERT_TRUE(Merge());
 }
 
-TEST_F(SnapuserdTest, Snapshot_IO_TEST) {
+TEST_P(SnapuserdTest, Snapshot_IO_TEST) {
     if (!harness_->HasUserDevice()) {
         GTEST_SKIP() << "Skipping snapshot read; not supported";
     }
@@ -794,7 +787,7 @@
     ASSERT_NO_FATAL_FAILURE(ReadSnapshotDeviceAndValidate());
 }
 
-TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST) {
+TEST_P(SnapuserdTest, Snapshot_MERGE_IO_TEST) {
     if (!harness_->HasUserDevice()) {
         GTEST_SKIP() << "Skipping snapshot read; not supported";
     }
@@ -808,7 +801,7 @@
     read_future.wait();
 }
 
-TEST_F(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) {
+TEST_P(SnapuserdTest, Snapshot_MERGE_IO_TEST_1) {
     if (!harness_->HasUserDevice()) {
         GTEST_SKIP() << "Skipping snapshot read; not supported";
     }
@@ -823,31 +816,31 @@
     read_future.wait();
 }
 
-TEST_F(SnapuserdTest, Snapshot_Merge_Resume) {
+TEST_P(SnapuserdTest, Snapshot_Merge_Resume) {
     ASSERT_NO_FATAL_FAILURE(SetupDefault());
     ASSERT_NO_FATAL_FAILURE(MergeInterrupt());
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_1) {
+TEST_P(SnapuserdTest, Snapshot_COPY_Overlap_TEST_1) {
     ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_1());
     ASSERT_TRUE(Merge());
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_TEST_2) {
+TEST_P(SnapuserdTest, Snapshot_COPY_Overlap_TEST_2) {
     ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_2());
     ASSERT_TRUE(Merge());
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
+TEST_P(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
     ASSERT_NO_FATAL_FAILURE(SetupCopyOverlap_1());
     ASSERT_NO_FATAL_FAILURE(MergeInterrupt());
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_IO_Validate_TEST) {
+TEST_P(SnapuserdTest, Snapshot_COPY_Overlap_Merge_Resume_IO_Validate_TEST) {
     if (!harness_->HasUserDevice()) {
         GTEST_SKIP() << "Skipping snapshot read; not supported";
     }
@@ -856,25 +849,25 @@
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Ordered) {
+TEST_P(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Ordered) {
     ASSERT_NO_FATAL_FAILURE(SetupOrderedOps());
     ASSERT_NO_FATAL_FAILURE(MergeInterruptFixed(300));
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Ordered) {
+TEST_P(SnapuserdTest, Snapshot_Merge_Crash_Random_Ordered) {
     ASSERT_NO_FATAL_FAILURE(SetupOrderedOps());
     ASSERT_NO_FATAL_FAILURE(MergeInterruptRandomly(500));
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Inverted) {
+TEST_P(SnapuserdTest, Snapshot_Merge_Crash_Fixed_Inverted) {
     ASSERT_NO_FATAL_FAILURE(SetupOrderedOpsInverted());
     ASSERT_NO_FATAL_FAILURE(MergeInterruptFixed(50));
     ValidateMerge();
 }
 
-TEST_F(SnapuserdTest, Snapshot_Merge_Crash_Random_Inverted) {
+TEST_P(SnapuserdTest, Snapshot_Merge_Crash_Random_Inverted) {
     ASSERT_NO_FATAL_FAILURE(SetupOrderedOpsInverted());
     ASSERT_NO_FATAL_FAILURE(MergeInterruptRandomly(50));
     ValidateMerge();
@@ -941,7 +934,7 @@
 }
 
 // This test mirrors ReadSnapshotDeviceAndValidate.
-TEST_F(HandlerTest, Read) {
+TEST_P(HandlerTest, Read) {
     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
 
     // COPY
@@ -970,20 +963,41 @@
     ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
 }
 
-TEST_F(HandlerTest, ReadUnalignedSector) {
+TEST_P(HandlerTest, ReadUnalignedSector) {
     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
 
     ASSERT_TRUE(ReadSectors(1, BLOCK_SZ, snapuserd_buffer.get()));
     ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get() + SECTOR_SIZE, BLOCK_SZ), 0);
 }
 
-TEST_F(HandlerTest, ReadUnalignedSize) {
+TEST_P(HandlerTest, ReadUnalignedSize) {
     std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(SECTOR_SIZE);
 
     ASSERT_TRUE(ReadSectors(0, SECTOR_SIZE, snapuserd_buffer.get()));
     ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), SECTOR_SIZE), 0);
 }
 
+std::vector<bool> GetIoUringConfigs() {
+#if __ANDROID__
+    if (!android::base::GetBoolProperty("ro.virtual_ab.io_uring.enabled", false)) {
+        return {false};
+    }
+#endif
+    if (!KernelSupportsIoUring()) {
+        return {false};
+    }
+    return {false, true};
+}
+
+std::string IoUringConfigName(const testing::TestParamInfo<SnapuserdTest::ParamType>& info) {
+    return info.param ? "io_uring" : "sync";
+}
+
+INSTANTIATE_TEST_SUITE_P(Io, SnapuserdTest, ::testing::ValuesIn(GetIoUringConfigs()),
+                         IoUringConfigName);
+INSTANTIATE_TEST_SUITE_P(Io, HandlerTest, ::testing::ValuesIn(GetIoUringConfigs()),
+                         IoUringConfigName);
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.cpp b/fs_mgr/libsnapshot/snapuserd/utility.cpp
index a84a7c1..fcdb69d 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/utility.cpp
@@ -15,6 +15,7 @@
 #include "utility.h"
 
 #include <sys/resource.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 
 #include <android-base/file.h>
@@ -32,5 +33,19 @@
 #endif
 }
 
+bool KernelSupportsIoUring() {
+    struct utsname uts {};
+    unsigned int major, minor;
+
+    uname(&uts);
+    if (sscanf(uts.release, "%u.%u", &major, &minor) != 2) {
+        return false;
+    }
+
+    // We will only support kernels from 5.6 onwards as IOSQE_ASYNC flag and
+    // IO_URING_OP_READ/WRITE opcodes were introduced only on 5.6 kernel
+    return major > 5 || (major == 5 && minor >= 6);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/utility.h b/fs_mgr/libsnapshot/snapuserd/utility.h
index 58ec3e6..255aee1 100644
--- a/fs_mgr/libsnapshot/snapuserd/utility.h
+++ b/fs_mgr/libsnapshot/snapuserd/utility.h
@@ -18,6 +18,7 @@
 namespace snapshot {
 
 bool SetThreadPriority(int priority);
+bool KernelSupportsIoUring();
 
 }  // namespace snapshot
 }  // namespace android