Use regular file for VM DTBO

Bug: 287379025
Test: adb shell /apex/com.android.virt/bin/vm run-microdroid \
          --protected --mem 512 --devices \
          /sys/bus/platform/devices/16d00000.eh
Change-Id: Iad237c86ff2d1eca89c03d1b399f52877f24fa9a
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 15e5407..91bd60b 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -474,7 +474,27 @@
                     ));
                 }
             }
-            Some(clone_file(&GLOBAL_SERVICE.bindDevicesToVfioDriver(&config.devices)?)?)
+            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
         };
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl
index 516b7a1..cb3ed0b 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVfioHandler.aidl
@@ -28,7 +28,7 @@
      * Bind given devices to vfio driver.
      *
      * @param devices paths of sysfs nodes of devices to assign.
-     * @return a file descriptor containing DTBO for VM.
+     * @param dtbo writable file descriptor to store VM DTBO.
      */
-    ParcelFileDescriptor bindDevicesToVfioDriver(in String[] devices);
+    void bindDevicesToVfioDriver(in String[] devices, in ParcelFileDescriptor dtbo);
 }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
index 3546355..4c7164a 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -70,7 +70,7 @@
      * Bind given devices to vfio driver.
      *
      * @param devices paths of sysfs nodes of devices to assign.
-     * @return a file descriptor containing DTBO for VM.
+     * @param dtbo writable file descriptor to store VM DTBO.
      */
-    ParcelFileDescriptor bindDevicesToVfioDriver(in String[] devices);
+    void bindDevicesToVfioDriver(in String[] devices, in ParcelFileDescriptor dtbo);
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 384915c..2e667d4 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -183,12 +183,18 @@
         }])
     }
 
-    fn bindDevicesToVfioDriver(&self, devices: &[String]) -> binder::Result<ParcelFileDescriptor> {
+    fn bindDevicesToVfioDriver(
+        &self,
+        devices: &[String],
+        dtbo: &ParcelFileDescriptor,
+    ) -> 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)
+
+        vfio_service.bindDevicesToVfioDriver(devices, dtbo)?;
+        Ok(())
     }
 }
 
diff --git a/virtualizationservice/vfio_handler/src/aidl.rs b/virtualizationservice/vfio_handler/src/aidl.rs
index 9a50fd3..f082aba 100644
--- a/virtualizationservice/vfio_handler/src/aidl.rs
+++ b/virtualizationservice/vfio_handler/src/aidl.rs
@@ -18,11 +18,9 @@
 use android_system_virtualizationservice_internal::binder::ParcelFileDescriptor;
 use binder::{self, ExceptionCode, Interface, Status};
 use lazy_static::lazy_static;
-use std::fs::{read_link, write, File};
-use std::os::fd::FromRawFd;
+use std::fs::{read_link, write};
+use std::io::Write;
 use std::path::Path;
-use nix::fcntl::OFlag;
-use nix::unistd::pipe2;
 
 #[derive(Debug, Default)]
 pub struct VfioHandler {}
@@ -36,7 +34,11 @@
 impl Interface for VfioHandler {}
 
 impl IVfioHandler for VfioHandler {
-    fn bindDevicesToVfioDriver(&self, devices: &[String]) -> binder::Result<ParcelFileDescriptor> {
+    fn bindDevicesToVfioDriver(
+        &self,
+        devices: &[String],
+        dtbo: &ParcelFileDescriptor,
+    ) -> binder::Result<()> {
         // permission check is already done by IVirtualizationServiceInternal.
         if !*IS_VFIO_SUPPORTED {
             return Err(Status::new_exception_str(
@@ -47,19 +49,20 @@
 
         devices.iter().try_for_each(|x| bind_device(Path::new(x)))?;
 
-        // TODO(b/278008182): create a file descriptor containing DTBO for devices.
-        let (raw_read, raw_write) = pipe2(OFlag::O_CLOEXEC).map_err(|e| {
+        let mut dtbo = dtbo.as_ref().try_clone().map_err(|e| {
             Status::new_exception_str(
-                ExceptionCode::SERVICE_SPECIFIC,
-                Some(format!("can't create fd for DTBO: {e:?}")),
+                ExceptionCode::BAD_PARCELABLE,
+                Some(format!("Failed to clone File from ParcelFileDescriptor: {e:?}")),
             )
         })?;
-        // SAFETY: We are the sole owner of this FD as we just created it, and it is valid and open.
-        let read_fd = unsafe { File::from_raw_fd(raw_read) };
-        // SAFETY: We are the sole owner of this FD as we just created it, and it is valid and open.
-        let _write_fd = unsafe { File::from_raw_fd(raw_write) };
-
-        Ok(ParcelFileDescriptor::new(read_fd))
+        // TODO(b/291191362): write DTBO for devices to dtbo.
+        dtbo.write(b"\n").map_err(|e| {
+            Status::new_exception_str(
+                ExceptionCode::BAD_PARCELABLE,
+                Some(format!("Can't write to ParcelFileDescriptor: {e:?}")),
+            )
+        })?;
+        Ok(())
     }
 }
 
@@ -120,13 +123,13 @@
     let Some(device) = path.file_name() else {
         return Err(Status::new_exception_str(
             ExceptionCode::ILLEGAL_ARGUMENT,
-            Some(format!("can't get device name from {path:?}"))
+            Some(format!("can't get device name from {path:?}")),
         ));
     };
     let Some(device_str) = device.to_str() else {
         return Err(Status::new_exception_str(
             ExceptionCode::ILLEGAL_ARGUMENT,
-            Some(format!("invalid filename {device:?}"))
+            Some(format!("invalid filename {device:?}")),
         ));
     };
     write(path.join("driver/unbind"), device_str.as_bytes()).map_err(|e| {