Loading aidl/binder/android/os/PersistableBundle.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -17,4 +17,4 @@ package android.os; @JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h"; @JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h" rust_type "binder::PersistableBundle"; libs/binder/rust/src/lib.rs +4 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,8 @@ mod binder_async; mod error; mod native; mod parcel; #[cfg(not(trusty))] mod persistable_bundle; mod proxy; #[cfg(not(any(trusty, android_ndk)))] mod service; Loading @@ -113,6 +115,8 @@ pub use crate::binder_async::{BinderAsyncPool, BoxFuture}; pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak}; pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode}; pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder}; #[cfg(not(trusty))] pub use persistable_bundle::PersistableBundle; pub use proxy::{DeathRecipient, SpIBinder, WpIBinder}; #[cfg(not(any(trusty, android_ndk)))] pub use service::{ Loading libs/binder/rust/src/persistable_bundle.rs 0 → 100644 +134 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use crate::{ binder::AsNative, error::{status_result, StatusCode}, impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, parcel::{BorrowedParcel, UnstructuredParcelable}, }; use binder_ndk_sys::{ APersistableBundle, APersistableBundle_delete, APersistableBundle_dup, APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_readFromParcel, APersistableBundle_size, APersistableBundle_writeToParcel, }; use std::ptr::{null_mut, NonNull}; /// A mapping from string keys to values of various types. #[derive(Debug)] pub struct PersistableBundle(NonNull<APersistableBundle>); impl PersistableBundle { /// Creates a new `PersistableBundle`. pub fn new() -> Self { // SAFETY: APersistableBundle_new doesn't actually have any safety requirements. let bundle = unsafe { APersistableBundle_new() }; Self(NonNull::new(bundle).expect("Allocated APersistableBundle was null")) } /// Returns the number of mappings in the bundle. pub fn size(&self) -> usize { // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. unsafe { APersistableBundle_size(self.0.as_ptr()) } .try_into() .expect("APersistableBundle_size returned a negative size") } } // SAFETY: The underlying *APersistableBundle can be moved between threads. unsafe impl Send for PersistableBundle {} // SAFETY: The underlying *APersistableBundle can be read from multiple threads, and we require // `&mut PersistableBundle` for any operations which mutate it. unsafe impl Sync for PersistableBundle {} impl Default for PersistableBundle { fn default() -> Self { Self::new() } } impl Drop for PersistableBundle { fn drop(&mut self) { // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of this `PersistableBundle`. unsafe { APersistableBundle_delete(self.0.as_ptr()) }; } } impl Clone for PersistableBundle { fn clone(&self) -> Self { // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. let duplicate = unsafe { APersistableBundle_dup(self.0.as_ptr()) }; Self(NonNull::new(duplicate).expect("Duplicated APersistableBundle was null")) } } impl PartialEq for PersistableBundle { fn eq(&self, other: &Self) -> bool { // SAFETY: The wrapped `APersistableBundle` pointers are guaranteed to be valid for the // lifetime of the `PersistableBundle`s. unsafe { APersistableBundle_isEqual(self.0.as_ptr(), other.0.as_ptr()) } } } impl UnstructuredParcelable for PersistableBundle { fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { let status = // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. `parcel.as_native_mut()` always returns a valid // parcel pointer. unsafe { APersistableBundle_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) }; status_result(status) } fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { let mut bundle = null_mut(); // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. `parcel.as_native()` always returns a valid parcel // pointer. let status = unsafe { APersistableBundle_readFromParcel(parcel.as_native(), &mut bundle) }; status_result(status)?; Ok(Self(NonNull::new(bundle).expect( "APersistableBundle_readFromParcel returned success but didn't allocate bundle", ))) } } impl_deserialize_for_unstructured_parcelable!(PersistableBundle); impl_serialize_for_unstructured_parcelable!(PersistableBundle); #[cfg(test)] mod test { use super::*; #[test] fn create_delete() { let bundle = PersistableBundle::new(); drop(bundle); } #[test] fn duplicate_equal() { let bundle = PersistableBundle::new(); let duplicate = bundle.clone(); assert_eq!(bundle, duplicate); } } libs/binder/rust/sys/BinderBindings.hpp +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <android/binder_ibinder.h> #include <android/binder_parcel.h> #include <android/binder_status.h> #include <android/persistable_bundle.h> /* Platform only */ #if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__) Loading Loading
aidl/binder/android/os/PersistableBundle.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -17,4 +17,4 @@ package android.os; @JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h"; @JavaOnlyStableParcelable @NdkOnlyStableParcelable @RustOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h" rust_type "binder::PersistableBundle";
libs/binder/rust/src/lib.rs +4 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,8 @@ mod binder_async; mod error; mod native; mod parcel; #[cfg(not(trusty))] mod persistable_bundle; mod proxy; #[cfg(not(any(trusty, android_ndk)))] mod service; Loading @@ -113,6 +115,8 @@ pub use crate::binder_async::{BinderAsyncPool, BoxFuture}; pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak}; pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode}; pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder}; #[cfg(not(trusty))] pub use persistable_bundle::PersistableBundle; pub use proxy::{DeathRecipient, SpIBinder, WpIBinder}; #[cfg(not(any(trusty, android_ndk)))] pub use service::{ Loading
libs/binder/rust/src/persistable_bundle.rs 0 → 100644 +134 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use crate::{ binder::AsNative, error::{status_result, StatusCode}, impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, parcel::{BorrowedParcel, UnstructuredParcelable}, }; use binder_ndk_sys::{ APersistableBundle, APersistableBundle_delete, APersistableBundle_dup, APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_readFromParcel, APersistableBundle_size, APersistableBundle_writeToParcel, }; use std::ptr::{null_mut, NonNull}; /// A mapping from string keys to values of various types. #[derive(Debug)] pub struct PersistableBundle(NonNull<APersistableBundle>); impl PersistableBundle { /// Creates a new `PersistableBundle`. pub fn new() -> Self { // SAFETY: APersistableBundle_new doesn't actually have any safety requirements. let bundle = unsafe { APersistableBundle_new() }; Self(NonNull::new(bundle).expect("Allocated APersistableBundle was null")) } /// Returns the number of mappings in the bundle. pub fn size(&self) -> usize { // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. unsafe { APersistableBundle_size(self.0.as_ptr()) } .try_into() .expect("APersistableBundle_size returned a negative size") } } // SAFETY: The underlying *APersistableBundle can be moved between threads. unsafe impl Send for PersistableBundle {} // SAFETY: The underlying *APersistableBundle can be read from multiple threads, and we require // `&mut PersistableBundle` for any operations which mutate it. unsafe impl Sync for PersistableBundle {} impl Default for PersistableBundle { fn default() -> Self { Self::new() } } impl Drop for PersistableBundle { fn drop(&mut self) { // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of this `PersistableBundle`. unsafe { APersistableBundle_delete(self.0.as_ptr()) }; } } impl Clone for PersistableBundle { fn clone(&self) -> Self { // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. let duplicate = unsafe { APersistableBundle_dup(self.0.as_ptr()) }; Self(NonNull::new(duplicate).expect("Duplicated APersistableBundle was null")) } } impl PartialEq for PersistableBundle { fn eq(&self, other: &Self) -> bool { // SAFETY: The wrapped `APersistableBundle` pointers are guaranteed to be valid for the // lifetime of the `PersistableBundle`s. unsafe { APersistableBundle_isEqual(self.0.as_ptr(), other.0.as_ptr()) } } } impl UnstructuredParcelable for PersistableBundle { fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { let status = // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. `parcel.as_native_mut()` always returns a valid // parcel pointer. unsafe { APersistableBundle_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) }; status_result(status) } fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { let mut bundle = null_mut(); // SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the // lifetime of the `PersistableBundle`. `parcel.as_native()` always returns a valid parcel // pointer. let status = unsafe { APersistableBundle_readFromParcel(parcel.as_native(), &mut bundle) }; status_result(status)?; Ok(Self(NonNull::new(bundle).expect( "APersistableBundle_readFromParcel returned success but didn't allocate bundle", ))) } } impl_deserialize_for_unstructured_parcelable!(PersistableBundle); impl_serialize_for_unstructured_parcelable!(PersistableBundle); #[cfg(test)] mod test { use super::*; #[test] fn create_delete() { let bundle = PersistableBundle::new(); drop(bundle); } #[test] fn duplicate_equal() { let bundle = PersistableBundle::new(); let duplicate = bundle.clone(); assert_eq!(bundle, duplicate); } }
libs/binder/rust/sys/BinderBindings.hpp +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <android/binder_ibinder.h> #include <android/binder_parcel.h> #include <android/binder_status.h> #include <android/persistable_bundle.h> /* Platform only */ #if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__) Loading