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

Commit 753cbfec authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "[binder_rs] Add get_declared_instances and is_declared APIs" am: 02ece05b am: 630bfc54

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1986208

Change-Id: I1eccf026dc100351064413b07e73004a015aa600
parents 838c02c7 630bfc54
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -114,8 +114,8 @@ pub use native::{
};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use proxy::{
    get_interface, get_service, wait_for_interface, wait_for_service, DeathRecipient, SpIBinder,
    WpIBinder,
    get_declared_instances, get_interface, get_service, is_declared, wait_for_interface,
    wait_for_service, DeathRecipient, SpIBinder, WpIBinder,
};
pub use state::{ProcessState, ThreadState};

+57 −1
Original line number Diff line number Diff line
@@ -28,9 +28,10 @@ use crate::sys;

use std::cmp::Ordering;
use std::convert::TryInto;
use std::ffi::{c_void, CString};
use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::mem;
use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
use std::sync::Arc;
@@ -778,6 +779,61 @@ pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<
    }
}

/// Check if a service is declared (e.g. in a VINTF manifest)
pub fn is_declared(interface: &str) -> Result<bool> {
    let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;

    unsafe {
        // Safety: `interface` is a valid null-terminated C-style string and is
        // only borrowed for the lifetime of the call. The `interface` local
        // outlives this call as it lives for the function scope.
        Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
    }
}

/// Retrieve all declared instances for a particular interface
///
/// For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo'
/// is passed here, then ["foo"] would be returned.
pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
    unsafe extern "C" fn callback(instance: *const c_char, opaque: *mut c_void) {
        // Safety: opaque was a mutable pointer created below from a Vec of
        // CString, and outlives this callback. The null handling here is just
        // to avoid the possibility of unwinding across C code if this crate is
        // ever compiled with panic=unwind.
        if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
            // Safety: instance is a valid null-terminated C string with a
            // lifetime at least as long as this function, and we immediately
            // copy it into an owned CString.
            instances.push(CStr::from_ptr(instance).to_owned());
        } else {
            eprintln!("Opaque pointer was null in get_declared_instances callback!");
        }
    }

    let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
    let mut instances: Vec<CString> = vec![];
    unsafe {
        // Safety: `interface` and `instances` are borrowed for the length of
        // this call and both outlive the call. `interface` is guaranteed to be
        // a valid null-terminated C-style string.
        sys::AServiceManager_forEachDeclaredInstance(
            interface.as_ptr(),
            &mut instances as *mut _ as *mut c_void,
            Some(callback),
        );
    }

    instances
        .into_iter()
        .map(CString::into_string)
        .collect::<std::result::Result<Vec<String>, _>>()
        .map_err(|e| {
            eprintln!("An interface instance name was not a valid UTF-8 string: {}", e);
            StatusCode::BAD_VALUE
        })
}

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

    #[test]
    fn get_declared_instances() {
        // At the time of writing this test, there is no good VINTF interface
        // guaranteed to be on all devices. Cuttlefish has light, so this will
        // generally test things.
        let has_lights = binder::is_declared("android.hardware.light.ILights/default")
            .expect("Could not check for declared interface");

        let instances = binder::get_declared_instances("android.hardware.light.ILights")
            .expect("Could not get declared instances");

        let expected_defaults = if has_lights { 1 } else { 0 };
        assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
    }

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