apkdmverity: build for Android.bp

... and some parts of the source code were revised to satisfy the
stricter lint checks for Android.

Bug: 189785765
Test: cargo test
Test: m apkdmverity

Change-Id: Ic3d80922396fb8e7cba29b092d6f74d17e936f7a
diff --git a/apkverity/Android.bp b/apkverity/Android.bp
new file mode 100644
index 0000000..3d0dab5
--- /dev/null
+++ b/apkverity/Android.bp
@@ -0,0 +1,42 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+    name: "apkdmverity.defaults",
+    crate_name: "apkdmverity",
+    srcs: ["src/main.rs"],
+    edition: "2018",
+    prefer_rlib: true,
+    rustlibs: [
+        "libanyhow",
+        "libbitflags",
+        "libclap",
+        "liblibc",
+        "libnix",
+        "libnum_traits",
+        "libscopeguard",
+        "libuuid",
+    ],
+    proc_macros: ["libnum_derive"],
+    multilib: {
+        lib32: {
+            enabled: false,
+        },
+    },
+}
+
+rust_binary {
+    name: "apkdmverity",
+    defaults: ["apkdmverity.defaults"],
+}
+
+rust_test {
+    name: "apkdmverity.test",
+    defaults: ["apkdmverity.defaults"],
+    test_suites: ["general-tests"],
+    compile_multilib: "first",
+    rustlibs: [
+        "libtempfile",
+    ],
+}
diff --git a/apkverity/src/apksigv4.rs b/apkverity/src/apksigv4.rs
index f1ee0a4..7d8f318 100644
--- a/apkverity/src/apksigv4.rs
+++ b/apkverity/src/apksigv4.rs
@@ -57,7 +57,7 @@
 
 impl Version {
     fn from(val: u32) -> Result<Version> {
-        Self::from_u32(val).ok_or(anyhow!("{} is an unsupported version", val))
+        Self::from_u32(val).ok_or_else(|| anyhow!("{} is an unsupported version", val))
     }
 }
 
@@ -69,7 +69,7 @@
 
 impl HashAlgorithm {
     fn from(val: u32) -> Result<HashAlgorithm> {
-        Self::from_u32(val).ok_or(anyhow!("{} is an unsupported hash algorithm", val))
+        Self::from_u32(val).ok_or_else(|| anyhow!("{} is an unsupported hash algorithm", val))
     }
 }
 
@@ -157,7 +157,7 @@
     use std::io::Cursor;
 
     fn hexstring_from(s: &[u8]) -> String {
-        s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or(String::new())
+        s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or_default()
     }
 
     #[test]
diff --git a/apkverity/src/dm.rs b/apkverity/src/dm.rs
index ec4248c..8828b0a 100644
--- a/apkverity/src/dm.rs
+++ b/apkverity/src/dm.rs
@@ -41,9 +41,10 @@
 pub use verity::*;
 
 nix::ioctl_readwrite!(_dm_dev_create, DM_IOCTL, Cmd::DM_DEV_CREATE, DmIoctl);
-nix::ioctl_readwrite!(_dm_dev_remove, DM_IOCTL, Cmd::DM_DEV_REMOVE, DmIoctl);
 nix::ioctl_readwrite!(_dm_dev_suspend, DM_IOCTL, Cmd::DM_DEV_SUSPEND, DmIoctl);
 nix::ioctl_readwrite!(_dm_table_load, DM_IOCTL, Cmd::DM_TABLE_LOAD, DmIoctl);
+#[cfg(test)]
+nix::ioctl_readwrite!(_dm_dev_remove, DM_IOCTL, Cmd::DM_DEV_REMOVE, DmIoctl);
 
 fn dm_dev_create(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
     // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
@@ -51,12 +52,6 @@
     Ok(unsafe { _dm_dev_create(dm.0.as_raw_fd(), ioctl) }?)
 }
 
-fn dm_dev_remove(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
-    // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
-    // state of this process in any way.
-    Ok(unsafe { _dm_dev_remove(dm.0.as_raw_fd(), ioctl) }?)
-}
-
 fn dm_dev_suspend(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
     // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
     // state of this process in any way.
@@ -69,6 +64,13 @@
     Ok(unsafe { _dm_table_load(dm.0.as_raw_fd(), ioctl) }?)
 }
 
+#[cfg(test)]
+fn dm_dev_remove(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
+    // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
+    // state of this process in any way.
+    Ok(unsafe { _dm_dev_remove(dm.0.as_raw_fd(), ioctl) }?)
+}
+
 // `DmTargetSpec` is the header of the data structure for a device-mapper target. When doing the
 // ioctl, one of more `DmTargetSpec` (and its body) are appened to the `DmIoctl` struct.
 #[repr(C)]
@@ -90,7 +92,7 @@
 
     fn as_u8_slice(&self) -> &[u8; size_of::<Self>()] {
         // SAFETY: lifetime of the output reference isn't changed.
-        unsafe { std::mem::transmute::<&Self, &[u8; size_of::<Self>()]>(&self) }
+        unsafe { &*(&self as *const &Self as *const [u8; size_of::<Self>()]) }
     }
 }
 
@@ -116,7 +118,7 @@
 
     fn as_u8_slice(&self) -> &[u8; size_of::<Self>()] {
         // SAFETY: lifetime of the output reference isn't changed.
-        unsafe { std::mem::transmute::<&Self, &[u8; size_of::<Self>()]>(&self) }
+        unsafe { &*(&self as *const &Self as *const [u8; size_of::<Self>()]) }
     }
 }
 
@@ -150,8 +152,8 @@
         data.flags |= Flag::DM_READONLY_FLAG;
 
         let mut payload = Vec::with_capacity(payload_size);
-        payload.extend_from_slice(&data.as_u8_slice()[..]);
-        payload.extend_from_slice(&target.as_u8_slice()[..]);
+        payload.extend_from_slice(data.as_u8_slice());
+        payload.extend_from_slice(target.as_u8_slice());
         dm_table_load(&self, payload.as_mut_ptr() as *mut DmIoctl)?;
 
         // Step 3: activate the device (note: the term 'suspend' might be misleading, but it
@@ -166,6 +168,7 @@
     }
 
     /// Removes a mapper device
+    #[cfg(test)]
     pub fn delete_device_deferred(&self, name: &str) -> Result<()> {
         let mut data = DmIoctl::new(&name)?;
         data.flags |= Flag::DM_DEFERRED_REMOVE;
diff --git a/apkverity/src/dm/verity.rs b/apkverity/src/dm/verity.rs
index cfc9504..950b26e 100644
--- a/apkverity/src/dm/verity.rs
+++ b/apkverity/src/dm/verity.rs
@@ -35,6 +35,7 @@
 }
 
 /// The hash algorithm to use. SHA256 and SHA512 are supported.
+#[allow(dead_code)]
 pub enum DmVerityHashAlgorithm {
     SHA256,
     SHA512,
diff --git a/apkverity/src/loopdevice.rs b/apkverity/src/loopdevice.rs
index bb0e767..519e3bd 100644
--- a/apkverity/src/loopdevice.rs
+++ b/apkverity/src/loopdevice.rs
@@ -36,6 +36,7 @@
 // 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> {
@@ -50,6 +51,7 @@
     Ok(unsafe { _loop_configure(device_file.as_raw_fd(), config) }?)
 }
 
+#[cfg(test)]
 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.
@@ -122,13 +124,14 @@
         .write(true)
         .open(&device_path)
         .context(format!("failed to open {:?}", &device_path))?;
-    loop_configure(&device_file, &mut config)
+    loop_configure(&device_file, &config)
         .context(format!("Failed to configure {:?}", &device_path))?;
 
     Ok(PathBuf::from(device_path))
 }
 
 /// 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/apkverity/src/loopdevice/sys.rs b/apkverity/src/loopdevice/sys.rs
index 2d4977b..3f10f22 100644
--- a/apkverity/src/loopdevice/sys.rs
+++ b/apkverity/src/loopdevice/sys.rs
@@ -24,6 +24,7 @@
 
 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)]
diff --git a/apkverity/src/main.rs b/apkverity/src/main.rs
index 6fe12a0..5094c50 100644
--- a/apkverity/src/main.rs
+++ b/apkverity/src/main.rs
@@ -57,12 +57,19 @@
                 )
                 .required(true),
         )
+        .arg(Arg::with_name("verbose").short("v").long("verbose").help("Shows verbose output"))
         .get_matches();
 
     let apk = matches.value_of("apk").unwrap();
     let idsig = matches.value_of("idsig").unwrap();
     let name = matches.value_of("name").unwrap();
-    enable_verity(apk, idsig, name)?;
+    let ret = enable_verity(apk, idsig, name)?;
+    if matches.is_present("verbose") {
+        println!(
+            "data_device: {:?}, hash_device: {:?}, mapper_device: {:?}",
+            ret.data_device, ret.hash_device, ret.mapper_device
+        );
+    }
     Ok(())
 }
 
diff --git a/apkverity/src/util.rs b/apkverity/src/util.rs
index 415e99b..d2bc799 100644
--- a/apkverity/src/util.rs
+++ b/apkverity/src/util.rs
@@ -16,7 +16,6 @@
 
 use anyhow::{bail, Result};
 use nix::sys::stat::FileStat;
-use std::fs;
 use std::fs::File;
 use std::os::unix::fs::FileTypeExt;
 use std::os::unix::io::AsRawFd;
@@ -40,7 +39,7 @@
 
 /// Returns hexadecimal reprentation of a given byte array.
 pub fn hexstring_from(s: &[u8]) -> String {
-    s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or(String::new())
+    s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or_default()
 }
 
 /// fstat that accepts a path rather than FD