diff options
-rw-r--r-- | cmds/servicemanager/Android.bp | 3 | ||||
-rw-r--r-- | libs/binder/rust/Android.bp | 22 | ||||
-rw-r--r-- | libs/binder/rust/src/binder.rs | 2 | ||||
-rw-r--r-- | libs/binder/rust/src/error.rs | 8 | ||||
-rw-r--r-- | libs/binder/rust/src/lib.rs | 2 | ||||
-rw-r--r-- | libs/binder/rust/src/native.rs | 12 | ||||
-rw-r--r-- | libs/binder/rust/src/parcel.rs | 95 | ||||
-rw-r--r-- | libs/binder/rust/src/proxy.rs | 20 | ||||
-rw-r--r-- | libs/binder/rust/sys/BinderBindings.h (renamed from libs/binder/rust/BinderBindings.h) | 0 | ||||
-rw-r--r-- | libs/binder/rust/sys/lib.rs | 38 |
10 files changed, 187 insertions, 15 deletions
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 7277e85d99..b1392515a2 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -44,6 +44,9 @@ cc_binary { cflags: [ "-DVENDORSERVICEMANAGER=1", ], + required: [ + "vndservice", + ], srcs: ["main.cpp"], } diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 16811eebe4..0234820b02 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -3,12 +3,24 @@ rust_library { crate_name: "binder", srcs: ["src/lib.rs"], shared_libs: [ - "libbinder_ndk", "libutils", ], rustlibs: [ "liblibc", - "libbinder_ndk_bindgen", + "libbinder_ndk_sys", + ], + host_supported: true, +} + +rust_library { + name: "libbinder_ndk_sys", + crate_name: "binder_ndk_sys", + srcs: [ + "sys/lib.rs", + ":libbinder_ndk_bindgen", + ], + shared_libs: [ + "libbinder_ndk", ], host_supported: true, } @@ -16,8 +28,8 @@ rust_library { rust_bindgen { name: "libbinder_ndk_bindgen", crate_name: "binder_ndk_bindgen", - wrapper_src: "BinderBindings.h", - source_stem: "ndk_bindings", + wrapper_src: "sys/BinderBindings.h", + source_stem: "bindings", cflags: [ "-x c++", ], @@ -69,6 +81,6 @@ rust_test { ], rustlibs: [ "liblibc", - "libbinder_ndk_bindgen", + "libbinder_ndk_sys", ], } diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index f5e75090c7..d55eafee67 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -61,7 +61,7 @@ pub trait Interface { /// 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 { +pub trait Remotable: Send + Sync { /// The Binder interface descriptor string. /// /// This string is a unique identifier for a Binder interface, and should be diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs index 289b1573db..4492cf72f4 100644 --- a/libs/binder/rust/src/error.rs +++ b/libs/binder/rust/src/error.rs @@ -43,14 +43,6 @@ pub fn status_result(status: status_t) -> Result<()> { } } -// 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, diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 4b9cccf41b..8ee6a62180 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -102,7 +102,7 @@ mod error; mod native; mod state; -use binder_ndk_bindgen as sys; +use binder_ndk_sys as sys; pub mod parcel; diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index 798fed813e..185645ef4a 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -36,6 +36,18 @@ pub struct Binder<T: Remotable> { rust_object: *mut T, } +/// # Safety +/// +/// A `Binder<T>` is a pair of unique owning pointers to two values: +/// * a C++ ABBinder which the C++ API guarantees can be passed between threads +/// * a Rust object which implements `Remotable`; this trait requires `Send + Sync` +/// +/// Both pointers are unique (never escape the `Binder<T>` object and are not copied) +/// so we can essentially treat `Binder<T>` as a box-like containing the two objects; +/// the box-like object inherits `Send` from the two inner values, similarly +/// to how `Box<T>` is `Send` if `T` is `Send`. +unsafe impl<T: Remotable> Send for Binder<T> {} + impl<T: Remotable> Binder<T> { /// Create a new Binder remotable object. /// diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 43850fe411..a248f5c510 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -21,6 +21,7 @@ use crate::error::{status_result, Result, StatusCode}; use crate::proxy::SpIBinder; use crate::sys; +use std::cell::RefCell; use std::convert::TryInto; use std::mem::ManuallyDrop; use std::ptr; @@ -117,6 +118,55 @@ impl Parcel { } } + /// Perform a series of writes to the `Parcel`, prepended with the length + /// (in bytes) of the written data. + /// + /// The length `0i32` will be written to the parcel first, followed by the + /// writes performed by the callback. The initial length will then be + /// updated to the length of all data written by the callback, plus the + /// size of the length elemement itself (4 bytes). + /// + /// # Examples + /// + /// After the following call: + /// + /// ``` + /// # use binder::{Binder, Interface, Parcel}; + /// # let mut parcel = Parcel::Owned(std::ptr::null_mut()); + /// parcel.sized_write(|subparcel| { + /// subparcel.write(&1u32)?; + /// subparcel.write(&2u32)?; + /// subparcel.write(&3u32) + /// }); + /// ``` + /// + /// `parcel` will contain the following: + /// + /// ```ignore + /// [16i32, 1u32, 2u32, 3u32] + /// ``` + pub fn sized_write<F>(&mut self, f: F) -> Result<()> + where for<'a> + F: Fn(&'a WritableSubParcel<'a>) -> Result<()> + { + let start = self.get_data_position(); + self.write(&0i32)?; + { + let subparcel = WritableSubParcel(RefCell::new(self)); + f(&subparcel)?; + } + let end = self.get_data_position(); + unsafe { + self.set_data_position(start)?; + } + assert!(end >= start); + self.write(&(end - start))?; + unsafe { + self.set_data_position(end)?; + } + Ok(()) + } + /// Returns the current position in the parcel data. pub fn get_data_position(&self) -> i32 { unsafe { @@ -143,6 +193,16 @@ impl Parcel { } } +/// A segment of a writable parcel, used for [`Parcel::sized_write`]. +pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>); + +impl<'a> WritableSubParcel<'a> { + /// Write a type that implements [`Serialize`] to the sub-parcel. + pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> { + parcelable.serialize(&mut *self.0.borrow_mut()) + } +} + // Data deserialization methods impl Parcel { /// Attempt to read a type that implements [`Deserialize`] from this @@ -445,3 +505,38 @@ fn test_utf8_utf16_conversions() { ); assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]); } + +#[test] +fn test_sized_write() { + 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(); + + let arr = [1i32, 2i32, 3i32]; + + parcel.sized_write(|subparcel| { + subparcel.write(&arr[..]) + }).expect("Could not perform sized write"); + + // i32 sub-parcel length + i32 array length + 3 i32 elements + let expected_len = 20i32; + + assert_eq!(parcel.get_data_position(), start + expected_len); + + unsafe { + parcel.set_data_position(start).unwrap(); + } + + assert_eq!( + expected_len, + parcel.read().unwrap(), + ); + + assert_eq!( + parcel.read::<Vec<i32>>().unwrap(), + &arr, + ); +} diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index f9519b4d01..13e5619237 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -122,6 +122,14 @@ impl AssociateClass for SpIBinder { } } +impl PartialEq for SpIBinder { + fn eq(&self, other: &Self) -> bool { + ptr::eq(self.0, other.0) + } +} + +impl Eq for SpIBinder {} + impl Clone for SpIBinder { fn clone(&self) -> Self { unsafe { @@ -363,6 +371,18 @@ impl WpIBinder { assert!(!ptr.is_null()); Self(ptr) } + + /// Promote this weak reference to a strong reference to the binder object. + pub fn promote(&self) -> Option<SpIBinder> { + unsafe { + // Safety: `WpIBinder` always contains a valid weak reference, so we + // can pass this pointer to `AIBinder_Weak_promote`. Returns either + // null or an AIBinder owned by the caller, both of which are valid + // to pass to `SpIBinder::from_raw`. + let ptr = sys::AIBinder_Weak_promote(self.0); + SpIBinder::from_raw(ptr) + } + } } /// Rust wrapper around DeathRecipient objects. diff --git a/libs/binder/rust/BinderBindings.h b/libs/binder/rust/sys/BinderBindings.h index c7a06d9a1c..c7a06d9a1c 100644 --- a/libs/binder/rust/BinderBindings.h +++ b/libs/binder/rust/sys/BinderBindings.h diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs new file mode 100644 index 0000000000..9095af29e0 --- /dev/null +++ b/libs/binder/rust/sys/lib.rs @@ -0,0 +1,38 @@ +/* + * 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. + */ + +//! Generated Rust bindings to libbinder_ndk + +#![allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused, + improper_ctypes, + missing_docs +)] +use std::error::Error; +use std::fmt; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +impl Error for android_c_interface_StatusCode {} + +impl fmt::Display for android_c_interface_StatusCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "StatusCode::{:?}", self) + } +} |