Create full VM DTBO only once under /data/misc/virtualizationservice

Bug: 297103622
Test: adb shell /apex/com.android.virt/bin/vm run-microdroid --devices /sys/bus/platform/devices/16d00000.eh --protected
Change-Id: I4a6e7b7928edb93b6707202a9cc205fcf3994444
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index f5f2718..fa99c63 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -435,7 +435,7 @@
             }
         };
 
-        let devices_dtbo = if !config.devices.is_empty() {
+        if !config.devices.is_empty() {
             let mut set = HashSet::new();
             for device in config.devices.iter() {
                 let path = canonicalize(device)
@@ -446,30 +446,8 @@
                         .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT);
                 }
             }
-            let dtbo_path = temporary_directory.join("dtbo");
-            // open a writable file descriptor for vfio_handler
-            let dtbo = File::create(&dtbo_path).map_err(|e| {
-                error!("Failed to create VM DTBO file {dtbo_path:?}: {e:?}");
-                Status::new_service_specific_error_str(
-                    -1,
-                    Some(format!("Failed to create VM DTBO file {dtbo_path:?}: {e:?}")),
-                )
-            })?;
-            GLOBAL_SERVICE
-                .bindDevicesToVfioDriver(&config.devices, &ParcelFileDescriptor::new(dtbo))?;
-
-            // open (again) a readable file descriptor for crosvm
-            let dtbo = File::open(&dtbo_path).map_err(|e| {
-                error!("Failed to open VM DTBO file {dtbo_path:?}: {e:?}");
-                Status::new_service_specific_error_str(
-                    -1,
-                    Some(format!("Failed to open VM DTBO file {dtbo_path:?}: {e:?}")),
-                )
-            })?;
-            Some(dtbo)
-        } else {
-            None
-        };
+            GLOBAL_SERVICE.bindDevicesToVfioDriver(&config.devices)?;
+        }
 
         // Actually start the VM.
         let crosvm_config = CrosvmConfig {
@@ -495,7 +473,6 @@
             detect_hangup: is_app_config,
             gdb_port,
             vfio_devices: config.devices.iter().map(PathBuf::from).collect(),
-            devices_dtbo,
         };
         let instance = Arc::new(
             VmInstance::new(
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 6372fa8..77dd76f 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -116,7 +116,6 @@
     pub detect_hangup: bool,
     pub gdb_port: Option<NonZeroU16>,
     pub vfio_devices: Vec<PathBuf>,
-    pub devices_dtbo: Option<File>,
 }
 
 /// A disk image to pass to crosvm for a VM.
@@ -719,9 +718,7 @@
     for device in &config.vfio_devices {
         command.arg(vfio_argument_for_platform_device(device)?);
     }
-    if let Some(_dtbo) = &config.devices_dtbo {
-        // TODO(b/291192693): add dtbo to command line
-    }
+    // TODO(b/291192693): add dtbo to command line when assigned device is not empty.
     Ok(())
 }
 
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl
index cb3ed0b..01906cb 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl
@@ -28,7 +28,13 @@
      * Bind given devices to vfio driver.
      *
      * @param devices paths of sysfs nodes of devices to assign.
+     */
+    void bindDevicesToVfioDriver(in String[] devices);
+
+    /**
+     * Store VM DTBO via the file descriptor.
+     *
      * @param dtbo writable file descriptor to store VM DTBO.
      */
-    void bindDevicesToVfioDriver(in String[] devices, in ParcelFileDescriptor dtbo);
+    void writeVmDtbo(in ParcelFileDescriptor dtbo);
 }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
index 9d698ea..62d66c0 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -68,7 +68,6 @@
      * Bind given devices to vfio driver.
      *
      * @param devices paths of sysfs nodes of devices to assign.
-     * @param dtbo writable file descriptor to store VM DTBO.
      */
-    void bindDevicesToVfioDriver(in String[] devices, in ParcelFileDescriptor dtbo);
+    void bindDevicesToVfioDriver(in String[] devices);
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 8586597..6f5a487 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -40,7 +40,7 @@
 use rustutils::system_properties;
 use serde::Deserialize;
 use std::collections::{HashMap, HashSet};
-use std::fs::{self, create_dir, remove_dir_all, set_permissions, Permissions};
+use std::fs::{self, create_dir, remove_dir_all, set_permissions, File, Permissions};
 use std::io::{Read, Write};
 use std::os::unix::fs::PermissionsExt;
 use std::os::unix::raw::{pid_t, uid_t};
@@ -206,17 +206,23 @@
         Ok(ret)
     }
 
-    fn bindDevicesToVfioDriver(
-        &self,
-        devices: &[String],
-        dtbo: &ParcelFileDescriptor,
-    ) -> binder::Result<()> {
+    fn bindDevicesToVfioDriver(&self, devices: &[String]) -> binder::Result<()> {
         check_use_custom_virtual_machine()?;
 
         let vfio_service: Strong<dyn IVfioHandler> =
             wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())?;
 
-        vfio_service.bindDevicesToVfioDriver(devices, dtbo)?;
+        vfio_service.bindDevicesToVfioDriver(devices)?;
+
+        let dtbo_path = Path::new(TEMPORARY_DIRECTORY).join("common").join("dtbo");
+        if !dtbo_path.exists() {
+            // open a writable file descriptor for vfio_handler
+            let dtbo = File::create(&dtbo_path)
+                .context("Failed to create VM DTBO file")
+                .or_service_specific_exception(-1)?;
+            vfio_service.writeVmDtbo(&ParcelFileDescriptor::new(dtbo))?;
+        }
+
         Ok(())
     }
 }
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 3af0d42..18b026d 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -28,8 +28,9 @@
 use anyhow::Error;
 use binder::{register_lazy_service, BinderFeatures, ProcessState, ThreadState};
 use log::{info, Level};
-use std::fs::read_dir;
+use std::fs::{create_dir, read_dir};
 use std::os::unix::raw::{pid_t, uid_t};
+use std::path::Path;
 
 const LOG_TAG: &str = "VirtualizationService";
 
@@ -56,6 +57,9 @@
 
     clear_temporary_files().expect("Failed to delete old temporary files");
 
+    let common_dir_path = Path::new(TEMPORARY_DIRECTORY).join("common");
+    create_dir(common_dir_path).expect("Failed to create common directory");
+
     ProcessState::start_thread_pool();
 
     let service = VirtualizationServiceInternal::init();
diff --git a/virtualizationservice/vfio_handler/src/aidl.rs b/virtualizationservice/vfio_handler/src/aidl.rs
index bb9faf1..1c3c5d9 100644
--- a/virtualizationservice/vfio_handler/src/aidl.rs
+++ b/virtualizationservice/vfio_handler/src/aidl.rs
@@ -41,20 +41,34 @@
 impl Interface for VfioHandler {}
 
 impl IVfioHandler for VfioHandler {
-    fn bindDevicesToVfioDriver(
-        &self,
-        devices: &[String],
-        dtbo: &ParcelFileDescriptor,
-    ) -> binder::Result<()> {
+    fn bindDevicesToVfioDriver(&self, devices: &[String]) -> binder::Result<()> {
         // permission check is already done by IVirtualizationServiceInternal.
         if !*IS_VFIO_SUPPORTED {
             return Err(anyhow!("VFIO-platform not supported"))
                 .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
         }
         devices.iter().try_for_each(|x| bind_device(Path::new(x)))?;
+        Ok(())
+    }
 
-        write_dtbo(dtbo)?;
+    fn writeVmDtbo(&self, dtbo_fd: &ParcelFileDescriptor) -> binder::Result<()> {
+        let dtbo_path = get_dtbo_img_path()?;
+        let mut dtbo_img = File::open(dtbo_path)
+            .context("Failed to open DTBO partition")
+            .or_service_specific_exception(-1)?;
 
+        let dt_table_header = get_dt_table_header(&mut dtbo_img)?;
+        let vm_dtbo_idx = system_properties::read("ro.boot.hypervisor.vm_dtbo_idx")
+            .context("Failed to read vm_dtbo_idx")
+            .or_service_specific_exception(-1)?
+            .ok_or_else(|| anyhow!("vm_dtbo_idx is none"))
+            .or_service_specific_exception(-1)?;
+        let vm_dtbo_idx = vm_dtbo_idx
+            .parse()
+            .context("vm_dtbo_idx is not an integer")
+            .or_service_specific_exception(-1)?;
+        let dt_table_entry = get_dt_table_entry(&mut dtbo_img, &dt_table_header, vm_dtbo_idx)?;
+        write_vm_full_dtbo_from_img(&mut dtbo_img, &dt_table_entry, dtbo_fd)?;
         Ok(())
     }
 }
@@ -254,7 +268,7 @@
     Ok(dt_table_entry)
 }
 
-fn filter_dtbo_from_img(
+fn write_vm_full_dtbo_from_img(
     dtbo_img_file: &mut File,
     entry: &DtTableEntry,
     dtbo_fd: &ParcelFileDescriptor,
@@ -273,31 +287,9 @@
         .context("Failed to clone File from ParcelFileDescriptor")
         .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?;
 
-    // TODO(b/296796644): Filter dtbo.img, not writing all information.
     dtbo_fd
         .write_all(&buffer)
         .context("Failed to write dtbo file")
         .or_service_specific_exception(-1)?;
     Ok(())
 }
-
-fn write_dtbo(dtbo_fd: &ParcelFileDescriptor) -> binder::Result<()> {
-    let dtbo_path = get_dtbo_img_path()?;
-    let mut dtbo_img = File::open(dtbo_path)
-        .context("Failed to open DTBO partition")
-        .or_service_specific_exception(-1)?;
-
-    let dt_table_header = get_dt_table_header(&mut dtbo_img)?;
-    let vm_dtbo_idx = system_properties::read("ro.boot.hypervisor.vm_dtbo_idx")
-        .context("Failed to read vm_dtbo_idx")
-        .or_service_specific_exception(-1)?
-        .ok_or_else(|| anyhow!("vm_dtbo_idx is none"))
-        .or_service_specific_exception(-1)?;
-    let vm_dtbo_idx = vm_dtbo_idx
-        .parse()
-        .context("vm_dtbo_idx is not an integer")
-        .or_service_specific_exception(-1)?;
-    let dt_table_entry = get_dt_table_entry(&mut dtbo_img, &dt_table_header, vm_dtbo_idx)?;
-    filter_dtbo_from_img(&mut dtbo_img, &dt_table_entry, dtbo_fd)?;
-    Ok(())
-}