diff --git a/.gitignore b/.gitignore index 1930e81..ab6db66 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.so tags test/test-* +.vscode diff --git a/Makefile b/Makefile index 4a876ae..51d33ae 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ CFLAGS += -fpic -shared -std=c11 -Wall -Wextra LDFLAGS += -Wl,--version-script=exports.txt -libandroid-shmem.a: shmem.o - $(AR) rcu $@ shmem.o +libandroid-shmem.a: shmem.o shmem_vanilla.o + $(AR) rcu $@ shmem.o shmem_vanilla.o -libandroid-shmem.so: shmem.o - $(CC) $(LDFLAGS) -shared shmem.o -o $@ -llog -landroid +libandroid-shmem.so: shmem.o shmem_vanilla.o + $(CC) $(LDFLAGS) -shared shmem.o shmem_vanilla.o -o $@ -llog -landroid shmem.o: shmem.c shm.h $(CC) $(CFLAGS) -c shmem.c -o $@ diff --git a/shm_vanilla.h b/shm_vanilla.h new file mode 100644 index 0000000..2c79fe9 --- /dev/null +++ b/shm_vanilla.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** fork of https://android.googlesource.com/platform/bionic/+/02ce401d1e2b31586c94c8b6999364bbbce27388/libc/include/sys/shm.h */ + +#pragma once + +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +/** Not useful on normal Android; disallowed by SELinux. */ +/** useful for partial Android userspace components running inside the unmodified kernel of a */ +/** different operating system that doesn't have ashmem, ion, dma-buf or SELinux, */ +/** for example using a container, or other method */ + +void* _Nonnull shmat_vanilla(int __shm_id, const void* _Nullable __addr, int __flags); +int shmctl_vanilla(int __shm_id, int __op, struct shmid64_ds* _Nullable __buf); +int shmdt_vanilla(const void* _Nonnull __addr); +int shmget_vanilla(key_t __key, size_t __size, int __flags); + +__END_DECLS diff --git a/shmem.c b/shmem.c index f95fc07..fd84cec 100644 --- a/shmem.c +++ b/shmem.c @@ -21,6 +21,7 @@ #endif #include "shm.h" +#include "shm_vanilla.h" #define DBG(...) __android_log_print(ANDROID_LOG_INFO, "shmem", __VA_ARGS__) #define ASHV_KEY_SYMLINK_PATH _PATH_TMP "ashv_key_%d" @@ -153,6 +154,21 @@ static int ashmem_create_region(char const* name, size_t size) #endif } +static bool ashmem_is_available(void) { +#if __ANDROID_API__ >= 26 + int fd = ASharedMemory_create("libandroid-shmem-test", 1); + if (fd == -1) { +#else + if (access("/dev/ashmem", F_OK) != 0) { +#endif + return false; + } +#if __ANDROID_API__ >= 26 + close(fd); +#endif + return true; +} + static void ashv_check_pid() { pid_t mypid = getpid(); @@ -296,7 +312,9 @@ static int ashv_read_remote_segment(int shmid) /* Get shared memory area identifier. */ int shmget(key_t key, size_t size, int flags) { - (void) flags; + if (!ashmem_is_available()) { + return shmget_vanilla(key, size, flags); + } ashv_check_pid(); @@ -441,6 +459,10 @@ int shmget(key_t key, size_t size, int flags) /* Attach shared memory segment. */ void* shmat(int shmid, void const* shmaddr, int shmflg) { + if (!ashmem_is_available()) { + return shmat_vanilla(shmid, shmaddr, shmflg); + } + ashv_check_pid(); int socket_id = ashv_socket_id_from_shmid(shmid); @@ -479,6 +501,10 @@ void* shmat(int shmid, void const* shmaddr, int shmflg) /* Detach shared memory segment. */ int shmdt(void const* shmaddr) { + if (!ashmem_is_available()) { + return shmdt_vanilla(shmaddr); + } + ashv_check_pid(); pthread_mutex_lock(&mutex); @@ -561,6 +587,10 @@ int libandroid_shmdt_fd(int fd) /* Shared memory control operation. */ int shmctl(int shmid, int cmd, struct shmid_ds *buf) { + if (!ashmem_is_available()) { + return shmctl_vanilla(shmid, cmd, buf); + } + ashv_check_pid(); if (cmd == IPC_RMID) { diff --git a/shmem_vanilla.c b/shmem_vanilla.c new file mode 100644 index 0000000..2871866 --- /dev/null +++ b/shmem_vanilla.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** fork of https://android.googlesource.com/platform/bionic/+/02ce401d1e2b31586c94c8b6999364bbbce27388/libc/bionic/sys_shm.cpp */ + +#include +#include + +#include "shm_vanilla.h" + +void* shmat_vanilla(int id, const void* address, int flags) { + return (void*)(syscall(SYS_shmat, id, address, flags)); +} + +int shmctl_vanilla(int id, int cmd, struct shmid64_ds* buf) { + // upstream bionic libc and also other libc implementations contain + // this code that ORs cmd with IPC_64, but unfortunately, for some reason + // in 32-bit termux-docker, an error always occurs during test-with-key + // 'shmctl: Invalid argument' unless the ORing with IPC_64 is disabled. + // when that is disabled, all tests pass. This result holds for both arm and i686 + // termux-docker running in both fully 32-bit kernels and the 32-bit mode of + // 64-bit kernels. +#if 0 +//#if !defined(__LP64__) + // Annoyingly, the kernel requires this for 32-bit but rejects it for 64-bit. + cmd |= IPC_64; +#endif + return syscall(SYS_shmctl, id, cmd, buf); +} + +int shmdt_vanilla(const void* address) { + return syscall(SYS_shmdt, address); +} + +int shmget_vanilla(key_t key, size_t size, int flags) { + return syscall(SYS_shmget, key, size, flags); +} diff --git a/test/Makefile b/test/Makefile index fbb54a2..35ecc94 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,11 +4,11 @@ OS := $(shell uname -o 2> /dev/null) ifeq ($(OS), Android) CFLAGS += -I.. -llog -EXTRA_CFILE = ../shmem.c +EXTRA_CFILES = ../shmem.c ../shmem_vanilla.c cleanup-memory: test ; else CFLAGS += -DSYSV_ASHMEM_TEST_SYSTEM -EXTRA_CFILE = +EXTRA_CFILES = cleanup-memory: test ./cleanup-shared-memory.sh endif @@ -18,7 +18,7 @@ test: $(addprefix testcase-,$(patsubst %.c,%,$(wildcard *.c))) ; testcase-% : test-% ./$^ -test-%: %.c $(EXTRA_CFILE) +test-%: %.c $(EXTRA_CFILES) $(CC) $(CFLAGS) $+ -o $@ clean: