Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05f5a2c4 authored by Alice Ryhl's avatar Alice Ryhl
Browse files

binder: add async Rust support

Test: add and run integration tests
Change-Id: I7671eeb7dfe4cc45efd57756753b361440529a3c
parent 676e9a9e
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -32,6 +32,27 @@ rust_library {
    ],
}

rust_library {
    name: "libbinder_tokio_rs",
    crate_name: "binder_tokio",
    srcs: ["binder_tokio/lib.rs"],
    rustlibs: [
        "libbinder_rs",
        "libtokio",
    ],
    host_supported: true,
    target: {
        darwin: {
            enabled: false,
        }
    },
    apex_available: [
        "//apex_available:platform",
        "com.android.compos",
        "com.android.virt",
    ],
}

rust_library {
    name: "libbinder_ndk_sys",
    crate_name: "binder_ndk_sys",
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! This crate lets you use the Tokio `spawn_blocking` pool with AIDL in async
//! Rust code.
//!
//! This crate works by defining a type [`Tokio`], which you can use as the
//! generic parameter in the async version of the trait generated by the AIDL
//! compiler.
//! ```text
//! use binder_tokio::Tokio;
//!
//! binder::get_interface::<dyn SomeAsyncInterface<Tokio>>("...").
//! ```
//!
//! [`Tokio`]: crate::Tokio

use binder::public_api::{BinderAsyncPool, BoxFuture};
use binder::StatusCode;
use std::future::Future;

/// Use the Tokio `spawn_blocking` pool with AIDL.
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>,
    {
        let handle = tokio::task::spawn_blocking(spawn_me);
        Box::pin(async move {
            // The `is_panic` branch is not actually reachable in Android as we compile
            // with `panic = abort`.
            match handle.await {
                Ok(res) => after_spawn(res).await,
                Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
                Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION.into()),
                Err(_) => Err(StatusCode::UNKNOWN_ERROR.into()),
            }
        })
    }
}

+78 −1
Original line number Diff line number Diff line
@@ -713,12 +713,14 @@ 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::Stability::default(),
            }
        }
@@ -728,6 +730,7 @@ macro_rules! declare_binder_interface {
        $interface:path[$descriptor:expr] {
            native: $native:ident($on_transact:path),
            proxy: $proxy:ident,
            $(async: $async_interface:ident,)?
            stability: $stability:expr,
        }
    } => {
@@ -735,6 +738,7 @@ macro_rules! declare_binder_interface {
            $interface[$descriptor] {
                native: $native($on_transact),
                proxy: $proxy {},
                $(async: $async_interface,)?
                stability: $stability,
            }
        }
@@ -746,6 +750,7 @@ macro_rules! declare_binder_interface {
            proxy: $proxy:ident {
                $($fname:ident: $fty:ty = $finit:expr),*
            },
            $(async: $async_interface:ident,)?
        }
    } => {
        $crate::declare_binder_interface! {
@@ -754,6 +759,7 @@ macro_rules! declare_binder_interface {
                proxy: $proxy {
                    $($fname: $fty = $finit),*
                },
                $(async: $async_interface,)?
                stability: $crate::Stability::default(),
            }
        }
@@ -765,6 +771,7 @@ macro_rules! declare_binder_interface {
            proxy: $proxy:ident {
                $($fname:ident: $fty:ty = $finit:expr),*
            },
            $(async: $async_interface:ident,)?
            stability: $stability:expr,
        }
    } => {
@@ -776,6 +783,7 @@ macro_rules! declare_binder_interface {
                proxy: $proxy {
                    $($fname: $fty = $finit),*
                },
                $(async: $async_interface,)?
                stability: $stability,
            }
        }
@@ -791,6 +799,8 @@ macro_rules! declare_binder_interface {
                $($fname:ident: $fty:ty = $finit:expr),*
            },

            $( async: $async_interface:ident, )?

            stability: $stability:expr,
        }
    } => {
@@ -924,7 +934,7 @@ macro_rules! declare_binder_interface {
            }
        }

        impl std::fmt::Debug for dyn $interface {
        impl std::fmt::Debug for dyn $interface + '_ {
            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                f.pad(stringify!($interface))
            }
@@ -938,6 +948,73 @@ macro_rules! declare_binder_interface {
                    .expect(concat!("Error cloning interface ", stringify!($interface)))
            }
        }

        $(
        // Async interface trait implementations.
        impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $async_interface<P>>> {
                use $crate::AssociateClass;

                let existing_class = ibinder.get_class();
                if let Some(class) = existing_class {
                    if class != <$native as $crate::Remotable>::get_class() &&
                        class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
                    {
                        // The binder object's descriptor string matches what we
                        // expect. We still need to treat this local or already
                        // associated object as remote, because we can't cast it
                        // into a Rust service object without a matching class
                        // pointer.
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                    }
                }

                if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
                    let service: $crate::Result<$crate::Binder<$native>> =
                        std::convert::TryFrom::try_from(ibinder.clone());
                    if let Ok(service) = service {
                        // We were able to associate with our expected class and
                        // the service is local.
                        todo!()
                        //return Ok($crate::Strong::new(Box::new(service)));
                    } else {
                        // Service is remote
                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
                    }
                }

                Err($crate::StatusCode::BAD_TYPE.into())
            }
        }

        impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
                let binder = $crate::Interface::as_binder(self);
                parcel.write(&binder)
            }
        }

        impl<P: $crate::BinderAsyncPool> $crate::parcel::SerializeOption for dyn $async_interface<P> + '_ {
            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
                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))
            }
        }

        /// Convert a &dyn $async_interface to Strong<dyn $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)))
            }
        }
        )?
    };
}

+55 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::future::Future;
use std::pin::Pin;

/// A type alias for a pinned, boxed future that lets you write shorter code without littering it
/// with Pin and Send bounds.
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A thread pool for running binder transactions.
pub trait BinderAsyncPool {
    /// This function should conceptually behave like this:
    ///
    /// ```text
    /// let result = spawn_thread(|| spawn_me()).await;
    /// return after_spawn(result).await;
    /// ```
    ///
    /// If the spawning fails for some reason, the method may also skip the `after_spawn` closure
    /// and immediately return an error.
    ///
    /// The only difference between different implementations should be which
    /// `spawn_thread` method is used. For Tokio, it would be `tokio::task::spawn_blocking`.
    ///
    /// This method has the design it has because the only way to define a trait that
    /// allows the return type of the spawn to be chosen by the caller is to return a
    /// boxed `Future` trait object, and including `after_spawn` in the trait function
    /// allows the caller to avoid double-boxing if they want to do anything to the value
    /// returned from the spawned thread.
    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>;
}
+5 −2
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ mod proxy;

#[macro_use]
mod binder;
mod binder_async;
mod error;
mod native;
mod state;
@@ -111,6 +112,7 @@ pub use crate::binder::{
    Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION,
    FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
};
pub use crate::binder_async::{BoxFuture, BinderAsyncPool};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
pub use parcel::{OwnedParcel, Parcel};
@@ -133,8 +135,9 @@ pub mod public_api {
        wait_for_interface,
    };
    pub use super::{
        BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
        Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
        BinderAsyncPool, BinderFeatures, BoxFuture, DeathRecipient, ExceptionCode, IBinder,
        Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState, Weak,
        WpIBinder,
    };

    /// Binder result containing a [`Status`] on error.
Loading