Add a function connecting to vsock to LLNDK libavf

Bug: 381195818
Test: boot cuttlefish
Change-Id: I48f9f8ed7b86c551934523ca7a73c38a2d856e42
diff --git a/libs/libavf/include/android/virtualization.h b/libs/libavf/include/android/virtualization.h
index ac46fca..92528d3 100644
--- a/libs/libavf/include/android/virtualization.h
+++ b/libs/libavf/include/android/virtualization.h
@@ -332,6 +332,19 @@
 int AVirtualMachine_stop(AVirtualMachine* _Nonnull vm) __INTRODUCED_IN(36);
 
 /**
+ * Open a vsock connection to the VM on the given port. The caller takes ownership of the returned
+ * file descriptor, and is responsible for closing the file descriptor.
+ *
+ * This operation is synchronous and `AVirtualMachine_connectVsock` may block.
+ *
+ * \param vm a handle on a virtual machine.
+ * \param port a vsock port number.
+ *
+ * \return If successful, it returns a valid file descriptor. Otherwise, it returns `-EIO`.
+ */
+int AVirtualMachine_connectVsock(AVirtualMachine* _Nonnull vm, uint32_t port) __INTRODUCED_IN(36);
+
+/**
  * Wait until a virtual machine stops or the given timeout elapses.
  *
  * \param vm a handle on a virtual machine.
diff --git a/libs/libavf/libavf.map.txt b/libs/libavf/libavf.map.txt
index 05a5b35..34ab0e5 100644
--- a/libs/libavf/libavf.map.txt
+++ b/libs/libavf/libavf.map.txt
@@ -17,6 +17,7 @@
     AVirtualMachine_createRaw; # apex llndk
     AVirtualMachine_start; # apex llndk
     AVirtualMachine_stop; # apex llndk
+    AVirtualMachine_connectVsock; # apex llndk
     AVirtualMachine_waitForStop; # apex llndk
     AVirtualMachine_destroy; # apex llndk
   local:
diff --git a/libs/libavf/src/lib.rs b/libs/libavf/src/lib.rs
index 1d7861f..c392ab2 100644
--- a/libs/libavf/src/lib.rs
+++ b/libs/libavf/src/lib.rs
@@ -16,7 +16,7 @@
 
 use std::ffi::CStr;
 use std::fs::File;
-use std::os::fd::FromRawFd;
+use std::os::fd::{FromRawFd, IntoRawFd};
 use std::os::raw::{c_char, c_int};
 use std::ptr;
 use std::time::Duration;
@@ -368,6 +368,21 @@
     }
 }
 
+/// Open a vsock connection to the CID of the virtual machine on the given vsock port.
+///
+/// # Safety
+/// `vm` must be a pointer returned by `AVirtualMachine_create`.
+#[no_mangle]
+pub unsafe extern "C" fn AVirtualMachine_connectVsock(vm: *const VmInstance, port: u32) -> c_int {
+    // SAFETY: `vm` is assumed to be a valid, non-null pointer returned by
+    // `AVirtualMachine_createRaw`. It's the only reference to the object.
+    let vm = unsafe { &*vm };
+    match vm.connect_vsock(port) {
+        Ok(pfd) => pfd.into_raw_fd(),
+        Err(_) => -libc::EIO,
+    }
+}
+
 fn death_reason_to_stop_reason(death_reason: DeathReason) -> AVirtualMachineStopReason {
     match death_reason {
         DeathReason::VirtualizationServiceDied => {
diff --git a/libs/libvmclient/src/lib.rs b/libs/libvmclient/src/lib.rs
index c0baea5..8dd3cd3 100644
--- a/libs/libvmclient/src/lib.rs
+++ b/libs/libvmclient/src/lib.rs
@@ -312,6 +312,11 @@
             }
         })
     }
+
+    /// Opens a vsock connection to the CID of the VM on the given vsock port.
+    pub fn connect_vsock(&self, port: u32) -> BinderResult<ParcelFileDescriptor> {
+        self.vm.connectVsock(port as i32)
+    }
 }
 
 impl Debug for VmInstance {