use std::any::Any;
use std::convert::TryFrom;
use std::fs::File;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::os::fd::FromRawFd;
use std::sync::{Arc, RwLock, Weak};
use crate::{
binder::*, error::*, parcel::*, parcelable::SerializeOption, ref_counter::RefCounter,
thread_state,
};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct BinderFeatures {
pub set_requesting_sid: bool,
}
impl BinderFeatures {
pub(crate) fn flat_flags(self) -> u32 {
let mut f = crate::sys::FLAT_BINDER_FLAG_ACCEPTS_FDS;
if self.set_requesting_sid {
f |= crate::sys::FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
}
f
}
}
struct Inner<T: Remotable + Send + Sync> {
remotable: T,
stability: Stability,
binder_flags: u32,
strong: RefCounter,
weak: RefCounter,
extension: RwLock<Option<SIBinder>>,
}
impl<T: Remotable> Inner<T> {
fn on_transact(
&self,
code: TransactionCode,
_reader: &mut Parcel,
reply: &mut Parcel,
) -> Result<()> {
match code {
INTERFACE_TRANSACTION => reply.write(T::descriptor()),
DUMP_TRANSACTION => {
let obj = _reader.read_object(true)?;
if obj.header_type() != crate::sys::BINDER_TYPE_FD {
return Err(StatusCode::BadType);
}
let fd = obj.handle();
let argc = _reader.read::<i32>()?;
let mut argv = Vec::new();
for _ in 0..argc {
argv.push(_reader.read::<String>()?);
}
let mut file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd as _)) };
self.remotable.on_dump(file.deref_mut(), argv.as_slice())
}
SHELL_COMMAND_TRANSACTION => {
log::error!("SHELL_COMMAND_TRANSACTION is not supported.");
Err(StatusCode::InvalidOperation)
}
SYSPROPS_TRANSACTION => {
log::error!("SYSPROPS_TRANSACTION is not supported.");
Err(StatusCode::InvalidOperation)
}
_ => Err(StatusCode::UnknownTransaction),
}
}
}
impl<T: 'static + Remotable> IBinder for Inner<T> {
fn get_extension(&self) -> Result<Option<SIBinder>> {
Ok(self
.extension
.read()
.expect("Extension lock poisoned")
.clone())
}
fn set_extension(&self, extension: &SIBinder) -> Result<()> {
let mut ext = self.extension.write().expect("Extension lock poisoned");
*ext = Some(extension.clone());
Ok(())
}
fn link_to_death(&self, _recipient: Weak<dyn DeathRecipient>) -> Result<()> {
log::error!("Binder<T> does not support link_to_death.");
Err(StatusCode::InvalidOperation)
}
fn unlink_to_death(&self, _recipient: Weak<dyn DeathRecipient>) -> Result<()> {
log::error!("Binder<T> does not support unlink_to_death.");
Err(StatusCode::InvalidOperation)
}
fn ping_binder(&self) -> Result<()> {
Ok(())
}
fn stability(&self) -> Stability {
self.stability
}
fn local_binder_flags(&self) -> u32 {
self.binder_flags
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_transactable(&self) -> Option<&dyn Transactable> {
Some(self)
}
fn descriptor(&self) -> &str {
T::descriptor()
}
fn is_remote(&self) -> bool {
false
}
fn inc_strong(&self, _strong: &SIBinder) -> Result<()> {
self.strong.inc(|| Ok(()))
}
fn attempt_inc_strong(&self) -> bool {
self.strong.attempt_inc(true, || true, || {})
}
fn dec_strong(&self, strong: Option<ManuallyDrop<SIBinder>>) -> Result<()> {
self.strong.dec(|| {
if let Some(strong) = strong {
let _ = ManuallyDrop::into_inner(strong);
}
Ok(())
})
}
fn inc_weak(&self, _weak: &WIBinder) -> Result<()> {
self.weak.inc(|| Ok(()))
}
fn dec_weak(&self) -> Result<()> {
self.weak.dec(|| Ok(()))
}
}
impl<T: Remotable> Transactable for Inner<T> {
fn transact(
&self,
code: TransactionCode,
reader: &mut Parcel,
reply: &mut Parcel,
) -> Result<()> {
reader.set_data_position(0);
match code {
PING_TRANSACTION => {
Ok(())
}
EXTENSION_TRANSACTION => {
let ext = self.extension.read().expect("Extension lock poisoned");
SerializeOption::serialize_option(ext.as_ref(), reply)?;
Ok(())
}
STOP_RECORDING_TRANSACTION => {
log::error!("STOP_RECORDING_TRANSACTION is not supported.");
Err(StatusCode::InvalidOperation)
}
START_RECORDING_TRANSACTION => {
log::error!("START_RECORDING_TRANSACTION is not supported.");
Err(StatusCode::InvalidOperation)
}
DEBUG_PID_TRANSACTION => {
reply.write::<i32>(&rustix::process::getpid().as_raw_nonzero().get())
}
_ => {
if (FIRST_CALL_TRANSACTION..=LAST_CALL_TRANSACTION).contains(&code)
&& !(thread_state::check_interface(reader, T::descriptor())?)
{
reply.write(&StatusCode::BadType)?;
return Ok(());
}
match self.remotable.on_transact(code, reader, reply) {
Ok(_) => Ok(()),
Err(err) => {
if err == StatusCode::UnknownTransaction {
self.on_transact(code, reader, reply)
} else {
Err(err)
}
}
}
}
}
}
}
pub struct Binder<T: 'static + Remotable + Send + Sync> {
inner: Arc<Inner<T>>,
}
impl<T: 'static + Remotable> Binder<T> {
pub fn new(remotable: T) -> Self {
Self::new_with_stability_and_features(remotable, Default::default(), Default::default())
}
pub fn new_with_features(remotable: T, features: BinderFeatures) -> Self {
Self::new_with_stability_and_features(remotable, Default::default(), features)
}
pub fn new_with_stability(remotable: T, stability: Stability) -> Self {
Self::new_with_stability_and_features(remotable, stability, Default::default())
}
pub fn new_with_stability_and_features(
remotable: T,
stability: Stability,
features: BinderFeatures,
) -> Self {
Binder::<T> {
inner: Arc::new(Inner {
remotable,
stability,
binder_flags: features.flat_flags(),
strong: Default::default(),
weak: Default::default(),
extension: RwLock::new(None),
}),
}
}
}
impl<T: 'static + Remotable> Binder<T> {
pub fn set_extension(&self, extension: &SIBinder) -> Result<()> {
self.inner.set_extension(extension)
}
pub fn get_extension(&self) -> Result<Option<SIBinder>> {
self.inner.get_extension()
}
}
impl<T: 'static + Remotable> Interface for Binder<T> {
fn as_binder(&self) -> SIBinder {
SIBinder::new(self.inner.clone()).unwrap_or_else(|e| {
panic!(
"Failed to create SIBinder for {}. StatusCode({:?})",
T::descriptor(),
e
)
})
}
}
impl<T: Remotable> Clone for Binder<T> {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
impl<T: 'static + Remotable> Deref for Binder<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner.remotable
}
}
impl<B: Remotable + 'static> TryFrom<SIBinder> for Binder<B> {
type Error = StatusCode;
fn try_from(ibinder: SIBinder) -> Result<Self> {
if B::descriptor() != ibinder.descriptor() {
log::error!(
"Binder type mismatch: expected {}, got {}",
B::descriptor(),
ibinder.descriptor()
);
return Err(StatusCode::BadType);
}
if ibinder.as_any().downcast_ref::<Inner<B>>().is_some() {
let arc_dyn = Arc::clone(ibinder.as_arc());
let raw_dyn = Arc::into_raw(arc_dyn);
let inner_raw = raw_dyn as *const Inner<B>;
let inner = unsafe { Arc::from_raw(inner_raw) };
Ok(Self { inner })
} else {
log::error!(
"Downcast failed: expected {}, got {}",
B::descriptor(),
ibinder.descriptor()
);
Err(StatusCode::BadValue)
}
}
}
pub fn is_handling_transaction() -> bool {
thread_state::is_handling_transaction()
}
#[cfg(test)]
mod feature_flags_tests {
use super::*;
use crate::sys::{FLAT_BINDER_FLAG_ACCEPTS_FDS, FLAT_BINDER_FLAG_TXN_SECURITY_CTX};
struct DummyRemotable;
impl crate::Remotable for DummyRemotable {
fn descriptor() -> &'static str
where
Self: Sized,
{
"test.dummy"
}
fn on_transact(
&self,
_: crate::TransactionCode,
_: &mut crate::Parcel,
_: &mut crate::Parcel,
) -> crate::Result<()> {
Ok(())
}
fn on_dump(&self, _: &mut dyn std::io::Write, _: &[String]) -> crate::Result<()> {
Ok(())
}
}
#[test]
fn default_features_set_only_accepts_fds() {
let b = Binder::new(DummyRemotable);
let flags = b.inner.local_binder_flags();
assert_eq!(flags, FLAT_BINDER_FLAG_ACCEPTS_FDS);
assert_eq!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX, 0);
}
#[test]
fn requesting_sid_sets_txn_security_ctx() {
let features = BinderFeatures {
set_requesting_sid: true,
..Default::default()
};
let b = Binder::new_with_features(DummyRemotable, features);
let flags = b.inner.local_binder_flags();
assert_ne!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX, 0);
assert_ne!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS, 0);
}
}