diff options
| -rw-r--r-- | libs/binder/rust/Android.bp | 74 | ||||
| -rw-r--r-- | libs/binder/rust/BinderBindings.h | 86 | ||||
| -rw-r--r-- | libs/binder/rust/TEST_MAPPING | 10 | ||||
| -rw-r--r-- | libs/binder/rust/src/binder.rs | 585 | ||||
| -rw-r--r-- | libs/binder/rust/src/error.rs | 373 | ||||
| -rw-r--r-- | libs/binder/rust/src/lib.rs | 130 | ||||
| -rw-r--r-- | libs/binder/rust/src/native.rs | 358 | ||||
| -rw-r--r-- | libs/binder/rust/src/parcel.rs | 447 | ||||
| -rw-r--r-- | libs/binder/rust/src/parcel/file_descriptor.rs | 126 | ||||
| -rw-r--r-- | libs/binder/rust/src/parcel/parcelable.rs | 922 | ||||
| -rw-r--r-- | libs/binder/rust/src/proxy.rs | 512 | ||||
| -rw-r--r-- | libs/binder/rust/src/state.rs | 101 | ||||
| -rw-r--r-- | libs/binder/rust/tests/Android.bp | 24 | ||||
| -rw-r--r-- | libs/binder/rust/tests/AndroidTest.xml | 28 | ||||
| -rw-r--r-- | libs/binder/rust/tests/integration.rs | 371 |
15 files changed, 4147 insertions, 0 deletions
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp new file mode 100644 index 0000000000..16811eebe4 --- /dev/null +++ b/libs/binder/rust/Android.bp @@ -0,0 +1,74 @@ +rust_library { + name: "libbinder_rs", + crate_name: "binder", + srcs: ["src/lib.rs"], + shared_libs: [ + "libbinder_ndk", + "libutils", + ], + rustlibs: [ + "liblibc", + "libbinder_ndk_bindgen", + ], + host_supported: true, +} + +rust_bindgen { + name: "libbinder_ndk_bindgen", + crate_name: "binder_ndk_bindgen", + wrapper_src: "BinderBindings.h", + source_stem: "ndk_bindings", + cflags: [ + "-x c++", + ], + bindgen_flags: [ + // Unfortunately the only way to specify the rust_non_exhaustive enum + // style for a type is to make it the default + "--default-enum-style", "rust_non_exhaustive", + // and then specify constified enums for the enums we don't want + // rustified + "--constified-enum", "android::c_interface::consts::.*", + + "--whitelist-type", "android::c_interface::.*", + "--whitelist-type", "AStatus", + "--whitelist-type", "AIBinder_Class", + "--whitelist-type", "AIBinder", + "--whitelist-type", "AIBinder_Weak", + "--whitelist-type", "AIBinder_DeathRecipient", + "--whitelist-type", "AParcel", + "--whitelist-type", "binder_status_t", + "--whitelist-function", ".*", + ], + shared_libs: [ + "libbinder_ndk", + ], + host_supported: true, + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + host: { + cflags: [ + "-D__INTRODUCED_IN(n)=", + "-D__assert(a,b,c)=", + // We want all the APIs to be available on the host. + "-D__ANDROID_API__=10000", + ], + }, + }, +} + +rust_test { + name: "libbinder_rs-internal_test", + crate_name: "binder", + srcs: ["src/lib.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + shared_libs: [ + "libbinder_ndk", + ], + rustlibs: [ + "liblibc", + "libbinder_ndk_bindgen", + ], +} diff --git a/libs/binder/rust/BinderBindings.h b/libs/binder/rust/BinderBindings.h new file mode 100644 index 0000000000..c7a06d9a1c --- /dev/null +++ b/libs/binder/rust/BinderBindings.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/binder_ibinder.h> +#include <android/binder_manager.h> +#include <android/binder_parcel.h> +#include <android/binder_process.h> +#include <android/binder_shell.h> +#include <android/binder_status.h> + +namespace android { + +namespace c_interface { + +// Expose error codes from anonymous enum in binder_status.h +enum StatusCode { + OK = STATUS_OK, + UNKNOWN_ERROR = STATUS_UNKNOWN_ERROR, + NO_MEMORY = STATUS_NO_MEMORY, + INVALID_OPERATION = STATUS_INVALID_OPERATION, + BAD_VALUE = STATUS_BAD_VALUE, + BAD_TYPE = STATUS_BAD_TYPE, + NAME_NOT_FOUND = STATUS_NAME_NOT_FOUND, + PERMISSION_DENIED = STATUS_PERMISSION_DENIED, + NO_INIT = STATUS_NO_INIT, + ALREADY_EXISTS = STATUS_ALREADY_EXISTS, + DEAD_OBJECT = STATUS_DEAD_OBJECT, + FAILED_TRANSACTION = STATUS_FAILED_TRANSACTION, + BAD_INDEX = STATUS_BAD_INDEX, + NOT_ENOUGH_DATA = STATUS_NOT_ENOUGH_DATA, + WOULD_BLOCK = STATUS_WOULD_BLOCK, + TIMED_OUT = STATUS_TIMED_OUT, + UNKNOWN_TRANSACTION = STATUS_UNKNOWN_TRANSACTION, + FDS_NOT_ALLOWED = STATUS_FDS_NOT_ALLOWED, + UNEXPECTED_NULL = STATUS_UNEXPECTED_NULL, +}; + +// Expose exception codes from anonymous enum in binder_status.h +enum ExceptionCode { + NONE = EX_NONE, + SECURITY = EX_SECURITY, + BAD_PARCELABLE = EX_BAD_PARCELABLE, + ILLEGAL_ARGUMENT = EX_ILLEGAL_ARGUMENT, + NULL_POINTER = EX_NULL_POINTER, + ILLEGAL_STATE = EX_ILLEGAL_STATE, + NETWORK_MAIN_THREAD = EX_NETWORK_MAIN_THREAD, + UNSUPPORTED_OPERATION = EX_UNSUPPORTED_OPERATION, + SERVICE_SPECIFIC = EX_SERVICE_SPECIFIC, + PARCELABLE = EX_PARCELABLE, + + /** + * This is special, and indicates to native binder proxies that the + * transaction has failed at a low level. + */ + TRANSACTION_FAILED = EX_TRANSACTION_FAILED, +}; + +namespace consts { + +enum { + FIRST_CALL_TRANSACTION = FIRST_CALL_TRANSACTION, + LAST_CALL_TRANSACTION = LAST_CALL_TRANSACTION, +}; + +enum { + FLAG_ONEWAY = FLAG_ONEWAY, +}; + +} // namespace consts + +} // namespace c_interface + +} // namespace android diff --git a/libs/binder/rust/TEST_MAPPING b/libs/binder/rust/TEST_MAPPING new file mode 100644 index 0000000000..4470e17734 --- /dev/null +++ b/libs/binder/rust/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "libbinder_rs-internal_test" + }, + { + "name": "rustBinderTest" + } + ] +} diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs new file mode 100644 index 0000000000..f5e75090c7 --- /dev/null +++ b/libs/binder/rust/src/binder.rs @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Trait definitions for binder objects + +use crate::error::{status_t, Result}; +use crate::parcel::Parcel; +use crate::proxy::{DeathRecipient, SpIBinder}; +use crate::sys; + +use std::ffi::{c_void, CString}; +use std::os::unix::io::AsRawFd; +use std::ptr; + +/// Binder action to perform. +/// +/// This must be a number between [`IBinder::FIRST_CALL_TRANSACTION`] and +/// [`IBinder::LAST_CALL_TRANSACTION`]. +pub type TransactionCode = u32; + +/// Additional operation flags. +/// +/// Can be either 0 for a normal RPC, or [`IBinder::FLAG_ONEWAY`] for a +/// one-way RPC. +pub type TransactionFlags = u32; + +/// Super-trait for Binder interfaces. +/// +/// This trait allows conversion of a Binder interface trait object into an +/// IBinder object for IPC calls. All Binder remotable interface (i.e. AIDL +/// interfaces) must implement this trait. +/// +/// This is equivalent `IInterface` in C++. +pub trait Interface { + /// Convert this binder object into a generic [`SpIBinder`] reference. + fn as_binder(&self) -> SpIBinder { + panic!("This object was not a Binder object and cannot be converted into an SpIBinder.") + } +} + +/// A local service that can be remotable via Binder. +/// +/// An object that implement this interface made be made into a Binder service +/// via `Binder::new(object)`. +/// +/// This is a low-level interface that should normally be automatically +/// generated from AIDL via the [`declare_binder_interface!`] macro. When using +/// the AIDL backend, users need only implement the high-level AIDL-defined +/// interface. The AIDL compiler then generates a container struct that wraps +/// the user-defined service and implements `Remotable`. +pub trait Remotable: Sync { + /// The Binder interface descriptor string. + /// + /// This string is a unique identifier for a Binder interface, and should be + /// the same between all implementations of that interface. + fn get_descriptor() -> &'static str; + + /// Handle and reply to a request to invoke a transaction on this object. + /// + /// `reply` may be [`None`] if the sender does not expect a reply. + fn on_transact(&self, code: TransactionCode, data: &Parcel, reply: &mut Parcel) -> Result<()>; + + /// Retrieve the class of this remote object. + /// + /// This method should always return the same InterfaceClass for the same + /// type. + fn get_class() -> InterfaceClass; +} + +/// Interface of binder local or remote objects. +/// +/// This trait corresponds to the interface of the C++ `IBinder` class. +pub trait IBinder { + /// First transaction code available for user commands (inclusive) + const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION; + /// Last transaction code available for user commands (inclusive) + const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION; + + /// Corresponds to TF_ONE_WAY -- an asynchronous call. + const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY; + + /// Is this object still alive? + fn is_binder_alive(&self) -> bool; + + /// Send a ping transaction to this object + fn ping_binder(&mut self) -> Result<()>; + + /// Dump this object to the given file handle + fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()>; + + /// Get a new interface that exposes additional extension functionality, if + /// available. + fn get_extension(&mut self) -> Result<Option<SpIBinder>>; + + /// Perform a generic operation with the object. + /// + /// # Arguments + /// * `code` - Transaction code for the operation + /// * `data` - [`Parcel`] with input data + /// * `reply` - Optional [`Parcel`] for reply data + /// * `flags` - Transaction flags, e.g. marking the transaction as + /// asynchronous ([`FLAG_ONEWAY`](IBinder::FLAG_ONEWAY)) + fn transact<F: FnOnce(&mut Parcel) -> Result<()>>( + &self, + code: TransactionCode, + flags: TransactionFlags, + input_callback: F, + ) -> Result<Parcel>; + + /// Register the recipient for a notification if this binder + /// goes away. If this binder object unexpectedly goes away + /// (typically because its hosting process has been killed), + /// then DeathRecipient::binder_died() will be called with a reference + /// to this. + /// + /// You will only receive death notifications for remote binders, + /// as local binders by definition can't die without you dying as well. + /// Trying to use this function on a local binder will result in an + /// INVALID_OPERATION code being returned and nothing happening. + /// + /// This link always holds a weak reference to its recipient. + /// + /// You will only receive a weak reference to the dead + /// binder. You should not try to promote this to a strong reference. + /// (Nor should you need to, as there is nothing useful you can + /// directly do with it now that it has passed on.) + fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>; + + /// Remove a previously registered death notification. + /// The recipient will no longer be called if this object + /// dies. + fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>; +} + +/// Opaque reference to the type of a Binder interface. +/// +/// This object encapsulates the Binder interface descriptor string, along with +/// the binder transaction callback, if the class describes a local service. +/// +/// A Binder remotable object may only have a single interface class, and any +/// given object can only be associated with one class. Two objects with +/// different classes are incompatible, even if both classes have the same +/// interface descriptor. +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct InterfaceClass(*const sys::AIBinder_Class); + +impl InterfaceClass { + /// Get a Binder NDK `AIBinder_Class` pointer for this object type. + /// + /// Note: the returned pointer will not be constant. Calling this method + /// multiple times for the same type will result in distinct class + /// pointers. A static getter for this value is implemented in + /// [`declare_binder_interface!`]. + pub fn new<I: InterfaceClassMethods>() -> InterfaceClass { + let descriptor = CString::new(I::get_descriptor()).unwrap(); + let ptr = unsafe { + // Safety: `AIBinder_Class_define` expects a valid C string, and + // three valid callback functions, all non-null pointers. The C + // string is copied and need not be valid for longer than the call, + // so we can drop it after the call. We can safely assign null to + // the onDump and handleShellCommand callbacks as long as the class + // pointer was non-null. Rust None for a Option<fn> is guaranteed to + // be a NULL pointer. Rust retains ownership of the pointer after it + // is defined. + let class = sys::AIBinder_Class_define( + descriptor.as_ptr(), + Some(I::on_create), + Some(I::on_destroy), + Some(I::on_transact), + ); + if class.is_null() { + panic!("Expected non-null class pointer from AIBinder_Class_define!"); + } + sys::AIBinder_Class_setOnDump(class, None); + sys::AIBinder_Class_setHandleShellCommand(class, None); + class + }; + InterfaceClass(ptr) + } + + /// Construct an `InterfaceClass` out of a raw, non-null `AIBinder_Class` + /// pointer. + /// + /// # Safety + /// + /// This function is safe iff `ptr` is a valid, non-null pointer to an + /// `AIBinder_Class`. + pub(crate) unsafe fn from_ptr(ptr: *const sys::AIBinder_Class) -> InterfaceClass { + InterfaceClass(ptr) + } +} + +impl From<InterfaceClass> for *const sys::AIBinder_Class { + fn from(class: InterfaceClass) -> *const sys::AIBinder_Class { + class.0 + } +} + +/// Create a function implementing a static getter for an interface class. +/// +/// Each binder interface (i.e. local [`Remotable`] service or remote proxy +/// [`Interface`]) must have global, static class that uniquely identifies +/// it. This macro implements an [`InterfaceClass`] getter to simplify these +/// implementations. +/// +/// The type of a structure that implements [`InterfaceClassMethods`] must be +/// passed to this macro. For local services, this should be `Binder<Self>` +/// since [`Binder`] implements [`InterfaceClassMethods`]. +/// +/// # Examples +/// +/// When implementing a local [`Remotable`] service `ExampleService`, the +/// `get_class` method is required in the [`Remotable`] impl block. This macro +/// should be used as follows to implement this functionality: +/// +/// ```rust +/// impl Remotable for ExampleService { +/// fn get_descriptor() -> &'static str { +/// "android.os.IExampleInterface" +/// } +/// +/// fn on_transact( +/// &self, +/// code: TransactionCode, +/// data: &Parcel, +/// reply: &mut Parcel, +/// ) -> Result<()> { +/// // ... +/// } +/// +/// binder_fn_get_class!(Binder<Self>); +/// } +/// ``` +macro_rules! binder_fn_get_class { + ($class:ty) => { + binder_fn_get_class!($crate::InterfaceClass::new::<$class>()); + }; + + ($constructor:expr) => { + fn get_class() -> $crate::InterfaceClass { + static CLASS_INIT: std::sync::Once = std::sync::Once::new(); + static mut CLASS: Option<$crate::InterfaceClass> = None; + + CLASS_INIT.call_once(|| unsafe { + // Safety: This assignment is guarded by the `CLASS_INIT` `Once` + // variable, and therefore is thread-safe, as it can only occur + // once. + CLASS = Some($constructor); + }); + unsafe { + // Safety: The `CLASS` variable can only be mutated once, above, + // and is subsequently safe to read from any thread. + CLASS.unwrap() + } + } + }; +} + +pub trait InterfaceClassMethods { + /// Get the interface descriptor string for this object type. + fn get_descriptor() -> &'static str + where + Self: Sized; + + /// Called during construction of a new `AIBinder` object of this interface + /// class. + /// + /// The opaque pointer parameter will be the parameter provided to + /// `AIBinder_new`. Returns an opaque userdata to be associated with the new + /// `AIBinder` object. + /// + /// # Safety + /// + /// Callback called from C++. The parameter argument provided to + /// `AIBinder_new` must match the type expected here. The `AIBinder` object + /// will take ownership of the returned pointer, which it will free via + /// `on_destroy`. + unsafe extern "C" fn on_create(args: *mut c_void) -> *mut c_void; + + /// Called when a transaction needs to be processed by the local service + /// implementation. + /// + /// # Safety + /// + /// Callback called from C++. The `binder` parameter must be a valid pointer + /// to a binder object of this class with userdata initialized via this + /// class's `on_create`. The parcel parameters must be valid pointers to + /// parcel objects. + unsafe extern "C" fn on_transact( + binder: *mut sys::AIBinder, + code: u32, + data: *const sys::AParcel, + reply: *mut sys::AParcel, + ) -> status_t; + + /// Called whenever an `AIBinder` object is no longer referenced and needs + /// to be destroyed. + /// + /// # Safety + /// + /// Callback called from C++. The opaque pointer parameter must be the value + /// returned by `on_create` for this class. This function takes ownership of + /// the provided pointer and destroys it. + unsafe extern "C" fn on_destroy(object: *mut c_void); +} + +/// Interface for transforming a generic SpIBinder into a specific remote +/// interface trait. +/// +/// # Example +/// +/// For Binder interface `IFoo`, the following implementation should be made: +/// ```no_run +/// # use binder::{FromIBinder, SpIBinder, Result}; +/// # trait IFoo {} +/// impl FromIBinder for dyn IFoo { +/// fn try_from(ibinder: SpIBinder) -> Result<Box<Self>> { +/// // ... +/// # Err(binder::StatusCode::OK) +/// } +/// } +/// ``` +pub trait FromIBinder { + /// Try to interpret a generic Binder object as this interface. + /// + /// Returns a trait object for the `Self` interface if this object + /// implements that interface. + fn try_from(ibinder: SpIBinder) -> Result<Box<Self>>; +} + +/// Trait for transparent Rust wrappers around android C++ native types. +/// +/// The pointer return by this trait's methods should be immediately passed to +/// C++ and not stored by Rust. The pointer is valid only as long as the +/// underlying C++ object is alive, so users must be careful to take this into +/// account, as Rust cannot enforce this. +/// +/// # Safety +/// +/// For this trait to be a correct implementation, `T` must be a valid android +/// C++ type. Since we cannot constrain this via the type system, this trait is +/// marked as unsafe. +pub unsafe trait AsNative<T> { + /// Return a pointer to the native version of `self` + fn as_native(&self) -> *const T; + + /// Return a mutable pointer to the native version of `self` + fn as_native_mut(&mut self) -> *mut T; +} + +unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> { + fn as_native(&self) -> *const T { + self.as_ref().map_or(ptr::null(), |v| v.as_native()) + } + + fn as_native_mut(&mut self) -> *mut T { + self.as_mut().map_or(ptr::null_mut(), |v| v.as_native_mut()) + } +} + +/// Declare typed interfaces for a binder object. +/// +/// Given an interface trait and descriptor string, create a native and remote +/// proxy wrapper for this interface. The native service object (`$native`) +/// implements `Remotable` and will dispatch to the function `$on_transact` to +/// handle transactions. The typed proxy object (`$proxy`) wraps remote binder +/// objects for this interface and can optionally contain additional fields. +/// +/// Assuming the interface trait is `Interface`, `$on_transact` function must +/// have the following type: +/// +/// ``` +/// # use binder::{Interface, TransactionCode, Parcel}; +/// # trait Placeholder { +/// fn on_transact( +/// service: &dyn Interface, +/// code: TransactionCode, +/// data: &Parcel, +/// reply: &mut Parcel, +/// ) -> binder::Result<()>; +/// # } +/// ``` +/// +/// # Examples +/// +/// The following example declares the local service type `BnServiceManager` and +/// a remote proxy type `BpServiceManager` (the `n` and `p` stand for native and +/// proxy respectively) for the `IServiceManager` Binder interface. The +/// interfaces will be identified by the descriptor string +/// "android.os.IServiceManager". The local service will dispatch transactions +/// using the provided function, `on_transact`. +/// +/// ``` +/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, Parcel}; +/// +/// pub trait IServiceManager: Interface { +/// // remote methods... +/// } +/// +/// declare_binder_interface! { +/// IServiceManager["android.os.IServiceManager"] { +/// native: BnServiceManager(on_transact), +/// proxy: BpServiceManager, +/// } +/// } +/// +/// fn on_transact( +/// service: &dyn IServiceManager, +/// code: TransactionCode, +/// data: &Parcel, +/// reply: &mut Parcel, +/// ) -> binder::Result<()> { +/// // ... +/// Ok(()) +/// } +/// +/// impl IServiceManager for BpServiceManager { +/// // parceling/unparceling code for the IServiceManager emitted here +/// } +/// +/// impl IServiceManager for Binder<BnServiceManager> { +/// // Forward calls to local implementation +/// } +/// ``` +#[macro_export] +macro_rules! declare_binder_interface { + { + $interface:path[$descriptor:expr] { + native: $native:ident($on_transact:path), + proxy: $proxy:ident, + } + } => { + $crate::declare_binder_interface! { + $interface[$descriptor] { + native: $native($on_transact), + proxy: $proxy {}, + } + } + }; + + { + $interface:path[$descriptor:expr] { + native: $native:ident($on_transact:path), + proxy: $proxy:ident { + $($fname:ident: $fty:ty = $finit:expr),* + }, + } + } => { + $crate::declare_binder_interface! { + $interface[$descriptor] { + @doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")] + native: $native($on_transact), + @doc[concat!("A binder [`Proxy`]($crate::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")] + proxy: $proxy { + $($fname: $fty = $finit),* + }, + } + } + }; + + { + $interface:path[$descriptor:expr] { + @doc[$native_doc:expr] + native: $native:ident($on_transact:path), + + @doc[$proxy_doc:expr] + proxy: $proxy:ident { + $($fname:ident: $fty:ty = $finit:expr),* + }, + } + } => { + #[doc = $proxy_doc] + pub struct $proxy { + binder: $crate::SpIBinder, + $($fname: $fty,)* + } + + impl $crate::Interface for $proxy { + fn as_binder(&self) -> $crate::SpIBinder { + self.binder.clone() + } + } + + impl $crate::Proxy for $proxy + where + $proxy: $interface, + { + fn get_descriptor() -> &'static str { + $descriptor + } + + 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) + } + } + } + + #[doc = $native_doc] + #[repr(transparent)] + pub struct $native(Box<dyn $interface + Sync + Send + 'static>); + + impl $native { + /// Create a new binder service. + pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> impl $interface { + $crate::Binder::new($native(Box::new(inner))) + } + } + + impl $crate::Remotable for $native { + fn get_descriptor() -> &'static str { + $descriptor + } + + fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> { + $on_transact(&*self.0, code, data, reply) + } + + fn get_class() -> $crate::InterfaceClass { + static CLASS_INIT: std::sync::Once = std::sync::Once::new(); + static mut CLASS: Option<$crate::InterfaceClass> = None; + + CLASS_INIT.call_once(|| unsafe { + // Safety: This assignment is guarded by the `CLASS_INIT` `Once` + // variable, and therefore is thread-safe, as it can only occur + // once. + CLASS = Some($crate::InterfaceClass::new::<$crate::Binder<$native>>()); + }); + unsafe { + // Safety: The `CLASS` variable can only be mutated once, above, + // and is subsequently safe to read from any thread. + CLASS.unwrap() + } + } + } + + 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 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)?)) + } + } + } + + impl $crate::parcel::Serialize for dyn $interface + '_ + where + $interface: $crate::Interface + { + fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> { + let binder = $crate::Interface::as_binder(self); + parcel.write(&binder) + } + } + + impl $crate::parcel::SerializeOption for dyn $interface + '_ { + fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> { + parcel.write(&this.map($crate::Interface::as_binder)) + } + } + }; +} diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs new file mode 100644 index 0000000000..289b1573db --- /dev/null +++ b/libs/binder/rust/src/error.rs @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::binder::AsNative; +use crate::sys; + +use std::error; +use std::ffi::CStr; +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; +use std::result; + +pub use sys::binder_status_t as status_t; + +/// Low-level status codes from Android `libutils`. +// All error codes are negative integer values. Derived from the anonymous enum +// in utils/Errors.h +pub use sys::android_c_interface_StatusCode as StatusCode; + +/// A specialized [`Result`](result::Result) for binder operations. +pub type Result<T> = result::Result<T, StatusCode>; + +/// Convert a low-level status code into an empty result. +/// +/// An OK status is converted into an `Ok` result, any other status is converted +/// into an `Err` result holding the status code. +pub fn status_result(status: status_t) -> Result<()> { + match parse_status_code(status) { + StatusCode::OK => Ok(()), + e => Err(e), + } +} + +// impl Display for StatusCode { +// fn fmt(&self, f: &mut Formatter) -> FmtResult { +// write!(f, "StatusCode::{:?}", self) +// } +// } + +// impl error::Error for StatusCode {} + +fn parse_status_code(code: i32) -> StatusCode { + match code { + e if e == StatusCode::OK as i32 => StatusCode::OK, + e if e == StatusCode::NO_MEMORY as i32 => StatusCode::NO_MEMORY, + e if e == StatusCode::INVALID_OPERATION as i32 => StatusCode::INVALID_OPERATION, + e if e == StatusCode::BAD_VALUE as i32 => StatusCode::BAD_VALUE, + e if e == StatusCode::BAD_TYPE as i32 => StatusCode::BAD_TYPE, + e if e == StatusCode::NAME_NOT_FOUND as i32 => StatusCode::NAME_NOT_FOUND, + e if e == StatusCode::PERMISSION_DENIED as i32 => StatusCode::PERMISSION_DENIED, + e if e == StatusCode::NO_INIT as i32 => StatusCode::NO_INIT, + e if e == StatusCode::ALREADY_EXISTS as i32 => StatusCode::ALREADY_EXISTS, + e if e == StatusCode::DEAD_OBJECT as i32 => StatusCode::DEAD_OBJECT, + e if e == StatusCode::FAILED_TRANSACTION as i32 => StatusCode::FAILED_TRANSACTION, + e if e == StatusCode::BAD_INDEX as i32 => StatusCode::BAD_INDEX, + e if e == StatusCode::NOT_ENOUGH_DATA as i32 => StatusCode::NOT_ENOUGH_DATA, + e if e == StatusCode::WOULD_BLOCK as i32 => StatusCode::WOULD_BLOCK, + e if e == StatusCode::TIMED_OUT as i32 => StatusCode::TIMED_OUT, + e if e == StatusCode::UNKNOWN_TRANSACTION as i32 => StatusCode::UNKNOWN_TRANSACTION, + e if e == StatusCode::FDS_NOT_ALLOWED as i32 => StatusCode::FDS_NOT_ALLOWED, + e if e == StatusCode::UNEXPECTED_NULL as i32 => StatusCode::UNEXPECTED_NULL, + _ => StatusCode::UNKNOWN_ERROR, + } +} + +pub use sys::android_c_interface_ExceptionCode as ExceptionCode; + +fn parse_exception_code(code: i32) -> ExceptionCode { + match code { + e if e == ExceptionCode::NONE as i32 => ExceptionCode::NONE, + e if e == ExceptionCode::SECURITY as i32 => ExceptionCode::SECURITY, + e if e == ExceptionCode::BAD_PARCELABLE as i32 => ExceptionCode::BAD_PARCELABLE, + e if e == ExceptionCode::ILLEGAL_ARGUMENT as i32 => ExceptionCode::ILLEGAL_ARGUMENT, + e if e == ExceptionCode::NULL_POINTER as i32 => ExceptionCode::NULL_POINTER, + e if e == ExceptionCode::ILLEGAL_STATE as i32 => ExceptionCode::ILLEGAL_STATE, + e if e == ExceptionCode::NETWORK_MAIN_THREAD as i32 => { + ExceptionCode::NETWORK_MAIN_THREAD + } + e if e == ExceptionCode::UNSUPPORTED_OPERATION as i32 => { + ExceptionCode::UNSUPPORTED_OPERATION + } + e if e == ExceptionCode::SERVICE_SPECIFIC as i32 => ExceptionCode::SERVICE_SPECIFIC, + _ => ExceptionCode::TRANSACTION_FAILED, + } +} + +// Safety: `Status` always contains a owning pointer to a valid `AStatus`. The +// lifetime of the contained pointer is the same as the `Status` object. +/// High-level binder status object that encapsulates a standard way to keep +/// track of and chain binder errors along with service specific errors. +/// +/// Used in AIDL transactions to represent failed transactions. +pub struct Status(*mut sys::AStatus); + +impl Status { + /// Create a status object representing a successful transaction. + pub fn ok() -> Self { + let ptr = unsafe { + // Safety: `AStatus_newOk` always returns a new, heap allocated + // pointer to an `ASTatus` object, so we know this pointer will be + // valid. + // + // Rust takes ownership of the returned pointer. + sys::AStatus_newOk() + }; + Self(ptr) + } + + /// Create a status object from a service specific error + pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status { + let ptr = if let Some(message) = message { + unsafe { + // Safety: Any i32 is a valid service specific error for the + // error code parameter. We construct a valid, null-terminated + // `CString` from the message, which must be a valid C-style + // string to pass as the message. This function always returns a + // new, heap allocated pointer to an `AStatus` object, so we + // know the returned pointer will be valid. + // + // Rust takes ownership of the returned pointer. + sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) + } + } else { + unsafe { + // Safety: Any i32 is a valid service specific error for the + // error code parameter. This function always returns a new, + // heap allocated pointer to an `AStatus` object, so we know the + // returned pointer will be valid. + // + // Rust takes ownership of the returned pointer. + sys::AStatus_fromServiceSpecificError(err) + } + }; + Self(ptr) + } + + /// Create a status object from an exception code + pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status { + if let Some(message) = message { + let ptr = unsafe { + sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr()) + }; + Self(ptr) + } else { + exception.into() + } + } + + /// Create a status object from a raw `AStatus` pointer. + /// + /// # Safety + /// + /// This constructor is safe iff `ptr` is a valid pointer to an `AStatus`. + pub(crate) unsafe fn from_ptr(ptr: *mut sys::AStatus) -> Self { + Self(ptr) + } + + /// Returns `true` if this status represents a successful transaction. + pub fn is_ok(&self) -> bool { + unsafe { + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_isOk` here. + sys::AStatus_isOk(self.as_native()) + } + } + + /// Returns a description of the status. + pub fn get_description(&self) -> String { + let description_ptr = unsafe { + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getDescription` + // here. + // + // `AStatus_getDescription` always returns a valid pointer to a null + // terminated C string. Rust is responsible for freeing this pointer + // via `AStatus_deleteDescription`. + sys::AStatus_getDescription(self.as_native()) + }; + let description = unsafe { + // Safety: `AStatus_getDescription` always returns a valid C string, + // which can be safely converted to a `CStr`. + CStr::from_ptr(description_ptr) + }; + let description = description.to_string_lossy().to_string(); + unsafe { + // Safety: `description_ptr` was returned from + // `AStatus_getDescription` above, and must be freed via + // `AStatus_deleteDescription`. We must not access the pointer after + // this call, so we copy it into an owned string above and return + // that string. + sys::AStatus_deleteDescription(description_ptr); + } + description + } + + /// Returns the exception code of the status. + pub fn exception_code(&self) -> ExceptionCode { + let code = unsafe { + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getExceptionCode` + // here. + sys::AStatus_getExceptionCode(self.as_native()) + }; + parse_exception_code(code) + } + + /// Return a status code representing a transaction failure, or + /// `StatusCode::OK` if there was no transaction failure. + /// + /// If this method returns `OK`, the status may still represent a different + /// exception or a service specific error. To find out if this transaction + /// as a whole is okay, use [`is_ok`](Self::is_ok) instead. + pub fn transaction_error(&self) -> StatusCode { + let code = unsafe { + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getStatus` here. + sys::AStatus_getStatus(self.as_native()) + }; + parse_status_code(code) + } + + /// Return a service specific error if this status represents one. + /// + /// This function will only ever return a non-zero result if + /// [`exception_code`](Self::exception_code) returns + /// `ExceptionCode::SERVICE_SPECIFIC`. If this function returns 0, the + /// status object may still represent a different exception or status. To + /// find out if this transaction as a whole is okay, use + /// [`is_ok`](Self::is_ok) instead. + pub fn service_specific_error(&self) -> i32 { + unsafe { + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to + // `AStatus_getServiceSpecificError` here. + sys::AStatus_getServiceSpecificError(self.as_native()) + } + } + + /// Calls `op` if the status was ok, otherwise returns an `Err` value of + /// `self`. + pub fn and_then<T, F>(self, op: F) -> result::Result<T, Status> + where + F: FnOnce() -> result::Result<T, Status>, + { + <result::Result<(), Status>>::from(self)?; + op() + } +} + +impl error::Error for Status {} + +impl Display for Status { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_str(&self.get_description()) + } +} + +impl Debug for Status { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_str(&self.get_description()) + } +} + +impl PartialEq for Status { + fn eq(&self, other: &Status) -> bool { + let self_code = self.exception_code(); + let other_code = other.exception_code(); + + match (self_code, other_code) { + (ExceptionCode::NONE, ExceptionCode::NONE) => true, + (ExceptionCode::TRANSACTION_FAILED, ExceptionCode::TRANSACTION_FAILED) => { + self.transaction_error() == other.transaction_error() + && self.get_description() == other.get_description() + } + (ExceptionCode::SERVICE_SPECIFIC, ExceptionCode::SERVICE_SPECIFIC) => { + self.service_specific_error() == other.service_specific_error() + && self.get_description() == other.get_description() + } + (e1, e2) => e1 == e2 && self.get_description() == other.get_description(), + } + } +} + +impl Eq for Status {} + +impl From<StatusCode> for Status { + fn from(status: StatusCode) -> Status { + (status as status_t).into() + } +} + +impl From<status_t> for Status { + fn from(status: status_t) -> Status { + let ptr = unsafe { + // Safety: `AStatus_fromStatus` expects any `status_t` integer, so + // this is a safe FFI call. Unknown values will be coerced into + // UNKNOWN_ERROR. + sys::AStatus_fromStatus(status) + }; + Self(ptr) + } +} + +impl From<ExceptionCode> for Status { + fn from(code: ExceptionCode) -> Status { + let ptr = unsafe { + // Safety: `AStatus_fromExceptionCode` expects any + // `binder_exception_t` (i32) integer, so this is a safe FFI call. + // Unknown values will be coerced into EX_TRANSACTION_FAILED. + sys::AStatus_fromExceptionCode(code as i32) + }; + Self(ptr) + } +} + +// TODO: impl Try for Status when try_trait is stabilized +// https://github.com/rust-lang/rust/issues/42327 +impl From<Status> for result::Result<(), Status> { + fn from(status: Status) -> result::Result<(), Status> { + if status.is_ok() { + Ok(()) + } else { + Err(status) + } + } +} + +impl From<Status> for status_t { + fn from(status: Status) -> status_t { + status.transaction_error() as status_t + } +} + +impl Drop for Status { + fn drop(&mut self) { + unsafe { + // Safety: `Status` manages the lifetime of its inner `AStatus` + // pointee, so we need to delete it here. We know that the pointer + // will be valid here since `Status` always contains a valid pointer + // while it is alive. + sys::AStatus_delete(self.0); + } + } +} + +/// # Safety +/// +/// `Status` always contains a valid pointer to an `AStatus` object, so we can +/// trivially convert it to a correctly-typed raw pointer. +/// +/// Care must be taken that the returned pointer is only dereferenced while the +/// `Status` object is still alive. +unsafe impl AsNative<sys::AStatus> for Status { + fn as_native(&self) -> *const sys::AStatus { + self.0 + } + + fn as_native_mut(&mut self) -> *mut sys::AStatus { + self.0 + } +} diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs new file mode 100644 index 0000000000..4b9cccf41b --- /dev/null +++ b/libs/binder/rust/src/lib.rs @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Safe Rust interface to Android `libbinder`. +//! +//! This crate is primarily designed as an target for a Rust AIDL compiler +//! backend, and should generally not be used directly by users. It is built on +//! top of the binder NDK library to be usable by APEX modules, and therefore +//! only exposes functionality available in the NDK interface. +//! +//! # Example +//! +//! The following example illustrates how the AIDL backend will use this crate. +//! +//! ``` +//! use binder::{ +//! declare_binder_interface, Binder, IBinder, Interface, Remotable, Parcel, SpIBinder, +//! StatusCode, TransactionCode, +//! }; +//! +//! // Generated by AIDL compiler +//! pub trait ITest: Interface { +//! fn test(&self) -> binder::Result<String>; +//! } +//! +//! // Creates a new local (native) service object, BnTest, and a remote proxy +//! // object, BpTest, that are the typed interfaces for their respective ends +//! // of the binder transaction. Generated by AIDL compiler. +//! declare_binder_interface! { +//! ITest["android.os.ITest"] { +//! native: BnTest(on_transact), +//! proxy: BpTest, +//! } +//! } +//! +//! // Generated by AIDL compiler +//! fn on_transact( +//! service: &dyn ITest, +//! code: TransactionCode, +//! _data: &Parcel, +//! reply: &mut Parcel, +//! ) -> binder::Result<()> { +//! match code { +//! SpIBinder::FIRST_CALL_TRANSACTION => { +//! reply.write(&service.test()?)?; +//! Ok(()) +//! } +//! _ => Err(StatusCode::UNKNOWN_TRANSACTION), +//! } +//! } +//! +//! // Generated by AIDL compiler +//! impl ITest for Binder<BnTest> { +//! fn test(&self) -> binder::Result<String> { +//! self.0.test() +//! } +//! } +//! +//! // Generated by AIDL compiler +//! impl ITest for BpTest { +//! fn test(&self) -> binder::Result<String> { +//! let reply = self +//! .as_binder() +//! .transact(SpIBinder::FIRST_CALL_TRANSACTION, 0, |_| Ok(()))?; +//! reply.read() +//! } +//! } +//! +//! // User implemented: +//! +//! // Local implementation of the ITest remotable interface. +//! struct TestService; +//! +//! impl Interface for TestService {} +//! +//! impl ITest for TestService { +//! fn test(&self) -> binder::Result<String> { +//! Ok("testing service".to_string()) +//! } +//! } +//! ``` + +#[macro_use] +mod proxy; + +#[macro_use] +mod binder; +mod error; +mod native; +mod state; + +use binder_ndk_bindgen as sys; + +pub mod parcel; + +pub use crate::binder::{ + FromIBinder, IBinder, Interface, InterfaceClass, Remotable, TransactionCode, TransactionFlags, +}; +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::{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::{ + ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, + }; + + /// Binder result containing a [`Status`] on error. + pub type Result<T> = std::result::Result<T, Status>; +} diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs new file mode 100644 index 0000000000..798fed813e --- /dev/null +++ b/libs/binder/rust/src/native.rs @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode}; +use crate::error::{status_result, status_t, Result, StatusCode}; +use crate::parcel::{Parcel, Serialize}; +use crate::proxy::SpIBinder; +use crate::sys; + +use std::convert::TryFrom; +use std::ffi::{c_void, CString}; +use std::mem::ManuallyDrop; +use std::ops::Deref; +use std::ptr; + +/// Rust wrapper around Binder remotable objects. +/// +/// Implements the C++ `BBinder` class, and therefore implements the C++ +/// `IBinder` interface. +#[repr(C)] +pub struct Binder<T: Remotable> { + ibinder: *mut sys::AIBinder, + rust_object: *mut T, +} + +impl<T: Remotable> Binder<T> { + /// Create a new Binder remotable object. + /// + /// This moves the `rust_object` into an owned [`Box`] and Binder will + /// manage its lifetime. + pub fn new(rust_object: T) -> Binder<T> { + let class = T::get_class(); + let rust_object = Box::into_raw(Box::new(rust_object)); + let ibinder = unsafe { + // Safety: `AIBinder_new` expects a valid class pointer (which we + // initialize via `get_class`), and an arbitrary pointer + // argument. The caller owns the returned `AIBinder` pointer, which + // is a strong reference to a `BBinder`. This reference should be + // decremented via `AIBinder_decStrong` when the reference lifetime + // ends. + sys::AIBinder_new(class.into(), rust_object as *mut c_void) + }; + Binder { + ibinder, + rust_object, + } + } + + /// Set the extension of a binder interface. This allows a downstream + /// developer to add an extension to an interface without modifying its + /// interface file. This should be called immediately when the object is + /// created before it is passed to another thread. + /// + /// # Examples + /// + /// For instance, imagine if we have this Binder AIDL interface definition: + /// interface IFoo { void doFoo(); } + /// + /// If an unrelated owner (perhaps in a downstream codebase) wants to make a + /// change to the interface, they have two options: + /// + /// 1) Historical option that has proven to be BAD! Only the original + /// author of an interface should change an interface. If someone + /// downstream wants additional functionality, they should not ever + /// change the interface or use this method. + /// ```AIDL + /// BAD TO DO: interface IFoo { BAD TO DO + /// BAD TO DO: void doFoo(); BAD TO DO + /// BAD TO DO: + void doBar(); // adding a method BAD TO DO + /// BAD TO DO: } BAD TO DO + /// ``` + /// + /// 2) Option that this method enables! + /// Leave the original interface unchanged (do not change IFoo!). + /// Instead, create a new AIDL interface in a downstream package: + /// ```AIDL + /// package com.<name>; // new functionality in a new package + /// interface IBar { void doBar(); } + /// ``` + /// + /// When registering the interface, add: + /// + /// # use binder::{Binder, Interface}; + /// # type MyFoo = (); + /// # type MyBar = (); + /// # let my_foo = (); + /// # let my_bar = (); + /// let mut foo: Binder<MyFoo> = Binder::new(my_foo); // class in AOSP codebase + /// let bar: Binder<MyBar> = Binder::new(my_bar); // custom extension class + /// foo.set_extension(&mut bar.as_binder()); // use method in Binder + /// + /// Then, clients of `IFoo` can get this extension: + /// + /// # use binder::{declare_binder_interface, Binder, TransactionCode, Parcel}; + /// # trait IBar {} + /// # declare_binder_interface! { + /// # IBar["test"] { + /// # native: BnBar(on_transact), + /// # proxy: BpBar, + /// # } + /// # } + /// # fn on_transact( + /// # service: &dyn IBar, + /// # code: TransactionCode, + /// # data: &Parcel, + /// # reply: &mut Parcel, + /// # ) -> binder::Result<()> { + /// # Ok(()) + /// # } + /// # impl IBar for BpBar {} + /// # impl IBar for Binder<BnBar> {} + /// # fn main() -> binder::Result<()> { + /// # let binder = Binder::new(()); + /// if let Some(barBinder) = binder.get_extension()? { + /// let bar = BpBar::new(barBinder) + /// .expect("Extension was not of type IBar"); + /// } else { + /// // There was no extension + /// } + /// # } + pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> { + let status = unsafe { + // Safety: `AIBinder_setExtension` expects two valid, mutable + // `AIBinder` pointers. We are guaranteed that both `self` and + // `extension` contain valid `AIBinder` pointers, because they + // cannot be initialized without a valid + // pointer. `AIBinder_setExtension` does not take ownership of + // either parameter. + sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) + }; + status_result(status) + } + + /// Retrieve the interface descriptor string for this object's Binder + /// interface. + pub fn get_descriptor() -> &'static str { + T::get_descriptor() + } +} + +impl<T: Remotable> Interface for Binder<T> { + /// Converts the local remotable object into a generic `SpIBinder` + /// reference. + /// + /// The resulting `SpIBinder` will hold its own strong reference to this + /// remotable object, which will prevent the object from being dropped while + /// the `SpIBinder` is alive. + fn as_binder(&self) -> SpIBinder { + unsafe { + // Safety: `self.ibinder` is guaranteed to always be a valid pointer + // to an `AIBinder` by the `Binder` constructor. We are creating a + // copy of the `self.ibinder` strong reference, but + // `SpIBinder::from_raw` assumes it receives an owned pointer with + // its own strong reference. We first increment the reference count, + // so that the new `SpIBinder` will be tracked as a new reference. + sys::AIBinder_incStrong(self.ibinder); + SpIBinder::from_raw(self.ibinder).unwrap() + } + } +} + +impl<T: Remotable> InterfaceClassMethods for Binder<T> { + fn get_descriptor() -> &'static str { + <T as Remotable>::get_descriptor() + } + + /// Called whenever a transaction needs to be processed by a local + /// implementation. + /// + /// # Safety + /// + /// Must be called with a non-null, valid pointer to a local `AIBinder` that + /// contains a `T` pointer in its user data. The `data` and `reply` parcel + /// parameters must be valid pointers to `AParcel` objects. This method does + /// not take ownership of any of its parameters. + /// + /// These conditions hold when invoked by `ABBinder::onTransact`. + unsafe extern "C" fn on_transact( + binder: *mut sys::AIBinder, + code: u32, + data: *const sys::AParcel, + reply: *mut sys::AParcel, + ) -> status_t { + let res = { + let mut reply = Parcel::borrowed(reply).unwrap(); + let data = Parcel::borrowed(data as *mut sys::AParcel).unwrap(); + let object = sys::AIBinder_getUserData(binder); + let binder: &T = &*(object as *const T); + binder.on_transact(code, &data, &mut reply) + }; + match res { + Ok(()) => 0i32, + Err(e) => e as i32, + } + } + + /// Called whenever an `AIBinder` object is no longer referenced and needs + /// destroyed. + /// + /// # Safety + /// + /// Must be called with a valid pointer to a `T` object. After this call, + /// the pointer will be invalid and should not be dereferenced. + unsafe extern "C" fn on_destroy(object: *mut c_void) { + ptr::drop_in_place(object as *mut T) + } + + /// Called whenever a new, local `AIBinder` object is needed of a specific + /// class. + /// + /// Constructs the user data pointer that will be stored in the object, + /// which will be a heap-allocated `T` object. + /// + /// # Safety + /// + /// Must be called with a valid pointer to a `T` object allocated via `Box`. + unsafe extern "C" fn on_create(args: *mut c_void) -> *mut c_void { + // We just return the argument, as it is already a pointer to the rust + // object created by Box. + args + } +} + +impl<T: Remotable> Drop for Binder<T> { + // This causes C++ to decrease the strong ref count of the `AIBinder` + // object. We specifically do not drop the `rust_object` here. When C++ + // actually destroys the object, it calls `on_destroy` and we can drop the + // `rust_object` then. + fn drop(&mut self) { + unsafe { + // Safety: When `self` is dropped, we can no longer access the + // reference, so can decrement the reference count. `self.ibinder` + // is always a valid `AIBinder` pointer, so is valid to pass to + // `AIBinder_decStrong`. + sys::AIBinder_decStrong(self.ibinder); + } + } +} + +impl<T: Remotable> Deref for Binder<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { + // Safety: While `self` is alive, the reference count of the + // underlying object is > 0 and therefore `on_destroy` cannot be + // called. Therefore while `self` is alive, we know that + // `rust_object` is still a valid pointer to a heap allocated object + // of type `T`. + &*self.rust_object + } + } +} + +impl<B: Remotable> Serialize for Binder<B> { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + parcel.write_binder(Some(&self.as_binder())) + } +} + +// This implementation is an idiomatic implementation of the C++ +// `IBinder::localBinder` interface if the binder object is a Rust binder +// service. +impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> { + type Error = StatusCode; + + fn try_from(mut ibinder: SpIBinder) -> Result<Self> { + let class = B::get_class(); + if Some(class) != ibinder.get_class() { + return Err(StatusCode::BAD_TYPE); + } + let userdata = unsafe { + // Safety: `SpIBinder` always holds a valid pointer pointer to an + // `AIBinder`, which we can safely pass to + // `AIBinder_getUserData`. `ibinder` retains ownership of the + // returned pointer. + sys::AIBinder_getUserData(ibinder.as_native_mut()) + }; + if userdata.is_null() { + return Err(StatusCode::UNEXPECTED_NULL); + } + // We are transferring the ownership of the AIBinder into the new Binder + // object. + let mut ibinder = ManuallyDrop::new(ibinder); + Ok(Binder { + ibinder: ibinder.as_native_mut(), + rust_object: userdata as *mut B, + }) + } +} + +/// # Safety +/// +/// The constructor for `Binder` guarantees that `self.ibinder` will contain a +/// valid, non-null pointer to an `AIBinder`, so this implementation is type +/// safe. `self.ibinder` will remain valid for the entire lifetime of `self` +/// because we hold a strong reference to the `AIBinder` until `self` is +/// dropped. +unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> { + fn as_native(&self) -> *const sys::AIBinder { + self.ibinder + } + + fn as_native_mut(&mut self) -> *mut sys::AIBinder { + self.ibinder + } +} + +/// Register a new service with the default service manager. +/// +/// Registers the given binder object with the given identifier. If successful, +/// this service can then be retrieved using that identifier. +pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { + let instance = CString::new(identifier).unwrap(); + let status = unsafe { + // Safety: `AServiceManager_addService` expects valid `AIBinder` and C + // string pointers. Caller retains ownership of both + // pointers. `AServiceManager_addService` creates a new strong reference + // and copies the string, so both pointers need only be valid until the + // call returns. + sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) + }; + status_result(status) +} + +/// Tests often create a base BBinder instance; so allowing the unit +/// type to be remotable translates nicely to Binder::new(()). +impl Remotable for () { + fn get_descriptor() -> &'static str { + "" + } + + fn on_transact( + &self, + _code: TransactionCode, + _data: &Parcel, + _reply: &mut Parcel, + ) -> Result<()> { + Ok(()) + } + + binder_fn_get_class!(Binder::<Self>); +} + +impl Interface for () {} diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs new file mode 100644 index 0000000000..43850fe411 --- /dev/null +++ b/libs/binder/rust/src/parcel.rs @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Container for messages that are sent via binder. + +use crate::binder::AsNative; +use crate::error::{status_result, Result, StatusCode}; +use crate::proxy::SpIBinder; +use crate::sys; + +use std::convert::TryInto; +use std::mem::ManuallyDrop; +use std::ptr; + +mod file_descriptor; +mod parcelable; + +pub use self::file_descriptor::ParcelFileDescriptor; +pub use self::parcelable::{ + Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption, +}; + +/// Container for a message (data and object references) that can be sent +/// through Binder. +/// +/// A Parcel can contain both serialized data that will be deserialized on the +/// other side of the IPC, and references to live Binder objects that will +/// result in the other side receiving a proxy Binder connected with the +/// original Binder in the Parcel. +pub enum Parcel { + /// Owned parcel pointer + Owned(*mut sys::AParcel), + /// Borrowed parcel pointer (will not be destroyed on drop) + Borrowed(*mut sys::AParcel), +} + +/// # Safety +/// +/// The `Parcel` constructors guarantee that a `Parcel` object will always +/// contain a valid pointer to an `AParcel`. +unsafe impl AsNative<sys::AParcel> for Parcel { + fn as_native(&self) -> *const sys::AParcel { + match *self { + Self::Owned(x) | Self::Borrowed(x) => x, + } + } + + fn as_native_mut(&mut self) -> *mut sys::AParcel { + match *self { + Self::Owned(x) | Self::Borrowed(x) => x, + } + } +} + +impl Parcel { + /// Create a borrowed reference to a parcel object from a raw pointer. + /// + /// # Safety + /// + /// This constructor is safe if the raw pointer parameter is either null + /// (resulting in `None`), or a valid pointer to an `AParcel` object. + pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> { + ptr.as_mut().map(|ptr| Self::Borrowed(ptr)) + } + + /// Create an owned reference to a parcel object from a raw pointer. + /// + /// # Safety + /// + /// This constructor is safe if the raw pointer parameter is either null + /// (resulting in `None`), or a valid pointer to an `AParcel` object. The + /// parcel object must be owned by the caller prior to this call, as this + /// constructor takes ownership of the parcel and will destroy it on drop. + pub(crate) unsafe fn owned(ptr: *mut sys::AParcel) -> Option<Parcel> { + ptr.as_mut().map(|ptr| Self::Owned(ptr)) + } + + /// Consume the parcel, transferring ownership to the caller if the parcel + /// was owned. + pub(crate) fn into_raw(mut self) -> *mut sys::AParcel { + let ptr = self.as_native_mut(); + let _ = ManuallyDrop::new(self); + ptr + } +} + +// Data serialization methods +impl Parcel { + /// Write a type that implements [`Serialize`] to the `Parcel`. + pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> { + parcelable.serialize(self) + } + + /// Writes the length of a slice to the `Parcel`. + /// + /// This is used in AIDL-generated client side code to indicate the + /// allocated space for an output array parameter. + pub fn write_slice_size<T>(&mut self, slice: Option<&[T]>) -> Result<()> { + if let Some(slice) = slice { + let len: i32 = slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?; + self.write(&len) + } else { + self.write(&-1i32) + } + } + + /// Returns the current position in the parcel data. + pub fn get_data_position(&self) -> i32 { + unsafe { + // Safety: `Parcel` always contains a valid pointer to an `AParcel`, + // and this call is otherwise safe. + sys::AParcel_getDataPosition(self.as_native()) + } + } + + /// Move the current read/write position in the parcel. + /// + /// The new position must be a position previously returned by + /// `self.get_data_position()`. + /// + /// # Safety + /// + /// This method is safe if `pos` is less than the current size of the parcel + /// data buffer. Otherwise, we are relying on correct bounds checking in the + /// Parcel C++ code on every subsequent read or write to this parcel. If all + /// accesses are bounds checked, this call is still safe, but we can't rely + /// on that. + pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> { + status_result(sys::AParcel_setDataPosition(self.as_native(), pos)) + } +} + +// Data deserialization methods +impl Parcel { + /// Attempt to read a type that implements [`Deserialize`] from this + /// `Parcel`. + pub fn read<D: Deserialize>(&self) -> Result<D> { + D::deserialize(self) + } + + /// Read a vector size from the `Parcel` and resize the given output vector + /// to be correctly sized for that amount of data. + /// + /// This method is used in AIDL-generated server side code for methods that + /// take a mutable slice reference parameter. + pub fn resize_out_vec<D: Default + Deserialize>(&self, out_vec: &mut Vec<D>) -> Result<()> { + let len: i32 = self.read()?; + + if len < 0 { + return Err(StatusCode::UNEXPECTED_NULL); + } + + // usize in Rust may be 16-bit, so i32 may not fit + let len = len.try_into().unwrap(); + out_vec.resize_with(len, Default::default); + + Ok(()) + } + + /// Read a vector size from the `Parcel` and either create a correctly sized + /// vector for that amount of data or set the output parameter to None if + /// the vector should be null. + /// + /// This method is used in AIDL-generated server side code for methods that + /// take a mutable slice reference parameter. + pub fn resize_nullable_out_vec<D: Default + Deserialize>( + &self, + out_vec: &mut Option<Vec<D>>, + ) -> Result<()> { + let len: i32 = self.read()?; + + if len < 0 { + *out_vec = None; + } else { + // usize in Rust may be 16-bit, so i32 may not fit + let len = len.try_into().unwrap(); + let mut vec = Vec::with_capacity(len); + vec.resize_with(len, Default::default); + *out_vec = Some(vec); + } + + Ok(()) + } +} + +// Internal APIs +impl Parcel { + pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> { + unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return + // null or a valid pointer to an `AIBinder`, both of which are + // valid, safe inputs to `AParcel_writeStrongBinder`. + // + // This call does not take ownership of the binder. However, it does + // require a mutable pointer, which we cannot extract from an + // immutable reference, so we clone the binder, incrementing the + // refcount before the call. The refcount will be immediately + // decremented when this temporary is dropped. + status_result(sys::AParcel_writeStrongBinder( + self.as_native_mut(), + binder.cloned().as_native_mut(), + )) + } + } + + pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> { + let mut binder = ptr::null_mut(); + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid, mutable out pointer to the `binder` + // parameter. After this call, `binder` will be either null or a + // valid pointer to an `AIBinder` owned by the caller. + sys::AParcel_readStrongBinder(self.as_native(), &mut binder) + }; + + status_result(status)?; + + Ok(unsafe { + // Safety: `binder` is either null or a valid, owned pointer at this + // point, so can be safely passed to `SpIBinder::from_raw`. + SpIBinder::from_raw(binder) + }) + } +} + +impl Drop for Parcel { + fn drop(&mut self) { + // Run the C++ Parcel complete object destructor + if let Self::Owned(ptr) = *self { + unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If we own the parcel, we can safely delete it + // here. + sys::AParcel_delete(ptr) + } + } + } +} + +#[cfg(test)] +impl Parcel { + /// Create a new parcel tied to a bogus binder. TESTING ONLY! + /// + /// This can only be used for testing! All real parcel operations must be + /// done in the callback to [`IBinder::transact`] or in + /// [`Remotable::on_transact`] using the parcels provided to these methods. + pub(crate) fn new_for_test(binder: &mut SpIBinder) -> Result<Self> { + let mut input = ptr::null_mut(); + let status = unsafe { + // Safety: `SpIBinder` guarantees that `binder` always contains a + // valid pointer to an `AIBinder`. We pass a valid, mutable out + // pointer to receive a newly constructed parcel. When successful + // this function assigns a new pointer to an `AParcel` to `input` + // and transfers ownership of this pointer to the caller. Thus, + // after this call, `input` will either be null or point to a valid, + // owned `AParcel`. + sys::AIBinder_prepareTransaction(binder.as_native_mut(), &mut input) + }; + status_result(status)?; + unsafe { + // Safety: `input` is either null or a valid, owned pointer to an + // `AParcel`, so is valid to safe to + // `Parcel::owned`. `Parcel::owned` takes ownership of the parcel + // pointer. + Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL) + } + } +} + +#[test] +fn test_read_write() { + use crate::binder::Interface; + use crate::native::Binder; + use std::ffi::CString; + + let mut service = Binder::new(()).as_binder(); + let mut parcel = Parcel::new_for_test(&mut service).unwrap(); + let start = parcel.get_data_position(); + + assert_eq!(parcel.read::<bool>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<i8>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<u16>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<i32>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<u32>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<i64>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<u64>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<f32>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<f64>(), Err(StatusCode::NOT_ENOUGH_DATA)); + assert_eq!(parcel.read::<Option<CString>>(), Ok(None)); + assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL)); + + assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE)); + + parcel.write(&1i32).unwrap(); + + unsafe { + parcel.set_data_position(start).unwrap(); + } + + let i: i32 = parcel.read().unwrap(); + assert_eq!(i, 1i32); +} + +#[test] +#[allow(clippy::float_cmp)] +fn test_read_data() { + use crate::binder::Interface; + use crate::native::Binder; + + let mut service = Binder::new(()).as_binder(); + let mut parcel = Parcel::new_for_test(&mut service).unwrap(); + let str_start = parcel.get_data_position(); + + parcel.write(&b"Hello, Binder!\0"[..]).unwrap(); + // Skip over string length + unsafe { + assert!(parcel.set_data_position(str_start).is_ok()); + } + assert_eq!(parcel.read::<i32>().unwrap(), 15); + let start = parcel.get_data_position(); + + assert_eq!(parcel.read::<bool>().unwrap(), true); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<i8>().unwrap(), 72i8); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u16>().unwrap(), 25928); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<i32>().unwrap(), 1819043144); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 1819043144); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<i64>().unwrap(), 4764857262830019912); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u64>().unwrap(), 4764857262830019912); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!( + parcel.read::<f32>().unwrap(), + 1143139100000000000000000000.0 + ); + assert_eq!(parcel.read::<f32>().unwrap(), 40.043392); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<f64>().unwrap(), 34732488246.197815); + + // Skip back to before the string length + unsafe { + assert!(parcel.set_data_position(str_start).is_ok()); + } + + assert_eq!(parcel.read::<Vec<u8>>().unwrap(), b"Hello, Binder!\0"); +} + +#[test] +fn test_utf8_utf16_conversions() { + use crate::binder::Interface; + use crate::native::Binder; + + let mut service = Binder::new(()).as_binder(); + let mut parcel = Parcel::new_for_test(&mut service).unwrap(); + let start = parcel.get_data_position(); + + assert!(parcel.write("Hello, Binder!").is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert_eq!( + parcel.read::<Option<String>>().unwrap().unwrap(), + "Hello, Binder!" + ); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok()); + assert!(parcel + .write( + &[ + String::from("str4"), + String::from("str5"), + String::from("str6"), + ][..] + ) + .is_ok()); + + let s1 = "Hello, Binder!"; + let s2 = "This is a utf8 string."; + let s3 = "Some more text here."; + + assert!(parcel.write(&[s1, s2, s3][..]).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!( + parcel.read::<Vec<String>>().unwrap(), + ["str1", "str2", "str3"] + ); + assert_eq!( + parcel.read::<Vec<String>>().unwrap(), + ["str4", "str5", "str6"] + ); + assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]); +} diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs new file mode 100644 index 0000000000..8a89ab09e0 --- /dev/null +++ b/libs/binder/rust/src/parcel/file_descriptor.rs @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use super::{ + Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray, + SerializeOption, +}; +use crate::binder::AsNative; +use crate::error::{status_result, Result, StatusCode}; +use crate::sys; + +use std::fs::File; +use std::os::unix::io::{AsRawFd, FromRawFd}; + +/// Rust version of the Java class android.os.ParcelFileDescriptor +pub struct ParcelFileDescriptor(File); + +impl ParcelFileDescriptor { + /// Create a new `ParcelFileDescriptor` + pub fn new(file: File) -> Self { + Self(file) + } +} + +impl AsRef<File> for ParcelFileDescriptor { + fn as_ref(&self) -> &File { + &self.0 + } +} + +impl From<ParcelFileDescriptor> for File { + fn from(file: ParcelFileDescriptor) -> File { + file.0 + } +} + +impl Serialize for ParcelFileDescriptor { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + let fd = self.0.as_raw_fd(); + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a + // valid file, so we can borrow a valid file + // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take + // ownership of the fd, so we need not duplicate it first. + sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) + }; + status_result(status) + } +} + +impl SerializeArray for ParcelFileDescriptor {} + +impl SerializeOption for ParcelFileDescriptor { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + if let Some(f) = this { + f.serialize(parcel) + } else { + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the + // value `-1` as the file descriptor to signify serializing a + // null file descriptor. + sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) + }; + status_result(status) + } + } +} + +impl SerializeArray for Option<ParcelFileDescriptor> {} + +impl DeserializeOption for ParcelFileDescriptor { + fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> { + let mut fd = -1i32; + unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid mutable pointer to an i32, which + // `AParcel_readParcelFileDescriptor` assigns the valid file + // descriptor into, or `-1` if deserializing a null file + // descriptor. The read function passes ownership of the file + // descriptor to its caller if it was non-null, so we must take + // ownership of the file and ensure that it is eventually closed. + status_result(sys::AParcel_readParcelFileDescriptor( + parcel.as_native(), + &mut fd, + ))?; + } + if fd < 0 { + Ok(None) + } else { + let file = unsafe { + // Safety: At this point, we know that the file descriptor was + // not -1, so must be a valid, owned file descriptor which we + // can safely turn into a `File`. + File::from_raw_fd(fd) + }; + Ok(Some(ParcelFileDescriptor::new(file))) + } + } +} + +impl DeserializeArray for Option<ParcelFileDescriptor> {} + +impl Deserialize for ParcelFileDescriptor { + fn deserialize(parcel: &Parcel) -> Result<Self> { + Deserialize::deserialize(parcel) + .transpose() + .unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) + } +} + +impl DeserializeArray for ParcelFileDescriptor {} diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs new file mode 100644 index 0000000000..78b3d2cfbe --- /dev/null +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -0,0 +1,922 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::binder::{AsNative, FromIBinder}; +use crate::error::{status_result, Result, Status, StatusCode}; +use crate::parcel::Parcel; +use crate::proxy::SpIBinder; +use crate::sys; + +use std::convert::TryInto; +use std::ffi::{c_void, CStr, CString}; +use std::ptr; + +/// A struct whose instances can be written to a [`Parcel`]. +// Might be able to hook this up as a serde backend in the future? +pub trait Serialize { + /// Serialize this instance into the given [`Parcel`]. + fn serialize(&self, parcel: &mut Parcel) -> Result<()>; +} + +/// A struct whose instances can be restored from a [`Parcel`]. +// Might be able to hook this up as a serde backend in the future? +pub trait Deserialize: Sized { + /// Deserialize an instance from the given [`Parcel`]. + fn deserialize(parcel: &Parcel) -> Result<Self>; +} + +/// Helper trait for types that can be serialized as arrays. +/// Defaults to calling Serialize::serialize() manually for every element, +/// but can be overridden for custom implementations like `writeByteArray`. +// Until specialization is stabilized in Rust, we need this to be a separate +// trait because it's the only way to have a default implementation for a method. +// We want the default implementation for most types, but an override for +// a few special ones like `readByteArray` for `u8`. +pub trait SerializeArray: Serialize + Sized { + /// Serialize an array of this type into the given [`Parcel`]. + fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> { + parcel.write_slice_size(Some(slice))?; + + for item in slice { + parcel.write(item)?; + } + + Ok(()) + } +} + +/// Helper trait for types that can be deserialized as arrays. +/// Defaults to calling Deserialize::deserialize() manually for every element, +/// but can be overridden for custom implementations like `readByteArray`. +pub trait DeserializeArray: Deserialize { + /// Deserialize an array of type from the given [`Parcel`]. + fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> { + let len: i32 = parcel.read()?; + if len < 0 { + return Ok(None); + } + + // TODO: Assumes that usize is at least 32 bits + let mut vec = Vec::with_capacity(len as usize); + + for _ in 0..len { + vec.push(parcel.read()?); + } + + Ok(Some(vec)) + } +} + +/// Helper trait for types that can be nullable when serialized. +// We really need this trait instead of implementing `Serialize for Option<T>` +// because of the Rust orphan rule which prevents us from doing +// `impl Serialize for Option<&dyn IFoo>` for AIDL interfaces. +// Instead we emit `impl SerializeOption for dyn IFoo` which is allowed. +// We also use it to provide a default implementation for AIDL-generated +// parcelables. +pub trait SerializeOption: Serialize { + /// Serialize an Option of this type into the given [`Parcel`]. + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + if let Some(inner) = this { + parcel.write(&1i32)?; + parcel.write(inner) + } else { + parcel.write(&0i32) + } + } +} + +/// Helper trait for types that can be nullable when deserialized. +pub trait DeserializeOption: Deserialize { + /// Deserialize an Option of this type from the given [`Parcel`]. + fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> { + let null: i32 = parcel.read()?; + if null == 0 { + Ok(None) + } else { + parcel.read().map(Some) + } + } +} + +/// Callback to allocate a vector for parcel array read functions. +/// +/// # Safety +/// +/// The opaque data pointer passed to the array read function must be a mutable +/// pointer to an `Option<Vec<T>>`. `buffer` will be assigned a mutable pointer +/// to the allocated vector data if this function returns true. +unsafe extern "C" fn allocate_vec<T: Clone + Default>( + data: *mut c_void, + len: i32, + buffer: *mut *mut T, +) -> bool { + let vec = &mut *(data as *mut Option<Vec<T>>); + if len < 0 { + *vec = None; + return true; + } + let mut new_vec: Vec<T> = Vec::with_capacity(len as usize); + new_vec.resize_with(len as usize, Default::default); + *buffer = new_vec.as_mut_ptr(); + *vec = Some(new_vec); + true +} + +macro_rules! parcelable_primitives { + { + $( + impl $trait:ident for $ty:ty = $fn:path; + )* + } => { + $(impl_parcelable!{$trait, $ty, $fn})* + }; +} + +macro_rules! impl_parcelable { + {Serialize, $ty:ty, $write_fn:path} => { + impl Serialize for $ty { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`, and any `$ty` literal value is safe to pass to + // `$write_fn`. + status_result($write_fn(parcel.as_native_mut(), *self)) + } + } + } + }; + + {Deserialize, $ty:ty, $read_fn:path} => { + impl Deserialize for $ty { + fn deserialize(parcel: &Parcel) -> Result<Self> { + let mut val = Self::default(); + unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid, mutable pointer to `val`, a + // literal of type `$ty`, and `$read_fn` will write the + // value read into `val` if successful + status_result($read_fn(parcel.as_native(), &mut val))? + }; + Ok(val) + } + } + }; + + {SerializeArray, $ty:ty, $write_array_fn:path} => { + impl SerializeArray for $ty { + fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> { + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` + // will be a valid pointer to an array of elements of type + // `$ty`. If the slice length is 0, `slice.as_ptr()` may be + // dangling, but this is safe since the pointer is not + // dereferenced if the length parameter is 0. + $write_array_fn( + parcel.as_native_mut(), + slice.as_ptr(), + slice + .len() + .try_into() + .or(Err(StatusCode::BAD_VALUE))?, + ) + }; + status_result(status) + } + } + }; + + {DeserializeArray, $ty:ty, $read_array_fn:path} => { + impl DeserializeArray for $ty { + fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> { + let mut vec: Option<Vec<Self>> = None; + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `allocate_vec<T>` expects the opaque pointer to + // be of type `*mut Option<Vec<T>>`, so `&mut vec` is + // correct for it. + $read_array_fn( + parcel.as_native(), + &mut vec as *mut _ as *mut c_void, + Some(allocate_vec), + ) + }; + status_result(status)?; + Ok(vec) + } + } + }; +} + +parcelable_primitives! { + impl Serialize for bool = sys::AParcel_writeBool; + impl Deserialize for bool = sys::AParcel_readBool; + + // This is only safe because `Option<Vec<u8>>` is interchangeable with + // `Option<Vec<i8>>` (what the allocator function actually allocates. + impl DeserializeArray for u8 = sys::AParcel_readByteArray; + + impl Serialize for i8 = sys::AParcel_writeByte; + impl Deserialize for i8 = sys::AParcel_readByte; + impl SerializeArray for i8 = sys::AParcel_writeByteArray; + impl DeserializeArray for i8 = sys::AParcel_readByteArray; + + impl Serialize for u16 = sys::AParcel_writeChar; + impl Deserialize for u16 = sys::AParcel_readChar; + impl SerializeArray for u16 = sys::AParcel_writeCharArray; + impl DeserializeArray for u16 = sys::AParcel_readCharArray; + + // This is only safe because `Option<Vec<i16>>` is interchangeable with + // `Option<Vec<u16>>` (what the allocator function actually allocates. + impl DeserializeArray for i16 = sys::AParcel_readCharArray; + + impl Serialize for u32 = sys::AParcel_writeUint32; + impl Deserialize for u32 = sys::AParcel_readUint32; + impl SerializeArray for u32 = sys::AParcel_writeUint32Array; + impl DeserializeArray for u32 = sys::AParcel_readUint32Array; + + impl Serialize for i32 = sys::AParcel_writeInt32; + impl Deserialize for i32 = sys::AParcel_readInt32; + impl SerializeArray for i32 = sys::AParcel_writeInt32Array; + impl DeserializeArray for i32 = sys::AParcel_readInt32Array; + + impl Serialize for u64 = sys::AParcel_writeUint64; + impl Deserialize for u64 = sys::AParcel_readUint64; + impl SerializeArray for u64 = sys::AParcel_writeUint64Array; + impl DeserializeArray for u64 = sys::AParcel_readUint64Array; + + impl Serialize for i64 = sys::AParcel_writeInt64; + impl Deserialize for i64 = sys::AParcel_readInt64; + impl SerializeArray for i64 = sys::AParcel_writeInt64Array; + impl DeserializeArray for i64 = sys::AParcel_readInt64Array; + + impl Serialize for f32 = sys::AParcel_writeFloat; + impl Deserialize for f32 = sys::AParcel_readFloat; + impl SerializeArray for f32 = sys::AParcel_writeFloatArray; + impl DeserializeArray for f32 = sys::AParcel_readFloatArray; + + impl Serialize for f64 = sys::AParcel_writeDouble; + impl Deserialize for f64 = sys::AParcel_readDouble; + impl SerializeArray for f64 = sys::AParcel_writeDoubleArray; + impl DeserializeArray for f64 = sys::AParcel_readDoubleArray; +} + +impl SerializeArray for bool {} +impl DeserializeArray for bool {} + +impl Serialize for u8 { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + (*self as i8).serialize(parcel) + } +} + +impl Deserialize for u8 { + fn deserialize(parcel: &Parcel) -> Result<Self> { + i8::deserialize(parcel).map(|v| v as u8) + } +} + +impl SerializeArray for u8 { + fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> { + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a + // valid pointer to an array of elements of type `$ty`. If the slice + // length is 0, `slice.as_ptr()` may be dangling, but this is safe + // since the pointer is not dereferenced if the length parameter is + // 0. + sys::AParcel_writeByteArray( + parcel.as_native_mut(), + slice.as_ptr() as *const i8, + slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?, + ) + }; + status_result(status) + } +} + +impl Serialize for i16 { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + (*self as u16).serialize(parcel) + } +} + +impl Deserialize for i16 { + fn deserialize(parcel: &Parcel) -> Result<Self> { + u16::deserialize(parcel).map(|v| v as i16) + } +} + +impl SerializeArray for i16 { + fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> { + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a + // valid pointer to an array of elements of type `$ty`. If the slice + // length is 0, `slice.as_ptr()` may be dangling, but this is safe + // since the pointer is not dereferenced if the length parameter is + // 0. + sys::AParcel_writeCharArray( + parcel.as_native_mut(), + slice.as_ptr() as *const u16, + slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?, + ) + }; + status_result(status) + } +} + +impl SerializeOption for CStr { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + match this { + None => unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the string pointer is null, + // `AParcel_writeString` requires that the length is -1 to + // indicate that we want to serialize a null string. + status_result(sys::AParcel_writeString( + parcel.as_native_mut(), + ptr::null(), + -1, + )) + }, + Some(s) => unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AParcel_writeString` assumes that we pass a + // null-terminated C string pointer with no nulls in the middle + // of the string. Rust guarantees exactly that for a valid CStr + // instance. + status_result(sys::AParcel_writeString( + parcel.as_native_mut(), + s.as_ptr(), + s.to_bytes() + .len() + .try_into() + .or(Err(StatusCode::BAD_VALUE))?, + )) + }, + } + } +} + +impl SerializeArray for Option<&CStr> {} + +impl Serialize for CStr { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + Some(self).serialize(parcel) + } +} + +impl Serialize for CString { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + Some(self.as_c_str()).serialize(parcel) + } +} + +impl SerializeArray for CString {} + +impl SerializeOption for CString { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + SerializeOption::serialize_option(this.map(CString::as_c_str), parcel) + } +} + +impl SerializeArray for Option<CString> {} + +impl Serialize for String { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + Some(self.as_str()).serialize(parcel) + } +} + +impl SerializeArray for String {} + +impl SerializeOption for String { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + SerializeOption::serialize_option(this.map(String::as_str), parcel) + } +} + +impl SerializeArray for Option<String> {} + +impl Deserialize for Option<CString> { + fn deserialize(parcel: &Parcel) -> Result<Self> { + let mut vec: Option<Vec<u8>> = None; + let status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an `AParcel`. + // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>` + // for `allocate_vec`, so `vec` is safe to pass as the opaque data + // pointer on platforms where char is signed. + sys::AParcel_readString( + parcel.as_native(), + &mut vec as *mut _ as *mut c_void, + Some(allocate_vec), + ) + }; + + status_result(status)?; + vec.map(|mut s| { + // The vector includes a null-terminator and CString::new requires + // no nulls, including terminating. + s.pop(); + CString::new(s).or(Err(StatusCode::BAD_VALUE)) + }) + .transpose() + } +} + +impl DeserializeArray for Option<CString> {} + +impl DeserializeOption for String { + fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> { + let c_str = <Option<CString>>::deserialize(parcel)?; + c_str + .map(|s| s.into_string().or(Err(StatusCode::BAD_VALUE))) + .transpose() + } +} + +impl DeserializeArray for Option<String> {} + +impl Deserialize for String { + fn deserialize(parcel: &Parcel) -> Result<Self> { + Deserialize::deserialize(parcel) + .transpose() + .unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) + } +} + +impl DeserializeArray for String {} + +impl SerializeOption for str { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + match this { + None => parcel.write(&-1i32), + Some(s) => { + let c_str = CString::new(s).or(Err(StatusCode::BAD_VALUE))?; + parcel.write(&c_str) + } + } + } +} + +impl Serialize for str { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + Some(self).serialize(parcel) + } +} + +impl SerializeArray for &str {} + +impl SerializeArray for Option<&str> {} + +impl<T: SerializeArray> Serialize for [T] { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + SerializeArray::serialize_array(self, parcel) + } +} + +impl<T: SerializeArray> Serialize for Vec<T> { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + SerializeArray::serialize_array(&self[..], parcel) + } +} + +impl<T: SerializeArray> SerializeOption for [T] { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + if let Some(v) = this { + SerializeArray::serialize_array(v, parcel) + } else { + parcel.write(&-1i32) + } + } +} + +impl<T: SerializeArray> SerializeOption for Vec<T> { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + SerializeOption::serialize_option(this.map(Vec::as_slice), parcel) + } +} + +impl<T: DeserializeArray> Deserialize for Vec<T> { + fn deserialize(parcel: &Parcel) -> Result<Self> { + DeserializeArray::deserialize_array(parcel) + .transpose() + .unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) + } +} + +impl<T: DeserializeArray> DeserializeOption for Vec<T> { + fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> { + DeserializeArray::deserialize_array(parcel) + } +} + +impl Serialize for Status { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + unsafe { + // Safety: `Parcel` always contains a valid pointer to an `AParcel` + // and `Status` always contains a valid pointer to an `AStatus`, so + // both parameters are valid and safe. This call does not take + // ownership of either of its parameters. + status_result(sys::AParcel_writeStatusHeader( + parcel.as_native_mut(), + self.as_native(), + )) + } + } +} + +impl Deserialize for Status { + fn deserialize(parcel: &Parcel) -> Result<Self> { + let mut status_ptr = ptr::null_mut(); + let ret_status = unsafe { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a mutable out pointer which will be + // assigned a valid `AStatus` pointer if the function returns + // status OK. This function passes ownership of the status + // pointer to the caller, if it was assigned. + sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) + }; + status_result(ret_status)?; + Ok(unsafe { + // Safety: At this point, the return status of the read call was ok, + // so we know that `status_ptr` is a valid, owned pointer to an + // `AStatus`, from which we can safely construct a `Status` object. + Status::from_ptr(status_ptr) + }) + } +} + +impl<T: Serialize + ?Sized> Serialize for Box<T> { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + Serialize::serialize(&**self, parcel) + } +} + +impl<T: SerializeOption + ?Sized> SerializeOption for Box<T> { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + SerializeOption::serialize_option(this.map(|b| &**b), parcel) + } +} + +impl<T: FromIBinder + ?Sized> Deserialize for Box<T> { + fn deserialize(parcel: &Parcel) -> Result<Self> { + let ibinder: SpIBinder = parcel.read()?; + FromIBinder::try_from(ibinder) + } +} + +impl<T: FromIBinder + ?Sized> DeserializeOption for Box<T> { + fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> { + let ibinder: Option<SpIBinder> = parcel.read()?; + ibinder.map(FromIBinder::try_from).transpose() + } +} + +// We need these to support Option<&T> for all T +impl<T: Serialize + ?Sized> Serialize for &T { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + Serialize::serialize(*self, parcel) + } +} + +impl<T: SerializeOption + ?Sized> SerializeOption for &T { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + SerializeOption::serialize_option(this.copied(), parcel) + } +} + +impl<T: SerializeOption> Serialize for Option<T> { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + SerializeOption::serialize_option(self.as_ref(), parcel) + } +} + +impl<T: DeserializeOption> Deserialize for Option<T> { + fn deserialize(parcel: &Parcel) -> Result<Self> { + DeserializeOption::deserialize_option(parcel) + } +} + +#[test] +fn test_custom_parcelable() { + use crate::binder::Interface; + use crate::native::Binder; + let mut service = Binder::new(()).as_binder(); + + struct Custom(u32, bool, String, Vec<String>); + + impl Serialize for Custom { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + self.0.serialize(parcel)?; + self.1.serialize(parcel)?; + self.2.serialize(parcel)?; + self.3.serialize(parcel) + } + } + + impl Deserialize for Custom { + fn deserialize(parcel: &Parcel) -> Result<Self> { + Ok(Custom( + parcel.read()?, + parcel.read()?, + parcel.read()?, + parcel.read::<Option<Vec<String>>>()?.unwrap(), + )) + } + } + + let string8 = "Custom Parcelable".to_string(); + + let s1 = "str1".to_string(); + let s2 = "str2".to_string(); + let s3 = "str3".to_string(); + + let strs = vec![s1, s2, s3]; + + let custom = Custom(123_456_789, true, string8, strs); + + let mut parcel = Parcel::new_for_test(&mut service).unwrap(); + let start = parcel.get_data_position(); + + assert!(custom.serialize(&mut parcel).is_ok()); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let custom2 = Custom::deserialize(&parcel).unwrap(); + + assert_eq!(custom2.0, 123_456_789); + assert!(custom2.1); + assert_eq!(custom2.2, custom.2); + assert_eq!(custom2.3, custom.3); +} + +#[test] +#[allow(clippy::excessive_precision)] +fn test_slice_parcelables() { + use crate::binder::Interface; + use crate::native::Binder; + let mut service = Binder::new(()).as_binder(); + + let bools = [true, false, false, true]; + + let mut parcel = Parcel::new_for_test(&mut service).unwrap(); + let start = parcel.get_data_position(); + + assert!(bools.serialize(&mut parcel).is_ok()); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); + assert_eq!(parcel.read::<u32>().unwrap(), 1); + assert_eq!(parcel.read::<u32>().unwrap(), 0); + assert_eq!(parcel.read::<u32>().unwrap(), 0); + assert_eq!(parcel.read::<u32>().unwrap(), 1); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<bool>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [true, false, false, true]); + + let u8s = [101u8, 255, 42, 117]; + + let mut parcel = Parcel::new_for_test(&mut service).unwrap(); + let start = parcel.get_data_position(); + + assert!(parcel.write(&u8s[..]).is_ok()); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items + assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<u8>::deserialize(&parcel).unwrap(); + assert_eq!(vec, [101, 255, 42, 117]); + + let i8s = [-128i8, 127, 42, -117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert!(parcel.write(&i8s[..]).is_ok()); + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items + assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<u8>::deserialize(&parcel).unwrap(); + assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]); + + let u16s = [u16::max_value(), 12_345, 42, 117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(u16s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items + assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value() + assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345 + assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 + assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117 + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<u16>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]); + + let i16s = [i16::max_value(), i16::min_value(), 42, -117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(i16s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items + assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value() + assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value() + assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 + assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117 + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<i16>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]); + + let u32s = [u32::max_value(), 12_345, 42, 117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(u32s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items + assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value() + assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345 + assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 + assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117 + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<u32>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]); + + let i32s = [i32::max_value(), i32::min_value(), 42, -117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(i32s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items + assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value() + assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value() + assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42 + assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117 + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<i32>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]); + + let u64s = [u64::max_value(), 12_345, 42, 117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(u64s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<u64>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]); + + let i64s = [i64::max_value(), i64::min_value(), 42, -117]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(i64s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<i64>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]); + + let f32s = [ + std::f32::NAN, + std::f32::INFINITY, + 1.23456789, + std::f32::EPSILON, + ]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(f32s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<f32>::deserialize(&parcel).unwrap(); + + // NAN != NAN so we can't use it in the assert_eq: + assert!(vec[0].is_nan()); + assert_eq!(vec[1..], f32s[1..]); + + let f64s = [ + std::f64::NAN, + std::f64::INFINITY, + 1.234567890123456789, + std::f64::EPSILON, + ]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(f64s.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<f64>::deserialize(&parcel).unwrap(); + + // NAN != NAN so we can't use it in the assert_eq: + assert!(vec[0].is_nan()); + assert_eq!(vec[1..], f64s[1..]); + + let s1 = "Hello, Binder!"; + let s2 = "This is a utf8 string."; + let s3 = "Some more text here."; + + let strs = [s1, s2, s3]; + + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + assert!(strs.serialize(&mut parcel).is_ok()); + unsafe { + assert!(parcel.set_data_position(start).is_ok()); + } + + let vec = Vec::<String>::deserialize(&parcel).unwrap(); + + assert_eq!(vec, strs); +} diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs new file mode 100644 index 0000000000..f9519b4d01 --- /dev/null +++ b/libs/binder/rust/src/proxy.rs @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Rust API for interacting with a remote binder service. + +use crate::binder::{ + AsNative, FromIBinder, IBinder, Interface, InterfaceClass, TransactionCode, TransactionFlags, +}; +use crate::error::{status_result, Result, StatusCode}; +use crate::parcel::{ + Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray, + SerializeOption, +}; +use crate::sys; + +use std::convert::TryInto; +use std::ffi::{c_void, CString}; +use std::os::unix::io::AsRawFd; +use std::ptr; + +/// A strong reference to a Binder remote object. +/// +/// This struct encapsulates the generic C++ `sp<IBinder>` class. This wrapper +/// is untyped; typed interface access is implemented by the AIDL compiler. +pub struct SpIBinder(*mut sys::AIBinder); + +/// # Safety +/// +/// An `SpIBinder` is a handle to a C++ IBinder, which is thread-safe +unsafe impl Send for SpIBinder {} + +impl SpIBinder { + /// Create an `SpIBinder` wrapper object from a raw `AIBinder` pointer. + /// + /// # Safety + /// + /// This constructor is safe iff `ptr` is a null pointer or a valid pointer + /// to an `AIBinder`. + /// + /// In the non-null case, this method conceptually takes ownership of a strong + /// reference to the object, so `AIBinder_incStrong` must have been called + /// on the pointer before passing it to this constructor. This is generally + /// done by Binder NDK methods that return an `AIBinder`, but care should be + /// taken to ensure this invariant. + /// + /// All `SpIBinder` objects that are constructed will hold a valid pointer + /// to an `AIBinder`, which will remain valid for the entire lifetime of the + /// `SpIBinder` (we keep a strong reference, and only decrement on drop). + pub(crate) unsafe fn from_raw(ptr: *mut sys::AIBinder) -> Option<Self> { + ptr.as_mut().map(|p| Self(p)) + } + + /// Return true if this binder object is hosted in a different process than + /// the current one. + pub fn is_remote(&self) -> bool { + unsafe { + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. + sys::AIBinder_isRemote(self.as_native()) + } + } + + /// Try to convert this Binder object into a trait object for the given + /// Binder interface. + /// + /// If this object does not implement the expected interface, the error + /// `StatusCode::BAD_TYPE` is returned. + pub fn into_interface<I: FromIBinder + ?Sized>(self) -> Result<Box<I>> { + FromIBinder::try_from(self) + } + + /// Return the interface class of this binder object, if associated with + /// one. + pub(crate) 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 + // pointer or a valid pointer to an `AIBinder_Class`. After mapping + // null to None, we can safely construct an `InterfaceClass` if the + // pointer was non-null. + let class = sys::AIBinder_getClass(self.as_native_mut()); + class.as_ref().map(|p| InterfaceClass::from_ptr(p)) + } + } +} + +/// An object that can be associate with an [`InterfaceClass`]. +pub trait AssociateClass { + /// Check if this object is a valid object for the given interface class + /// `I`. + /// + /// Returns `Some(self)` if this is a valid instance of the interface, and + /// `None` otherwise. + /// + /// Classes constructed by `InterfaceClass` are unique per type, so + /// repeatedly calling this method for the same `InterfaceClass` is allowed. + fn associate_class(&mut self, class: InterfaceClass) -> bool; +} + +impl AssociateClass for SpIBinder { + fn associate_class(&mut self, class: InterfaceClass) -> bool { + unsafe { + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. An `InterfaceClass` can always be converted + // into a valid `AIBinder_Class` pointer, so these parameters are + // always safe. + sys::AIBinder_associateClass(self.as_native_mut(), class.into()) + } + } +} + +impl Clone for SpIBinder { + fn clone(&self) -> Self { + unsafe { + // Safety: Cloning a strong reference must increment the reference + // count. We are guaranteed by the `SpIBinder` constructor + // invariants that `self.0` is always a valid `AIBinder` pointer. + sys::AIBinder_incStrong(self.0); + } + Self(self.0) + } +} + +impl Drop for SpIBinder { + // We hold a strong reference to the IBinder in SpIBinder and need to give up + // this reference on drop. + fn drop(&mut self) { + unsafe { + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we + // know this pointer is safe to pass to `AIBinder_decStrong` here. + sys::AIBinder_decStrong(self.as_native_mut()); + } + } +} + +impl<T: AsNative<sys::AIBinder>> IBinder for T { + /// Perform a binder transaction + fn transact<F: FnOnce(&mut Parcel) -> Result<()>>( + &self, + code: TransactionCode, + flags: TransactionFlags, + input_callback: F, + ) -> Result<Parcel> { + let mut input = ptr::null_mut(); + let status = unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. It is safe to cast from an + // immutable pointer to a mutable pointer here, because + // `AIBinder_prepareTransaction` only calls immutable `AIBinder` + // methods but the parameter is unfortunately not marked as const. + // + // After the call, input will be either a valid, owned `AParcel` + // pointer, or null. + sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input) + }; + status_result(status)?; + let mut input = unsafe { + // Safety: At this point, `input` is either a valid, owned `AParcel` + // pointer, or null. `Parcel::owned` safely handles both cases, + // taking ownership of the parcel. + Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)? + }; + input_callback(&mut input)?; + let mut reply = ptr::null_mut(); + let status = unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. Although `IBinder::transact` is + // not a const method, it is still safe to cast our immutable + // pointer to mutable for the call. First, `IBinder::transact` is + // thread-safe, so concurrency is not an issue. The only way that + // `transact` can affect any visible, mutable state in the current + // process is by calling `onTransact` for a local service. However, + // in order for transactions to be thread-safe, this method must + // dynamically lock its data before modifying it. We enforce this + // property in Rust by requiring `Sync` for remotable objects and + // only providing `on_transact` with an immutable reference to + // `self`. + // + // This call takes ownership of the `input` parcel pointer, and + // passes ownership of the `reply` out parameter to its caller. It + // does not affect ownership of the `binder` parameter. + sys::AIBinder_transact( + self.as_native() as *mut sys::AIBinder, + code, + &mut input.into_raw(), + &mut reply, + flags, + ) + }; + status_result(status)?; + + unsafe { + // Safety: `reply` is either a valid `AParcel` pointer or null + // after the call to `AIBinder_transact` above, so we can + // construct a `Parcel` out of it. `AIBinder_transact` passes + // ownership of the `reply` parcel to Rust, so we need to + // construct an owned variant. `Parcel::owned` takes ownership + // of the parcel pointer. + Parcel::owned(reply).ok_or(StatusCode::UNEXPECTED_NULL) + } + } + + fn is_binder_alive(&self) -> bool { + unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. + sys::AIBinder_isAlive(self.as_native()) + } + } + + fn ping_binder(&mut self) -> Result<()> { + let status = unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. + sys::AIBinder_ping(self.as_native_mut()) + }; + status_result(status) + } + + fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> { + let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect(); + let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect(); + let status = unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the + // file descriptor parameter is always be a valid open file. The + // `args` pointer parameter is a valid pointer to an array of C + // strings that will outlive the call since `args` lives for the + // whole function scope. + // + // This call does not affect ownership of its binder pointer + // parameter and does not take ownership of the file or args array + // parameters. + sys::AIBinder_dump( + self.as_native_mut(), + fp.as_raw_fd(), + arg_ptrs.as_mut_ptr(), + arg_ptrs.len().try_into().unwrap(), + ) + }; + status_result(status) + } + + fn get_extension(&mut self) -> Result<Option<SpIBinder>> { + let mut out = ptr::null_mut(); + let status = unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. After this call, the `out` + // parameter will be either null, or a valid pointer to an + // `AIBinder`. + // + // This call passes ownership of the out pointer to its caller + // (assuming it is set to a non-null value). + sys::AIBinder_getExtension(self.as_native_mut(), &mut out) + }; + let ibinder = unsafe { + // Safety: The call above guarantees that `out` is either null or a + // valid, owned pointer to an `AIBinder`, both of which are safe to + // pass to `SpIBinder::from_raw`. + SpIBinder::from_raw(out) + }; + + status_result(status)?; + Ok(ibinder) + } + + fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> { + status_result(unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `recipient` can always be + // converted into a valid pointer to an + // `AIBinder_DeatRecipient`. Any value is safe to pass as the + // cookie, although we depend on this value being set by + // `get_cookie` when the death recipient callback is called. + sys::AIBinder_linkToDeath( + self.as_native_mut(), + recipient.as_native_mut(), + recipient.get_cookie(), + ) + }) + } + + fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> { + status_result(unsafe { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `recipient` can always be + // converted into a valid pointer to an + // `AIBinder_DeatRecipient`. Any value is safe to pass as the + // cookie, although we depend on this value being set by + // `get_cookie` when the death recipient callback is called. + sys::AIBinder_unlinkToDeath( + self.as_native_mut(), + recipient.as_native_mut(), + recipient.get_cookie(), + ) + }) + } +} + +impl Serialize for SpIBinder { + fn serialize(&self, parcel: &mut Parcel) -> Result<()> { + parcel.write_binder(Some(self)) + } +} + +impl SerializeOption for SpIBinder { + fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> { + parcel.write_binder(this) + } +} + +impl SerializeArray for SpIBinder {} +impl SerializeArray for Option<&SpIBinder> {} + +impl Deserialize for SpIBinder { + fn deserialize(parcel: &Parcel) -> Result<SpIBinder> { + parcel.read_binder().transpose().unwrap() + } +} + +impl DeserializeOption for SpIBinder { + fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> { + parcel.read_binder() + } +} + +impl DeserializeArray for SpIBinder {} +impl DeserializeArray for Option<SpIBinder> {} + +/// A weak reference to a Binder remote object. +/// +/// This struct encapsulates the C++ `wp<IBinder>` class. However, this wrapper +/// is untyped, so properly typed versions implementing a particular binder +/// interface should be crated with [`declare_binder_interface!`]. +pub struct WpIBinder(*mut sys::AIBinder_Weak); + +impl WpIBinder { + /// Create a new weak reference from an object that can be converted into a + /// raw `AIBinder` pointer. + pub fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder { + let ptr = unsafe { + // Safety: `SpIBinder` guarantees that `binder` always contains a + // valid pointer to an `AIBinder`. + sys::AIBinder_Weak_new(binder.as_native_mut()) + }; + assert!(!ptr.is_null()); + Self(ptr) + } +} + +/// Rust wrapper around DeathRecipient objects. +#[repr(C)] +pub struct DeathRecipient { + recipient: *mut sys::AIBinder_DeathRecipient, + callback: Box<dyn Fn() + Send + 'static>, +} + +impl DeathRecipient { + /// Create a new death recipient that will call the given callback when its + /// associated object dies. + pub fn new<F>(callback: F) -> DeathRecipient + where + F: Fn() + Send + 'static, + { + let callback = Box::new(callback); + let recipient = unsafe { + // Safety: The function pointer is a valid death recipient callback. + // + // This call returns an owned `AIBinder_DeathRecipient` pointer + // which must be destroyed via `AIBinder_DeathRecipient_delete` when + // no longer needed. + sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>)) + }; + DeathRecipient { + recipient, + callback, + } + } + + /// Get the opaque cookie that identifies this death recipient. + /// + /// This cookie will be used to link and unlink this death recipient to a + /// binder object and will be passed to the `binder_died` callback as an + /// opaque userdata pointer. + fn get_cookie(&self) -> *mut c_void { + &*self.callback as *const _ as *mut c_void + } + + /// Callback invoked from C++ when the binder object dies. + /// + /// # Safety + /// + /// The `cookie` parameter must have been created with the `get_cookie` + /// method of this object. + unsafe extern "C" fn binder_died<F>(cookie: *mut c_void) + where + F: Fn() + Send + 'static, + { + let callback = (cookie as *mut F).as_ref().unwrap(); + callback(); + } +} + +/// # Safety +/// +/// A `DeathRecipient` is always constructed with a valid raw pointer to an +/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this +/// pointer. +unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient { + fn as_native(&self) -> *const sys::AIBinder_DeathRecipient { + self.recipient + } + + fn as_native_mut(&mut self) -> *mut sys::AIBinder_DeathRecipient { + self.recipient + } +} + +impl Drop for DeathRecipient { + fn drop(&mut self) { + unsafe { + // Safety: `self.recipient` is always a valid, owned + // `AIBinder_DeathRecipient` pointer returned by + // `AIBinder_DeathRecipient_new` when `self` was created. This + // delete method can only be called once when `self` is dropped. + sys::AIBinder_DeathRecipient_delete(self.recipient); + } + } +} + +/// Generic interface to remote binder objects. +/// +/// Corresponds to the C++ `BpInterface` class. +pub trait Proxy: Sized + Interface { + /// The Binder interface descriptor string. + /// + /// This string is a unique identifier for a Binder interface, and should be + /// the same between all implementations of that interface. + fn get_descriptor() -> &'static str; + + /// Create a new interface from the given proxy, if it matches the expected + /// type of this interface. + fn from_binder(binder: SpIBinder) -> Result<Self>; +} + +/// # Safety +/// +/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow +/// invocation of `IBinder` methods directly from `Interface` objects. It shares +/// the same safety as the implementation for `SpIBinder`. +unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T { + fn as_native(&self) -> *const sys::AIBinder { + self.as_binder().as_native() + } + + fn as_native_mut(&mut self) -> *mut sys::AIBinder { + self.as_binder().as_native_mut() + } +} + +/// Retrieve an existing service, blocking for a few seconds if it doesn't yet +/// exist. +pub fn get_service(name: &str) -> Option<SpIBinder> { + let name = CString::new(name).ok()?; + unsafe { + // Safety: `AServiceManager_getService` 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_getService(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<Box<T>> { + let service = get_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 +/// `AIBinder`, so we can trivially extract this pointer here. +unsafe impl AsNative<sys::AIBinder> for SpIBinder { + fn as_native(&self) -> *const sys::AIBinder { + self.0 + } + + fn as_native_mut(&mut self) -> *mut sys::AIBinder { + self.0 + } +} diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs new file mode 100644 index 0000000000..992f074f26 --- /dev/null +++ b/libs/binder/rust/src/state.rs @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::sys; + +use libc::{pid_t, uid_t}; + +/// Static utility functions to manage Binder process state. +pub struct ProcessState; + +impl ProcessState { + /// Start the Binder IPC thread pool + pub fn start_thread_pool() { + unsafe { + // Safety: Safe FFI + sys::ABinderProcess_startThreadPool(); + } + } + + /// Set the maximum number of threads that can be started in the threadpool. + /// + /// By default, after startThreadPool is called, this is 15. If it is called + /// additional times, it will only prevent the kernel from starting new + /// threads and will not delete already existing threads. + pub fn set_thread_pool_max_thread_count(num_threads: u32) { + unsafe { + // Safety: Safe FFI + sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads); + } + } + + /// Block on the Binder IPC thread pool + pub fn join_thread_pool() { + unsafe { + // Safety: Safe FFI + sys::ABinderProcess_joinThreadPool(); + } + } +} + +/// Static utility functions to manage Binder thread state. +pub struct ThreadState; + +impl ThreadState { + /// This returns the calling UID assuming that this thread is called from a + /// thread that is processing a binder transaction (for instance, in the + /// implementation of + /// [`Remotable::on_transact`](crate::Remotable::on_transact)). + /// + /// This can be used with higher-level system services to determine the + /// caller's identity and check permissions. + /// + /// Available since API level 29. + /// + /// \return calling uid or the current process's UID if this thread isn't + /// processing a transaction. + pub fn get_calling_uid() -> uid_t { + unsafe { + // Safety: Safe FFI + sys::AIBinder_getCallingUid() + } + } + + /// This returns the calling PID assuming that this thread is called from a + /// thread that is processing a binder transaction (for instance, in the + /// implementation of + /// [`Remotable::on_transact`](crate::Remotable::on_transact)). + /// + /// This can be used with higher-level system services to determine the + /// caller's identity and check permissions. However, when doing this, one + /// should be aware of possible TOCTOU problems when the calling process + /// dies and is replaced with another process with elevated permissions and + /// the same PID. + /// + /// Available since API level 29. + /// + /// \return calling pid or the current process's PID if this thread isn't + /// processing a transaction. + /// + /// If the transaction being processed is a oneway transaction, then this + /// method will return 0. + pub fn get_calling_pid() -> pid_t { + unsafe { + // Safety: Safe FFI + sys::AIBinder_getCallingPid() + } + } +} diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp new file mode 100644 index 0000000000..712711099c --- /dev/null +++ b/libs/binder/rust/tests/Android.bp @@ -0,0 +1,24 @@ +rust_test { + name: "rustBinderTest", + srcs: ["integration.rs"], + rustlibs: [ + "libbinder_rs", + ], + // For the binaries to be pushed properly as specified in AndroidTest.xml, + // this cannot be the same as the module name. + stem: "rustBinderTestClientBinary", + test_suites: ["general-tests"], +} + +rust_test { + name: "rustBinderTestService", + srcs: ["integration.rs"], + rustlibs: [ + "libbinder_rs", + "liblibc", + ], + // For the binaries to be pushed properly as specified in AndroidTest.xml, + // this cannot be the same as the module name. + stem: "rustBinderTestServiceBinary", + test_harness: false, +} diff --git a/libs/binder/rust/tests/AndroidTest.xml b/libs/binder/rust/tests/AndroidTest.xml new file mode 100644 index 0000000000..d8d735d3ee --- /dev/null +++ b/libs/binder/rust/tests/AndroidTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs Binder Rust integration tests."> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="rustBinderTestClientBinary->/data/local/tmp/rustBinderTest" /> + <option name="push" value="rustBinderTestServiceBinary->/data/local/tmp/rustBinderTestService" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.rust.RustBinaryTest" > + <option name="test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="rustBinderTest" /> + </test> +</configuration> diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs new file mode 100644 index 0000000000..fe59416a99 --- /dev/null +++ b/libs/binder/rust/tests/integration.rs @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! Rust Binder crate integration tests + +use binder::declare_binder_interface; +use binder::parcel::Parcel; +use binder::{Binder, IBinder, Interface, SpIBinder, TransactionCode}; + +/// Name of service runner. +/// +/// Must match the binary name in Android.bp +const RUST_SERVICE_BINARY: &str = "rustBinderTestService"; + +/// Binary to run a test service. +/// +/// This needs to be in a separate process from the tests, so we spawn this +/// binary as a child, providing the service name as an argument. +fn main() -> Result<(), &'static str> { + // Ensure that we can handle all transactions on the main thread. + binder::ProcessState::set_thread_pool_max_thread_count(0); + binder::ProcessState::start_thread_pool(); + + let mut args = std::env::args().skip(1); + if args.len() < 1 || args.len() > 2 { + print_usage(); + return Err(""); + } + let service_name = args.next().ok_or_else(|| { + print_usage(); + "Missing SERVICE_NAME argument" + })?; + let extension_name = args.next(); + + { + let mut service = Binder::new(BnTest(Box::new(TestService { + s: service_name.clone(), + }))); + if let Some(extension_name) = extension_name { + let extension = BnTest::new_binder(TestService { s: extension_name }); + service + .set_extension(&mut extension.as_binder()) + .expect("Could not add extension"); + } + binder::add_service(&service_name, service.as_binder()) + .expect("Could not register service"); + } + + binder::ProcessState::join_thread_pool(); + Err("Unexpected exit after join_thread_pool") +} + +fn print_usage() { + eprintln!( + "Usage: {} SERVICE_NAME [EXTENSION_NAME]", + RUST_SERVICE_BINARY + ); + eprintln!(concat!( + "Spawn a Binder test service identified by SERVICE_NAME,", + " optionally with an extesion named EXTENSION_NAME", + )); +} + +#[derive(Clone)] +struct TestService { + s: String, +} + +impl Interface for TestService {} + +impl ITest for TestService { + fn test(&self) -> binder::Result<String> { + Ok(self.s.clone()) + } +} + +/// Trivial testing binder interface +pub trait ITest: Interface { + /// Returns a test string + fn test(&self) -> binder::Result<String>; +} + +declare_binder_interface! { + ITest["android.os.ITest"] { + native: BnTest(on_transact), + proxy: BpTest { + x: i32 = 100 + }, + } +} + +fn on_transact( + service: &dyn ITest, + _code: TransactionCode, + _data: &Parcel, + reply: &mut Parcel, +) -> binder::Result<()> { + reply.write(&service.test()?)?; + Ok(()) +} + +impl ITest for BpTest { + fn test(&self) -> binder::Result<String> { + let reply = self + .binder + .transact(SpIBinder::FIRST_CALL_TRANSACTION, 0, |_| Ok(()))?; + reply.read() + } +} + +impl ITest for Binder<BnTest> { + fn test(&self) -> binder::Result<String> { + self.0.test() + } +} + +#[cfg(test)] +mod tests { + use std::fs::File; + use std::process::{Child, Command}; + use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::Arc; + use std::thread; + use std::time::Duration; + + use binder::{DeathRecipient, FromIBinder, IBinder, SpIBinder, StatusCode}; + + use super::{ITest, RUST_SERVICE_BINARY}; + + pub struct ScopedServiceProcess(Child); + + impl ScopedServiceProcess { + pub fn new(identifier: &str) -> Self { + Self::new_internal(identifier, None) + } + + pub fn new_with_extension(identifier: &str, extension: &str) -> Self { + Self::new_internal(identifier, Some(extension)) + } + + fn new_internal(identifier: &str, extension: Option<&str>) -> Self { + let mut binary_path = + std::env::current_exe().expect("Could not retrieve current executable path"); + binary_path.pop(); + binary_path.push(RUST_SERVICE_BINARY); + let mut command = Command::new(&binary_path); + command.arg(identifier); + if let Some(ext) = extension { + command.arg(ext); + } + let child = command.spawn().expect("Could not start service"); + Self(child) + } + } + + impl Drop for ScopedServiceProcess { + fn drop(&mut self) { + self.0.kill().expect("Could not kill child process"); + self.0 + .wait() + .expect("Could not wait for child process to die"); + } + } + + #[test] + fn check_services() { + let mut sm = binder::get_service("manager").expect("Did not get manager binder service"); + assert!(sm.is_binder_alive()); + assert!(sm.ping_binder().is_ok()); + + assert!(binder::get_service("this_service_does_not_exist").is_none()); + assert_eq!( + binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(), + Some(StatusCode::NAME_NOT_FOUND) + ); + + // The service manager service isn't an ITest, so this must fail. + assert_eq!( + binder::get_interface::<dyn ITest>("manager").err(), + Some(StatusCode::BAD_TYPE) + ); + } + + #[test] + fn trivial_client() { + let service_name = "trivial_client_test"; + let _process = ScopedServiceProcess::new(service_name); + let test_client: Box<dyn ITest> = + binder::get_interface(service_name).expect("Did not get manager binder service"); + assert_eq!(test_client.test().unwrap(), "trivial_client_test"); + } + + fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) { + let binder_died = Arc::new(AtomicBool::new(false)); + + let mut death_recipient = { + let flag = binder_died.clone(); + DeathRecipient::new(move || { + flag.store(true, Ordering::Relaxed); + }) + }; + + binder + .link_to_death(&mut death_recipient) + .expect("link_to_death failed"); + + (binder_died, death_recipient) + } + + /// Killing a remote service should unregister the service and trigger + /// death notifications. + #[test] + fn test_death_notifications() { + binder::ProcessState::start_thread_pool(); + + let service_name = "test_death_notifications"; + let service_process = ScopedServiceProcess::new(service_name); + let mut remote = binder::get_service(service_name).expect("Could not retrieve service"); + + let (binder_died, _recipient) = register_death_notification(&mut remote); + + drop(service_process); + remote + .ping_binder() + .expect_err("Service should have died already"); + + // Pause to ensure any death notifications get delivered + thread::sleep(Duration::from_secs(1)); + + assert!( + binder_died.load(Ordering::Relaxed), + "Did not receive death notification" + ); + } + + /// Test unregistering death notifications. + #[test] + fn test_unregister_death_notifications() { + binder::ProcessState::start_thread_pool(); + + let service_name = "test_unregister_death_notifications"; + let service_process = ScopedServiceProcess::new(service_name); + let mut remote = binder::get_service(service_name).expect("Could not retrieve service"); + + let (binder_died, mut recipient) = register_death_notification(&mut remote); + + remote + .unlink_to_death(&mut recipient) + .expect("Could not unlink death notifications"); + + drop(service_process); + remote + .ping_binder() + .expect_err("Service should have died already"); + + // Pause to ensure any death notifications get delivered + thread::sleep(Duration::from_secs(1)); + + assert!( + !binder_died.load(Ordering::Relaxed), + "Received unexpected death notification after unlinking", + ); + } + + /// Dropping a remote handle should unregister any death notifications. + #[test] + fn test_death_notification_registration_lifetime() { + binder::ProcessState::start_thread_pool(); + + let service_name = "test_death_notification_registration_lifetime"; + let service_process = ScopedServiceProcess::new(service_name); + let mut remote = binder::get_service(service_name).expect("Could not retrieve service"); + + let (binder_died, _recipient) = register_death_notification(&mut remote); + + // This should automatically unregister our death notification. + drop(remote); + + drop(service_process); + + // Pause to ensure any death notifications get delivered + thread::sleep(Duration::from_secs(1)); + + // We dropped the remote handle, so we should not receive the death + // notification when the remote process dies here. + assert!( + !binder_died.load(Ordering::Relaxed), + "Received unexpected death notification after dropping remote handle" + ); + } + + /// Test IBinder interface methods not exercised elsewhere. + #[test] + fn test_misc_ibinder() { + let service_name = "rust_test_ibinder"; + + { + let _process = ScopedServiceProcess::new(service_name); + + let mut remote = binder::get_service(service_name); + assert!(remote.is_binder_alive()); + remote.ping_binder().expect("Could not ping remote service"); + + // We're not testing the output of dump here, as that's really a + // property of the C++ implementation. There is the risk that the + // method just does nothing, but we don't want to depend on any + // particular output from the underlying library. + let null_out = File::open("/dev/null").expect("Could not open /dev/null"); + remote + .dump(&null_out, &[]) + .expect("Could not dump remote service"); + } + + // get/set_extensions is tested in test_extensions() + + // transact is tested everywhere else, and we can't make raw + // transactions outside the [FIRST_CALL_TRANSACTION, + // LAST_CALL_TRANSACTION] range from the NDK anyway. + + // link_to_death is tested in test_*_death_notification* tests. + } + + #[test] + fn test_extensions() { + let service_name = "rust_test_extensions"; + let extension_name = "rust_test_extensions_ext"; + + { + let _process = ScopedServiceProcess::new(service_name); + + let mut remote = binder::get_service(service_name); + assert!(remote.is_binder_alive()); + + let extension = remote + .get_extension() + .expect("Could not check for an extension"); + assert!(extension.is_none()); + } + + { + let _process = ScopedServiceProcess::new_with_extension(service_name, extension_name); + + let mut remote = binder::get_service(service_name); + assert!(remote.is_binder_alive()); + + let maybe_extension = remote + .get_extension() + .expect("Could not check for an extension"); + + let extension = maybe_extension.expect("Remote binder did not have an extension"); + + let extension: Box<dyn ITest> = FromIBinder::try_from(extension) + .expect("Extension could not be converted to the expected interface"); + + assert_eq!(extension.test().unwrap(), extension_name); + } + } +} |