Merge "Set logwrapper timeout to the longest test time"
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 614a5ed..043577d 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -15,13 +15,9 @@
     # set RLIMIT_NICE to allow priorities from 19 to -20
     setrlimit nice 40 40
 
-    # in microdroid, we don't use "bootstrap" mount namespace
-    # because APEXes are passed from host and are available
-    # from the start. We don't need to wait till /data is ready.
-    enter_default_mount_ns
-
     start ueventd
 
+    start microdroid_manager
     # TODO(b/190343842) verify apexes/apk before mounting them.
 
     # Exec apexd in the VM mode to avoid unnecessary overhead of normal mode.
@@ -86,10 +82,6 @@
 
     start adbd
 
-    # TODO(b/186396070) microdroid_manager starts zipfuse if necessary
-    # TODO(b/186396070) move this before apexd for DICE derivation
-    start microdroid_manager
-
 on load_persist_props_action
     start logd
     start logd-reinit
diff --git a/microdroid/microdroid.json b/microdroid/microdroid.json
index da82289..1337edf 100644
--- a/microdroid/microdroid.json
+++ b/microdroid/microdroid.json
@@ -5,23 +5,23 @@
       "partitions": [
         {
           "label": "boot_a",
-          "paths": ["/apex/com.android.virt/etc/fs/microdroid_boot-5.10.img"]
+          "path": "/apex/com.android.virt/etc/fs/microdroid_boot-5.10.img"
         },
         {
           "label": "vendor_boot_a",
-          "paths": ["/apex/com.android.virt/etc/fs/microdroid_vendor_boot-5.10.img"]
+          "path": "/apex/com.android.virt/etc/fs/microdroid_vendor_boot-5.10.img"
         },
         {
           "label": "vbmeta_a",
-          "paths": ["/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"]
+          "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"
         },
         {
           "label": "vbmeta_system_a",
-          "paths": ["/apex/com.android.virt/etc/fs/microdroid_vbmeta_system.img"]
+          "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta_system.img"
         },
         {
           "label": "super",
-          "paths": ["/apex/com.android.virt/etc/fs/microdroid_super.img"]
+          "path": "/apex/com.android.virt/etc/fs/microdroid_super.img"
         }
       ],
       "writable": false
@@ -30,7 +30,7 @@
       "partitions": [
         {
           "label": "uboot_env",
-          "paths": ["/apex/com.android.virt/etc/uboot_env.img"],
+          "path": "/apex/com.android.virt/etc/uboot_env.img",
           "writable": false
         }
       ],
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index dabcf31..4ea156a 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -27,6 +27,7 @@
 rust_binary {
     name: "microdroid_manager",
     defaults: ["microdroid_manager_defaults"],
+    bootstrap: true,
 }
 
 rust_test {
diff --git a/microdroid_manager/src/metadata.rs b/microdroid_manager/src/metadata.rs
index 86a9e3e..432a134 100644
--- a/microdroid_manager/src/metadata.rs
+++ b/microdroid_manager/src/metadata.rs
@@ -14,15 +14,19 @@
 
 //! Payload metadata from /dev/block/by-name/payload-metadata
 
+use crate::ioutil;
+
 use anyhow::Result;
 use log::info;
 use microdroid_metadata::{read_metadata, Metadata};
-use std::fs::File;
+use std::time::Duration;
 
+const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
 const PAYLOAD_METADATA_PATH: &str = "/dev/block/by-name/payload-metadata";
 
 /// loads payload metadata from /dev/block/by-name/paylaod-metadata
 pub fn load() -> Result<Metadata> {
     info!("loading payload metadata...");
-    read_metadata(File::open(PAYLOAD_METADATA_PATH)?)
+    let file = ioutil::wait_for_file(PAYLOAD_METADATA_PATH, WAIT_TIMEOUT)?;
+    read_metadata(file)
 }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
index 9b8658b..825c3da 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/Partition.aidl
@@ -20,8 +20,8 @@
     /** A label for the partition. */
     @utf8InCpp String label;
 
-    /** The backing file descriptors of the partition images. */
-    ParcelFileDescriptor[] images;
+    /** The backing file descriptor of the partition image. */
+    ParcelFileDescriptor image;
 
     /** Whether the partition should be writable by the VM. */
     boolean writable;
diff --git a/virtualizationservice/src/composite.rs b/virtualizationservice/src/composite.rs
index 378ed78..685d0e6 100644
--- a/virtualizationservice/src/composite.rs
+++ b/virtualizationservice/src/composite.rs
@@ -50,20 +50,14 @@
 const LINUX_FILESYSTEM_GUID: Uuid = Uuid::from_u128(0x0FC63DAF_8483_4772_8E79_3D69D8477DE4);
 const EFI_SYSTEM_PARTITION_GUID: Uuid = Uuid::from_u128(0xC12A7328_F81F_11D2_BA4B_00A0C93EC93B);
 
-/// Information about a single image file to be included in a partition.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct PartitionFileInfo {
-    path: PathBuf,
-    size: u64,
-}
-
-/// Information about a partition to create, including the set of image files which make it up.
+/// Information about a partition to create.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct PartitionInfo {
     label: String,
-    files: Vec<PartitionFileInfo>,
+    path: PathBuf,
     partition_type: ImagePartitionType,
     writable: bool,
+    size: u64,
 }
 
 /// Round `val` up to the next multiple of 2**`align_log`.
@@ -79,7 +73,7 @@
 
 impl PartitionInfo {
     fn aligned_size(&self) -> u64 {
-        align_to_partition_size(self.files.iter().map(|file| file.size).sum())
+        align_to_partition_size(self.size)
     }
 }
 
@@ -172,26 +166,18 @@
 ) -> Result<Vec<ComponentDisk>, Error> {
     let aligned_size = partition.aligned_size();
 
-    if partition.files.is_empty() {
-        bail!("No image files for partition {:?}", partition);
-    }
-    let mut file_size_sum = 0;
-    let mut component_disks = vec![];
-    for file in &partition.files {
-        component_disks.push(ComponentDisk {
-            offset: offset + file_size_sum,
-            file_path: file.path.to_str().context("Invalid partition path")?.to_string(),
-            read_write_capability: if partition.writable {
-                ReadWriteCapability::READ_WRITE
-            } else {
-                ReadWriteCapability::READ_ONLY
-            },
-            ..ComponentDisk::new()
-        });
-        file_size_sum += file.size;
-    }
+    let mut component_disks = vec![ComponentDisk {
+        offset,
+        file_path: partition.path.to_str().context("Invalid partition path")?.to_string(),
+        read_write_capability: if partition.writable {
+            ReadWriteCapability::READ_WRITE
+        } else {
+            ReadWriteCapability::READ_ONLY
+        },
+        ..ComponentDisk::new()
+    }];
 
-    if file_size_sum != aligned_size {
+    if partition.size != aligned_size {
         if partition.writable {
             bail!(
                 "Read-write partition {:?} size is not a multiple of {}.",
@@ -207,7 +193,7 @@
                 1 << PARTITION_SIZE_SHIFT
             );
             component_disks.push(ComponentDisk {
-                offset: offset + file_size_sum,
+                offset: offset + partition.size,
                 file_path: zero_filler_path.to_owned(),
                 read_write_capability: ReadWriteCapability::READ_ONLY,
                 ..ComponentDisk::new()
@@ -348,7 +334,7 @@
     Ok((composite_image, files))
 }
 
-/// Given the AIDL config containing a list of partitions, with [`ParcelFileDescriptor`]s for each
+/// Given the AIDL config containing a list of partitions, with a [`ParcelFileDescriptor`] for each
 /// partition, return the list of file descriptors which must be passed to the composite disk image
 /// partition configuration for it.
 fn convert_partitions(partitions: &[Partition]) -> Result<(Vec<PartitionInfo>, Vec<File>), Error> {
@@ -358,29 +344,24 @@
     let partitions = partitions
         .iter()
         .map(|partition| {
-            let image_files = partition
-                .images
-                .iter()
-                .map(|image| {
-                    let file = image
-                        .as_ref()
-                        .try_clone()
-                        .context("Failed to clone partition image file descriptor")?;
-
-                    let size = get_partition_size(&file)?;
-                    let fd = file.as_raw_fd();
-                    let partition_info_file =
-                        PartitionFileInfo { path: format!("/proc/self/fd/{}", fd).into(), size };
-                    files.push(file);
-                    Ok(partition_info_file)
-                })
-                .collect::<Result<Vec<_>, Error>>()?;
+            // TODO(b/187187765): This shouldn't be an Option.
+            let file = partition
+                .image
+                .as_ref()
+                .context("Invalid partition image file descriptor")?
+                .as_ref()
+                .try_clone()
+                .context("Failed to clone partition image file descriptor")?;
+            let size = get_partition_size(&file)?;
+            let fd = file.as_raw_fd();
+            files.push(file);
 
             Ok(PartitionInfo {
                 label: partition.label.to_owned(),
-                files: image_files,
+                path: format!("/proc/self/fd/{}", fd).into(),
                 partition_type: ImagePartitionType::LinuxFilesystem,
                 writable: partition.writable,
+                size,
             })
         })
         .collect::<Result<_, Error>>()?;
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index a176e71..338e9a2 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -129,7 +129,7 @@
     // put metadata at the first partition
     let mut partitions = vec![Partition {
         label: "payload-metadata".to_owned(),
-        images: vec![metadata_file],
+        image: Some(metadata_file),
         writable: false,
     }];
 
@@ -139,18 +139,18 @@
         let apex_file = open_parcel_file(&apex_path, false)?;
         partitions.push(Partition {
             label: format!("microdroid-apex-{}", i),
-            images: vec![apex_file],
+            image: Some(apex_file),
             writable: false,
         });
     }
     partitions.push(Partition {
         label: "microdroid-apk".to_owned(),
-        images: vec![ParcelFileDescriptor::new(apk_file)],
+        image: Some(ParcelFileDescriptor::new(apk_file)),
         writable: false,
     });
     partitions.push(Partition {
         label: "microdroid-apk-idsig".to_owned(),
-        images: vec![ParcelFileDescriptor::new(idsig_file)],
+        image: Some(ParcelFileDescriptor::new(idsig_file)),
         writable: false,
     });
 
@@ -182,10 +182,10 @@
     if config.debug {
         vm_config.disks[1].partitions.push(Partition {
             label: "bootconfig".to_owned(),
-            images: vec![open_parcel_file(
+            image: Some(open_parcel_file(
                 Path::new("/apex/com.android.virt/etc/microdroid_bootconfig.debug"),
                 false,
-            )?],
+            )?),
             writable: false,
         });
     }
@@ -193,7 +193,7 @@
     // instance image is at the second partition in the second disk.
     vm_config.disks[1].partitions.push(Partition {
         label: "vm-instance".to_owned(),
-        images: vec![ParcelFileDescriptor::new(instance_file)],
+        image: Some(ParcelFileDescriptor::new(instance_file)),
         writable: true,
     });
 
diff --git a/vmconfig/src/lib.rs b/vmconfig/src/lib.rs
index 7739e36..3828742 100644
--- a/vmconfig/src/lib.rs
+++ b/vmconfig/src/lib.rs
@@ -131,8 +131,7 @@
     /// A label for the partition.
     pub label: String,
     /// The filename of the partition image.
-    #[serde(default)]
-    pub paths: Vec<PathBuf>,
+    pub path: PathBuf,
     /// Whether the partition should be writable.
     #[serde(default)]
     pub writable: bool,
@@ -140,15 +139,11 @@
 
 impl Partition {
     fn to_parcelable(&self) -> Result<AidlPartition> {
-        if self.paths.is_empty() {
-            bail!("Partition {} contains no paths", &self.label);
-        }
-        let images = self
-            .paths
-            .iter()
-            .map(|path| open_parcel_file(path, self.writable))
-            .collect::<Result<Vec<_>, _>>()?;
-        Ok(AidlPartition { images, writable: self.writable, label: self.label.to_owned() })
+        Ok(AidlPartition {
+            image: Some(open_parcel_file(&self.path, self.writable)?),
+            writable: self.writable,
+            label: self.label.to_owned(),
+        })
     }
 }