use crate::binder::{AsNative, FromIBinder, Strong};
use crate::binder_impl::Mutex;
use crate::binder_impl::panic_if_poisoned;
use crate::error::{Result, StatusCode, status_result};
use crate::proxy::SpIBinder;
use crate::sys;
use alloc::borrow::ToOwned;
use alloc::ffi::CString;
use alloc::string::String;
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use core::ffi::c_char;
use core::ffi::{CStr, c_void};
#[cfg(not(any(trusty, android_ndk, android_vendor, android_vndk)))]
use libc::{pid_t, uid_t};
#[cfg(feature = "std")]
use std::os::raw::c_char;
#[cfg(not(any(trusty, android_ndk, android_vendor, android_vndk)))]
pub const CHECK_ACCESS_PERMISSION_FIND: u32 =
sys::AServiceManager_PermissionType::CHECK_ACCESS_PERMISSION_FIND as u32;
#[cfg(not(any(trusty, android_ndk, android_vendor, android_vndk)))]
pub const CHECK_ACCESS_PERMISSION_LIST: u32 =
sys::AServiceManager_PermissionType::CHECK_ACCESS_PERMISSION_LIST as u32;
#[cfg(not(any(trusty, android_ndk, android_vendor, android_vndk)))]
pub const CHECK_ACCESS_PERMISSION_ADD: u32 =
sys::AServiceManager_PermissionType::CHECK_ACCESS_PERMISSION_ADD as u32;
pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status =
unsafe { sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) };
status_result(status)
}
pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status = unsafe {
sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
};
status_result(status)
}
pub fn force_lazy_services_persist(persist: bool) {
unsafe { sys::AServiceManager_forceLazyServicesPersist(persist) }
}
#[must_use]
#[derive(Debug)]
pub struct LazyServiceGuard {
_private: (),
}
static GUARD_COUNT: Mutex<u64> = Mutex::new(0);
impl LazyServiceGuard {
pub fn new() -> Self {
let mut count = panic_if_poisoned!(GUARD_COUNT.lock());
*count += 1;
if *count == 1 {
force_lazy_services_persist(true);
}
Self { _private: () }
}
}
impl Drop for LazyServiceGuard {
fn drop(&mut self) {
let mut count = panic_if_poisoned!(GUARD_COUNT.lock());
*count -= 1;
if *count == 0 {
force_lazy_services_persist(false);
}
}
}
impl Clone for LazyServiceGuard {
fn clone(&self) -> Self {
Self::new()
}
}
impl Default for LazyServiceGuard {
fn default() -> Self {
Self::new()
}
}
pub fn is_handling_transaction() -> bool {
unsafe { sys::AIBinder_isHandlingTransaction() }
}
fn interface_cast<T: FromIBinder + ?Sized>(service: Option<SpIBinder>) -> Result<Strong<T>> {
if let Some(service) = service {
FromIBinder::try_from(service)
} else {
Err(StatusCode::NAME_NOT_FOUND)
}
}
#[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()?;
unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) }
}
pub fn check_service(name: &str) -> Option<SpIBinder> {
let name = CString::new(name).ok()?;
unsafe { SpIBinder::from_raw(sys::AServiceManager_checkService(name.as_ptr())) }
}
pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
let name = CString::new(name).ok()?;
unsafe { SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) }
}
#[deprecated = "this polls 5s, use wait_for_interface or check_interface"]
pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
#[allow(deprecated)]
interface_cast(get_service(name))
}
pub fn check_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
interface_cast(check_service(name))
}
pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
interface_cast(wait_for_service(name))
}
pub fn is_declared(interface: &str) -> Result<bool> {
let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
unsafe { Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) }
}
pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
unsafe extern "C" fn callback(instance: *const c_char, opaque: *mut c_void) {
if let Some(instances) = unsafe { opaque.cast::<Vec<CString>>().as_mut() } {
unsafe {
instances.push(CStr::from_ptr(instance).to_owned());
}
} else {
log::error!("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 {
sys::AServiceManager_forEachDeclaredInstance(
interface.as_ptr(),
&mut instances as *mut _ as *mut c_void,
Some(callback),
);
}
#[allow(unused_variables)]
instances
.into_iter()
.map(CString::into_string)
.collect::<core::result::Result<Vec<String>, _>>()
.map_err(|e| {
log::error!("An interface instance name was not a valid UTF-8 string: {}", e);
StatusCode::BAD_VALUE
})
}
#[cfg(not(any(trusty, android_ndk, android_vendor, android_vndk)))]
pub fn check_service_access(
caller_sid: &str,
caller_debug_pid: pid_t,
caller_uid: uid_t,
name: &str,
permission: u32,
) -> Result<bool> {
let caller_sid = CString::new(caller_sid).or(Err(StatusCode::UNEXPECTED_NULL))?;
let name = CString::new(name).or(Err(StatusCode::UNEXPECTED_NULL))?;
let permission = match permission {
CHECK_ACCESS_PERMISSION_FIND => {
sys::AServiceManager_PermissionType::CHECK_ACCESS_PERMISSION_FIND
}
CHECK_ACCESS_PERMISSION_LIST => {
sys::AServiceManager_PermissionType::CHECK_ACCESS_PERMISSION_LIST
}
CHECK_ACCESS_PERMISSION_ADD => {
sys::AServiceManager_PermissionType::CHECK_ACCESS_PERMISSION_ADD
}
_ => return Err(StatusCode::BAD_TYPE),
};
unsafe {
Ok(sys::AServiceManager_checkServiceAccess(
caller_sid.as_ptr(),
caller_debug_pid,
caller_uid,
name.as_ptr(),
permission,
))
}
}