[API] Wrap raw binder_rpc_unstable calls in vm_payload

Bug: 243513370
Test: atest MicrodroidTests

Change-Id: Idb1885a7c39080fd21fa6968e8bf062d935317fb
diff --git a/microdroid/vm_payload/Android.bp b/microdroid/vm_payload/Android.bp
index 925928e..dc314ce 100644
--- a/microdroid/vm_payload/Android.bp
+++ b/microdroid/vm_payload/Android.bp
@@ -14,6 +14,7 @@
         "libanyhow",
         "libbinder_rs",
         "liblog_rust",
+        "librpcbinder_rs",
     ],
     apex_available: [
         "com.android.compos",
diff --git a/microdroid/vm_payload/include/vm_payload.h b/microdroid/vm_payload/include/vm_payload.h
index 6e065a5..dc01662 100644
--- a/microdroid/vm_payload/include/vm_payload.h
+++ b/microdroid/vm_payload/include/vm_payload.h
@@ -25,6 +25,9 @@
 extern "C" {
 #endif
 
+struct AIBinder;
+typedef struct AIBinder AIBinder;
+
 /**
  * Notifies the host that the payload is ready.
  *
@@ -33,6 +36,27 @@
 bool AVmPayload_notifyPayloadReady(void);
 
 /**
+ * Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
+ * port.
+ *
+ * If and when the server is ready for connections (it is listening on the port), `on_ready` is
+ * called to allow appropriate action to be taken - e.g. to notify clients that they may now
+ * attempt to connect with `AVmPayload_notifyPayloadReady`.
+ *
+ * The current thread is joined to the binder thread pool to handle incoming messages.
+ *
+ * \param service the service to bind to the given port.
+ * \param port vsock port.
+ * \param on_ready the callback to execute once the server is ready for connections. The callback
+ *                 will be called at most once.
+ * \param param param for the `on_ready` callback.
+ *
+ * \return true if the server has shutdown normally, false if it failed in some way.
+ */
+bool AVmPayload_runVsockRpcServer(AIBinder *service, unsigned int port,
+                                  void (*on_ready)(void *param), void *param);
+
+/**
  * Get a secret that is uniquely bound to this VM instance. The secrets are 32-byte values and the
  * value associated with an identifier will not change over the lifetime of the VM instance.
  *
diff --git a/microdroid/vm_payload/src/vm_payload_service.rs b/microdroid/vm_payload/src/vm_payload_service.rs
index 44013c9..bec4fde 100644
--- a/microdroid/vm_payload/src/vm_payload_service.rs
+++ b/microdroid/vm_payload/src/vm_payload_service.rs
@@ -17,8 +17,10 @@
 use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
     IVmPayloadService, VM_PAYLOAD_SERVICE_NAME};
 use anyhow::{Context, Result};
-use binder::{wait_for_interface, Strong};
+use binder::{wait_for_interface, Strong, unstable_api::{AIBinder, new_spibinder}};
 use log::{error, info, Level};
+use rpcbinder::run_vsock_rpc_server;
+use std::os::raw::c_void;
 
 /// Notifies the host that the payload is ready.
 /// Returns true if the notification succeeds else false.
@@ -42,6 +44,44 @@
     get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
 }
 
+/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
+/// port.
+///
+/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
+/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
+/// attempt to connect.
+///
+/// The current thread is joined to the binder thread pool to handle incoming messages.
+///
+/// Returns true if the server has shutdown normally, false if it failed in some way.
+///
+/// # Safety
+///
+/// The `on_ready` callback is only called inside `run_vsock_rpc_server`, within the lifetime of
+/// `ReadyNotifier` (the last parameter of `run_vsock_rpc_server`). If `on_ready` is called with
+/// wrong param, the callback execution could go wrong.
+#[no_mangle]
+pub unsafe extern "C" fn AVmPayload_runVsockRpcServer(
+    service: *mut AIBinder,
+    port: u32,
+    on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
+    param: *mut c_void,
+) -> bool {
+    // SAFETY: AIBinder returned has correct reference count, and the ownership can
+    // safely be taken by new_spibinder.
+    let service = new_spibinder(service);
+    if let Some(service) = service {
+        run_vsock_rpc_server(service, port, || {
+            if let Some(on_ready) = on_ready {
+                on_ready(param);
+            }
+        })
+    } else {
+        error!("Failed to convert the given service from AIBinder to SpIBinder.");
+        false
+    }
+}
+
 /// Get a secret that is uniquely bound to this VM instance.
 ///
 /// # Safety
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index bb17058..da2c626 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -38,7 +38,6 @@
         "com.android.microdroid.testservice-ndk",
         "libbase",
         "libbinder_ndk",
-        "libbinder_rpc_unstable",
         "MicrodroidTestNativeLibSub",
         "libvm_payload",
     ],
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 5d6ca8b..d57d224 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -30,7 +30,6 @@
 #include <vm_main.h>
 #include <vm_payload.h>
 
-#include <binder_rpc_unstable.hpp>
 #include <string>
 
 using android::base::ErrnoError;
@@ -122,8 +121,8 @@
             abort();
         }
     };
-    if (!RunVsockRpcServerCallback(testService->asBinder().get(), testService->SERVICE_PORT,
-                                   callback, nullptr)) {
+    if (!AVmPayload_runVsockRpcServer(testService->asBinder().get(), testService->SERVICE_PORT,
+                                      callback, nullptr)) {
         return Error() << "RPC Server failed to run";
     }