blob: 50aa33664188379ac9a4d4ea5861fddf075ec4da [file] [log] [blame]
/*
* Copyright (C) 2024 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::binder::AsNative;
use crate::error::{status_result, Result};
use crate::proxy::SpIBinder;
use crate::sys;
use std::ffi::{c_void, CStr, CString};
use std::os::raw::c_char;
use libc::{sockaddr, sockaddr_un, sockaddr_vm, socklen_t};
use std::boxed::Box;
use std::{mem, ptr};
/// Rust wrapper around ABinderRpc_Accessor objects for RPC binder service management.
///
/// Dropping the `Accessor` will drop the underlying object and the binder it owns.
#[derive(Debug)]
pub struct Accessor {
accessor: *mut sys::ABinderRpc_Accessor,
}
/// Socket connection info required for libbinder to connect to a service.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectionInfo {
/// For vsock connection
Vsock(sockaddr_vm),
/// For unix domain socket connection
Unix(sockaddr_un),
}
/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is
/// `Sync` and `Send`. As
/// `ABinderRpc_Accessor` is threadsafe, this structure is too.
/// The Fn owned the Accessor has `Sync` and `Send` properties
unsafe impl Send for Accessor {}
/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is
/// `Sync` and `Send`. As `ABinderRpc_Accessor` is threadsafe, this structure is too.
/// The Fn owned the Accessor has `Sync` and `Send` properties
unsafe impl Sync for Accessor {}
impl Accessor {
/// Create a new accessor that will call the given callback when its
/// connection info is required.
/// The callback object and all objects it captures are owned by the Accessor
/// and will be deleted some time after the Accessor is Dropped. If the callback
/// is being called when the Accessor is Dropped, the callback will not be deleted
/// immediately.
pub fn new<F>(instance: &str, callback: F) -> Accessor
where
F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
{
let callback: *mut c_void = Box::into_raw(Box::new(callback)) as *mut c_void;
let inst = CString::new(instance).unwrap();
// Safety: The function pointer is a valid connection_info callback.
// This call returns an owned `ABinderRpc_Accessor` pointer which
// must be destroyed via `ABinderRpc_Accessor_delete` when no longer
// needed.
// When the underlying ABinderRpc_Accessor is deleted, it will call
// the cookie_decr_refcount callback to release its strong ref.
let accessor = unsafe {
sys::ABinderRpc_Accessor_new(
inst.as_ptr(),
Some(Self::connection_info::<F>),
callback,
Some(Self::cookie_decr_refcount::<F>),
)
};
Accessor { accessor }
}
/// Creates a new Accessor instance based on an existing Accessor's binder.
/// This is useful when the Accessor instance is hosted in another process
/// that has the permissions to create the socket connection FD.
///
/// The `instance` argument must match the instance that the original Accessor
/// is responsible for.
/// `instance` must not contain null bytes and is used to create a CString to
/// pass through FFI.
/// The `binder` argument must be a valid binder from an Accessor
pub fn from_binder(instance: &str, binder: SpIBinder) -> Option<Accessor> {
let inst = CString::new(instance).unwrap();
// Safety: All `SpIBinder` objects (the `binder` argument) hold a valid pointer
// to an `AIBinder` that is guaranteed to remain valid for the lifetime of the
// SpIBinder. `ABinderRpc_Accessor_fromBinder` creates a new pointer to that binder
// that it is responsible for.
// The `inst` argument is a new CString that will copied by
// `ABinderRpc_Accessor_fromBinder` and not modified.
let accessor =
unsafe { sys::ABinderRpc_Accessor_fromBinder(inst.as_ptr(), binder.as_raw()) };
if accessor.is_null() {
return None;
}
Some(Accessor { accessor })
}
/// Get the underlying binder for this Accessor for when it needs to be either
/// registered with service manager or sent to another process.
pub fn as_binder(&self) -> Option<SpIBinder> {
// Safety: `ABinderRpc_Accessor_asBinder` returns either a null pointer or a
// valid pointer to an owned `AIBinder`. Either of these values is safe to
// pass to `SpIBinder::from_raw`.
unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) }
}
/// Release the underlying ABinderRpc_Accessor pointer for use with the ndk API
/// This gives up ownership of the ABinderRpc_Accessor and it is the responsibility of
/// the caller to delete it with ABinderRpc_Accessor_delete
///
/// # Safety
///
/// - The returned `ABinderRpc_Accessor` pointer is now owned by the caller, who must
/// call `ABinderRpc_Accessor_delete` to delete the object.
/// - This `Accessor` object is now useless after `release` so it can be dropped.
unsafe fn release(mut self) -> *mut sys::ABinderRpc_Accessor {
if self.accessor.is_null() {
log::error!("Attempting to release an Accessor that was already released");
return ptr::null_mut();
}
let ptr = self.accessor;
self.accessor = ptr::null_mut();
ptr
}
/// Callback invoked from C++ when the connection info is needed.
///
/// # Safety
///
/// - The `instance` parameter must be a non-null pointer to a valid C string for
/// CStr::from_ptr. The memory must contain a valid null terminator at the end of
/// the string within isize::MAX from the pointer. The memory must not be mutated for
/// the duration of this function call and must be valid for reads from the pointer
/// to the null terminator.
/// - The `cookie` parameter must be the cookie for a `Box<F>` and
/// the caller must hold a ref-count to it.
unsafe extern "C" fn connection_info<F>(
instance: *const c_char,
cookie: *mut c_void,
) -> *mut binder_ndk_sys::ABinderRpc_ConnectionInfo
where
F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
{
if cookie.is_null() || instance.is_null() {
log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!");
return ptr::null_mut();
}
// Safety: The caller promises that `cookie` is for a Box<F>.
let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
// Safety: The caller in libbinder_ndk will have already verified this is a valid
// C string
let inst = unsafe {
match CStr::from_ptr(instance).to_str() {
Ok(s) => s,
Err(err) => {
log::error!("Failed to get a valid C string! {err:?}");
return ptr::null_mut();
}
}
};
let connection = match callback(inst) {
Some(con) => con,
None => {
return ptr::null_mut();
}
};
match connection {
ConnectionInfo::Vsock(addr) => {
// Safety: The sockaddr is being copied in the NDK API
unsafe {
sys::ABinderRpc_ConnectionInfo_new(
&addr as *const sockaddr_vm as *const sockaddr,
mem::size_of::<sockaddr_vm>() as socklen_t,
)
}
}
ConnectionInfo::Unix(addr) => {
// Safety: The sockaddr is being copied in the NDK API
// The cast is from sockaddr_un* to sockaddr*.
unsafe {
sys::ABinderRpc_ConnectionInfo_new(
&addr as *const sockaddr_un as *const sockaddr,
mem::size_of::<sockaddr_un>() as socklen_t,
)
}
}
}
}
/// Callback that drops the `Box<F>`.
/// This is invoked from C++ when a binder is unlinked.
///
/// # Safety
///
/// - The `cookie` parameter must be the cookie for a `Box<F>` and
/// the owner must give up a ref-count to it.
unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
where
F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
{
// Safety: The caller promises that `cookie` is for a Box<F>.
unsafe { std::mem::drop(Box::from_raw(cookie as *mut F)) };
}
}
impl Drop for Accessor {
fn drop(&mut self) {
if self.accessor.is_null() {
// This Accessor was already released.
return;
}
// Safety: `self.accessor` is always a valid, owned
// `ABinderRpc_Accessor` pointer returned by
// `ABinderRpc_Accessor_new` when `self` was created. This delete
// method can only be called once when `self` is dropped.
unsafe {
sys::ABinderRpc_Accessor_delete(self.accessor);
}
}
}
/// Register a new service with the default service manager.
///
/// Registers the given binder object with the given identifier. If successful,
/// this service can then be retrieved using that identifier.
///
/// This function will panic if the identifier contains a 0 byte (NUL).
pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder> {
let instance = CString::new(name).unwrap();
let mut delegator = ptr::null_mut();
let status =
// Safety: `AServiceManager_addService` expects valid `AIBinder` and C
// string pointers. Caller retains ownership of both pointers.
// `AServiceManager_addService` creates a new strong reference and copies
// the string, so both pointers need only be valid until the call returns.
unsafe { sys::ABinderRpc_Accessor_delegateAccessor(instance.as_ptr(),
binder.as_native_mut(), &mut delegator) };
status_result(status)?;
// Safety: `delegator` is either null or a valid, owned pointer at this
// point, so can be safely passed to `SpIBinder::from_raw`.
Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") })
}
/// Rust wrapper around ABinderRpc_AccessorProvider objects for RPC binder service management.
///
/// Dropping the `AccessorProvider` will drop/unregister the underlying object.
#[derive(Debug)]
pub struct AccessorProvider {
accessor_provider: *mut sys::ABinderRpc_AccessorProvider,
}
/// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is
/// `Sync` and `Send`. As
/// `ABinderRpc_AccessorProvider` is threadsafe, this structure is too.
/// The Fn owned the AccessorProvider has `Sync` and `Send` properties
unsafe impl Send for AccessorProvider {}
/// Safety: A `AccessorProvider` is a wrapper around `ABinderRpc_AccessorProvider` which is
/// `Sync` and `Send`. As `ABinderRpc_AccessorProvider` is threadsafe, this structure is too.
/// The Fn owned the AccessorProvider has `Sync` and `Send` properties
unsafe impl Sync for AccessorProvider {}
impl AccessorProvider {
/// Create a new `AccessorProvider` that will give libbinder `Accessors` in order to
/// connect to binder services over sockets.
///
/// `instances` is a list of all instances that this `AccessorProvider` is responsible for.
/// It is declaring these instances as available to this process and will return
/// `Accessor` objects for them when libbinder calls the `provider` callback.
/// `provider` is the callback that libbinder will call when a service is being requested.
/// The callback takes a `&str` argument representing the service that is being requested.
/// See the `ABinderRpc_AccessorProvider_getAccessorCallback` for the C++ equivalent.
pub fn new<F>(instances: &[String], provider: F) -> Option<AccessorProvider>
where
F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
{
let callback: *mut c_void = Box::into_raw(Box::new(provider)) as *mut c_void;
let c_str_instances: Vec<CString> =
instances.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect();
let mut c_instances: Vec<*const c_char> =
c_str_instances.iter().map(|s| s.as_ptr()).collect();
let num_instances: usize = c_instances.len();
// Safety:
// - The function pointer for the first argument is a valid `get_accessor` callback.
// - This call returns an owned `ABinderRpc_AccessorProvider` pointer which
// must be destroyed via `ABinderRpc_unregisterAccessorProvider` when no longer
// needed.
// - When the underlying ABinderRpc_AccessorProvider is deleted, it will call
// the `cookie_decr_refcount` callback on the `callback` pointer to release its
// strong ref.
// - The `c_instances` vector is not modified by the function
let accessor_provider = unsafe {
sys::ABinderRpc_registerAccessorProvider(
Some(Self::get_accessor::<F>),
c_instances.as_mut_ptr(),
num_instances,
callback,
Some(Self::accessor_cookie_decr_refcount::<F>),
)
};
if accessor_provider.is_null() {
return None;
}
Some(AccessorProvider { accessor_provider })
}
/// Callback invoked from C++ when an Accessor is needed.
///
/// # Safety
///
/// - libbinder guarantees the `instance` argument is a valid C string if it's not null.
/// - The `cookie` pointer is same pointer that we pass to ABinderRpc_registerAccessorProvider
/// in AccessorProvider.new() which is the closure that we will delete with
/// self.accessor_cookie_decr_refcount when unregistering the AccessorProvider.
unsafe extern "C" fn get_accessor<F>(
instance: *const c_char,
cookie: *mut c_void,
) -> *mut binder_ndk_sys::ABinderRpc_Accessor
where
F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
{
if cookie.is_null() || instance.is_null() {
log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!");
return ptr::null_mut();
}
// Safety: The caller promises that `cookie` is for a Box<F>.
let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
let inst = {
// Safety: The caller in libbinder_ndk will have already verified this is a valid
// C string
match unsafe { CStr::from_ptr(instance) }.to_str() {
Ok(s) => s,
Err(err) => {
log::error!("Failed to get a valid C string! {err:?}");
return ptr::null_mut();
}
}
};
match callback(inst) {
Some(a) => {
// Safety: This is giving up ownership of this ABinderRpc_Accessor
// to the caller of this function (libbinder) and it is responsible
// for deleting it.
unsafe { a.release() }
}
None => ptr::null_mut(),
}
}
/// Callback that decrements the ref-count.
/// This is invoked from C++ when the provider is unregistered.
///
/// # Safety
///
/// - The `cookie` parameter must be the cookie for a `Box<F>` and
/// the owner must give up a ref-count to it.
unsafe extern "C" fn accessor_cookie_decr_refcount<F>(cookie: *mut c_void)
where
F: Fn(&str) -> Option<Accessor> + Send + Sync + 'static,
{
// Safety: The caller promises that `cookie` is for a Box<F>.
unsafe { std::mem::drop(Box::from_raw(cookie as *mut F)) };
}
}
impl Drop for AccessorProvider {
fn drop(&mut self) {
// Safety: `self.accessor_provider` is always a valid, owned
// `ABinderRpc_AccessorProvider` pointer returned by
// `ABinderRpc_registerAccessorProvider` when `self` was created. This delete
// method can only be called once when `self` is dropped.
unsafe {
sys::ABinderRpc_unregisterAccessorProvider(self.accessor_provider);
}
}
}