@@ -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 } ;
3939use std:: ptr:: { null_mut, slice_from_raw_parts_mut, NonNull } ;
4040use 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.
549624unsafe 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.
617692unsafe 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