Skip to content

Commit 5714afd

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge changes I2ba487b6,I398a9bf9 into main
* changes: Support Rust PersistableBundle in AIDL. Start on Rust bindings for APersistableBundle.
2 parents d17f9c4 + eea6599 commit 5714afd

4 files changed

Lines changed: 140 additions & 1 deletion

File tree

aidl/binder/android/os/PersistableBundle.aidl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717

1818
package android.os;
1919

20-
@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h";
20+
@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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ mod binder_async;
9999
mod error;
100100
mod native;
101101
mod parcel;
102+
#[cfg(not(trusty))]
103+
mod persistable_bundle;
102104
mod proxy;
103105
#[cfg(not(any(trusty, android_ndk)))]
104106
mod service;
@@ -113,6 +115,8 @@ pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
113115
pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
114116
pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
115117
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
118+
#[cfg(not(trusty))]
119+
pub use persistable_bundle::PersistableBundle;
116120
pub use proxy::{DeathRecipient, SpIBinder, WpIBinder};
117121
#[cfg(not(any(trusty, android_ndk)))]
118122
pub use service::{
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
use crate::{
18+
binder::AsNative,
19+
error::{status_result, StatusCode},
20+
impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable,
21+
parcel::{BorrowedParcel, UnstructuredParcelable},
22+
};
23+
use binder_ndk_sys::{
24+
APersistableBundle, APersistableBundle_delete, APersistableBundle_dup,
25+
APersistableBundle_isEqual, APersistableBundle_new, APersistableBundle_readFromParcel,
26+
APersistableBundle_size, APersistableBundle_writeToParcel,
27+
};
28+
use std::ptr::{null_mut, NonNull};
29+
30+
/// A mapping from string keys to values of various types.
31+
#[derive(Debug)]
32+
pub struct PersistableBundle(NonNull<APersistableBundle>);
33+
34+
impl PersistableBundle {
35+
/// Creates a new `PersistableBundle`.
36+
pub fn new() -> Self {
37+
// SAFETY: APersistableBundle_new doesn't actually have any safety requirements.
38+
let bundle = unsafe { APersistableBundle_new() };
39+
Self(NonNull::new(bundle).expect("Allocated APersistableBundle was null"))
40+
}
41+
42+
/// Returns the number of mappings in the bundle.
43+
pub fn size(&self) -> usize {
44+
// SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
45+
// lifetime of the `PersistableBundle`.
46+
unsafe { APersistableBundle_size(self.0.as_ptr()) }
47+
.try_into()
48+
.expect("APersistableBundle_size returned a negative size")
49+
}
50+
}
51+
52+
// SAFETY: The underlying *APersistableBundle can be moved between threads.
53+
unsafe impl Send for PersistableBundle {}
54+
55+
// SAFETY: The underlying *APersistableBundle can be read from multiple threads, and we require
56+
// `&mut PersistableBundle` for any operations which mutate it.
57+
unsafe impl Sync for PersistableBundle {}
58+
59+
impl Default for PersistableBundle {
60+
fn default() -> Self {
61+
Self::new()
62+
}
63+
}
64+
65+
impl Drop for PersistableBundle {
66+
fn drop(&mut self) {
67+
// SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
68+
// lifetime of this `PersistableBundle`.
69+
unsafe { APersistableBundle_delete(self.0.as_ptr()) };
70+
}
71+
}
72+
73+
impl Clone for PersistableBundle {
74+
fn clone(&self) -> Self {
75+
// SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
76+
// lifetime of the `PersistableBundle`.
77+
let duplicate = unsafe { APersistableBundle_dup(self.0.as_ptr()) };
78+
Self(NonNull::new(duplicate).expect("Duplicated APersistableBundle was null"))
79+
}
80+
}
81+
82+
impl PartialEq for PersistableBundle {
83+
fn eq(&self, other: &Self) -> bool {
84+
// SAFETY: The wrapped `APersistableBundle` pointers are guaranteed to be valid for the
85+
// lifetime of the `PersistableBundle`s.
86+
unsafe { APersistableBundle_isEqual(self.0.as_ptr(), other.0.as_ptr()) }
87+
}
88+
}
89+
90+
impl UnstructuredParcelable for PersistableBundle {
91+
fn write_to_parcel(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> {
92+
let status =
93+
// SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
94+
// lifetime of the `PersistableBundle`. `parcel.as_native_mut()` always returns a valid
95+
// parcel pointer.
96+
unsafe { APersistableBundle_writeToParcel(self.0.as_ptr(), parcel.as_native_mut()) };
97+
status_result(status)
98+
}
99+
100+
fn from_parcel(parcel: &BorrowedParcel) -> Result<Self, StatusCode> {
101+
let mut bundle = null_mut();
102+
103+
// SAFETY: The wrapped `APersistableBundle` pointer is guaranteed to be valid for the
104+
// lifetime of the `PersistableBundle`. `parcel.as_native()` always returns a valid parcel
105+
// pointer.
106+
let status = unsafe { APersistableBundle_readFromParcel(parcel.as_native(), &mut bundle) };
107+
status_result(status)?;
108+
109+
Ok(Self(NonNull::new(bundle).expect(
110+
"APersistableBundle_readFromParcel returned success but didn't allocate bundle",
111+
)))
112+
}
113+
}
114+
115+
impl_deserialize_for_unstructured_parcelable!(PersistableBundle);
116+
impl_serialize_for_unstructured_parcelable!(PersistableBundle);
117+
118+
#[cfg(test)]
119+
mod test {
120+
use super::*;
121+
122+
#[test]
123+
fn create_delete() {
124+
let bundle = PersistableBundle::new();
125+
drop(bundle);
126+
}
127+
128+
#[test]
129+
fn duplicate_equal() {
130+
let bundle = PersistableBundle::new();
131+
let duplicate = bundle.clone();
132+
assert_eq!(bundle, duplicate);
133+
}
134+
}

libs/binder/rust/sys/BinderBindings.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <android/binder_ibinder.h>
1818
#include <android/binder_parcel.h>
1919
#include <android/binder_status.h>
20+
#include <android/persistable_bundle.h>
2021

2122
/* Platform only */
2223
#if defined(ANDROID_PLATFORM) || defined(__ANDROID_VENDOR__)

0 commit comments

Comments
 (0)