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

Commit c9b164d4 authored by Andrew Walbran's avatar Andrew Walbran Committed by Gerrit Code Review
Browse files

Merge "Add wait_for_interface and wait_for_service."

parents 08d2f47d c3ce5c35
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -115,14 +115,14 @@ pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
pub use native::Binder;
pub use parcel::Parcel;
pub use proxy::{get_interface, get_service};
pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
pub use state::{ProcessState, ThreadState};

/// The public API usable outside AIDL-generated interface crates.
pub mod public_api {
    pub use super::parcel::ParcelFileDescriptor;
    pub use super::{add_service, get_interface};
    pub use super::{add_service, get_interface, wait_for_interface};
    pub use super::{
        BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
        Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
+22 −0
Original line number Diff line number Diff line
@@ -653,6 +653,18 @@ pub fn get_service(name: &str) -> Option<SpIBinder> {
    }
}

/// 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> {
    let name = CString::new(name).ok()?;
    unsafe {
        // Safety: `AServiceManager_waitforService` 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`.
        SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr()))
    }
}

/// Retrieve an existing service for a particular interface, blocking for a few
/// seconds if it doesn't yet exist.
pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
@@ -663,6 +675,16 @@ pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
    }
}

/// 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>> {
    let service = wait_for_service(name);
    match service {
        Some(service) => FromIBinder::try_from(service),
        None => Err(StatusCode::NAME_NOT_FOUND),
    }
}

/// # Safety
///
/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
+23 −0
Original line number Diff line number Diff line
@@ -273,6 +273,20 @@ mod tests {
        );
    }

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

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

    #[test]
    fn trivial_client() {
        let service_name = "trivial_client_test";
@@ -282,6 +296,15 @@ mod tests {
        assert_eq!(test_client.test().unwrap(), "trivial_client_test");
    }

    #[test]
    fn wait_for_trivial_client() {
        let service_name = "wait_for_trivial_client_test";
        let _process = ScopedServiceProcess::new(service_name);
        let test_client: Strong<dyn ITest> =
            binder::wait_for_interface(service_name).expect("Did not get manager binder service");
        assert_eq!(test_client.test().unwrap(), "wait_for_trivial_client_test");
    }

    #[test]
    fn get_selinux_context() {
        let service_name = "get_selinux_context";