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

Commit 61d93fc2 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "deprecate binder::get_service, add binder::check_service" into main

parents ad42babc 68f34bf2
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ use std::future::Future;

/// Retrieve an existing service for a particular interface, sleeping for a few
/// seconds if it doesn't yet exist.
#[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
    name: &str,
) -> Result<Strong<T>, StatusCode> {
@@ -56,6 +57,32 @@ pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
    }
}

/// Retrieve an existing service for a particular interface. Returns
/// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available.
///
/// NOTE: "immediately" above does not mean the future will complete the first time it is polled.
pub async fn check_interface<T: FromIBinder + ?Sized + 'static>(
    name: &str,
) -> Result<Strong<T>, StatusCode> {
    if binder::is_handling_transaction() {
        // See comment in the BinderAsyncPool impl.
        return binder::check_interface::<T>(name);
    }

    let name = name.to_string();
    let res = tokio::task::spawn_blocking(move || binder::check_interface::<T>(&name)).await;

    // The `is_panic` branch is not actually reachable in Android as we compile
    // with `panic = abort`.
    match res {
        Ok(Ok(service)) => Ok(service),
        Ok(Err(err)) => Err(err),
        Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
        Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
        Err(_) => Err(StatusCode::UNKNOWN_ERROR),
    }
}

/// Retrieve an existing service for a particular interface, or start it if it
/// is configured as a dynamic service and isn't yet started.
pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
+3 −3
Original line number Diff line number Diff line
@@ -114,9 +114,9 @@ pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
#[cfg(not(trusty))]
pub use service::{
    add_service, force_lazy_services_persist, get_declared_instances, get_interface, get_service,
    is_declared, is_handling_transaction, register_lazy_service, wait_for_interface,
    wait_for_service, LazyServiceGuard,
    add_service, check_interface, check_service, force_lazy_services_persist,
    get_declared_instances, get_interface, get_service, is_declared, is_handling_transaction,
    register_lazy_service, wait_for_interface, wait_for_service, LazyServiceGuard,
};
#[cfg(not(trusty))]
pub use state::{ProcessState, ThreadState};
+17 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ fn interface_cast<T: FromIBinder + ?Sized>(service: Option<SpIBinder>) -> Result

/// Retrieve an existing service, blocking for a few seconds if it doesn't yet
/// exist.
#[deprecated = "this polls 5s, use wait_for_service or check_service"]
pub fn get_service(name: &str) -> Option<SpIBinder> {
    let name = CString::new(name).ok()?;
    // Safety: `AServiceManager_getService` returns either a null pointer or a
@@ -152,6 +153,15 @@ pub fn get_service(name: &str) -> Option<SpIBinder> {
    unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) }
}

/// Retrieve an existing service. Returns `None` immediately if the service is not available.
pub fn check_service(name: &str) -> Option<SpIBinder> {
    let name = CString::new(name).ok()?;
    // Safety: `AServiceManager_checkService` returns either a null pointer or
    // a valid pointer to an owned `AIBinder`. Either of these values is safe to
    // pass to `SpIBinder::from_raw`.
    unsafe { SpIBinder::from_raw(sys::AServiceManager_checkService(name.as_ptr())) }
}

/// Retrieve an existing service, or start it if it is configured as a dynamic
/// service and isn't yet started.
pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
@@ -164,10 +174,17 @@ pub fn wait_for_service(name: &str) -> Option<SpIBinder> {

/// Retrieve an existing service for a particular interface, blocking for a few
/// seconds if it doesn't yet exist.
#[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
    interface_cast(get_service(name))
}

/// Retrieve an existing service for a particular interface. Returns
/// `Err(StatusCode::NAME_NOT_FOUND)` immediately if the service is not available.
pub fn check_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
    interface_cast(check_service(name))
}

/// Retrieve an existing service for a particular interface, or start it if it
/// is configured as a dynamic service and isn't yet started.
pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
+58 −2
Original line number Diff line number Diff line
@@ -421,7 +421,7 @@ mod tests {
    }

    #[test]
    fn check_services() {
    fn check_get_service() {
        let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
        assert!(sm.is_binder_alive());
        assert!(sm.ping_binder().is_ok());
@@ -445,7 +445,7 @@ mod tests {
    }

    #[tokio::test]
    async fn check_services_async() {
    async fn check_get_service_async() {
        let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
        assert!(sm.is_binder_alive());
        assert!(sm.ping_binder().is_ok());
@@ -473,6 +473,62 @@ mod tests {
        );
    }

    #[test]
    fn check_check_service() {
        let mut sm = binder::check_service("manager").expect("Did not find manager binder service");
        assert!(sm.is_binder_alive());
        assert!(sm.ping_binder().is_ok());

        assert!(binder::check_service("this_service_does_not_exist").is_none());
        assert_eq!(
            binder::check_interface::<dyn ITest>("this_service_does_not_exist").err(),
            Some(StatusCode::NAME_NOT_FOUND)
        );
        assert_eq!(
            binder::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
            Some(StatusCode::NAME_NOT_FOUND)
        );

        // The service manager service isn't an ITest, so this must fail.
        assert_eq!(
            binder::check_interface::<dyn ITest>("manager").err(),
            Some(StatusCode::BAD_TYPE)
        );
        assert_eq!(
            binder::check_interface::<dyn IATest<Tokio>>("manager").err(),
            Some(StatusCode::BAD_TYPE)
        );
    }

    #[tokio::test]
    async fn check_check_service_async() {
        let mut sm = binder::check_service("manager").expect("Did not find manager binder service");
        assert!(sm.is_binder_alive());
        assert!(sm.ping_binder().is_ok());

        assert!(binder::check_service("this_service_does_not_exist").is_none());
        assert_eq!(
            binder_tokio::check_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
            Some(StatusCode::NAME_NOT_FOUND)
        );
        assert_eq!(
            binder_tokio::check_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
                .await
                .err(),
            Some(StatusCode::NAME_NOT_FOUND)
        );

        // The service manager service isn't an ITest, so this must fail.
        assert_eq!(
            binder_tokio::check_interface::<dyn ITest>("manager").await.err(),
            Some(StatusCode::BAD_TYPE)
        );
        assert_eq!(
            binder_tokio::check_interface::<dyn IATest<Tokio>>("manager").await.err(),
            Some(StatusCode::BAD_TYPE)
        );
    }

    #[test]
    fn check_wait_for_service() {
        let mut sm =