Move log_fd and composite_disks into CrosvmConfig.

Pass values rather than references for various other files, and keep
indirect files open for as long as CrosvmConfig exists.

Bug: 199127239
Test: atest VirtualizationTestCases
Change-Id: I301843a2a4122ba0611d68257da6786826586f9f
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index f89181f..ad89ba5 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -51,7 +51,7 @@
 use std::fs::{File, OpenOptions, create_dir};
 use std::io::{Error, ErrorKind, Write};
 use std::num::NonZeroU32;
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::unix::io::{FromRawFd, IntoRawFd};
 use std::path::{Path, PathBuf};
 use std::sync::{Arc, Mutex, Weak};
 use vmconfig::VmConfig;
@@ -164,20 +164,18 @@
         // Actually start the VM.
         let crosvm_config = CrosvmConfig {
             cid,
-            bootloader: as_asref(&config.bootloader),
-            kernel: as_asref(&config.kernel),
-            initrd: as_asref(&config.initrd),
+            bootloader: maybe_clone_file(&config.bootloader)?,
+            kernel: maybe_clone_file(&config.kernel)?,
+            initrd: maybe_clone_file(&config.initrd)?,
             disks,
             params: config.params.to_owned(),
             protected: config.protectedVm,
             memory_mib: config.memoryMib.try_into().ok().and_then(NonZeroU32::new),
-        };
-        let composite_disk_fds: Vec<_> =
-            indirect_files.iter().map(|file| file.as_raw_fd()).collect();
-        let instance = VmInstance::start(
-            &crosvm_config,
             log_fd,
-            &composite_disk_fds,
+            indirect_files,
+        };
+        let instance = VmInstance::start(
+            crosvm_config,
             temporary_directory,
             requester_uid,
             requester_sid,
@@ -734,11 +732,6 @@
     }
 }
 
-/// Converts an `&Option<T>` to an `Option<U>` where `T` implements `AsRef<U>`.
-fn as_asref<T: AsRef<U>, U>(option: &Option<T>) -> Option<&U> {
-    option.as_ref().map(|t| t.as_ref())
-}
-
 /// Gets the `VirtualMachineState` of the given `VmInstance`.
 fn get_state(instance: &VmInstance) -> VirtualMachineState {
     if instance.running() {
@@ -763,6 +756,11 @@
     })
 }
 
+/// Converts an `&Option<ParcelFileDescriptor>` to an `Option<File>` by cloning the file.
+fn maybe_clone_file(file: &Option<ParcelFileDescriptor>) -> Result<Option<File>, Status> {
+    file.as_ref().map(clone_file).transpose()
+}
+
 /// Converts a `VsockStream` to a `ParcelFileDescriptor`.
 fn vsock_stream_to_pfd(stream: VsockStream) -> ParcelFileDescriptor {
     // SAFETY: ownership is transferred from stream to f
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index abaa955..4b6a351 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -34,15 +34,17 @@
 
 /// Configuration for a VM to run with crosvm.
 #[derive(Debug)]
-pub struct CrosvmConfig<'a> {
+pub struct CrosvmConfig {
     pub cid: Cid,
-    pub bootloader: Option<&'a File>,
-    pub kernel: Option<&'a File>,
-    pub initrd: Option<&'a File>,
+    pub bootloader: Option<File>,
+    pub kernel: Option<File>,
+    pub initrd: Option<File>,
     pub disks: Vec<DiskFile>,
     pub params: Option<String>,
     pub protected: bool,
     pub memory_mib: Option<NonZeroU32>,
+    pub log_fd: Option<File>,
+    pub indirect_files: Vec<File>,
 }
 
 /// A disk image to pass to crosvm for a VM.
@@ -121,19 +123,19 @@
     /// Start an instance of `crosvm` to manage a new VM. The `crosvm` instance will be killed when
     /// the `VmInstance` is dropped.
     pub fn start(
-        config: &CrosvmConfig,
-        log_fd: Option<File>,
-        composite_disk_fds: &[RawFd],
+        config: CrosvmConfig,
         temporary_directory: PathBuf,
         requester_uid: u32,
         requester_sid: String,
         requester_debug_pid: i32,
     ) -> Result<Arc<VmInstance>, Error> {
-        let child = run_vm(config, log_fd, composite_disk_fds)?;
+        let cid = config.cid;
+        let protected = config.protected;
+        let child = run_vm(config)?;
         let instance = Arc::new(VmInstance::new(
             child,
-            config.cid,
-            config.protected,
+            cid,
+            protected,
             temporary_directory,
             requester_uid,
             requester_sid,
@@ -196,13 +198,9 @@
     }
 }
 
-/// Start an instance of `crosvm` to manage a new VM.
-fn run_vm(
-    config: &CrosvmConfig,
-    log_fd: Option<File>,
-    composite_disk_fds: &[RawFd],
-) -> Result<SharedChild, Error> {
-    validate_config(config)?;
+/// Starts an instance of `crosvm` to manage a new VM.
+fn run_vm(config: CrosvmConfig) -> Result<SharedChild, Error> {
+    validate_config(&config)?;
 
     let mut command = Command::new(CROSVM_PATH);
     // TODO(qwandor): Remove --disable-sandbox.
@@ -216,7 +214,7 @@
         command.arg("--mem").arg(memory_mib.to_string());
     }
 
-    if let Some(log_fd) = log_fd {
+    if let Some(log_fd) = config.log_fd {
         command.stdout(log_fd);
     } else {
         // Ignore console output.
@@ -224,7 +222,7 @@
     }
 
     // Keep track of what file descriptors should be mapped to the crosvm process.
-    let mut preserved_fds = composite_disk_fds.to_vec();
+    let mut preserved_fds = config.indirect_files.iter().map(|file| file.as_raw_fd()).collect();
 
     if let Some(bootloader) = &config.bootloader {
         command.arg("--bios").arg(add_preserved_fd(&mut preserved_fds, bootloader));