use std::any::Any;
use std::fmt::{Debug, Formatter};
use std::mem::ManuallyDrop;
use std::os::fd::IntoRawFd;
use std::sync::atomic::AtomicBool;
use std::sync::{self, Arc, RwLock};
use crate::{
binder::*, binder_object::*, error::*, parcel::*, parcelable::DeserializeOption,
process_state::ProcessState, ref_counter::RefCounter, thread_state,
};
enum ExtensionCache {
NotQueried,
Queried(Option<SIBinder>),
}
pub struct ProxyHandle {
handle: u32,
descriptor: String,
stability: Stability,
obituary_sent: AtomicBool,
recipients: RwLock<Vec<sync::Weak<dyn DeathRecipient>>>,
strong: RefCounter,
weak: RefCounter,
extension: RwLock<ExtensionCache>,
}
impl ProxyHandle {
pub fn new(handle: u32, descriptor: String, stability: Stability) -> Arc<Self> {
Arc::new(Self {
handle,
descriptor,
stability,
obituary_sent: AtomicBool::new(false),
recipients: RwLock::new(Vec::new()),
strong: Default::default(),
weak: Default::default(),
extension: RwLock::new(ExtensionCache::NotQueried),
})
}
pub fn handle(&self) -> u32 {
self.handle
}
pub fn descriptor(&self) -> &str {
&self.descriptor
}
pub fn submit_transact(
&self,
code: TransactionCode,
data: &Parcel,
flags: TransactionFlags,
) -> Result<Option<Parcel>> {
thread_state::transact(self.handle(), code, data, flags)
}
pub fn prepare_transact(&self, write_header: bool) -> Result<Parcel> {
let mut data = Parcel::new();
if write_header {
data.write_interface_token(self.descriptor())?;
}
Ok(data)
}
pub(crate) fn send_obituary(&self, who: &WIBinder) -> Result<()> {
self.obituary_sent
.store(true, std::sync::atomic::Ordering::Relaxed);
let recipients = self.recipients.read().expect("Recipients lock poisoned");
if !recipients.is_empty() {
thread_state::clear_death_notification(self.handle())?;
thread_state::flush_commands()?;
}
let mut recipients_to_remove = Vec::new();
for recipient in recipients.iter() {
if let Some(recipient) = recipient.upgrade() {
recipient.binder_died(who);
} else {
recipients_to_remove.push(recipient.clone());
}
}
drop(recipients);
if !recipients_to_remove.is_empty() {
let mut recipients = self.recipients.write().expect("Recipients lock poisoned");
for recipient in recipients_to_remove {
recipients.retain(|r| !sync::Weak::ptr_eq(r, &recipient));
}
}
Ok(())
}
pub fn dump<F: IntoRawFd>(&self, fd: F, args: &[String]) -> Result<()> {
let mut send = Parcel::new();
let obj = flat_binder_object::new_with_fd(fd.into_raw_fd(), true);
send.write_object(&obj, true)?;
send.write::<i32>(&(args.len() as i32))?;
for arg in args {
send.write(arg)?;
}
self.submit_transact(DUMP_TRANSACTION, &send, FLAG_CLEAR_BUF)?;
Ok(())
}
}
impl Debug for ProxyHandle {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Inner")
.field("handle", &self.handle)
.field("descriptor", &self.descriptor)
.field("stability", &self.stability)
.field("obituary_sent", &self.obituary_sent)
.finish()
}
}
impl PartialEq for ProxyHandle {
fn eq(&self, other: &Self) -> bool {
self.handle() == other.handle()
}
}
impl IBinder for ProxyHandle {
fn get_extension(&self) -> Result<Option<SIBinder>> {
{
let cached = self.extension.read().expect("Extension lock poisoned");
if let ExtensionCache::Queried(ref ext) = *cached {
return Ok(ext.clone());
}
}
let data = Parcel::new();
let ext: Option<SIBinder> = match self.submit_transact(EXTENSION_TRANSACTION, &data, 0) {
Ok(Some(mut reply)) => match DeserializeOption::deserialize_option(&mut reply) {
Ok(ext) => ext,
Err(_) => return Ok(None),
},
_ => return Ok(None),
};
let mut cache = self.extension.write().expect("Extension lock poisoned");
*cache = ExtensionCache::Queried(ext.clone());
Ok(ext)
}
fn set_extension(&self, extension: &SIBinder) -> Result<()> {
let mut ext = self.extension.write().expect("Extension lock poisoned");
*ext = ExtensionCache::Queried(Some(extension.clone()));
Ok(())
}
fn link_to_death(&self, recipient: sync::Weak<dyn DeathRecipient>) -> Result<()> {
if self
.obituary_sent
.load(std::sync::atomic::Ordering::Relaxed)
{
return Err(StatusCode::DeadObject);
} else {
let mut recipients = self.recipients.write().expect("Recipients lock poisoned");
if recipients.is_empty() {
thread_state::request_death_notification(self.handle())?;
thread_state::flush_commands()?;
}
recipients.push(recipient);
}
Ok(())
}
fn unlink_to_death(&self, recipient: sync::Weak<dyn DeathRecipient>) -> Result<()> {
if self
.obituary_sent
.load(std::sync::atomic::Ordering::Relaxed)
{
return Err(StatusCode::DeadObject);
} else {
let mut recipients = self.recipients.write().expect("Recipients lock poisoned");
recipients.retain(|r| !sync::Weak::ptr_eq(r, &recipient));
if recipients.is_empty() {
thread_state::clear_death_notification(self.handle())?;
thread_state::flush_commands()?;
}
}
Ok(())
}
fn ping_binder(&self) -> Result<()> {
thread_state::ping_binder(self.handle())
}
fn stability(&self) -> Stability {
self.stability
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_transactable(&self) -> Option<&dyn Transactable> {
None
}
fn descriptor(&self) -> &str {
self.descriptor()
}
fn is_remote(&self) -> bool {
true
}
fn inc_strong(&self, strong: &SIBinder) -> Result<()> {
self.strong
.inc(|| thread_state::inc_strong_handle(self.handle(), strong.clone()))
}
fn attempt_inc_strong(&self) -> bool {
self.strong.attempt_inc(
false,
|| {
if let Err(err) = thread_state::attempt_inc_strong_handle(self.handle()) {
log::error!("Error in attempt_inc_strong_handle() is {err:?}");
false
} else {
true
}
},
|| {
thread_state::dec_strong_handle(self.handle())
.expect("Failed to decrease the binder strong reference count.");
},
)
}
fn dec_strong(&self, _strong: Option<ManuallyDrop<SIBinder>>) -> Result<()> {
let handle = self.handle;
self.strong.dec(|| {
thread_state::dec_strong_handle(handle)?;
let strong_count = self.strong.count.load(std::sync::atomic::Ordering::Relaxed);
let weak_count = self.weak.count.load(std::sync::atomic::Ordering::Relaxed);
if strong_count == crate::ref_counter::INITIAL_STRONG_VALUE
&& weak_count == crate::ref_counter::INITIAL_STRONG_VALUE
{
ProcessState::as_self().expunge_handle(handle);
}
Ok(())
})
}
fn inc_weak(&self, weak: &WIBinder) -> Result<()> {
self.weak
.inc(|| thread_state::inc_weak_handle(self.handle(), weak))
}
fn dec_weak(&self) -> Result<()> {
let handle = self.handle;
self.weak.dec(|| {
thread_state::dec_weak_handle(handle)?;
let strong_count = self.strong.count.load(std::sync::atomic::Ordering::Relaxed);
let weak_count = self.weak.count.load(std::sync::atomic::Ordering::Relaxed);
if strong_count == crate::ref_counter::INITIAL_STRONG_VALUE
&& weak_count == crate::ref_counter::INITIAL_STRONG_VALUE
{
ProcessState::as_self().expunge_handle(handle);
}
Ok(())
})
}
}
pub trait Proxy: Sized + Interface {
fn descriptor() -> &'static str;
fn from_binder(binder: SIBinder) -> Option<Self>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_proxy_handle() {
let handle = ProxyHandle::new(1, "test".to_string(), Stability::Local);
assert_eq!(handle.handle(), 1);
assert_eq!(handle.descriptor(), "test");
assert!(handle.as_transactable().is_none());
assert!(handle.is_remote());
let debug_str = format!("{handle:?}");
assert_eq!(
debug_str,
"Inner { handle: 1, descriptor: \"test\", stability: Local, obituary_sent: false }"
);
let handle2 = ProxyHandle::new(1, "test".to_string(), Stability::Local);
assert_eq!(handle, handle2);
}
}