Move loopdevice module to dm_rust lib

This is a generic module, not specific to apkdmverity. Will be reused
for unit-testing other dm- devices. Also, setup the test infra for
dm_rust module...

Bug: 250880499
Test: atest libdm_rust.test
Test: atest apkdmverity.test
Change-Id: I32971938908ea8c0213583885403910baac8be10
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index 1a4a929..23457c4 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -21,11 +21,10 @@
 //! system managed by the host Android which is assumed to be compromisable, it is important to
 //! keep the integrity of the file "inside" Microdroid.
 
-mod loopdevice;
-
 use anyhow::{bail, Context, Result};
 use apkverify::{HashAlgorithm, V4Signature};
 use clap::{App, Arg};
+use dm::loopdevice;
 use dm::util;
 use dm::verity::{DmVerityHashAlgorithm, DmVerityTargetBuilder};
 use itertools::Itertools;
diff --git a/libs/devicemapper/Android.bp b/libs/devicemapper/Android.bp
index 61ffa22..088b320 100644
--- a/libs/devicemapper/Android.bp
+++ b/libs/devicemapper/Android.bp
@@ -27,3 +27,14 @@
     name: "libdm_rust",
     defaults: ["libdm_rust.defaults"],
 }
+
+rust_test {
+    name: "libdm_rust.test",
+    defaults: ["libdm_rust.defaults"],
+    test_suites: ["general-tests"],
+    rustlibs: [
+        "libscopeguard",
+        "libtempfile",
+    ],
+    data: ["tests/data/*"],
+}
diff --git a/libs/devicemapper/AndroidTest.xml b/libs/devicemapper/AndroidTest.xml
new file mode 100644
index 0000000..9890bb6
--- /dev/null
+++ b/libs/devicemapper/AndroidTest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<configuration description="Config for device mapper tests">
+  <!--
+    Creating and configuring the loop devices and the device-mapper devices require root privilege.
+  -->
+  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+  <!--
+    We need to disable selinux because kernel (which is implementing the loop device) doesn't have
+    the privilege to read files on /data. Otherwise, we hit the following errors:
+
+    avc: denied { read } for comm="loop32"
+    path="/data/local/tmp/.tmp.ptPChH/**" dev="dm-8" ino=2939
+    scontext=u:r:kernel:s0 tcontext=u:object_r:shell_data_file:s0
+    tclass=file
+  -->
+  <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/>
+
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="push-file" key="libdm_rust.test" value="/data/local/tmp/libdm_rust.test" />
+  </target_preparer>
+
+  <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+    <option name="test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="libdm_rust.test" />
+  </test>
+</configuration>
diff --git a/libs/devicemapper/TEST_MAPPING b/libs/devicemapper/TEST_MAPPING
new file mode 100644
index 0000000..23d10c4
--- /dev/null
+++ b/libs/devicemapper/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "avf-presubmit" : [
+    {
+      "name" : "libdm_rust.test"
+    }
+  ]
+}
diff --git a/libs/devicemapper/src/lib.rs b/libs/devicemapper/src/lib.rs
index 1bcaf1a..938ca0f 100644
--- a/libs/devicemapper/src/lib.rs
+++ b/libs/devicemapper/src/lib.rs
@@ -42,6 +42,8 @@
 pub mod util;
 /// Exposes the DmVerityTarget & related builder
 pub mod verity;
+// Expose loopdevice
+pub mod loopdevice;
 
 mod sys;
 use sys::*;
diff --git a/apkdmverity/src/loopdevice.rs b/libs/devicemapper/src/loopdevice.rs
similarity index 98%
rename from apkdmverity/src/loopdevice.rs
rename to libs/devicemapper/src/loopdevice.rs
index fa49cea..bdbc0f6 100644
--- a/apkdmverity/src/loopdevice.rs
+++ b/libs/devicemapper/src/loopdevice.rs
@@ -23,9 +23,9 @@
 
 mod sys;
 
+use crate::util::*;
 use anyhow::{Context, Result};
 use data_model::DataInit;
-use dm::util::*;
 use libc::O_DIRECT;
 use std::fs::{File, OpenOptions};
 use std::mem::size_of;
@@ -40,7 +40,6 @@
 // These are old-style ioctls, thus *_bad.
 nix::ioctl_none_bad!(_loop_ctl_get_free, LOOP_CTL_GET_FREE);
 nix::ioctl_write_ptr_bad!(_loop_configure, LOOP_CONFIGURE, loop_config);
-#[cfg(test)]
 nix::ioctl_none_bad!(_loop_clr_fd, LOOP_CLR_FD);
 
 fn loop_ctl_get_free(ctrl_file: &File) -> Result<i32> {
@@ -55,8 +54,7 @@
     Ok(unsafe { _loop_configure(device_file.as_raw_fd(), config) }?)
 }
 
-#[cfg(test)]
-fn loop_clr_fd(device_file: &File) -> Result<i32> {
+pub fn loop_clr_fd(device_file: &File) -> Result<i32> {
     // SAFETY: this ioctl disassociates the loop device with `device_file`, where the FD will
     // remain opened afterward. The association itself is kept for open FDs.
     Ok(unsafe { _loop_clr_fd(device_file.as_raw_fd()) }?)
@@ -148,7 +146,6 @@
 }
 
 /// Detaches backing file from the loop device `path`.
-#[cfg(test)]
 pub fn detach<P: AsRef<Path>>(path: P) -> Result<()> {
     let device_file = OpenOptions::new().read(true).write(true).open(&path)?;
     loop_clr_fd(&device_file)?;
diff --git a/apkdmverity/src/loopdevice/sys.rs b/libs/devicemapper/src/loopdevice/sys.rs
similarity index 99%
rename from apkdmverity/src/loopdevice/sys.rs
rename to libs/devicemapper/src/loopdevice/sys.rs
index fa87548..98b5085 100644
--- a/apkdmverity/src/loopdevice/sys.rs
+++ b/libs/devicemapper/src/loopdevice/sys.rs
@@ -25,7 +25,6 @@
 
 pub const LOOP_CTL_GET_FREE: libc::c_ulong = 0x4C82;
 pub const LOOP_CONFIGURE: libc::c_ulong = 0x4C0A;
-#[cfg(test)]
 pub const LOOP_CLR_FD: libc::c_ulong = 0x4C01;
 
 #[repr(C)]