Merge changes from topic "fmayle-flock-test" into main am: d093f03589

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Virtualization/+/3255192

Change-Id: I73e7b60d3821407ad549203237e3d267626d181b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/android/virtmgr/Android.bp b/android/virtmgr/Android.bp
index f0b6881..0148ff6 100644
--- a/android/virtmgr/Android.bp
+++ b/android/virtmgr/Android.bp
@@ -70,6 +70,7 @@
         "liblibfdt",
         "libfsfdt",
         "libhypervisor_props",
+        "libzerocopy",
         "libuuid",
         // TODO(b/202115393) stabilize the interface
         "packagemanager_aidl-rust",
diff --git a/android/virtmgr/src/composite.rs b/android/virtmgr/src/composite.rs
index 681ec59..1219150 100644
--- a/android/virtmgr/src/composite.rs
+++ b/android/virtmgr/src/composite.rs
@@ -15,13 +15,16 @@
 //! Functions for creating a composite disk image.
 
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::Partition::Partition;
-use anyhow::{anyhow, Context, Error};
-use disk::{
-    create_composite_disk, create_disk_file, ImagePartitionType, PartitionInfo, MAX_NESTING_DEPTH,
-};
+use anyhow::{bail, Context, Error};
+use disk::{create_composite_disk, ImagePartitionType, PartitionInfo};
 use std::fs::{File, OpenOptions};
+use std::io::ErrorKind;
+use std::os::unix::fs::FileExt;
 use std::os::unix::io::AsRawFd;
 use std::path::{Path, PathBuf};
+use zerocopy::AsBytes;
+use zerocopy::FromBytes;
+use zerocopy::FromZeroes;
 
 use uuid::Uuid;
 
@@ -98,7 +101,7 @@
                 .context("Failed to clone partition image file descriptor")?
                 .into();
             let path = fd_path_for_file(&file);
-            let size = get_partition_size(&file, &path)?;
+            let size = get_partition_size(&file)?;
             files.push(file);
 
             Ok(PartitionInfo {
@@ -122,16 +125,74 @@
 
 /// Find the size of the partition image in the given file by parsing the header.
 ///
-/// This will work for raw, QCOW2, composite and Android sparse images.
-fn get_partition_size(partition: &File, path: &Path) -> Result<u64, Error> {
-    // TODO: Use `context` once disk::Error implements std::error::Error.
-    // TODO: Add check for is_sparse_file
-    Ok(create_disk_file(
-        partition.try_clone()?,
-        /* is_sparse_file */ false,
-        MAX_NESTING_DEPTH,
-        path,
-    )
-    .map_err(|e| anyhow!("Failed to open partition image: {}", e))?
-    .get_len()?)
+/// This will work for raw and Android sparse images. QCOW2 and composite images aren't supported.
+fn get_partition_size(file: &File) -> Result<u64, Error> {
+    match detect_image_type(file).context("failed to detect partition image type")? {
+        ImageType::Raw => Ok(file.metadata().context("failed to get metadata")?.len()),
+        ImageType::AndroidSparse => {
+            // Source: system/core/libsparse/sparse_format.h
+            #[repr(C)]
+            #[derive(Clone, Copy, Debug, AsBytes, FromZeroes, FromBytes)]
+            struct SparseHeader {
+                magic: u32,
+                major_version: u16,
+                minor_version: u16,
+                file_hdr_sz: u16,
+                chunk_hdr_size: u16,
+                blk_sz: u32,
+                total_blks: u32,
+                total_chunks: u32,
+                image_checksum: u32,
+            }
+            let mut header = SparseHeader::new_zeroed();
+            file.read_exact_at(header.as_bytes_mut(), 0)
+                .context("failed to read android sparse header")?;
+            let len = u64::from(header.total_blks)
+                .checked_mul(header.blk_sz.into())
+                .context("android sparse image len too big")?;
+            Ok(len)
+        }
+        t => bail!("unsupported partition image type: {t:?}"),
+    }
+}
+
+/// Image file types we can detect.
+#[derive(Debug, PartialEq, Eq)]
+enum ImageType {
+    Raw,
+    Qcow2,
+    CompositeDisk,
+    AndroidSparse,
+}
+
+/// Detect image type by looking for magic bytes.
+fn detect_image_type(file: &File) -> std::io::Result<ImageType> {
+    const CDISK_MAGIC: &str = "composite_disk\x1d";
+    const QCOW_MAGIC: u32 = 0x5146_49fb;
+    const SPARSE_HEADER_MAGIC: u32 = 0xed26ff3a;
+
+    let mut magic4 = [0u8; 4];
+    match file.read_exact_at(&mut magic4[..], 0) {
+        Ok(()) => {}
+        Err(e) if e.kind() == ErrorKind::UnexpectedEof => return Ok(ImageType::Raw),
+        Err(e) => return Err(e),
+    }
+    if magic4 == QCOW_MAGIC.to_be_bytes() {
+        return Ok(ImageType::Qcow2);
+    }
+    if magic4 == SPARSE_HEADER_MAGIC.to_le_bytes() {
+        return Ok(ImageType::AndroidSparse);
+    }
+
+    let mut buf = [0u8; CDISK_MAGIC.len()];
+    match file.read_exact_at(buf.as_bytes_mut(), 0) {
+        Ok(()) => {}
+        Err(e) if e.kind() == ErrorKind::UnexpectedEof => return Ok(ImageType::Raw),
+        Err(e) => return Err(e),
+    }
+    if buf == CDISK_MAGIC.as_bytes() {
+        return Ok(ImageType::CompositeDisk);
+    }
+
+    Ok(ImageType::Raw)
 }
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 5886535..0f41932 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -1045,8 +1045,9 @@
     }
 
     for disk in config.disks {
+        // Disk file locking is disabled because of missing SELinux policies.
         command.arg("--block").arg(format!(
-            "path={},ro={}",
+            "path={},ro={},lock=false",
             add_preserved_fd(&mut preserved_fds, disk.image),
             !disk.writable,
         ));
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
index 11a2115..99dc648 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
@@ -20,7 +20,12 @@
     /** A label for the partition. */
     @utf8InCpp String label;
 
-    /** The backing file descriptor of the partition image. */
+    /**
+     * The backing file descriptor of the partition image.
+     *
+     * The image file must either be a raw binary file, or an android-sparse
+     * formatted file.
+     */
     ParcelFileDescriptor image;
 
     /** Whether the partition should be writable by the VM. */