summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ashmem/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/ashmem/src')
-rwxr-xr-xthird_party/rust/ashmem/src/lib.rs160
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);
+ }
+ }
+}