use crate::error::{status_t, Result, StatusCode};
use crate::parcel::{BorrowedParcel, Parcel};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::fs::File;
use std::marker::PhantomData;
use std::ops::Deref;
use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
pub type TransactionCode = u32;
pub type TransactionFlags = u32;
pub trait Interface: Send + Sync {
fn as_binder(&self) -> SpIBinder {
panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
}
fn dump(&self, _file: &File, _args: &[&CStr]) -> Result<()> {
Ok(())
}
}
pub trait ToAsyncInterface<P>
where
Self: Interface,
Self::Target: FromIBinder,
{
type Target: ?Sized;
}
pub trait ToSyncInterface
where
Self: Interface,
Self::Target: FromIBinder,
{
type Target: ?Sized;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Stability {
Local,
Vintf,
}
impl Default for Stability {
fn default() -> Self {
Stability::Local
}
}
impl From<Stability> for i32 {
fn from(stability: Stability) -> i32 {
use Stability::*;
match stability {
Local => 0,
Vintf => 1,
}
}
}
impl TryFrom<i32> for Stability {
type Error = StatusCode;
fn try_from(stability: i32) -> Result<Stability> {
use Stability::*;
match stability {
0 => Ok(Local),
1 => Ok(Vintf),
_ => Err(StatusCode::BAD_VALUE),
}
}
}
pub trait Remotable: Send + Sync {
fn get_descriptor() -> &'static str;
fn on_transact(
&self,
code: TransactionCode,
data: &BorrowedParcel<'_>,
reply: &mut BorrowedParcel<'_>,
) -> Result<()>;
fn on_dump(&self, file: &File, args: &[&CStr]) -> Result<()>;
fn get_class() -> InterfaceClass;
}
pub const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION;
pub const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION;
pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
pub const FLAG_PRIVATE_LOCAL: TransactionFlags = sys::FLAG_PRIVATE_LOCAL;
pub trait IBinderInternal: IBinder {
fn is_binder_alive(&self) -> bool;
#[cfg(not(android_vndk))]
fn set_requesting_sid(&mut self, enable: bool);
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()>;
fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
fn prepare_transact(&self) -> Result<Parcel>;
fn submit_transact(
&self,
code: TransactionCode,
data: Parcel,
flags: TransactionFlags,
) -> Result<Parcel>;
fn transact<F: FnOnce(BorrowedParcel<'_>) -> Result<()>>(
&self,
code: TransactionCode,
flags: TransactionFlags,
input_callback: F,
) -> Result<Parcel> {
let mut parcel = self.prepare_transact()?;
input_callback(parcel.borrowed())?;
self.submit_transact(code, parcel, flags)
}
}
pub trait IBinder {
fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
fn ping_binder(&mut self) -> Result<()>;
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct InterfaceClass(*const sys::AIBinder_Class);
impl InterfaceClass {
pub fn new<I: InterfaceClassMethods>() -> InterfaceClass {
let descriptor = CString::new(I::get_descriptor()).unwrap();
let ptr = unsafe {
let class = sys::AIBinder_Class_define(
descriptor.as_ptr(),
Some(I::on_create),
Some(I::on_destroy),
Some(I::on_transact),
);
if class.is_null() {
panic!("Expected non-null class pointer from AIBinder_Class_define!");
}
sys::AIBinder_Class_setOnDump(class, Some(I::on_dump));
sys::AIBinder_Class_setHandleShellCommand(class, None);
class
};
InterfaceClass(ptr)
}
pub(crate) unsafe fn from_ptr(ptr: *const sys::AIBinder_Class) -> InterfaceClass {
InterfaceClass(ptr)
}
pub fn get_descriptor(&self) -> String {
unsafe {
let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
CStr::from_ptr(raw_descriptor)
.to_str()
.expect("Expected valid UTF-8 string from AIBinder_Class_getDescriptor")
.into()
}
}
}
impl From<InterfaceClass> for *const sys::AIBinder_Class {
fn from(class: InterfaceClass) -> *const sys::AIBinder_Class {
class.0
}
}
pub struct Strong<I: FromIBinder + ?Sized>(Box<I>);
impl<I: FromIBinder + ?Sized> Strong<I> {
pub fn new(binder: Box<I>) -> Self {
Self(binder)
}
pub fn downgrade(this: &Strong<I>) -> Weak<I> {
Weak::new(this)
}
pub fn into_async<P>(self) -> Strong<<I as ToAsyncInterface<P>>::Target>
where
I: ToAsyncInterface<P>,
{
FromIBinder::try_from(self.0.as_binder()).unwrap()
}
pub fn into_sync(self) -> Strong<<I as ToSyncInterface>::Target>
where
I: ToSyncInterface,
{
FromIBinder::try_from(self.0.as_binder()).unwrap()
}
}
impl<I: FromIBinder + ?Sized> Clone for Strong<I> {
fn clone(&self) -> Self {
FromIBinder::try_from(self.0.as_binder()).unwrap()
}
}
impl<I: FromIBinder + ?Sized> Borrow<I> for Strong<I> {
fn borrow(&self) -> &I {
&self.0
}
}
impl<I: FromIBinder + ?Sized> AsRef<I> for Strong<I> {
fn as_ref(&self) -> &I {
&self.0
}
}
impl<I: FromIBinder + ?Sized> Deref for Strong<I> {
type Target = I;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<I: FromIBinder + fmt::Debug + ?Sized> fmt::Debug for Strong<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<I: FromIBinder + ?Sized> Ord for Strong<I> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.as_binder().cmp(&other.0.as_binder())
}
}
impl<I: FromIBinder + ?Sized> PartialOrd for Strong<I> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.as_binder().partial_cmp(&other.0.as_binder())
}
}
impl<I: FromIBinder + ?Sized> PartialEq for Strong<I> {
fn eq(&self, other: &Self) -> bool {
self.0.as_binder().eq(&other.0.as_binder())
}
}
impl<I: FromIBinder + ?Sized> Eq for Strong<I> {}
#[derive(Debug)]
pub struct Weak<I: FromIBinder + ?Sized> {
weak_binder: WpIBinder,
interface_type: PhantomData<I>,
}
impl<I: FromIBinder + ?Sized> Weak<I> {
fn new(binder: &Strong<I>) -> Self {
let weak_binder = binder.as_binder().downgrade();
Weak { weak_binder, interface_type: PhantomData }
}
pub fn upgrade(&self) -> Result<Strong<I>> {
self.weak_binder.promote().ok_or(StatusCode::DEAD_OBJECT).and_then(FromIBinder::try_from)
}
}
impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
fn clone(&self) -> Self {
Self { weak_binder: self.weak_binder.clone(), interface_type: PhantomData }
}
}
impl<I: FromIBinder + ?Sized> Ord for Weak<I> {
fn cmp(&self, other: &Self) -> Ordering {
self.weak_binder.cmp(&other.weak_binder)
}
}
impl<I: FromIBinder + ?Sized> PartialOrd for Weak<I> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.weak_binder.partial_cmp(&other.weak_binder)
}
}
impl<I: FromIBinder + ?Sized> PartialEq for Weak<I> {
fn eq(&self, other: &Self) -> bool {
self.weak_binder == other.weak_binder
}
}
impl<I: FromIBinder + ?Sized> Eq for Weak<I> {}
macro_rules! binder_fn_get_class {
($class:ty) => {
binder_fn_get_class!($crate::binder_impl::InterfaceClass::new::<$class>());
};
($constructor:expr) => {
fn get_class() -> $crate::binder_impl::InterfaceClass {
static CLASS_INIT: std::sync::Once = std::sync::Once::new();
static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
CLASS_INIT.call_once(|| unsafe {
CLASS = Some($constructor);
});
unsafe {
CLASS.unwrap()
}
}
};
}
pub trait InterfaceClassMethods {
fn get_descriptor() -> &'static str
where
Self: Sized;
unsafe extern "C" fn on_create(args: *mut c_void) -> *mut c_void;
unsafe extern "C" fn on_transact(
binder: *mut sys::AIBinder,
code: u32,
data: *const sys::AParcel,
reply: *mut sys::AParcel,
) -> status_t;
unsafe extern "C" fn on_destroy(object: *mut c_void);
unsafe extern "C" fn on_dump(
binder: *mut sys::AIBinder,
fd: i32,
args: *mut *const c_char,
num_args: u32,
) -> status_t;
}
pub trait FromIBinder: Interface {
fn try_from(ibinder: SpIBinder) -> Result<Strong<Self>>;
}
pub unsafe trait AsNative<T> {
fn as_native(&self) -> *const T;
fn as_native_mut(&mut self) -> *mut T;
}
unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> {
fn as_native(&self) -> *const T {
self.as_ref().map_or(ptr::null(), |v| v.as_native())
}
fn as_native_mut(&mut self) -> *mut T {
self.as_mut().map_or(ptr::null_mut(), |v| v.as_native_mut())
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct BinderFeatures {
#[cfg(not(android_vndk))]
pub set_requesting_sid: bool,
#[doc(hidden)]
pub _non_exhaustive: (),
}
#[macro_export]
macro_rules! declare_binder_interface {
{
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident,
$(async: $async_interface:ident,)?
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
$(async: $async_interface,)?
stability: $crate::binder_impl::Stability::default(),
}
}
};
{
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident,
$(async: $async_interface:ident,)?
stability: $stability:expr,
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
$(async: $async_interface,)?
stability: $stability,
}
}
};
{
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
$(async: $async_interface:ident,)?
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {
$($fname: $fty = $finit),*
},
$(async: $async_interface,)?
stability: $crate::binder_impl::Stability::default(),
}
}
};
{
$interface:path[$descriptor:expr] {
native: $native:ident($on_transact:path),
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
$(async: $async_interface:ident,)?
stability: $stability:expr,
}
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
@doc[concat!("A binder [`Remotable`]($crate::binder_impl::Remotable) that holds an [`", stringify!($interface), "`] object.")]
native: $native($on_transact),
@doc[concat!("A binder [`Proxy`]($crate::binder_impl::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
proxy: $proxy {
$($fname: $fty = $finit),*
},
$(async: $async_interface,)?
stability: $stability,
}
}
};
{
$interface:path[$descriptor:expr] {
@doc[$native_doc:expr]
native: $native:ident($on_transact:path),
@doc[$proxy_doc:expr]
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
$( async: $async_interface:ident, )?
stability: $stability:expr,
}
} => {
#[doc = $proxy_doc]
pub struct $proxy {
binder: $crate::SpIBinder,
$($fname: $fty,)*
}
impl $crate::Interface for $proxy {
fn as_binder(&self) -> $crate::SpIBinder {
self.binder.clone()
}
}
impl $crate::binder_impl::Proxy for $proxy
where
$proxy: $interface,
{
fn get_descriptor() -> &'static str {
$descriptor
}
fn from_binder(mut binder: $crate::SpIBinder) -> std::result::Result<Self, $crate::StatusCode> {
Ok(Self { binder, $($fname: $finit),* })
}
}
#[doc = $native_doc]
#[repr(transparent)]
pub struct $native(Box<dyn $interface + Sync + Send + 'static>);
impl $native {
pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
let mut binder = $crate::binder_impl::Binder::new_with_stability($native(Box::new(inner)), $stability);
#[cfg(not(android_vndk))]
$crate::binder_impl::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
$crate::Strong::new(Box::new(binder))
}
}
impl $crate::binder_impl::Remotable for $native {
fn get_descriptor() -> &'static str {
$descriptor
}
fn on_transact(&self, code: $crate::binder_impl::TransactionCode, data: &$crate::binder_impl::BorrowedParcel<'_>, reply: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
match $on_transact(&*self.0, code, data, reply) {
Err($crate::StatusCode::UNEXPECTED_NULL) => {
let status = $crate::Status::new_exception(
$crate::ExceptionCode::NULL_POINTER,
None,
);
reply.write(&status)
},
result => result
}
}
fn on_dump(&self, file: &std::fs::File, args: &[&std::ffi::CStr]) -> std::result::Result<(), $crate::StatusCode> {
self.0.dump(file, args)
}
fn get_class() -> $crate::binder_impl::InterfaceClass {
static CLASS_INIT: std::sync::Once = std::sync::Once::new();
static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
CLASS_INIT.call_once(|| unsafe {
CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>());
});
unsafe {
CLASS.unwrap()
}
}
}
impl $crate::FromIBinder for dyn $interface {
fn try_from(mut ibinder: $crate::SpIBinder) -> std::result::Result<$crate::Strong<dyn $interface>, $crate::StatusCode> {
use $crate::binder_impl::AssociateClass;
let existing_class = ibinder.get_class();
if let Some(class) = existing_class {
if class != <$native as $crate::binder_impl::Remotable>::get_class() &&
class.get_descriptor() == <$native as $crate::binder_impl::Remotable>::get_descriptor()
{
return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
}
if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
std::convert::TryFrom::try_from(ibinder.clone());
if let Ok(service) = service {
return Ok($crate::Strong::new(Box::new(service)));
} else {
return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
}
Err($crate::StatusCode::BAD_TYPE.into())
}
}
impl $crate::binder_impl::Serialize for dyn $interface + '_
where
dyn $interface: $crate::Interface
{
fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
let binder = $crate::Interface::as_binder(self);
parcel.write(&binder)
}
}
impl $crate::binder_impl::SerializeOption for dyn $interface + '_ {
fn serialize_option(this: Option<&Self>, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
parcel.write(&this.map($crate::Interface::as_binder))
}
}
impl std::fmt::Debug for dyn $interface + '_ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.pad(stringify!($interface))
}
}
impl std::borrow::ToOwned for dyn $interface {
type Owned = $crate::Strong<dyn $interface>;
fn to_owned(&self) -> Self::Owned {
self.as_binder().into_interface()
.expect(concat!("Error cloning interface ", stringify!($interface)))
}
}
$(
impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
fn try_from(mut ibinder: $crate::SpIBinder) -> std::result::Result<$crate::Strong<dyn $async_interface<P>>, $crate::StatusCode> {
use $crate::binder_impl::AssociateClass;
let existing_class = ibinder.get_class();
if let Some(class) = existing_class {
if class != <$native as $crate::binder_impl::Remotable>::get_class() &&
class.get_descriptor() == <$native as $crate::binder_impl::Remotable>::get_descriptor()
{
return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
}
if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
std::convert::TryFrom::try_from(ibinder.clone());
if let Ok(service) = service {
todo!()
} else {
return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
}
}
Err($crate::StatusCode::BAD_TYPE.into())
}
}
impl<P: $crate::BinderAsyncPool> $crate::binder_impl::Serialize for dyn $async_interface<P> + '_ {
fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
let binder = $crate::Interface::as_binder(self);
parcel.write(&binder)
}
}
impl<P: $crate::BinderAsyncPool> $crate::binder_impl::SerializeOption for dyn $async_interface<P> + '_ {
fn serialize_option(this: Option<&Self>, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
parcel.write(&this.map($crate::Interface::as_binder))
}
}
impl<P: $crate::BinderAsyncPool> std::fmt::Debug for dyn $async_interface<P> + '_ {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.pad(stringify!($async_interface))
}
}
impl<P: $crate::BinderAsyncPool> std::borrow::ToOwned for dyn $async_interface<P> {
type Owned = $crate::Strong<dyn $async_interface<P>>;
fn to_owned(&self) -> Self::Owned {
self.as_binder().into_interface()
.expect(concat!("Error cloning interface ", stringify!($async_interface)))
}
}
impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToAsyncInterface<P> for dyn $interface {
type Target = dyn $async_interface<P>;
}
impl<P: $crate::BinderAsyncPool> $crate::binder_impl::ToSyncInterface for dyn $async_interface<P> {
type Target = dyn $interface;
}
)?
};
}
#[macro_export]
macro_rules! declare_binder_enum {
{
$( #[$attr:meta] )*
$enum:ident : [$backing:ty; $size:expr] {
$( $( #[$value_attr:meta] )* $name:ident = $value:expr, )*
}
} => {
$( #[$attr] )*
#[derive(Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub struct $enum(pub $backing);
impl $enum {
$( $( #[$value_attr] )* #[allow(missing_docs)] pub const $name: Self = Self($value); )*
#[inline(always)]
#[allow(missing_docs)]
pub const fn enum_values() -> [Self; $size] {
[$(Self::$name),*]
}
}
impl std::fmt::Debug for $enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
$($value => f.write_str(stringify!($name)),)*
_ => f.write_fmt(format_args!("{}", self.0))
}
}
}
impl $crate::binder_impl::Serialize for $enum {
fn serialize(&self, parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
parcel.write(&self.0)
}
}
impl $crate::binder_impl::SerializeArray for $enum {
fn serialize_array(slice: &[Self], parcel: &mut $crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<(), $crate::StatusCode> {
let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
<$backing as $crate::binder_impl::SerializeArray>::serialize_array(&v[..], parcel)
}
}
impl $crate::binder_impl::Deserialize for $enum {
fn deserialize(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Self, $crate::StatusCode> {
parcel.read().map(Self)
}
}
impl $crate::binder_impl::DeserializeArray for $enum {
fn deserialize_array(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Option<Vec<Self>>, $crate::StatusCode> {
let v: Option<Vec<$backing>> =
<$backing as $crate::binder_impl::DeserializeArray>::deserialize_array(parcel)?;
Ok(v.map(|v| v.into_iter().map(Self).collect()))
}
}
};
}