use std::any::Any;
use std::mem::ManuallyDrop;
use std::sync::{Arc, Weak};
use crate::binder::{
DeathRecipient, IBinder, Interface, SIBinder, Stability, Transactable, TransactionCode,
WIBinder,
};
use crate::error::Result;
use crate::parcel::Parcel;
use crate::rpc::RpcSession;
include!(concat!(env!("OUT_DIR"), "/accessor_16.rs"));
pub use android::os::IAccessor::{
BnAccessor, BpAccessor, IAccessor, IAccessorDefault, IAccessorDefaultRef,
ERROR_CONNECTION_INFO_NOT_FOUND, ERROR_FAILED_TO_CONNECT_EACCES,
ERROR_FAILED_TO_CONNECT_TO_SOCKET, ERROR_FAILED_TO_CREATE_SOCKET,
ERROR_UNSUPPORTED_SOCKET_FAMILY,
};
#[cfg(feature = "async")]
pub use android::os::IAccessor::{IAccessorAsync, IAccessorAsyncService};
pub(crate) struct AccessorRoot {
inner: SIBinder,
#[allow(dead_code)]
session: RpcSession,
}
impl AccessorRoot {
fn into_sibinder(inner: SIBinder, session: RpcSession) -> Result<SIBinder> {
SIBinder::new(Arc::new(AccessorRoot { inner, session }))
}
fn inner_binder(&self) -> &dyn IBinder {
&**self.inner.as_arc()
}
}
impl Interface for AccessorRoot {
fn as_binder(&self) -> SIBinder {
self.inner.clone()
}
}
impl IBinder for AccessorRoot {
fn link_to_death(&self, recipient: Weak<dyn DeathRecipient>) -> Result<()> {
self.inner_binder().link_to_death(recipient)
}
fn unlink_to_death(&self, recipient: Weak<dyn DeathRecipient>) -> Result<()> {
self.inner_binder().unlink_to_death(recipient)
}
fn ping_binder(&self) -> Result<()> {
self.inner_binder().ping_binder()
}
fn as_any(&self) -> &dyn Any {
self.inner_binder().as_any()
}
fn as_transactable(&self) -> Option<&dyn Transactable> {
self.inner_binder().as_transactable()
}
fn descriptor(&self) -> &str {
self.inner_binder().descriptor()
}
fn is_remote(&self) -> bool {
self.inner_binder().is_remote()
}
fn stability(&self) -> Stability {
self.inner_binder().stability()
}
fn rpc_transact(
&self,
code: TransactionCode,
reader: &mut Parcel,
reply: &mut Parcel,
) -> Result<()> {
self.inner_binder().rpc_transact(code, reader, reply)
}
fn inc_strong(&self, strong: &SIBinder) -> Result<()> {
self.inner_binder().inc_strong(strong)
}
fn attempt_inc_strong(&self) -> bool {
self.inner_binder().attempt_inc_strong()
}
fn dec_strong(&self, strong: Option<ManuallyDrop<SIBinder>>) -> Result<()> {
self.inner_binder().dec_strong(strong)
}
fn inc_weak(&self, weak: &WIBinder) -> Result<()> {
self.inner_binder().inc_weak(weak)
}
fn dec_weak(&self) -> Result<()> {
self.inner_binder().dec_weak()
}
}
pub fn resolve_accessor(
name: &str,
accessor: SIBinder,
) -> Option<super::servicemanager_16::android::os::ServiceWithMetadata::ServiceWithMetadata> {
let bp = match <dyn IAccessor as crate::FromIBinder>::try_from(accessor) {
Ok(bp) => bp,
Err(e) => {
log::warn!("IAccessor cast failed for {name}: {e}");
return None;
}
};
match bp.getInstanceName() {
Ok(reported) if reported == name => {}
Ok(other) => {
log::warn!(
"IAccessor instance-name mismatch for {name}: reported {other:?} — rejecting"
);
return None;
}
Err(status) => {
log::warn!(
"IAccessor::getInstanceName failed for {name}: {status} \
(service_specific={})",
accessor_error_name(status.service_specific_error())
);
return None;
}
}
let pfd = match bp.addConnection() {
Ok(pfd) => pfd,
Err(status) => {
log::warn!(
"IAccessor::addConnection failed for {name}: {status} \
(service_specific={})",
accessor_error_name(status.service_specific_error())
);
return None;
}
};
let fd: std::os::fd::OwnedFd = pfd.into();
let session = match RpcSession::from_preconnected_fd(fd, 2) {
Ok(s) => s,
Err(e) => {
log::warn!(
"RpcSession::from_preconnected_fd failed for {name}: {e} (code={:?})",
e
);
return None;
}
};
let root = match session.get_root() {
Ok(b) => b,
Err(e) => {
log::warn!("RPC get_root failed for {name}: {e}");
return None;
}
};
let wrapped = match AccessorRoot::into_sibinder(root, session) {
Ok(b) => b,
Err(e) => {
log::warn!("AccessorRoot wrap failed for {name}: {e}");
return None;
}
};
Some(
super::servicemanager_16::android::os::ServiceWithMetadata::ServiceWithMetadata {
r#service: Some(wrapped),
r#isLazyService: false,
},
)
}
pub fn accessor_error_name(code: i32) -> &'static str {
match code {
ERROR_CONNECTION_INFO_NOT_FOUND => "ERROR_CONNECTION_INFO_NOT_FOUND",
ERROR_FAILED_TO_CREATE_SOCKET => "ERROR_FAILED_TO_CREATE_SOCKET",
ERROR_FAILED_TO_CONNECT_TO_SOCKET => "ERROR_FAILED_TO_CONNECT_TO_SOCKET",
ERROR_FAILED_TO_CONNECT_EACCES => "ERROR_FAILED_TO_CONNECT_EACCES",
ERROR_UNSUPPORTED_SOCKET_FAMILY => "ERROR_UNSUPPORTED_SOCKET_FAMILY",
_ => "unknown",
}
}
#[doc(hidden)]
pub fn __fuzz_accessor_error_decode(input: &[u8]) {
let mut buf = [0u8; 4];
let n = input.len().min(4);
buf[..n].copy_from_slice(&input[..n]);
let code = i32::from_le_bytes(buf);
let _ = std::hint::black_box(accessor_error_name(code));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accessor_error_name_covers_all_aosp_codes() {
assert_eq!(
accessor_error_name(ERROR_CONNECTION_INFO_NOT_FOUND),
"ERROR_CONNECTION_INFO_NOT_FOUND"
);
assert_eq!(
accessor_error_name(ERROR_FAILED_TO_CREATE_SOCKET),
"ERROR_FAILED_TO_CREATE_SOCKET"
);
assert_eq!(
accessor_error_name(ERROR_FAILED_TO_CONNECT_TO_SOCKET),
"ERROR_FAILED_TO_CONNECT_TO_SOCKET"
);
assert_eq!(
accessor_error_name(ERROR_FAILED_TO_CONNECT_EACCES),
"ERROR_FAILED_TO_CONNECT_EACCES"
);
assert_eq!(
accessor_error_name(ERROR_UNSUPPORTED_SOCKET_FAMILY),
"ERROR_UNSUPPORTED_SOCKET_FAMILY"
);
}
#[test]
fn accessor_error_name_unknown_is_safe() {
for code in [5, 6, 1_000, -1, -1_000, i32::MAX, i32::MIN] {
assert_eq!(accessor_error_name(code), "unknown", "code {code}");
}
}
#[test]
fn fuzz_accessor_error_decode_never_panics() {
__fuzz_accessor_error_decode(&[]);
__fuzz_accessor_error_decode(&[0]);
__fuzz_accessor_error_decode(&[0, 0]);
__fuzz_accessor_error_decode(&[0, 0, 0]);
__fuzz_accessor_error_decode(&[0, 0, 0, 0]);
__fuzz_accessor_error_decode(&[1, 2, 3, 4, 5, 6, 7, 8]);
__fuzz_accessor_error_decode(&u32::MAX.to_le_bytes());
__fuzz_accessor_error_decode(&i32::MAX.to_le_bytes());
__fuzz_accessor_error_decode(&i32::MIN.to_le_bytes());
}
}