blob: 42f55675428fd3f9f3351fbb76f10a9c70b13194 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use binder::{
unstable_api::{AIBinder, AsNative},
SpIBinder,
};
use binder_rpc_unstable_bindgen::ARpcServer;
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
use std::io::{Error, ErrorKind};
use std::{ffi::CString, os::raw, ptr::null_mut};
foreign_type! {
type CType = binder_rpc_unstable_bindgen::ARpcServer;
fn drop = binder_rpc_unstable_bindgen::ARpcServer_free;
/// A type that represents a foreign instance of RpcServer.
#[derive(Debug)]
pub struct RpcServer;
/// A borrowed RpcServer.
pub struct RpcServerRef;
}
/// SAFETY - The opaque handle can be cloned freely.
unsafe impl Send for RpcServer {}
/// SAFETY - The underlying C++ RpcServer class is thread-safe.
unsafe impl Sync for RpcServer {}
impl RpcServer {
/// Creates a binder RPC server, serving the supplied binder service implementation on the given
/// vsock port.
pub fn new_vsock(mut service: SpIBinder, port: u32) -> 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.
unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newVsock(service, port))
}
}
/// Creates 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.
pub fn new_init_unix_domain(
mut service: SpIBinder,
socket_name: &str,
) -> Result<RpcServer, Error> {
let socket_name = match CString::new(socket_name) {
Ok(s) => s,
Err(e) => {
log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
return Err(Error::from(ErrorKind::InvalidInput));
}
};
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.
unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInitUnixDomain(
service,
socket_name.as_ptr(),
))
}
}
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"));
}
Ok(RpcServer::from_ptr(ptr))
}
}
impl RpcServerRef {
/// Starts a new background thread and calls join(). Returns immediately.
pub fn start(&self) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
}
/// Joins the RpcServer thread. The call blocks until the server terminates.
/// This must be called from exactly one thread.
pub fn join(&self) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
}
/// Shuts down the running RpcServer. Can be called multiple times and from
/// multiple threads. Called automatically during drop().
pub fn shutdown(&self) {
unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) };
}
}
type RpcServerFactoryRef<'a> = &'a mut (dyn FnMut(u32) -> Option<SpIBinder> + Send + Sync);
/// Runs a binder RPC server, using the given factory function to construct a binder service
/// implementation for each connection.
///
/// 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_vsock_rpc_server_with_factory(
port: u32,
mut factory: impl FnMut(u32) -> Option<SpIBinder> + Send + Sync,
) -> bool {
// Double reference the factory because trait objects aren't FFI safe.
// NB: The type annotation is necessary to ensure that we have a `dyn` rather than an `impl`.
let mut factory_ref: RpcServerFactoryRef = &mut factory;
let context = &mut factory_ref as *mut RpcServerFactoryRef as *mut raw::c_void;
// SAFETY: `factory_wrapper` is only ever called by `RunVsockRpcServerWithFactory`, with context
// taking the pointer value above (so a properly aligned non-null pointer to an initialized
// `RpcServerFactoryRef`), within the lifetime of `factory_ref` (i.e. no more calls will be made
// after `RunVsockRpcServerWithFactory` returns).
unsafe {
binder_rpc_unstable_bindgen::RunVsockRpcServerWithFactory(
Some(factory_wrapper),
context,
port,
)
}
}
unsafe extern "C" fn factory_wrapper(cid: u32, context: *mut raw::c_void) -> *mut AIBinder {
// SAFETY: `context` was created from an `&mut RpcServerFactoryRef` by
// `run_vsock_rpc_server_with_factory`, and we are still within the lifetime of the value it is
// pointing to.
let factory_ptr = context as *mut RpcServerFactoryRef;
let factory = factory_ptr.as_mut().unwrap();
if let Some(mut service) = factory(cid) {
service.as_native_mut()
} else {
null_mut()
}
}