@@ -25,16 +25,19 @@ use binder_ndk_sys::{
2525 APersistableBundle_erase , APersistableBundle_getBoolean , APersistableBundle_getBooleanVector ,
2626 APersistableBundle_getDouble , APersistableBundle_getDoubleVector , APersistableBundle_getInt ,
2727 APersistableBundle_getIntVector , APersistableBundle_getLong , APersistableBundle_getLongVector ,
28- APersistableBundle_getPersistableBundle , APersistableBundle_isEqual , APersistableBundle_new ,
29- APersistableBundle_putBoolean , APersistableBundle_putBooleanVector ,
30- APersistableBundle_putDouble , APersistableBundle_putDoubleVector , APersistableBundle_putInt ,
31- APersistableBundle_putIntVector , APersistableBundle_putLong , APersistableBundle_putLongVector ,
28+ 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 ,
3233 APersistableBundle_putPersistableBundle , APersistableBundle_putString ,
3334 APersistableBundle_putStringVector , APersistableBundle_readFromParcel , APersistableBundle_size ,
34- APersistableBundle_writeToParcel , APERSISTABLEBUNDLE_KEY_NOT_FOUND ,
35+ APersistableBundle_writeToParcel , APERSISTABLEBUNDLE_ALLOCATOR_FAILED ,
36+ APERSISTABLEBUNDLE_KEY_NOT_FOUND ,
3537} ;
36- use std:: ffi:: { c_char, CString , NulError } ;
37- use std:: ptr:: { null_mut, NonNull } ;
38+ use std:: ffi:: { c_char, c_void, CString , NulError } ;
39+ use std:: ptr:: { null_mut, slice_from_raw_parts_mut, NonNull } ;
40+ use zerocopy:: FromZeros ;
3841
3942/// A mapping from string keys to values of various types.
4043#[ derive( Debug ) ]
@@ -374,6 +377,53 @@ impl PersistableBundle {
374377 }
375378 }
376379
380+ /// Gets the string value associated with the given key.
381+ ///
382+ /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
383+ /// in the bundle.
384+ pub fn get_string ( & self , key : & str ) -> Result < Option < String > , NulError > {
385+ let key = CString :: new ( key) ?;
386+ let mut value = null_mut ( ) ;
387+ let mut allocated_size: usize = 0 ;
388+ // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
389+ // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed
390+ // to be valid for the lifetime of `key`. The value pointer must be valid because it comes
391+ // from a reference.
392+ let value_size_bytes = unsafe {
393+ APersistableBundle_getString (
394+ self . 0 . as_ptr ( ) ,
395+ key. as_ptr ( ) ,
396+ & mut value,
397+ Some ( string_allocator) ,
398+ ( & raw mut allocated_size) . cast ( ) ,
399+ )
400+ } ;
401+ match value_size_bytes {
402+ APERSISTABLEBUNDLE_KEY_NOT_FOUND => Ok ( None ) ,
403+ APERSISTABLEBUNDLE_ALLOCATOR_FAILED => {
404+ panic ! ( "APersistableBundle_getString failed to allocate string" ) ;
405+ }
406+ _ => {
407+ let raw_slice = slice_from_raw_parts_mut ( value. cast ( ) , allocated_size) ;
408+ // SAFETY: The pointer was returned from string_allocator, which used
409+ // `Box::into_raw`, and we've got the appropriate size back from allocated_size.
410+ let boxed_slice: Box < [ u8 ] > = unsafe { Box :: from_raw ( raw_slice) } ;
411+ assert_eq ! (
412+ allocated_size,
413+ usize :: try_from( value_size_bytes)
414+ . expect( "APersistableBundle_getString returned negative value size" )
415+ + 1
416+ ) ;
417+ let c_string = CString :: from_vec_with_nul ( boxed_slice. into ( ) )
418+ . expect ( "APersistableBundle_getString returned string missing NUL byte" ) ;
419+ let string = c_string
420+ . into_string ( )
421+ . expect ( "APersistableBundle_getString returned invalid UTF-8" ) ;
422+ Ok ( Some ( string) )
423+ }
424+ }
425+ }
426+
377427 /// Gets the vector of `T` associated with the given key.
378428 ///
379429 /// Returns an error if the key contains a NUL character, or `Ok(None)` if the key doesn't exist
@@ -558,6 +608,26 @@ impl UnstructuredParcelable for PersistableBundle {
558608 }
559609}
560610
611+ /// Allocates a boxed slice of the given size in bytes, returns a pointer to it and writes its size
612+ /// to `*context`.
613+ ///
614+ /// # Safety
615+ ///
616+ /// `context` must point to a `usize` to which we can write.
617+ unsafe extern "C" fn string_allocator ( size : i32 , context : * mut c_void ) -> * mut c_char {
618+ let Ok ( size) = size. try_into ( ) else {
619+ return null_mut ( ) ;
620+ } ;
621+ let Ok ( boxed_slice) = <[ c_char ] >:: new_box_zeroed_with_elems ( size) else {
622+ return null_mut ( ) ;
623+ } ;
624+ // SAFETY: The caller promised that `context` points to a `usize` to which we can write.
625+ unsafe {
626+ * context. cast :: < usize > ( ) = size;
627+ }
628+ Box :: into_raw ( boxed_slice) . cast ( )
629+ }
630+
561631impl_deserialize_for_unstructured_parcelable ! ( PersistableBundle ) ;
562632impl_serialize_for_unstructured_parcelable ! ( PersistableBundle ) ;
563633
@@ -589,6 +659,7 @@ mod test {
589659 assert_eq ! ( bundle. get_int_vec( "foo" ) , Ok ( None ) ) ;
590660 assert_eq ! ( bundle. get_long_vec( "foo" ) , Ok ( None ) ) ;
591661 assert_eq ! ( bundle. get_double_vec( "foo" ) , Ok ( None ) ) ;
662+ assert_eq ! ( bundle. get_string( "foo" ) , Ok ( None ) ) ;
592663 }
593664
594665 #[ test]
@@ -639,10 +710,15 @@ mod test {
639710 }
640711
641712 #[ test]
642- fn insert_string ( ) {
713+ fn insert_get_string ( ) {
643714 let mut bundle = PersistableBundle :: new ( ) ;
715+
644716 assert_eq ! ( bundle. insert_string( "string" , "foo" ) , Ok ( ( ) ) ) ;
645- assert_eq ! ( bundle. size( ) , 1 ) ;
717+ assert_eq ! ( bundle. insert_string( "empty" , "" ) , Ok ( ( ) ) ) ;
718+ assert_eq ! ( bundle. size( ) , 2 ) ;
719+
720+ assert_eq ! ( bundle. get_string( "string" ) , Ok ( Some ( "foo" . to_string( ) ) ) ) ;
721+ assert_eq ! ( bundle. get_string( "empty" ) , Ok ( Some ( "" . to_string( ) ) ) ) ;
646722 }
647723
648724 #[ test]
0 commit comments