#![cfg_attr(
target_os = "android",
allow(
clippy::missing_const_for_thread_local,
reason = "android-only false positive, even on thread_locals already using `const { .. }`"
)
)]
use std::alloc::{GlobalAlloc, Layout, System};
use std::cell::Cell;
use rsbinder::{Parcel, ParcelFileDescriptor};
struct Counting;
thread_local! {
#[allow(clippy::missing_const_for_thread_local)]
static ALLOCS: Cell<usize> = const { Cell::new(0) };
}
fn bump() {
let _ = ALLOCS.try_with(|c| c.set(c.get() + 1));
}
unsafe impl GlobalAlloc for Counting {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
bump();
unsafe { System.alloc(layout) }
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
bump();
unsafe { System.alloc_zeroed(layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
bump();
unsafe { System.realloc(ptr, layout, new_size) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
}
#[global_allocator]
static GLOBAL: Counting = Counting;
fn count<R>(f: impl FnOnce() -> R) -> usize {
let before = ALLOCS.with(Cell::get);
drop(f());
ALLOCS.with(Cell::get) - before
}
#[test]
fn a_scalar_only_parcel_allocates_its_data_buffer_only() {
let write = || {
let mut p = Parcel::with_capacity(256);
p.write(&1i32).unwrap();
p.write(&2u64).unwrap();
p
};
drop(write());
assert_eq!(count(write), 1);
}
#[test]
fn a_parcel_carrying_an_fd_allocates_no_pin_list() {
let pfd = ParcelFileDescriptor::new(std::fs::File::open("/dev/null").unwrap());
let write = || {
let mut p = Parcel::with_capacity(256);
p.write(&1i32).unwrap();
p.write(&pfd).unwrap();
p
};
drop(write());
assert_eq!(count(write), 3);
}
#[test]
#[ignore = "needs /dev/binder, a running rsb_hub and test_service"]
fn a_parcel_carrying_a_handle_allocates_the_pin_list_once() {
rsbinder::ProcessState::init_default().expect("init_default");
let proxy = rsbinder::hub::check_service("android.aidl.tests.ITestService")
.expect("test_service is not registered");
assert!(proxy.as_proxy().is_some(), "expected a remote binder");
let write = || {
let mut p = Parcel::with_capacity(256);
p.write(&1i32).unwrap();
p.write(&proxy).unwrap();
p
};
drop(write());
assert_eq!(count(write), 3);
}