Skip to content

Commit 7671143

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge "Add method to get vector of strings." into main
2 parents 37a49f2 + d2e0740 commit 7671143

1 file changed

Lines changed: 97 additions & 15 deletions

File tree

libs/binder/rust/src/persistable_bundle.rs

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ use binder_ndk_sys::{
2626
APersistableBundle_getDouble, APersistableBundle_getDoubleVector, APersistableBundle_getInt,
2727
APersistableBundle_getIntVector, APersistableBundle_getLong, APersistableBundle_getLongVector,
2828
APersistableBundle_getPersistableBundle, APersistableBundle_getString,
29-
APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_putBoolean,
30-
APersistableBundle_putBooleanVector, APersistableBundle_putDouble,
31-
APersistableBundle_putDoubleVector, APersistableBundle_putInt, APersistableBundle_putIntVector,
32-
APersistableBundle_putLong, APersistableBundle_putLongVector,
29+
APersistableBundle_getStringVector, APersistableBundle_isEqual, APersistableBundle_new,
30+
APersistableBundle_putBoolean, APersistableBundle_putBooleanVector,
31+
APersistableBundle_putDouble, APersistableBundle_putDoubleVector, APersistableBundle_putInt,
32+
APersistableBundle_putIntVector, APersistableBundle_putLong, APersistableBundle_putLongVector,
3333
APersistableBundle_putPersistableBundle, APersistableBundle_putString,
3434
APersistableBundle_putStringVector, APersistableBundle_readFromParcel, APersistableBundle_size,
3535
APersistableBundle_writeToParcel, APERSISTABLEBUNDLE_ALLOCATOR_FAILED,
3636
APERSISTABLEBUNDLE_KEY_NOT_FOUND,
3737
};
38-
use std::ffi::{c_char, c_void, CString, NulError};
38+
use std::ffi::{c_char, c_void, CStr, CString, NulError};
3939
use std::ptr::{null_mut, slice_from_raw_parts_mut, NonNull};
4040
use zerocopy::FromZeros;
4141

@@ -438,9 +438,10 @@ impl PersistableBundle {
438438
/// call. It must allow a null pointer for the buffer, and must return the size in bytes of
439439
/// buffer it requires. If it is given a non-null buffer pointer it must write that number of
440440
/// bytes to the buffer, which must be a whole number of valid `T` values.
441-
unsafe fn get_vec<T: Clone + Default>(
441+
unsafe fn get_vec<T: Clone>(
442442
&self,
443443
key: &str,
444+
default: T,
444445
get_func: unsafe extern "C" fn(
445446
*const APersistableBundle,
446447
*const c_char,
@@ -454,9 +455,12 @@ impl PersistableBundle {
454455
// to be valid for the lifetime of `key`. A null pointer is allowed for the buffer.
455456
match unsafe { get_func(self.0.as_ptr(), key.as_ptr(), null_mut(), 0) } {
456457
APERSISTABLEBUNDLE_KEY_NOT_FOUND => Ok(None),
458+
APERSISTABLEBUNDLE_ALLOCATOR_FAILED => {
459+
panic!("APersistableBundle_getStringVector failed to allocate string");
460+
}
457461
required_buffer_size => {
458462
let mut value = vec![
459-
T::default();
463+
default;
460464
usize::try_from(required_buffer_size).expect(
461465
"APersistableBundle_get*Vector returned invalid size"
462466
) / size_of::<T>()
@@ -476,6 +480,9 @@ impl PersistableBundle {
476480
APERSISTABLEBUNDLE_KEY_NOT_FOUND => {
477481
panic!("APersistableBundle_get*Vector failed to find key after first finding it");
478482
}
483+
APERSISTABLEBUNDLE_ALLOCATOR_FAILED => {
484+
panic!("APersistableBundle_getStringVector failed to allocate string");
485+
}
479486
_ => Ok(Some(value)),
480487
}
481488
}
@@ -489,7 +496,7 @@ impl PersistableBundle {
489496
pub fn get_bool_vec(&self, key: &str) -> Result<Option<Vec<bool>>, NulError> {
490497
// SAFETY: APersistableBundle_getBooleanVector fulfils all the safety requirements of
491498
// `get_vec`.
492-
unsafe { self.get_vec(key, APersistableBundle_getBooleanVector) }
499+
unsafe { self.get_vec(key, Default::default(), APersistableBundle_getBooleanVector) }
493500
}
494501

495502
/// Gets the i32 vector value associated with the given key.
@@ -499,7 +506,7 @@ impl PersistableBundle {
499506
pub fn get_int_vec(&self, key: &str) -> Result<Option<Vec<i32>>, NulError> {
500507
// SAFETY: APersistableBundle_getIntVector fulfils all the safety requirements of
501508
// `get_vec`.
502-
unsafe { self.get_vec(key, APersistableBundle_getIntVector) }
509+
unsafe { self.get_vec(key, Default::default(), APersistableBundle_getIntVector) }
503510
}
504511

505512
/// Gets the i64 vector value associated with the given key.
@@ -509,7 +516,7 @@ impl PersistableBundle {
509516
pub fn get_long_vec(&self, key: &str) -> Result<Option<Vec<i64>>, NulError> {
510517
// SAFETY: APersistableBundle_getLongVector fulfils all the safety requirements of
511518
// `get_vec`.
512-
unsafe { self.get_vec(key, APersistableBundle_getLongVector) }
519+
unsafe { self.get_vec(key, Default::default(), APersistableBundle_getLongVector) }
513520
}
514521

515522
/// Gets the f64 vector value associated with the given key.
@@ -519,7 +526,45 @@ impl PersistableBundle {
519526
pub fn get_double_vec(&self, key: &str) -> Result<Option<Vec<f64>>, NulError> {
520527
// SAFETY: APersistableBundle_getDoubleVector fulfils all the safety requirements of
521528
// `get_vec`.
522-
unsafe { self.get_vec(key, APersistableBundle_getDoubleVector) }
529+
unsafe { self.get_vec(key, Default::default(), APersistableBundle_getDoubleVector) }
530+
}
531+
532+
/// Gets the string vector value associated with the given key.
533+
///
534+
/// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
535+
/// in the bundle.
536+
pub fn get_string_vec(&self, key: &str) -> Result<Option<Vec<String>>, NulError> {
537+
if let Some(value) =
538+
// SAFETY: `get_string_vector_with_allocator` fulfils all the safety requirements of
539+
// `get_vec`.
540+
unsafe { self.get_vec(key, null_mut(), get_string_vector_with_allocator) }?
541+
{
542+
Ok(Some(
543+
value
544+
.into_iter()
545+
.map(|s| {
546+
// SAFETY: The pointer was returned from `string_allocator`, which used
547+
// `Box::into_raw`, and `APersistableBundle_getStringVector` should have
548+
// written valid bytes to it including a NUL terminator in the last
549+
// position.
550+
let string_length = unsafe { CStr::from_ptr(s) }.count_bytes();
551+
let raw_slice = slice_from_raw_parts_mut(s.cast(), string_length + 1);
552+
// SAFETY: The pointer was returned from `string_allocator`, which used
553+
// `Box::into_raw`, and we've got the appropriate size back by checking the
554+
// length of the string.
555+
let boxed_slice: Box<[u8]> = unsafe { Box::from_raw(raw_slice) };
556+
let c_string = CString::from_vec_with_nul(boxed_slice.into()).expect(
557+
"APersistableBundle_getStringVector returned string missing NUL byte",
558+
);
559+
c_string
560+
.into_string()
561+
.expect("APersistableBundle_getStringVector returned invalid UTF-8")
562+
})
563+
.collect(),
564+
))
565+
} else {
566+
Ok(None)
567+
}
523568
}
524569

525570
/// Gets the `PersistableBundle` value associated with the given key.
@@ -545,6 +590,36 @@ impl PersistableBundle {
545590
}
546591
}
547592

593+
/// Wrapper around `APersistableBundle_getStringVector` to pass `string_allocator` and a null
594+
/// context pointer.
595+
///
596+
/// # Safety
597+
///
598+
/// * `bundle` must point to a valid `APersistableBundle` which is not modified for the duration of
599+
/// the call.
600+
/// * `key` must point to a valid NUL-terminated C string.
601+
/// * `buffer` must either be null or point to a buffer of at least `buffer_size_bytes` bytes,
602+
/// properly aligned for `T`, and not otherwise accessed for the duration of the call.
603+
unsafe extern "C" fn get_string_vector_with_allocator(
604+
bundle: *const APersistableBundle,
605+
key: *const c_char,
606+
buffer: *mut *mut c_char,
607+
buffer_size_bytes: i32,
608+
) -> i32 {
609+
// SAFETY: The safety requirements are all guaranteed by our caller according to the safety
610+
// documentation above.
611+
unsafe {
612+
APersistableBundle_getStringVector(
613+
bundle,
614+
key,
615+
buffer,
616+
buffer_size_bytes,
617+
Some(string_allocator),
618+
null_mut(),
619+
)
620+
}
621+
}
622+
548623
// SAFETY: The underlying *APersistableBundle can be moved between threads.
549624
unsafe impl Send for PersistableBundle {}
550625

@@ -613,17 +688,20 @@ impl UnstructuredParcelable for PersistableBundle {
613688
///
614689
/// # Safety
615690
///
616-
/// `context` must point to a `usize` to which we can write.
691+
/// `context` must either be null or point to a `usize` to which we can write.
617692
unsafe extern "C" fn string_allocator(size: i32, context: *mut c_void) -> *mut c_char {
618693
let Ok(size) = size.try_into() else {
619694
return null_mut();
620695
};
621696
let Ok(boxed_slice) = <[c_char]>::new_box_zeroed_with_elems(size) else {
622697
return null_mut();
623698
};
624-
// SAFETY: The caller promised that `context` points to a `usize` to which we can write.
625-
unsafe {
626-
*context.cast::<usize>() = size;
699+
if !context.is_null() {
700+
// SAFETY: The caller promised that `context` is either null or points to a `usize` to which
701+
// we can write, and we just checked that it's not null.
702+
unsafe {
703+
*context.cast::<usize>() = size;
704+
}
627705
}
628706
Box::into_raw(boxed_slice).cast()
629707
}
@@ -751,6 +829,10 @@ mod test {
751829
assert_eq!(bundle.get_int_vec("int"), Ok(Some(vec![42])));
752830
assert_eq!(bundle.get_long_vec("long"), Ok(Some(vec![66, 67, 68])));
753831
assert_eq!(bundle.get_double_vec("double"), Ok(Some(vec![123.4])));
832+
assert_eq!(
833+
bundle.get_string_vec("string"),
834+
Ok(Some(vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]))
835+
);
754836
}
755837

756838
#[test]

0 commit comments

Comments
 (0)