Revert "Revert "libbinder_rs: Treat previously associated Binder as remote""
This reverts commit f6b9ad98ee61149f42b6ca0bf84068d4411a92f8.
Reason for revert: Includes fix for aidl_integration_test failure that prompted the initial revert
Original commit message:
libbinder_rs: Treat previously associated Binder as remote
A binder object may have already been associated by another module (e.g.
NDK code that created the object if it is local) and therefore already
have an NDK AIBinder_Class. In this case we still want to transact with
the object, but must treat it as remote if its class does not match the
class expected for a compatible Rust service.
Re-landing this change with the fix for aidl_integration_test failure
that prompted its reversion.
Bug: 167723746
Test: atest rustBinderTest binderRustNdkInteropTest
Change-Id: I9a848bcc4b8003a22ebe59c89a95be70ef6ee7ec
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 037ee95..ed3b9ec 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -21,7 +21,8 @@
use crate::proxy::{DeathRecipient, SpIBinder};
use crate::sys;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
+use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
@@ -205,6 +206,22 @@
pub(crate) unsafe fn from_ptr(ptr: *const sys::AIBinder_Class) -> InterfaceClass {
InterfaceClass(ptr)
}
+
+ /// Get the interface descriptor string of this class.
+ pub fn get_descriptor(&self) -> String {
+ unsafe {
+ // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor
+ // is always a two-byte null terminated sequence of u16s. Thus, we
+ // can continue reading from the pointer until we hit a null value,
+ // and this pointer can be a valid slice if the slice length is <=
+ // the number of u16 elements before the null terminator.
+
+ let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
+ CStr::from_ptr(raw_descriptor).to_str()
+ .expect("Expected valid UTF-8 string from AIBinder_Class_getDescriptor")
+ .into()
+ }
+ }
}
impl From<InterfaceClass> for *const sys::AIBinder_Class {
@@ -507,12 +524,7 @@
}
fn from_binder(mut binder: $crate::SpIBinder) -> $crate::Result<Self> {
- use $crate::AssociateClass;
- if binder.associate_class(<$native as $crate::Remotable>::get_class()) {
- Ok(Self { binder, $($fname: $finit),* })
- } else {
- Err($crate::StatusCode::BAD_TYPE)
- }
+ Ok(Self { binder, $($fname: $finit),* })
}
}
@@ -567,16 +579,35 @@
impl $crate::FromIBinder for dyn $interface {
fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
use $crate::AssociateClass;
- if !ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
- return Err($crate::StatusCode::BAD_TYPE.into());
+
+ let existing_class = ibinder.get_class();
+ if let Some(class) = existing_class {
+ if class != <$native as $crate::Remotable>::get_class() &&
+ class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
+ {
+ // The binder object's descriptor string matches what we
+ // expect. We still need to treat this local or already
+ // associated object as remote, because we can't cast it
+ // into a Rust service object without a matching class
+ // pointer.
+ return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ }
}
- let service: $crate::Result<$crate::Binder<$native>> = std::convert::TryFrom::try_from(ibinder.clone());
- if let Ok(service) = service {
- Ok(Box::new(service))
- } else {
- Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?))
+ if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
+ let service: $crate::Result<$crate::Binder<$native>> =
+ std::convert::TryFrom::try_from(ibinder.clone());
+ if let Ok(service) = service {
+ // We were able to associate with our expected class and
+ // the service is local.
+ return Ok(Box::new(service));
+ } else {
+ // Service is remote
+ return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ }
}
+
+ Err($crate::StatusCode::BAD_TYPE.into())
}
}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 5002fc6..485bb42 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -91,7 +91,7 @@
/// Return the interface class of this binder object, if associated with
/// one.
- pub(crate) fn get_class(&mut self) -> Option<InterfaceClass> {
+ pub fn get_class(&mut self) -> Option<InterfaceClass> {
unsafe {
// Safety: `SpIBinder` guarantees that it always contains a valid
// `AIBinder` pointer. `AIBinder_getClass` returns either a null