Add a way to add a vendor disk image when launching Microdroid VM

This is a first patch in a series that adds support for "pluggable"
vendor images in Microdroid VMs.

In this patch virtmanager passes the vendor disk image to crosvm
invocation to make it available to guest Micrdroid.

Only callers with USE_CUSTOM_VIRTUAL_MACHINE permission can configure
the vendor image used in Microdroid.

Bug: 285855433
Test: presubmit
Test: vm run-microdroid --vendor /data/local/tmp/test_microdroid_vendor_image.img
Change-Id: I376468d6ef7dd675856f40b1361ca5d8a96cefb5
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 0800f57..d7c2c4d 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -115,6 +115,10 @@
         /// Path to custom kernel image to use when booting Microdroid.
         #[clap(long)]
         kernel: Option<PathBuf>,
+
+        /// Path to disk image containing vendor-specific modules.
+        #[clap(long)]
+        vendor: Option<PathBuf>,
     },
     /// Run a virtual machine with Microdroid inside
     RunMicrodroid {
@@ -179,6 +183,10 @@
         /// Path to custom kernel image to use when booting Microdroid.
         #[clap(long)]
         kernel: Option<PathBuf>,
+
+        /// Path to disk image containing vendor-specific modules.
+        #[clap(long)]
+        vendor: Option<PathBuf>,
     },
     /// Run a virtual machine
     Run {
@@ -299,6 +307,7 @@
             extra_idsigs,
             gdb,
             kernel,
+            vendor,
         } => command_run_app(
             name,
             get_service()?.as_ref(),
@@ -320,6 +329,7 @@
             &extra_idsigs,
             gdb,
             kernel.as_deref(),
+            vendor.as_deref(),
         ),
         Opt::RunMicrodroid {
             name,
@@ -336,6 +346,7 @@
             task_profiles,
             gdb,
             kernel,
+            vendor,
         } => command_run_microdroid(
             name,
             get_service()?.as_ref(),
@@ -352,6 +363,7 @@
             task_profiles,
             gdb,
             kernel.as_deref(),
+            vendor.as_deref(),
         ),
         Opt::Run { name, config, cpu_topology, task_profiles, console, console_in, log, gdb } => {
             command_run(
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 84072ca..64da2d9 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -65,6 +65,7 @@
     extra_idsigs: &[PathBuf],
     gdb: Option<NonZeroU16>,
     kernel: Option<&Path>,
+    vendor: Option<&Path>,
 ) -> Result<(), Error> {
     let apk_file = File::open(apk).context("Failed to open APK file")?;
 
@@ -122,6 +123,8 @@
 
     let kernel = kernel.map(|p| open_parcel_file(p, false)).transpose()?;
 
+    let vendor = vendor.map(|p| open_parcel_file(p, false)).transpose()?;
+
     let extra_idsig_files: Result<Vec<File>, _> = extra_idsigs.iter().map(File::open).collect();
     let extra_idsig_fds = extra_idsig_files?.into_iter().map(ParcelFileDescriptor::new).collect();
 
@@ -144,6 +147,7 @@
         customKernelImage: kernel,
         gdbPort: gdb.map(u16::from).unwrap_or(0) as i32, // 0 means no gdb
         taskProfiles: task_profiles,
+        vendorImage: vendor,
     };
 
     let config = VirtualMachineConfig::AppConfig(VirtualMachineAppConfig {
@@ -203,6 +207,7 @@
     task_profiles: Vec<String>,
     gdb: Option<NonZeroU16>,
     kernel: Option<&Path>,
+    vendor: Option<&Path>,
 ) -> Result<(), Error> {
     let apk = find_empty_payload_apk_path()?;
     println!("found path {}", apk.display());
@@ -236,6 +241,7 @@
         &extra_sig,
         gdb,
         kernel,
+        vendor,
     )
 }