use crate::{
hub, BinderAsyncPool, BinderAsyncRuntime, BoxFuture, DeathRecipient, FromIBinder, SIBinder,
StatusCode, Strong, WIBinder,
};
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
pub(crate) fn join_error_status(e: tokio::task::JoinError) -> StatusCode {
if e.is_panic() {
std::panic::resume_unwind(e.into_panic());
}
if e.is_cancelled() {
StatusCode::FailedTransaction
} else {
StatusCode::Unknown
}
}
pub async fn get_interface_async<T: FromIBinder + ?Sized + 'static>(
name: &str,
) -> Result<Strong<T>, StatusCode> {
fn lookup<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
hub::try_get_interface::<T>(name)?.ok_or(StatusCode::NameNotFound)
}
if crate::is_handling_transaction() {
return lookup::<T>(name);
}
let name = name.to_string();
tokio::task::spawn_blocking(move || lookup::<T>(&name))
.await
.unwrap_or_else(|e| Err(join_error_status(e)))
}
pub async fn wait_for_interface_async<T: FromIBinder + ?Sized + 'static>(
name: &str,
) -> Result<Strong<T>, StatusCode> {
let state = Arc::new(hub::WaiterState::default());
let _cancel = CancelWaitOnDrop(state.clone());
let name = name.to_string();
let wait_state = state.clone();
let res = tokio::task::spawn_blocking(move || {
let binder = hub::default()?
.wait_for_service_cancellable(&name, wait_state)
.map_err(|end| {
end.log(&name);
StatusCode::NameNotFound
})?;
FromIBinder::try_from(binder)
})
.await;
res.unwrap_or_else(|e| Err(join_error_status(e)))
}
struct CancelWaitOnDrop(Arc<hub::WaiterState>);
impl Drop for CancelWaitOnDrop {
fn drop(&mut self) {
self.0.cancel();
}
}
pub async fn check_interface_async<T: FromIBinder + ?Sized + 'static>(
name: &str,
) -> Result<Strong<T>, StatusCode> {
fn lookup<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
hub::check_interface::<T>(name)
}
if crate::is_handling_transaction() {
return lookup::<T>(name);
}
let name = name.to_string();
tokio::task::spawn_blocking(move || lookup::<T>(&name))
.await
.unwrap_or_else(|e| Err(join_error_status(e)))
}
pub struct DeathSignal {
rx: tokio::sync::oneshot::Receiver<()>,
recipient: Arc<SignalRecipient>,
binder: SIBinder,
linked: bool,
fired: bool,
}
struct SignalRecipient(Mutex<Option<tokio::sync::oneshot::Sender<()>>>);
impl SignalRecipient {
fn fire(&self) {
if let Some(tx) = self.0.lock().unwrap_or_else(|e| e.into_inner()).take() {
let _ = tx.send(());
}
}
}
impl DeathRecipient for SignalRecipient {
fn binder_died(&self, _who: &WIBinder) {
self.fire();
}
}
impl Future for DeathSignal {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = self.get_mut();
if this.fired {
return Poll::Ready(());
}
match Pin::new(&mut this.rx).poll(cx) {
Poll::Ready(_) => {
this.fired = true;
Poll::Ready(())
}
Poll::Pending => Poll::Pending,
}
}
}
impl Drop for DeathSignal {
fn drop(&mut self) {
if !self.linked {
return;
}
let unlink = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
self.binder.unlink_to_death_arc(&self.recipient)
}));
match unlink {
Ok(Ok(())) => {}
Ok(Err(err)) => log::debug!("DeathSignal: unlink_to_death returned {err:?}"),
Err(_) => {
log::error!("DeathSignal: unlink_to_death panicked; a death link stays registered")
}
}
}
}
pub fn death_signal(binder: &SIBinder) -> Result<DeathSignal, StatusCode> {
let (tx, rx) = tokio::sync::oneshot::channel();
let recipient = Arc::new(SignalRecipient(Mutex::new(Some(tx))));
match binder.link_to_death_arc(&recipient) {
Ok(()) => Ok(DeathSignal {
rx,
recipient,
binder: binder.clone(),
linked: true,
fired: false,
}),
Err(StatusCode::DeadObject) => {
recipient.fire();
Ok(DeathSignal {
rx,
recipient,
binder: binder.clone(),
linked: false,
fired: false,
})
}
Err(err) => Err(err),
}
}
pub enum Tokio {}
impl BinderAsyncPool for Tokio {
fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
where
F1: FnOnce() -> A,
F2: FnOnce(A) -> Fut,
Fut: Future<Output = Result<B, E>>,
F1: Send + 'static,
F2: Send + 'a,
Fut: Send + 'a,
A: Send + 'static,
B: Send + 'a,
E: From<crate::StatusCode>,
{
if crate::is_handling_transaction() {
let result = spawn_me();
Box::pin(after_spawn(result))
} else {
let handle = tokio::task::spawn_blocking(spawn_me);
Box::pin(async move {
match handle.await {
Ok(res) => after_spawn(res).await,
Err(e) => Err(join_error_status(e).into()),
}
})
}
}
}
pub struct TokioRuntime<R>(pub R);
impl BinderAsyncRuntime for TokioRuntime<tokio::runtime::Handle> {
fn block_on<F: Future>(&self, future: F) -> F::Output {
match tokio::runtime::Handle::try_current() {
Ok(handle) if handle.runtime_flavor() == tokio::runtime::RuntimeFlavor::MultiThread => {
tokio::task::block_in_place(|| self.0.block_on(future))
}
_ => self.0.block_on(future),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::binder::{IBinder, Stability};
use std::mem::ManuallyDrop;
use std::sync::atomic::{AtomicUsize, Ordering};
struct FakeRemote {
link: Option<StatusCode>,
unlink_panics: bool,
unlinked: AtomicUsize,
strong: AtomicUsize,
recipient: Mutex<Option<std::sync::Weak<dyn DeathRecipient>>>,
}
impl FakeRemote {
fn new(link: Option<StatusCode>, unlink_panics: bool) -> Arc<Self> {
Arc::new(Self {
link,
unlink_panics,
unlinked: AtomicUsize::new(0),
strong: AtomicUsize::new(0),
recipient: Mutex::new(None),
})
}
fn fire_obituary(&self, who: &WIBinder) {
let recipient = self
.recipient
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone();
let recipient = recipient.expect("no recipient registered").upgrade();
recipient
.expect("the signal dropped its recipient")
.binder_died(who);
}
fn unlink_count(&self) -> usize {
self.unlinked.load(Ordering::SeqCst)
}
}
impl IBinder for FakeRemote {
fn link_to_death(
&self,
recipient: std::sync::Weak<dyn DeathRecipient>,
) -> crate::Result<()> {
if let Some(err) = self.link {
return Err(err);
}
*self.recipient.lock().unwrap_or_else(|e| e.into_inner()) = Some(recipient);
Ok(())
}
fn unlink_to_death(
&self,
recipient: std::sync::Weak<dyn DeathRecipient>,
) -> crate::Result<()> {
assert!(!self.unlink_panics, "injected unlink panic");
let mut slot = self.recipient.lock().unwrap_or_else(|e| e.into_inner());
if !slot
.as_ref()
.is_some_and(|stored| std::sync::Weak::ptr_eq(stored, &recipient))
{
return Err(StatusCode::NameNotFound);
}
*slot = None;
self.unlinked.fetch_add(1, Ordering::SeqCst);
Ok(())
}
fn ping_binder(&self) -> crate::Result<()> {
Ok(())
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_transactable(&self) -> Option<&dyn crate::Transactable> {
None
}
fn descriptor(&self) -> &str {
"rsbinder.test.IFakeRemote"
}
fn is_remote(&self) -> bool {
true
}
fn stability(&self) -> Stability {
Stability::default()
}
fn inc_strong(&self, _: &SIBinder) -> crate::Result<()> {
self.strong.fetch_add(1, Ordering::SeqCst);
Ok(())
}
fn attempt_inc_strong(&self) -> bool {
true
}
fn dec_strong(&self, _: Option<ManuallyDrop<SIBinder>>) -> crate::Result<()> {
if self.strong.fetch_sub(1, Ordering::SeqCst) == 1 {
*self.recipient.lock().unwrap_or_else(|e| e.into_inner()) = None;
}
Ok(())
}
fn inc_weak(&self, _: &WIBinder) -> crate::Result<()> {
Ok(())
}
fn dec_weak(&self) -> crate::Result<()> {
Ok(())
}
}
fn poll_once(signal: &mut DeathSignal) -> Poll<()> {
let mut cx = Context::from_waker(std::task::Waker::noop());
Pin::new(signal).poll(&mut cx)
}
#[test]
fn completes_when_the_obituary_arrives() {
let fake = FakeRemote::new(None, false);
let binder = SIBinder::new(fake.clone()).unwrap();
let mut signal = death_signal(&binder).unwrap();
assert_eq!(poll_once(&mut signal), Poll::Pending);
fake.fire_obituary(&SIBinder::downgrade(&binder));
assert_eq!(poll_once(&mut signal), Poll::Ready(()));
}
#[test]
fn an_already_dead_binder_is_complete_at_once() {
let fake = FakeRemote::new(Some(StatusCode::DeadObject), false);
let binder = SIBinder::new(fake.clone()).unwrap();
let mut signal = death_signal(&binder).unwrap();
assert_eq!(poll_once(&mut signal), Poll::Ready(()));
drop(signal);
assert_eq!(fake.unlink_count(), 0);
}
#[test]
fn a_local_binder_has_no_death_notification() {
let fake = FakeRemote::new(Some(StatusCode::InvalidOperation), false);
let binder = SIBinder::new(fake).unwrap();
assert_eq!(
death_signal(&binder).err(),
Some(StatusCode::InvalidOperation)
);
}
#[test]
fn dropping_the_signal_unlinks_once() {
let fake = FakeRemote::new(None, false);
let binder = SIBinder::new(fake.clone()).unwrap();
let signal = death_signal(&binder).unwrap();
assert_eq!(fake.unlink_count(), 0);
drop(signal);
assert_eq!(fake.unlink_count(), 1);
}
#[test]
fn a_panicking_unlink_stays_inside_drop() {
let fake = FakeRemote::new(None, true);
let binder = SIBinder::new(fake).unwrap();
let signal = death_signal(&binder).unwrap();
let escaped = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| drop(signal)));
assert!(escaped.is_ok(), "the injected unlink panic escaped Drop");
}
#[test]
fn the_signal_survives_the_binder_handle_going_away() {
let fake = FakeRemote::new(None, false);
let (mut signal, who) = {
let binder = SIBinder::new(fake.clone()).unwrap();
(death_signal(&binder).unwrap(), SIBinder::downgrade(&binder))
};
assert_eq!(poll_once(&mut signal), Poll::Pending);
fake.fire_obituary(&who);
assert_eq!(poll_once(&mut signal), Poll::Ready(()));
}
#[test]
fn death_signal_is_send_and_static() {
fn assert_send_static<T: Send + 'static>() {}
assert_send_static::<DeathSignal>();
}
}