Merge "Add method to get vector of strings." into main am: 7671143194 am: 99be628cf6
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/3457319
Change-Id: I3a5997c28bfec5de60a16acd7c59b93fd0c732ec
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/binder/rust/src/persistable_bundle.rs b/libs/binder/rust/src/persistable_bundle.rs
index 46d0fe7..e1d64ad 100644
--- a/libs/binder/rust/src/persistable_bundle.rs
+++ b/libs/binder/rust/src/persistable_bundle.rs
@@ -26,16 +26,16 @@
APersistableBundle_getDouble, APersistableBundle_getDoubleVector, APersistableBundle_getInt,
APersistableBundle_getIntVector, APersistableBundle_getLong, APersistableBundle_getLongVector,
APersistableBundle_getPersistableBundle, APersistableBundle_getString,
- APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_putBoolean,
- APersistableBundle_putBooleanVector, APersistableBundle_putDouble,
- APersistableBundle_putDoubleVector, APersistableBundle_putInt, APersistableBundle_putIntVector,
- APersistableBundle_putLong, APersistableBundle_putLongVector,
+ APersistableBundle_getStringVector, APersistableBundle_isEqual, APersistableBundle_new,
+ APersistableBundle_putBoolean, APersistableBundle_putBooleanVector,
+ APersistableBundle_putDouble, APersistableBundle_putDoubleVector, APersistableBundle_putInt,
+ APersistableBundle_putIntVector, APersistableBundle_putLong, APersistableBundle_putLongVector,
APersistableBundle_putPersistableBundle, APersistableBundle_putString,
APersistableBundle_putStringVector, APersistableBundle_readFromParcel, APersistableBundle_size,
APersistableBundle_writeToParcel, APERSISTABLEBUNDLE_ALLOCATOR_FAILED,
APERSISTABLEBUNDLE_KEY_NOT_FOUND,
};
-use std::ffi::{c_char, c_void, CString, NulError};
+use std::ffi::{c_char, c_void, CStr, CString, NulError};
use std::ptr::{null_mut, slice_from_raw_parts_mut, NonNull};
use zerocopy::FromZeros;
@@ -438,9 +438,10 @@
/// call. It must allow a null pointer for the buffer, and must return the size in bytes of
/// buffer it requires. If it is given a non-null buffer pointer it must write that number of
/// bytes to the buffer, which must be a whole number of valid `T` values.
- unsafe fn get_vec<T: Clone + Default>(
+ unsafe fn get_vec<T: Clone>(
&self,
key: &str,
+ default: T,
get_func: unsafe extern "C" fn(
*const APersistableBundle,
*const c_char,
@@ -454,9 +455,12 @@
// to be valid for the lifetime of `key`. A null pointer is allowed for the buffer.
match unsafe { get_func(self.0.as_ptr(), key.as_ptr(), null_mut(), 0) } {
APERSISTABLEBUNDLE_KEY_NOT_FOUND => Ok(None),
+ APERSISTABLEBUNDLE_ALLOCATOR_FAILED => {
+ panic!("APersistableBundle_getStringVector failed to allocate string");
+ }
required_buffer_size => {
let mut value = vec![
- T::default();
+ default;
usize::try_from(required_buffer_size).expect(
"APersistableBundle_get*Vector returned invalid size"
) / size_of::<T>()
@@ -476,6 +480,9 @@
APERSISTABLEBUNDLE_KEY_NOT_FOUND => {
panic!("APersistableBundle_get*Vector failed to find key after first finding it");
}
+ APERSISTABLEBUNDLE_ALLOCATOR_FAILED => {
+ panic!("APersistableBundle_getStringVector failed to allocate string");
+ }
_ => Ok(Some(value)),
}
}
@@ -489,7 +496,7 @@
pub fn get_bool_vec(&self, key: &str) -> Result<Option<Vec<bool>>, NulError> {
// SAFETY: APersistableBundle_getBooleanVector fulfils all the safety requirements of
// `get_vec`.
- unsafe { self.get_vec(key, APersistableBundle_getBooleanVector) }
+ unsafe { self.get_vec(key, Default::default(), APersistableBundle_getBooleanVector) }
}
/// Gets the i32 vector value associated with the given key.
@@ -499,7 +506,7 @@
pub fn get_int_vec(&self, key: &str) -> Result<Option<Vec<i32>>, NulError> {
// SAFETY: APersistableBundle_getIntVector fulfils all the safety requirements of
// `get_vec`.
- unsafe { self.get_vec(key, APersistableBundle_getIntVector) }
+ unsafe { self.get_vec(key, Default::default(), APersistableBundle_getIntVector) }
}
/// Gets the i64 vector value associated with the given key.
@@ -509,7 +516,7 @@
pub fn get_long_vec(&self, key: &str) -> Result<Option<Vec<i64>>, NulError> {
// SAFETY: APersistableBundle_getLongVector fulfils all the safety requirements of
// `get_vec`.
- unsafe { self.get_vec(key, APersistableBundle_getLongVector) }
+ unsafe { self.get_vec(key, Default::default(), APersistableBundle_getLongVector) }
}
/// Gets the f64 vector value associated with the given key.
@@ -519,7 +526,45 @@
pub fn get_double_vec(&self, key: &str) -> Result<Option<Vec<f64>>, NulError> {
// SAFETY: APersistableBundle_getDoubleVector fulfils all the safety requirements of
// `get_vec`.
- unsafe { self.get_vec(key, APersistableBundle_getDoubleVector) }
+ unsafe { self.get_vec(key, Default::default(), APersistableBundle_getDoubleVector) }
+ }
+
+ /// Gets the string vector value associated with the given key.
+ ///
+ /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
+ /// in the bundle.
+ pub fn get_string_vec(&self, key: &str) -> Result<Option<Vec<String>>, NulError> {
+ if let Some(value) =
+ // SAFETY: `get_string_vector_with_allocator` fulfils all the safety requirements of
+ // `get_vec`.
+ unsafe { self.get_vec(key, null_mut(), get_string_vector_with_allocator) }?
+ {
+ Ok(Some(
+ value
+ .into_iter()
+ .map(|s| {
+ // SAFETY: The pointer was returned from `string_allocator`, which used
+ // `Box::into_raw`, and `APersistableBundle_getStringVector` should have
+ // written valid bytes to it including a NUL terminator in the last
+ // position.
+ let string_length = unsafe { CStr::from_ptr(s) }.count_bytes();
+ let raw_slice = slice_from_raw_parts_mut(s.cast(), string_length + 1);
+ // SAFETY: The pointer was returned from `string_allocator`, which used
+ // `Box::into_raw`, and we've got the appropriate size back by checking the
+ // length of the string.
+ let boxed_slice: Box<[u8]> = unsafe { Box::from_raw(raw_slice) };
+ let c_string = CString::from_vec_with_nul(boxed_slice.into()).expect(
+ "APersistableBundle_getStringVector returned string missing NUL byte",
+ );
+ c_string
+ .into_string()
+ .expect("APersistableBundle_getStringVector returned invalid UTF-8")
+ })
+ .collect(),
+ ))
+ } else {
+ Ok(None)
+ }
}
/// Gets the `PersistableBundle` value associated with the given key.
@@ -545,6 +590,36 @@
}
}
+/// Wrapper around `APersistableBundle_getStringVector` to pass `string_allocator` and a null
+/// context pointer.
+///
+/// # Safety
+///
+/// * `bundle` must point to a valid `APersistableBundle` which is not modified for the duration of
+/// the call.
+/// * `key` must point to a valid NUL-terminated C string.
+/// * `buffer` must either be null or point to a buffer of at least `buffer_size_bytes` bytes,
+/// properly aligned for `T`, and not otherwise accessed for the duration of the call.
+unsafe extern "C" fn get_string_vector_with_allocator(
+ bundle: *const APersistableBundle,
+ key: *const c_char,
+ buffer: *mut *mut c_char,
+ buffer_size_bytes: i32,
+) -> i32 {
+ // SAFETY: The safety requirements are all guaranteed by our caller according to the safety
+ // documentation above.
+ unsafe {
+ APersistableBundle_getStringVector(
+ bundle,
+ key,
+ buffer,
+ buffer_size_bytes,
+ Some(string_allocator),
+ null_mut(),
+ )
+ }
+}
+
// SAFETY: The underlying *APersistableBundle can be moved between threads.
unsafe impl Send for PersistableBundle {}
@@ -613,7 +688,7 @@
///
/// # Safety
///
-/// `context` must point to a `usize` to which we can write.
+/// `context` must either be null or point to a `usize` to which we can write.
unsafe extern "C" fn string_allocator(size: i32, context: *mut c_void) -> *mut c_char {
let Ok(size) = size.try_into() else {
return null_mut();
@@ -621,9 +696,12 @@
let Ok(boxed_slice) = <[c_char]>::new_box_zeroed_with_elems(size) else {
return null_mut();
};
- // SAFETY: The caller promised that `context` points to a `usize` to which we can write.
- unsafe {
- *context.cast::<usize>() = size;
+ if !context.is_null() {
+ // SAFETY: The caller promised that `context` is either null or points to a `usize` to which
+ // we can write, and we just checked that it's not null.
+ unsafe {
+ *context.cast::<usize>() = size;
+ }
}
Box::into_raw(boxed_slice).cast()
}
@@ -751,6 +829,10 @@
assert_eq!(bundle.get_int_vec("int"), Ok(Some(vec![42])));
assert_eq!(bundle.get_long_vec("long"), Ok(Some(vec![66, 67, 68])));
assert_eq!(bundle.get_double_vec("double"), Ok(Some(vec![123.4])));
+ assert_eq!(
+ bundle.get_string_vec("string"),
+ Ok(Some(vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]))
+ );
}
#[test]