blob: 6fda878d0705dbdd1735a562a45b162842400fd9 [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 crate::session::FileDescriptorTransportMode;
use binder::{unstable_api::AsNative, SpIBinder};
use binder_rpc_unstable_bindgen::ARpcServer;
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;
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. Only connections from the given CID are accepted.
///
// Set `cid` to libc::VMADDR_CID_ANY to accept connections from any client.
// Set `cid` to libc::VMADDR_CID_LOCAL to only bind to the local vsock interface.
pub fn new_vsock(mut service: SpIBinder, cid: u32, 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, cid, port,
))
}
}
/// Creates a binder RPC server, serving the supplied binder service implementation on the given
/// socket file descriptor. The socket should be bound to an address before calling this
/// function.
pub fn new_bound_socket(
mut service: SpIBinder,
socket_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 socket FD.
unsafe {
Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
service,
socket_fd.into_raw_fd(),
))
}
}
/// 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(),
))
}
}
/// Creates a binder RPC server, serving the supplied binder service implementation on the given
/// IP address and port.
pub fn new_inet(mut service: SpIBinder, address: &str, port: u32) -> Result<RpcServer, Error> {
let address = match CString::new(address) {
Ok(s) => s,
Err(e) => {
log::error!("Cannot convert {} to CString. Error: {:?}", address, 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_newInet(
service,
address.as_ptr(),
port,
))
}
}
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"));
}
// SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
// null.
Ok(unsafe { RpcServer::from_ptr(ptr) })
}
}
impl RpcServerRef {
/// Sets the list of file descriptor transport modes supported by this server.
pub fn set_supported_file_descriptor_transport_modes(
&self,
modes: &[FileDescriptorTransportMode],
) {
// SAFETY: Does not keep the pointer after returning does, nor does it
// read past its boundary. Only passes the 'self' pointer as an opaque handle.
unsafe {
binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
self.as_ptr(),
modes.as_ptr(),
modes.len(),
)
}
}
/// Starts a new background thread and calls join(). Returns immediately.
pub fn start(&self) {
// SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
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) {
// SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
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) -> Result<(), Error> {
// SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
Ok(())
} else {
Err(Error::from(ErrorKind::UnexpectedEof))
}
}
}