Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0af893b3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add methods to get keys." into main

parents 8906d1d9 e200cb18
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -116,7 +116,7 @@ pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
#[cfg(not(trusty))]
#[cfg(not(trusty))]
pub use persistable_bundle::PersistableBundle;
pub use persistable_bundle::{PersistableBundle, ValueType};
pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
#[cfg(not(any(trusty, android_ndk)))]
#[cfg(not(any(trusty, android_ndk)))]
pub use service::{
pub use service::{
+232 −5
Original line number Original line Diff line number Diff line
@@ -22,11 +22,17 @@ use crate::{
};
};
use binder_ndk_sys::{
use binder_ndk_sys::{
    APersistableBundle, APersistableBundle_delete, APersistableBundle_dup,
    APersistableBundle, APersistableBundle_delete, APersistableBundle_dup,
    APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getBooleanVector,
    APersistableBundle_erase, APersistableBundle_getBoolean, APersistableBundle_getBooleanKeys,
    APersistableBundle_getDouble, APersistableBundle_getDoubleVector, APersistableBundle_getInt,
    APersistableBundle_getBooleanVector, APersistableBundle_getBooleanVectorKeys,
    APersistableBundle_getIntVector, APersistableBundle_getLong, APersistableBundle_getLongVector,
    APersistableBundle_getDouble, APersistableBundle_getDoubleKeys,
    APersistableBundle_getPersistableBundle, APersistableBundle_getString,
    APersistableBundle_getDoubleVector, APersistableBundle_getDoubleVectorKeys,
    APersistableBundle_getStringVector, APersistableBundle_isEqual, APersistableBundle_new,
    APersistableBundle_getInt, APersistableBundle_getIntKeys, APersistableBundle_getIntVector,
    APersistableBundle_getIntVectorKeys, APersistableBundle_getLong,
    APersistableBundle_getLongKeys, APersistableBundle_getLongVector,
    APersistableBundle_getLongVectorKeys, APersistableBundle_getPersistableBundle,
    APersistableBundle_getPersistableBundleKeys, APersistableBundle_getString,
    APersistableBundle_getStringKeys, APersistableBundle_getStringVector,
    APersistableBundle_getStringVectorKeys, APersistableBundle_isEqual, APersistableBundle_new,
    APersistableBundle_putBoolean, APersistableBundle_putBooleanVector,
    APersistableBundle_putBoolean, APersistableBundle_putBooleanVector,
    APersistableBundle_putDouble, APersistableBundle_putDoubleVector, APersistableBundle_putInt,
    APersistableBundle_putDouble, APersistableBundle_putDoubleVector, APersistableBundle_putInt,
    APersistableBundle_putIntVector, APersistableBundle_putLong, APersistableBundle_putLongVector,
    APersistableBundle_putIntVector, APersistableBundle_putLong, APersistableBundle_putLongVector,
@@ -588,6 +594,171 @@ impl PersistableBundle {
            Ok(None)
            Ok(None)
        }
        }
    }
    }

    /// Calls the appropriate `APersistableBundle_get*Keys` function for the given `value_type`,
    /// with our `string_allocator` and a null context pointer.
    ///
    /// # Safety
    ///
    /// `out_keys` 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 fn get_keys_raw(
        &self,
        value_type: ValueType,
        out_keys: *mut *mut c_char,
        buffer_size_bytes: i32,
    ) -> i32 {
        // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
        // lifetime of the `PersistableBundle`. Our caller guarantees an appropriate value for
        // `out_keys` and `buffer_size_bytes`.
        unsafe {
            match value_type {
                ValueType::Boolean => APersistableBundle_getBooleanKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::Integer => APersistableBundle_getIntKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::Long => APersistableBundle_getLongKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::Double => APersistableBundle_getDoubleKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::String => APersistableBundle_getStringKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::BooleanVector => APersistableBundle_getBooleanVectorKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::IntegerVector => APersistableBundle_getIntVectorKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::LongVector => APersistableBundle_getLongVectorKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::DoubleVector => APersistableBundle_getDoubleVectorKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::StringVector => APersistableBundle_getStringVectorKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
                ValueType::PersistableBundle => APersistableBundle_getPersistableBundleKeys(
                    self.0.as_ptr(),
                    out_keys,
                    buffer_size_bytes,
                    Some(string_allocator),
                    null_mut(),
                ),
            }
        }
    }

    /// Gets all the keys associated with values of the given type.
    pub fn keys_for_type(&self, value_type: ValueType) -> Vec<String> {
        // SAFETY: A null pointer is allowed for the buffer.
        match unsafe { self.get_keys_raw(value_type, null_mut(), 0) } {
            APERSISTABLEBUNDLE_ALLOCATOR_FAILED => {
                panic!("APersistableBundle_get*Keys failed to allocate string");
            }
            required_buffer_size => {
                let required_buffer_size_usize = usize::try_from(required_buffer_size)
                    .expect("APersistableBundle_get*Keys returned invalid size");
                assert_eq!(required_buffer_size_usize % size_of::<*mut c_char>(), 0);
                let mut keys =
                    vec![null_mut(); required_buffer_size_usize / size_of::<*mut c_char>()];
                // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for
                // the lifetime of the `PersistableBundle`. The keys buffer pointer is valid as it
                // comes from the Vec we just allocated.
                if unsafe { self.get_keys_raw(value_type, keys.as_mut_ptr(), required_buffer_size) }
                    == APERSISTABLEBUNDLE_ALLOCATOR_FAILED
                {
                    panic!("APersistableBundle_get*Keys failed to allocate string");
                }
                keys.into_iter()
                    .map(|key| {
                        // 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(key) }.count_bytes();
                        let raw_slice = slice_from_raw_parts_mut(key.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_get*Keys returned string missing NUL byte");
                        c_string
                            .into_string()
                            .expect("APersistableBundle_get*Keys returned invalid UTF-8")
                    })
                    .collect()
            }
        }
    }

    /// Returns an iterator over all keys in the bundle, along with the type of their associated
    /// value.
    pub fn keys(&self) -> impl Iterator<Item = (String, ValueType)> + use<'_> {
        [
            ValueType::Boolean,
            ValueType::Integer,
            ValueType::Long,
            ValueType::Double,
            ValueType::String,
            ValueType::BooleanVector,
            ValueType::IntegerVector,
            ValueType::LongVector,
            ValueType::DoubleVector,
            ValueType::StringVector,
            ValueType::PersistableBundle,
        ]
        .iter()
        .flat_map(|value_type| {
            self.keys_for_type(*value_type).into_iter().map(|key| (key, *value_type))
        })
    }
}
}


/// Wrapper around `APersistableBundle_getStringVector` to pass `string_allocator` and a null
/// Wrapper around `APersistableBundle_getStringVector` to pass `string_allocator` and a null
@@ -709,6 +880,33 @@ unsafe extern "C" fn string_allocator(size: i32, context: *mut c_void) -> *mut c
impl_deserialize_for_unstructured_parcelable!(PersistableBundle);
impl_deserialize_for_unstructured_parcelable!(PersistableBundle);
impl_serialize_for_unstructured_parcelable!(PersistableBundle);
impl_serialize_for_unstructured_parcelable!(PersistableBundle);


/// The types which may be stored as values in a [`PersistableBundle`].
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ValueType {
    /// A `bool`.
    Boolean,
    /// An `i32`.
    Integer,
    /// An `i64`.
    Long,
    /// An `f64`.
    Double,
    /// A string.
    String,
    /// A vector of `bool`s.
    BooleanVector,
    /// A vector of `i32`s.
    IntegerVector,
    /// A vector of `i64`s.
    LongVector,
    /// A vector of `f64`s.
    DoubleVector,
    /// A vector of strings.
    StringVector,
    /// A nested `PersistableBundle`.
    PersistableBundle,
}

#[cfg(test)]
#[cfg(test)]
mod test {
mod test {
    use super::*;
    use super::*;
@@ -846,4 +1044,33 @@ mod test {


        assert_eq!(bundle.get_persistable_bundle("bundle"), Ok(Some(sub_bundle)));
        assert_eq!(bundle.get_persistable_bundle("bundle"), Ok(Some(sub_bundle)));
    }
    }

    #[test]
    fn get_keys() {
        let mut bundle = PersistableBundle::new();

        assert_eq!(bundle.keys_for_type(ValueType::Boolean), Vec::<String>::new());
        assert_eq!(bundle.keys_for_type(ValueType::Integer), Vec::<String>::new());
        assert_eq!(bundle.keys_for_type(ValueType::StringVector), Vec::<String>::new());

        assert_eq!(bundle.insert_bool("bool1", false), Ok(()));
        assert_eq!(bundle.insert_bool("bool2", true), Ok(()));
        assert_eq!(bundle.insert_int("int", 42), Ok(()));

        assert_eq!(
            bundle.keys_for_type(ValueType::Boolean),
            vec!["bool1".to_string(), "bool2".to_string()]
        );
        assert_eq!(bundle.keys_for_type(ValueType::Integer), vec!["int".to_string()]);
        assert_eq!(bundle.keys_for_type(ValueType::StringVector), Vec::<String>::new());

        assert_eq!(
            bundle.keys().collect::<Vec<_>>(),
            vec![
                ("bool1".to_string(), ValueType::Boolean),
                ("bool2".to_string(), ValueType::Boolean),
                ("int".to_string(), ValueType::Integer),
            ]
        );
    }
}
}