use std::any::{Any, TypeId};
use std::collections::HashMap;
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::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::{Arc, Mutex, 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,
pub min_sched_policy: Option<i32>,
pub min_priority: Option<i32>,
pub inherit_rt: 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;
}
if let Some(priority) = self.min_priority {
f |= (priority as u32) & crate::sys::FLAT_BINDER_FLAG_PRIORITY_MASK;
}
if let Some(policy) = self.min_sched_policy {
f |= ((policy as u32) & 0x3) << 9;
}
if self.inherit_rt {
f |= crate::sys::FLAT_BINDER_FLAG_INHERIT_RT;
}
f
}
}
const STABILITY_TAG_LOCAL: u8 = 0;
const STABILITY_TAG_VENDOR: u8 = 1;
const STABILITY_TAG_SYSTEM: u8 = 2;
const STABILITY_TAG_VINTF: u8 = 3;
fn stability_to_tag(s: Stability) -> u8 {
match s {
Stability::Local => STABILITY_TAG_LOCAL,
Stability::Vendor => STABILITY_TAG_VENDOR,
Stability::System => STABILITY_TAG_SYSTEM,
Stability::Vintf => STABILITY_TAG_VINTF,
}
}
fn stability_from_tag(tag: u8) -> Stability {
match tag {
STABILITY_TAG_LOCAL => Stability::Local,
STABILITY_TAG_VENDOR => Stability::Vendor,
STABILITY_TAG_SYSTEM => Stability::System,
STABILITY_TAG_VINTF => Stability::Vintf,
other => unreachable!("invalid stability tag {other}: only 0..=3 are stored"),
}
}
struct Inner<T: Remotable + Send + Sync> {
remotable: T,
stability: AtomicU8,
parceled: AtomicBool,
binder_flags: u32,
strong: RefCounter,
weak: RefCounter,
extension: RwLock<Option<SIBinder>>,
objects: Mutex<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
}
impl<T: Remotable> Inner<T> {
fn set_stability_guarded(&self, level: Stability) -> Result<()> {
if self.parceled.load(Ordering::Acquire) {
return Err(StatusCode::InvalidOperation);
}
self.stability
.store(stability_to_tag(level), Ordering::Relaxed);
Ok(())
}
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 {
stability_from_tag(self.stability.load(Ordering::Relaxed))
}
fn local_binder_flags(&self) -> u32 {
self.binder_flags
}
fn force_downgrade_to_system_stability(&self) -> Result<()> {
self.set_stability_guarded(Stability::System)
}
fn force_downgrade_to_vendor_stability(&self) -> Result<()> {
self.set_stability_guarded(Stability::Vendor)
}
fn mark_vintf(&self) -> Result<()> {
self.set_stability_guarded(Stability::Vintf)
}
fn was_parceled(&self) -> bool {
self.parceled.load(Ordering::Acquire)
}
fn set_parceled(&self) {
self.parceled.store(true, Ordering::Release);
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_transactable(&self) -> Option<&dyn Transactable> {
Some(self)
}
#[cfg(feature = "rpc")]
fn rpc_transact(
&self,
code: TransactionCode,
reader: &mut Parcel,
reply: &mut Parcel,
) -> Result<()> {
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 | START_RECORDING_TRANSACTION => {
log::error!("recording transactions are not supported over RPC");
Err(StatusCode::InvalidOperation)
}
DEBUG_PID_TRANSACTION => {
reply.write::<i32>(&rustix::process::getpid().as_raw_nonzero().get())
}
_ => match self.remotable.on_transact(code, reader, reply) {
Ok(_) => Ok(()),
Err(StatusCode::UnknownTransaction) => {
self.on_transact(code, reader, reply)
}
Err(err) => Err(err),
},
}
}
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: AtomicU8::new(stability_to_tag(stability)),
parceled: AtomicBool::new(false),
binder_flags: features.flat_flags(),
strong: Default::default(),
weak: Default::default(),
extension: RwLock::new(None),
objects: Mutex::new(HashMap::new()),
}),
}
}
pub fn attach_object<O: Any + Send + Sync>(
&self,
object: Arc<O>,
) -> Option<Arc<dyn Any + Send + Sync>> {
let mut map = self.inner.objects.lock().expect("objects lock poisoned");
map.insert(TypeId::of::<O>(), object)
}
pub fn find_object<O: Any + Send + Sync>(&self) -> Option<Arc<O>> {
let map = self.inner.objects.lock().expect("objects lock poisoned");
map.get(&TypeId::of::<O>()).cloned().map(|arc| {
arc.downcast::<O>()
.expect("TypeId-keyed entry must downcast back to its insertion type")
})
}
pub fn detach_object<O: Any + Send + Sync>(&self) -> Option<Arc<O>> {
let mut map = self.inner.objects.lock().expect("objects lock poisoned");
map.remove(&TypeId::of::<O>()).map(|arc| {
arc.downcast::<O>()
.expect("TypeId-keyed entry must downcast back to its insertion type")
})
}
}
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 interface cast 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);
}
use crate::sys::{
FLAT_BINDER_FLAG_INHERIT_RT, FLAT_BINDER_FLAG_PRIORITY_MASK,
FLAT_BINDER_FLAG_SCHED_POLICY_MASK,
};
#[test]
fn flat_binder_flag_inherit_rt_matches_kernel_uapi() {
assert_eq!(FLAT_BINDER_FLAG_INHERIT_RT, 0x800);
}
#[test]
fn flat_binder_flag_sched_policy_mask_matches_kernel_uapi() {
assert_eq!(FLAT_BINDER_FLAG_SCHED_POLICY_MASK, 0x600);
}
#[test]
fn default_features_zero_rt_bits() {
let b = Binder::new(DummyRemotable);
let flags = b.inner.local_binder_flags();
assert_eq!(flags & FLAT_BINDER_FLAG_INHERIT_RT, 0);
assert_eq!(flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK, 0);
assert_eq!(flags & FLAT_BINDER_FLAG_PRIORITY_MASK, 0);
}
#[test]
fn rt_policy_and_priority_encoded_in_canonical_bit_positions() {
let features = BinderFeatures {
min_sched_policy: Some(1), min_priority: Some(42),
..Default::default()
};
let b = Binder::new_with_features(DummyRemotable, features);
let flags = b.inner.local_binder_flags();
assert_eq!(flags & FLAT_BINDER_FLAG_PRIORITY_MASK, 42);
assert_eq!(flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK, 1 << 9);
assert_eq!(flags & FLAT_BINDER_FLAG_INHERIT_RT, 0);
}
#[test]
fn inherit_rt_sets_bit_11_independently_of_policy_field() {
let features = BinderFeatures {
inherit_rt: true,
min_sched_policy: Some(2), min_priority: Some(99),
..Default::default()
};
let b = Binder::new_with_features(DummyRemotable, features);
let flags = b.inner.local_binder_flags();
assert_eq!(flags & FLAT_BINDER_FLAG_INHERIT_RT, 0x800);
assert_eq!(flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK, 2 << 9);
assert_eq!(flags & FLAT_BINDER_FLAG_PRIORITY_MASK, 99);
assert_eq!(0x800 & (2u32 << 9), 0);
assert_eq!(0x800 & 99, 0);
assert_eq!((2u32 << 9) & 99, 0);
}
#[test]
fn out_of_range_priority_is_masked_to_low_byte() {
let features = BinderFeatures {
min_priority: Some(0x1234), ..Default::default()
};
let flags = features.flat_flags();
assert_eq!(flags & FLAT_BINDER_FLAG_PRIORITY_MASK, 0x34);
assert_eq!(flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK, 0);
}
#[test]
fn out_of_range_policy_is_masked_to_two_bits() {
let features = BinderFeatures {
min_sched_policy: Some(0xFF), ..Default::default()
};
let flags = features.flat_flags();
assert_eq!(flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK, 0x600);
assert_eq!(flags & FLAT_BINDER_FLAG_INHERIT_RT, 0);
}
}
#[cfg(test)]
mod stability_mutation_tests {
use super::*;
struct DummyRemotable;
impl crate::Remotable for DummyRemotable {
fn descriptor() -> &'static str
where
Self: Sized,
{
"test.stability_mutation"
}
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_binder_is_system_and_not_parceled() {
let b = Binder::new(DummyRemotable);
assert_eq!(b.inner.stability(), Stability::System);
assert!(!b.inner.was_parceled());
}
#[test]
fn mark_vintf_upgrades_to_vintf() {
let b = Binder::new(DummyRemotable);
b.inner.mark_vintf().expect("not parceled yet");
assert_eq!(b.inner.stability(), Stability::Vintf);
let wire: i32 = b.inner.stability().into();
assert_eq!(wire & 0xFF, 0b111111);
}
#[test]
fn force_downgrade_to_vendor_works_from_system() {
let b = Binder::new(DummyRemotable);
b.inner
.force_downgrade_to_vendor_stability()
.expect("not parceled yet");
assert_eq!(b.inner.stability(), Stability::Vendor);
}
#[test]
fn vintf_then_force_downgrade_to_system() {
let b = Binder::new(DummyRemotable);
b.inner.mark_vintf().unwrap();
b.inner.force_downgrade_to_system_stability().unwrap();
assert_eq!(b.inner.stability(), Stability::System);
}
#[test]
fn parceled_guard_blocks_all_setters() {
let b = Binder::new(DummyRemotable);
b.inner.set_parceled();
assert!(b.inner.was_parceled());
assert_eq!(
b.inner.mark_vintf().unwrap_err(),
StatusCode::InvalidOperation
);
assert_eq!(
b.inner.force_downgrade_to_system_stability().unwrap_err(),
StatusCode::InvalidOperation
);
assert_eq!(
b.inner.force_downgrade_to_vendor_stability().unwrap_err(),
StatusCode::InvalidOperation
);
assert_eq!(b.inner.stability(), Stability::System);
}
#[test]
fn sibinder_delegation_path_round_trips() {
let b = Binder::new(DummyRemotable);
let si = crate::Interface::as_binder(&b);
assert_eq!(si.stability(), Stability::System);
si.mark_vintf().unwrap();
assert_eq!(si.stability(), Stability::Vintf);
si.force_downgrade_to_vendor_stability().unwrap();
assert_eq!(si.stability(), Stability::Vendor);
assert!(!si.was_parceled());
}
#[test]
fn explicit_vintf_construction_is_observable_and_mutable() {
let b = Binder::new_with_stability(DummyRemotable, Stability::Vintf);
assert_eq!(b.inner.stability(), Stability::Vintf);
b.inner.force_downgrade_to_system_stability().unwrap();
assert_eq!(b.inner.stability(), Stability::System);
}
#[test]
fn attach_find_detach_round_trip() {
let b = Binder::new(DummyRemotable);
#[derive(Debug, PartialEq)]
struct Side(u32);
assert!(b.find_object::<Side>().is_none());
assert!(b.attach_object(Arc::new(Side(42))).is_none());
let found = b.find_object::<Side>().expect("attached then found");
assert_eq!(found.0, 42);
let detached = b.detach_object::<Side>().expect("detached returns");
assert_eq!(detached.0, 42);
assert!(b.find_object::<Side>().is_none(), "detach removes entry");
}
#[test]
fn attach_object_replaces_returns_old() {
let b = Binder::new(DummyRemotable);
struct Side(u32);
assert!(b.attach_object(Arc::new(Side(1))).is_none());
let prev = b
.attach_object(Arc::new(Side(2)))
.expect("second attach returns old");
let old: Arc<Side> = prev.downcast::<Side>().expect("type preserved");
assert_eq!(old.0, 1);
assert_eq!(b.find_object::<Side>().unwrap().0, 2);
}
#[test]
fn distinct_types_do_not_collide() {
let b = Binder::new(DummyRemotable);
struct A(u32);
struct B(&'static str);
b.attach_object(Arc::new(A(7)));
b.attach_object(Arc::new(B("hi")));
assert_eq!(b.find_object::<A>().unwrap().0, 7);
assert_eq!(b.find_object::<B>().unwrap().0, "hi");
assert!(b.detach_object::<A>().is_some());
assert!(b.find_object::<A>().is_none());
assert!(b.find_object::<B>().is_some(), "B still attached");
}
#[test]
fn binder_drop_releases_attached_objects() {
struct Probe(#[allow(dead_code)] u32);
let probe = Arc::new(Probe(99));
assert_eq!(Arc::strong_count(&probe), 1);
{
let b = Binder::new(DummyRemotable);
b.attach_object(probe.clone());
assert_eq!(Arc::strong_count(&probe), 2);
}
assert_eq!(
Arc::strong_count(&probe),
1,
"binder drop must release attached arc"
);
}
#[test]
fn sibinder_set_parceled_via_trait_dispatch_flips_guard() {
let b = Binder::new(DummyRemotable);
let si = crate::Interface::as_binder(&b);
assert!(!si.was_parceled());
si.set_parceled();
assert!(si.was_parceled());
assert_eq!(
si.mark_vintf().unwrap_err(),
StatusCode::InvalidOperation,
"mutation after parceled-flip must fail"
);
}
}