From d62d565534734da11718f19f0096227f17f75347 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 16 Jan 2025 14:22:46 +0000 Subject: Add methods to insert string, vectors and bundles. Bug: 389074518 Test: atest libbinder_rs-internal_test Change-Id: Ie147ab0027b96dee7f1d96e90fd80163e6e68ca3 --- libs/binder/rust/src/persistable_bundle.rs | 246 +++++++++++++++++++++++++++-- 1 file changed, 230 insertions(+), 16 deletions(-) diff --git a/libs/binder/rust/src/persistable_bundle.rs b/libs/binder/rust/src/persistable_bundle.rs index 58ea1380fb..093f88fe14 100644 --- a/libs/binder/rust/src/persistable_bundle.rs +++ b/libs/binder/rust/src/persistable_bundle.rs @@ -24,9 +24,12 @@ use binder_ndk_sys::{ APersistableBundle, APersistableBundle_delete, APersistableBundle_dup, APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getDouble, APersistableBundle_getInt, APersistableBundle_getLong, APersistableBundle_isEqual, - APersistableBundle_new, APersistableBundle_putBoolean, APersistableBundle_putDouble, - APersistableBundle_putInt, APersistableBundle_putLong, APersistableBundle_readFromParcel, - APersistableBundle_size, APersistableBundle_writeToParcel, + 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, }; use std::ffi::{CString, NulError}; use std::ptr::{null_mut, NonNull}; @@ -60,7 +63,7 @@ impl PersistableBundle { let key = CString::new(key)?; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. + // to be valid for the duration of this call. Ok(unsafe { APersistableBundle_erase(self.0.as_ptr(), key.as_ptr()) != 0 }) } @@ -73,7 +76,7 @@ impl PersistableBundle { let key = CString::new(key)?; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. + // to be valid for the duration of this call. unsafe { APersistableBundle_putBoolean(self.0.as_ptr(), key.as_ptr(), value); } @@ -89,7 +92,7 @@ impl PersistableBundle { let key = CString::new(key)?; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. + // to be valid for the duration of this call. unsafe { APersistableBundle_putInt(self.0.as_ptr(), key.as_ptr(), value); } @@ -105,7 +108,7 @@ impl PersistableBundle { let key = CString::new(key)?; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. + // to be valid for the duration of this call. unsafe { APersistableBundle_putLong(self.0.as_ptr(), key.as_ptr(), value); } @@ -121,13 +124,182 @@ impl PersistableBundle { let key = CString::new(key)?; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. + // to be valid for the duration of this call. unsafe { APersistableBundle_putDouble(self.0.as_ptr(), key.as_ptr(), value); } Ok(()) } + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key or value contains a NUL character. + pub fn insert_string(&mut self, key: &str, value: &str) -> Result<(), NulError> { + let key = CString::new(key)?; + let value = CString::new(value)?; + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `CStr::as_ptr` is guaranteed + // to be valid for the duration of this call. + unsafe { + APersistableBundle_putString(self.0.as_ptr(), key.as_ptr(), value.as_ptr()); + } + Ok(()) + } + + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key contains a NUL character. + pub fn insert_bool_vec(&mut self, key: &str, value: &[bool]) -> Result<(), NulError> { + let key = CString::new(key)?; + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed + // to be valid for the duration of this call, and likewise the pointer returned by + // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the + // duration of the call. + unsafe { + APersistableBundle_putBooleanVector( + self.0.as_ptr(), + key.as_ptr(), + value.as_ptr(), + value.len().try_into().unwrap(), + ); + } + Ok(()) + } + + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key contains a NUL character. + pub fn insert_int_vec(&mut self, key: &str, value: &[i32]) -> Result<(), NulError> { + let key = CString::new(key)?; + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed + // to be valid for the duration of this call, and likewise the pointer returned by + // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the + // duration of the call. + unsafe { + APersistableBundle_putIntVector( + self.0.as_ptr(), + key.as_ptr(), + value.as_ptr(), + value.len().try_into().unwrap(), + ); + } + Ok(()) + } + + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key contains a NUL character. + pub fn insert_long_vec(&mut self, key: &str, value: &[i64]) -> Result<(), NulError> { + let key = CString::new(key)?; + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed + // to be valid for the duration of this call, and likewise the pointer returned by + // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the + // duration of the call. + unsafe { + APersistableBundle_putLongVector( + self.0.as_ptr(), + key.as_ptr(), + value.as_ptr(), + value.len().try_into().unwrap(), + ); + } + Ok(()) + } + + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key contains a NUL character. + pub fn insert_double_vec(&mut self, key: &str, value: &[f64]) -> Result<(), NulError> { + let key = CString::new(key)?; + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed + // to be valid for the duration of this call, and likewise the pointer returned by + // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the + // duration of the call. + unsafe { + APersistableBundle_putDoubleVector( + self.0.as_ptr(), + key.as_ptr(), + value.as_ptr(), + value.len().try_into().unwrap(), + ); + } + Ok(()) + } + + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key contains a NUL character. + pub fn insert_string_vec<'a, T: ToString + 'a>( + &mut self, + key: &str, + value: impl IntoIterator, + ) -> Result<(), NulError> { + let key = CString::new(key)?; + // We need to collect the new `CString`s into something first so that they live long enough + // for their pointers to be valid for the `APersistableBundle_putStringVector` call below. + let c_strings = value + .into_iter() + .map(|s| CString::new(s.to_string())) + .collect::, NulError>>()?; + let char_pointers = c_strings.iter().map(|s| s.as_ptr()).collect::>(); + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed + // to be valid for the duration of this call, and likewise the pointer returned by + // `value.as_ptr()` is guaranteed to be valid for at least `value.len()` values for the + // duration of the call. + unsafe { + APersistableBundle_putStringVector( + self.0.as_ptr(), + key.as_ptr(), + char_pointers.as_ptr(), + char_pointers.len().try_into().unwrap(), + ); + } + Ok(()) + } + + /// Inserts a key-value pair into the bundle. + /// + /// If the key is already present then its value will be overwritten by the given value. + /// + /// Returns an error if the key contains a NUL character. + pub fn insert_persistable_bundle( + &mut self, + key: &str, + value: &PersistableBundle, + ) -> Result<(), NulError> { + let key = CString::new(key)?; + // SAFETY: The wrapped `APersistableBundle` pointers are guaranteed to be valid for the + // lifetime of the `PersistableBundle`s. The pointer returned by `CStr::as_ptr` is + // guaranteed to be valid for the duration of this call, and + // `APersistableBundle_putPersistableBundle` does a deep copy so that is all that is + // required. + unsafe { + APersistableBundle_putPersistableBundle( + self.0.as_ptr(), + key.as_ptr(), + value.0.as_ptr(), + ); + } + Ok(()) + } + /// Gets the boolean 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 @@ -137,8 +309,8 @@ impl PersistableBundle { let mut value = false; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. The value pointer must be valid because it comes - // from a reference. + // to be valid for the duration of this call. The value pointer must be valid because it + // comes from a reference. if unsafe { APersistableBundle_getBoolean(self.0.as_ptr(), key.as_ptr(), &mut value) } { Ok(Some(value)) } else { @@ -155,8 +327,8 @@ impl PersistableBundle { let mut value = 0; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. The value pointer must be valid because it comes - // from a reference. + // to be valid for the duration of this call. The value pointer must be valid because it + // comes from a reference. if unsafe { APersistableBundle_getInt(self.0.as_ptr(), key.as_ptr(), &mut value) } { Ok(Some(value)) } else { @@ -173,8 +345,8 @@ impl PersistableBundle { let mut value = 0; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. The value pointer must be valid because it comes - // from a reference. + // to be valid for the duration of this call. The value pointer must be valid because it + // comes from a reference. if unsafe { APersistableBundle_getLong(self.0.as_ptr(), key.as_ptr(), &mut value) } { Ok(Some(value)) } else { @@ -191,8 +363,8 @@ impl PersistableBundle { let mut value = 0.0; // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed - // to be valid for the lifetime of `key`. The value pointer must be valid because it comes - // from a reference. + // to be valid for the duration of this call. The value pointer must be valid because it + // comes from a reference. if unsafe { APersistableBundle_getDouble(self.0.as_ptr(), key.as_ptr(), &mut value) } { Ok(Some(value)) } else { @@ -339,4 +511,46 @@ mod test { assert_eq!(bundle.get_double("double"), Ok(None)); assert_eq!(bundle.size(), 0); } + + #[test] + fn insert_string() { + let mut bundle = PersistableBundle::new(); + assert_eq!(bundle.insert_string("string", "foo"), Ok(())); + assert_eq!(bundle.size(), 1); + } + + #[test] + fn insert_vec() { + let mut bundle = PersistableBundle::new(); + + assert_eq!(bundle.insert_bool_vec("bool", &[]), Ok(())); + assert_eq!(bundle.insert_int_vec("int", &[42]), Ok(())); + assert_eq!(bundle.insert_long_vec("long", &[66, 67, 68]), Ok(())); + assert_eq!(bundle.insert_double_vec("double", &[123.4]), Ok(())); + assert_eq!(bundle.insert_string_vec("string", &["foo", "bar", "baz"]), Ok(())); + assert_eq!( + bundle.insert_string_vec( + "string", + &[&"foo".to_string(), &"bar".to_string(), &"baz".to_string()] + ), + Ok(()) + ); + assert_eq!( + bundle.insert_string_vec( + "string", + &["foo".to_string(), "bar".to_string(), "baz".to_string()] + ), + Ok(()) + ); + + assert_eq!(bundle.size(), 5); + } + + #[test] + fn insert_bundle() { + let mut bundle = PersistableBundle::new(); + + let sub_bundle = PersistableBundle::new(); + assert_eq!(bundle.insert_persistable_bundle("bundle", &sub_bundle), Ok(())); + } } -- cgit v1.2.3-59-g8ed1b From de68aaa0f2adbac66d54a263b375c64aa9b5edd8 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 16 Jan 2025 18:12:00 +0000 Subject: Add method to get bundle value from bundle. Bug: 389074518 Test: atest libbinder_rs-internal_test Change-Id: I4dc1263b1dc903f7f8b631ffbe144ced8076908d --- libs/binder/rust/src/persistable_bundle.rs | 39 +++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/libs/binder/rust/src/persistable_bundle.rs b/libs/binder/rust/src/persistable_bundle.rs index 093f88fe14..367f334803 100644 --- a/libs/binder/rust/src/persistable_bundle.rs +++ b/libs/binder/rust/src/persistable_bundle.rs @@ -23,10 +23,11 @@ use crate::{ use binder_ndk_sys::{ APersistableBundle, APersistableBundle_delete, APersistableBundle_dup, APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getDouble, - APersistableBundle_getInt, APersistableBundle_getLong, APersistableBundle_isEqual, - APersistableBundle_new, APersistableBundle_putBoolean, APersistableBundle_putBooleanVector, - APersistableBundle_putDouble, APersistableBundle_putDoubleVector, APersistableBundle_putInt, - APersistableBundle_putIntVector, APersistableBundle_putLong, APersistableBundle_putLongVector, + APersistableBundle_getInt, APersistableBundle_getLong, APersistableBundle_getPersistableBundle, + 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, @@ -371,6 +372,28 @@ impl PersistableBundle { Ok(None) } } + + /// Gets the `PersistableBundle` 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_persistable_bundle(&self, key: &str) -> Result, NulError> { + let key = CString::new(key)?; + let mut value = null_mut(); + // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the + // lifetime of the `PersistableBundle`. The pointer returned by `key.as_ptr()` is guaranteed + // to be valid for the lifetime of `key`. The value pointer must be valid because it comes + // from a reference. + if unsafe { + APersistableBundle_getPersistableBundle(self.0.as_ptr(), key.as_ptr(), &mut value) + } { + Ok(Some(Self(NonNull::new(value).expect( + "APersistableBundle_getPersistableBundle returned true but didn't set outBundle", + )))) + } else { + Ok(None) + } + } } // SAFETY: The underlying *APersistableBundle can be moved between threads. @@ -547,10 +570,14 @@ mod test { } #[test] - fn insert_bundle() { + fn insert_get_bundle() { let mut bundle = PersistableBundle::new(); - let sub_bundle = PersistableBundle::new(); + let mut sub_bundle = PersistableBundle::new(); + assert_eq!(sub_bundle.insert_int("int", 42), Ok(())); + assert_eq!(sub_bundle.size(), 1); assert_eq!(bundle.insert_persistable_bundle("bundle", &sub_bundle), Ok(())); + + assert_eq!(bundle.get_persistable_bundle("bundle"), Ok(Some(sub_bundle))); } } -- cgit v1.2.3-59-g8ed1b