rpc_binder: Create C/Rust bindings for bootstrap UDS

Add bindings for running a UnixDomainSocketBootstrap server/client to
libbinder_rpc_unstable and the librpcbinder Rust wrapper.

Bug: 250685929
Test: builds
Change-Id: I6a38f3fb055401dfacdd67c843b22f3738938a20
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index f3b5fa0..311db2e 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -47,6 +47,16 @@
 // could not be started.
 [[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name);
 
+// Starts an RPC server that bootstraps sessions using an existing Unix domain
+// socket pair, with a given root IBinder object.
+// Callers should create a pair of SOCK_STREAM Unix domain sockets, pass one to
+// this function and the other to UnixDomainBootstrapClient(). Multiple client
+// session can be created from the client end of the pair.
+// Does not take ownership of `service`.
+// Returns an opaque handle to the running server instance, or null if the server
+// could not be started.
+[[nodiscard]] ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd);
+
 // Sets the list of supported file descriptor transport modes of this RPC server.
 void ARpcServer_setSupportedFileDescriptorTransportModes(
         ARpcServer* handle,
@@ -83,6 +93,11 @@
 // Returns the root Binder object of the server.
 AIBinder* ARpcSession_setupUnixDomainClient(ARpcSession* session, const char* name);
 
+// Connects to an RPC server over the given bootstrap Unix domain socket.
+// Does NOT take ownership of `bootstrapFd`.
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* session,
+                                                     int bootstrapFd);
+
 // Connects to an RPC server with preconnected file descriptors.
 //
 // requestFd should connect to the server and return a valid file descriptor, or
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 8dd9a87..8886f7d 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -121,6 +121,23 @@
     return createObjectHandle<ARpcServer>(server);
 }
 
+ARpcServer* ARpcServer_newUnixDomainBootstrap(AIBinder* service, int bootstrapFd) {
+    auto server = RpcServer::make();
+    auto fd = unique_fd(bootstrapFd);
+    if (!fd.ok()) {
+        LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+        return nullptr;
+    }
+    if (status_t status = server->setupUnixDomainSocketBootstrapServer(std::move(fd));
+        status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC server with bootstrap fd " << bootstrapFd
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    server->setRootObject(AIBinder_toPlatformBinder(service));
+    return createObjectHandle<ARpcServer>(server);
+}
+
 void ARpcServer_setSupportedFileDescriptorTransportModes(
         ARpcServer* handle, const ARpcSession_FileDescriptorTransportMode modes[],
         size_t modes_len) {
@@ -179,6 +196,22 @@
     return AIBinder_fromPlatformBinder(session->getRootObject());
 }
 
+AIBinder* ARpcSession_setupUnixDomainBootstrapClient(ARpcSession* handle, int bootstrapFd) {
+    auto session = handleToStrongPointer<RpcSession>(handle);
+    auto fd = unique_fd(dup(bootstrapFd));
+    if (!fd.ok()) {
+        LOG(ERROR) << "Invalid bootstrap fd " << bootstrapFd;
+        return nullptr;
+    }
+    if (status_t status = session->setupUnixDomainSocketBootstrapClient(std::move(fd));
+        status != OK) {
+        LOG(ERROR) << "Failed to set up Unix Domain RPC client with bootstrap fd: " << bootstrapFd
+                   << " error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    return AIBinder_fromPlatformBinder(session->getRootObject());
+}
+
 AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param),
                                               void* param) {
     auto session = handleToStrongPointer<RpcSession>(handle);
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 242cb71..73a2aa2 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -20,6 +20,7 @@
 use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
 use std::ffi::CString;
 use std::io::{Error, ErrorKind};
+use std::os::unix::io::{IntoRawFd, OwnedFd};
 
 foreign_type! {
     type CType = binder_rpc_unstable_bindgen::ARpcServer;
@@ -80,6 +81,27 @@
         }
     }
 
+    /// Creates a binder RPC server that bootstraps sessions using an existing Unix domain socket
+    /// pair, with a given root IBinder object. Callers should create a pair of SOCK_STREAM Unix
+    /// domain sockets, pass one to the server and the other to the client. Multiple client session
+    /// can be created from the client end of the pair.
+    pub fn new_unix_domain_bootstrap(
+        mut service: SpIBinder,
+        bootstrap_fd: OwnedFd,
+    ) -> Result<RpcServer, Error> {
+        let service = service.as_native_mut();
+
+        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+        // Plus the binder objects are threadsafe.
+        // The server takes ownership of the bootstrap FD.
+        unsafe {
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newUnixDomainBootstrap(
+                service,
+                bootstrap_fd.into_raw_fd(),
+            ))
+        }
+    }
+
     unsafe fn checked_from_ptr(ptr: *mut ARpcServer) -> Result<RpcServer, Error> {
         if ptr.is_null() {
             return Err(Error::new(ErrorKind::Other, "Failed to start server"));
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
index b5e11c2..62fedb1 100644
--- a/libs/binder/rust/rpcbinder/src/session.rs
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -20,7 +20,7 @@
 use std::ffi::CString;
 use std::os::{
     raw::{c_int, c_void},
-    unix::io::RawFd,
+    unix::io::{AsRawFd, BorrowedFd, RawFd},
 };
 
 pub use binder_rpc_unstable_bindgen::ARpcSession_FileDescriptorTransportMode as FileDescriptorTransportMode;
@@ -126,6 +126,24 @@
         Self::get_interface(service)
     }
 
+    /// Connects to an RPC Binder server over a bootstrap Unix Domain Socket
+    /// for a particular interface.
+    pub fn setup_unix_domain_bootstrap_client<T: FromIBinder + ?Sized>(
+        &self,
+        bootstrap_fd: BorrowedFd,
+    ) -> Result<Strong<T>, StatusCode> {
+        // SAFETY: ARpcSession_setupUnixDomainBootstrapClient does not take
+        // ownership of bootstrap_fd. The returned AIBinder has correct
+        // reference count, and the ownership can safely be taken by new_spibinder.
+        let service = unsafe {
+            new_spibinder(binder_rpc_unstable_bindgen::ARpcSession_setupUnixDomainBootstrapClient(
+                self.as_ptr(),
+                bootstrap_fd.as_raw_fd(),
+            ))
+        };
+        Self::get_interface(service)
+    }
+
     /// Connects to an RPC Binder server, using the given callback to get (and
     /// take ownership of) file descriptors already connected to it.
     pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(