[rpc_binder] Implement RPC binder over init-managed Unix domain socket
This implements an RPC binder over init-managed Unix domain sockets.
The cl adds binder tests and the new API is also used for
vm_payload_service inside Microdroid.
A previous cl aosp/2229557 sets up the binder over anonymous Unix sockets.
Test: atest MicrodroidTests ComposHostTestCases
Bug: 222479468
Change-Id: I0c7c38f4792c4536f5f88eb7e035091505f782f7
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 5ebc27f..9771cc9 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -20,6 +20,7 @@
"libbinder_rs",
"libdowncast_rs",
"liblibc",
+ "liblog_rust",
],
apex_available: [
"com.android.compos",
diff --git a/libs/binder/rust/rpcbinder/src/client.rs b/libs/binder/rust/rpcbinder/src/client.rs
index 4343ff4..48c787b 100644
--- a/libs/binder/rust/rpcbinder/src/client.rs
+++ b/libs/binder/rust/rpcbinder/src/client.rs
@@ -15,6 +15,7 @@
*/
use binder::{unstable_api::new_spibinder, FromIBinder, SpIBinder, StatusCode, Strong};
+use std::ffi::CString;
use std::os::{
raw::{c_int, c_void},
unix::io::RawFd,
@@ -35,6 +36,27 @@
interface_cast(get_vsock_rpc_service(cid, port))
}
+/// Connects to an RPC Binder server over Unix domain socket.
+pub fn get_unix_domain_rpc_service(socket_name: &str) -> Option<SpIBinder> {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return None;
+ }
+ };
+ // SAFETY: AIBinder returned by UnixDomainRpcClient has correct reference count,
+ // and the ownership can safely be taken by new_spibinder.
+ unsafe { new_spibinder(binder_rpc_unstable_bindgen::UnixDomainRpcClient(socket_name.as_ptr())) }
+}
+
+/// Connects to an RPC Binder server for a particular interface over Unix domain socket.
+pub fn get_unix_domain_rpc_interface<T: FromIBinder + ?Sized>(
+ socket_name: &str,
+) -> Result<Strong<T>, StatusCode> {
+ interface_cast(get_unix_domain_rpc_service(socket_name))
+}
+
/// Connects to an RPC Binder server, using the given callback to get (and take ownership of)
/// file descriptors already connected to it.
pub fn get_preconnected_rpc_service(
diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs
index fb6b90c..89a49a4 100644
--- a/libs/binder/rust/rpcbinder/src/lib.rs
+++ b/libs/binder/rust/rpcbinder/src/lib.rs
@@ -20,7 +20,9 @@
mod server;
pub use client::{
- get_preconnected_rpc_interface, get_preconnected_rpc_service, get_vsock_rpc_interface,
- get_vsock_rpc_service,
+ get_preconnected_rpc_interface, get_preconnected_rpc_service, get_unix_domain_rpc_interface,
+ get_unix_domain_rpc_service, get_vsock_rpc_interface, get_vsock_rpc_service,
};
-pub use server::{run_vsock_rpc_server, run_vsock_rpc_server_with_factory};
+pub use server::{
+ run_init_unix_domain_rpc_server, run_vsock_rpc_server, run_vsock_rpc_server_with_factory,
+};
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index 8009297..b350a13 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -18,7 +18,7 @@
unstable_api::{AIBinder, AsNative},
SpIBinder,
};
-use std::{os::raw, ptr::null_mut};
+use std::{ffi::CString, os::raw, ptr::null_mut};
/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
/// port.
@@ -35,7 +35,28 @@
F: FnOnce(),
{
let mut ready_notifier = ReadyNotifier(Some(on_ready));
- ready_notifier.run_server(service, port)
+ ready_notifier.run_vsock_server(service, port)
+}
+
+/// Runs a binder RPC server, serving the supplied binder service implementation on the given
+/// socket file name. The socket should be initialized in init.rc with the same name.
+///
+/// If and when the server is ready for connections, `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.
+pub fn run_init_unix_domain_rpc_server<F>(
+ service: SpIBinder,
+ socket_name: &str,
+ on_ready: F,
+) -> bool
+where
+ F: FnOnce(),
+{
+ let mut ready_notifier = ReadyNotifier(Some(on_ready));
+ ready_notifier.run_init_unix_domain_server(service, socket_name)
}
struct ReadyNotifier<F>(Option<F>)
@@ -46,7 +67,7 @@
where
F: FnOnce(),
{
- fn run_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
+ fn run_vsock_server(&mut self, mut service: SpIBinder, port: u32) -> bool {
let service = service.as_native_mut();
let param = self.as_void_ptr();
@@ -64,6 +85,31 @@
}
}
+ fn run_init_unix_domain_server(&mut self, mut service: SpIBinder, socket_name: &str) -> bool {
+ let socket_name = match CString::new(socket_name) {
+ Ok(s) => s,
+ Err(e) => {
+ log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
+ return false;
+ }
+ };
+ let service = service.as_native_mut();
+ let param = self.as_void_ptr();
+
+ // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
+ // Plus the binder objects are threadsafe.
+ // RunInitUnixDomainRpcServer does not retain a reference to `ready_callback` or `param`;
+ // it only uses them before it returns, which is during the lifetime of `self`.
+ unsafe {
+ binder_rpc_unstable_bindgen::RunInitUnixDomainRpcServer(
+ service,
+ socket_name.as_ptr(),
+ Some(Self::ready_callback),
+ param,
+ )
+ }
+ }
+
fn as_void_ptr(&mut self) -> *mut raw::c_void {
self as *mut _ as *mut raw::c_void
}