diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/ashmem/src | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/ashmem/src')
-rwxr-xr-x | third_party/rust/ashmem/src/lib.rs | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/third_party/rust/ashmem/src/lib.rs b/third_party/rust/ashmem/src/lib.rs new file mode 100755 index 0000000000..93c91c8969 --- /dev/null +++ b/third_party/rust/ashmem/src/lib.rs @@ -0,0 +1,160 @@ +#![cfg(target_os = "android")] +//! Provides a wrapper around Android's ASharedMemory API. +//! +//! ashmem has existed in Android as a non-public API for some time. +//! Originally accessed via ioctl, it was later available via libcutils as ashmem_create_region etc. +//! ASharedMemory is the new public API, but it isn't available until API 26 (Android 8). +//! Builds targeting Android 10 (API 29) are no longer permitted to access ashmem via the ioctl interface. +//! This makes life for a portable program difficult - you can't reliably use the old or new interface during this transition period. +//! We try to dynamically load the new API first, then fall back to the ioctl interface. +//! +//! References: +//! - [ASharedMemory documentation](https://developer.android.com/ndk/reference/group/memory) +//! - [Linux ashmem.h definitions](https://elixir.bootlin.com/linux/v5.11.8/source/drivers/staging/android/uapi/ashmem.h) + +#[macro_use] +extern crate ioctl_sys; + +const __ASHMEMIOC: u32 = 0x77; + +static mut LIBANDROID_ASHAREDMEMORY_CREATE: Option< + extern "C" fn(*const libc::c_char, libc::size_t) -> libc::c_int, +> = None; +static mut LIBANDROID_ASHAREDMEMORY_GETSIZE: Option<extern "C" fn(libc::c_int) -> libc::size_t> = + None; +static mut LIBANDROID_ASHAREDMEMORY_SETPROT: Option< + extern "C" fn(libc::c_int, libc::c_int) -> libc::c_int, +> = None; + +unsafe fn maybe_init() { + const LIBANDROID_NAME: *const libc::c_char = "libandroid.so\0".as_ptr() as *const libc::c_char; + const LIBANDROID_ASHAREDMEMORY_CREATE_NAME: *const libc::c_char = + "ASharedMemory_create\0".as_ptr() as _; + const LIBANDROID_ASHAREDMEMORY_GETSIZE_NAME: *const libc::c_char = + "ASharedMemory_getSize\0".as_ptr() as _; + const LIBANDROID_ASHAREDMEMORY_SETPROT_NAME: *const libc::c_char = + "ASharedMemory_setProt\0".as_ptr() as _; + static ONCE: std::sync::Once = std::sync::Once::new(); + ONCE.call_once(|| { + // Leak the handle, there's no safe time to close it. + let handle = libc::dlopen(LIBANDROID_NAME, libc::RTLD_LAZY | libc::RTLD_LOCAL); + if handle.is_null() { + return; + } + // Transmute guarantee for `fn -> Option<fn>`: https://doc.rust-lang.org/std/option/#representation + LIBANDROID_ASHAREDMEMORY_CREATE = + std::mem::transmute(libc::dlsym(handle, LIBANDROID_ASHAREDMEMORY_CREATE_NAME)); + LIBANDROID_ASHAREDMEMORY_GETSIZE = + std::mem::transmute(libc::dlsym(handle, LIBANDROID_ASHAREDMEMORY_GETSIZE_NAME)); + LIBANDROID_ASHAREDMEMORY_SETPROT = + std::mem::transmute(libc::dlsym(handle, LIBANDROID_ASHAREDMEMORY_SETPROT_NAME)); + }); +} + +/// See [ASharedMemory_create NDK documentation](https://developer.android.com/ndk/reference/group/memory#asharedmemory_create) +/// +/// # Safety +/// +/// Directly calls C or kernel APIs. +#[allow(non_snake_case)] +pub unsafe fn ASharedMemory_create(name: *const libc::c_char, size: libc::size_t) -> libc::c_int { + const ASHMEM_NAME_DEF: *const libc::c_char = "/dev/ashmem\0".as_ptr() as _; + const ASHMEM_NAME_LEN: usize = 256; + const ASHMEM_SET_NAME: libc::c_int = iow!( + __ASHMEMIOC, + 1, + std::mem::size_of::<[libc::c_char; ASHMEM_NAME_LEN]>() + ) as _; + const ASHMEM_SET_SIZE: libc::c_int = + iow!(__ASHMEMIOC, 3, std::mem::size_of::<libc::size_t>()) as _; + + maybe_init(); + if let Some(fun) = LIBANDROID_ASHAREDMEMORY_CREATE { + return fun(name, size); + } + + let fd = libc::open(ASHMEM_NAME_DEF, libc::O_RDWR, 0o600); + if fd < 0 { + return fd; + } + + if !name.is_null() { + // NOTE: libcutils uses a local stack copy of `name`. + let r = libc::ioctl(fd, ASHMEM_SET_NAME, name); + if r != 0 { + libc::close(fd); + return -1; + } + } + + let r = libc::ioctl(fd, ASHMEM_SET_SIZE, size); + if r != 0 { + libc::close(fd); + return -1; + } + + fd +} + +/// See [ASharedMemory_getSize NDK documentation](https://developer.android.com/ndk/reference/group/memory#asharedmemory_getsize) +/// +/// # Safety +/// +/// Directly calls C or kernel APIs. +#[allow(non_snake_case)] +pub unsafe fn ASharedMemory_getSize(fd: libc::c_int) -> libc::size_t { + const ASHMEM_GET_SIZE: libc::c_int = io!(__ASHMEMIOC, 4) as _; + + maybe_init(); + if let Some(fun) = LIBANDROID_ASHAREDMEMORY_GETSIZE { + return fun(fd); + } + + libc::ioctl(fd, ASHMEM_GET_SIZE) as libc::size_t +} + +/// See [ASharedMemory_setProt NDK documentation](https://developer.android.com/ndk/reference/group/memory#asharedmemory_setprot) +/// +/// # Safety +/// +/// Directly calls C or kernel APIs. +#[allow(non_snake_case)] +pub unsafe fn ASharedMemory_setProt(fd: libc::c_int, prot: libc::c_int) -> libc::c_int { + const ASHMEM_SET_PROT_MASK: libc::c_int = + iow!(__ASHMEMIOC, 5, std::mem::size_of::<libc::c_ulong>()) as _; + + maybe_init(); + if let Some(fun) = LIBANDROID_ASHAREDMEMORY_SETPROT { + return fun(fd, prot); + } + + let r = libc::ioctl(fd, ASHMEM_SET_PROT_MASK, prot); + if r != 0 { + return -1; + } + r +} + +#[cfg(test)] +mod tests { + #[test] + fn basic() { + unsafe { + let name = std::ffi::CString::new("/test-ashmem").unwrap(); + let fd = super::ASharedMemory_create(name.as_ptr(), 128); + assert!(fd >= 0); + assert_eq!(super::ASharedMemory_getSize(fd), 128); + assert_eq!(super::ASharedMemory_setProt(fd, 0), 0); + libc::close(fd); + } + } + + #[test] + fn anonymous() { + unsafe { + let fd = super::ASharedMemory_create(std::ptr::null(), 128); + assert!(fd >= 0); + libc::close(fd); + } + } +} |