diff --git a/INSTALL.android b/INSTALL.android index ed0bd0f68dc..06211e5ec93 100644 --- a/INSTALL.android +++ b/INSTALL.android @@ -165,6 +165,9 @@ work, along with what has to be patched to make them work: and apply the patch at the end of this file.) icu4c - https://android.googlesource.com/platform/external/icu/ (You must apply the patch at the end of this file.) + sqlite3 - https://android.googlesource.com/platform/external/sqlite/ + (You must apply the patch at the end of this file, and add the `dist' + directory to ``--with-ndk-path''.) Many of these dependencies have been migrated over to the ``Android.bp'' build system now used to build Android itself. @@ -592,3 +595,18 @@ index 8e5f757..44bb130 100644 LOCAL_MODULE_TAGS := optional LOCAL_MODULE := libicuuc LOCAL_RTTI_FLAG := -frtti + +PATCH FOR SQLITE3 + +diff --git a/dist/Android.mk b/dist/Android.mk +index bf277d2..36734d9 100644 +--- a/dist/Android.mk ++++ b/dist/Android.mk +@@ -141,6 +141,7 @@ include $(BUILD_HOST_EXECUTABLE) + include $(CLEAR_VARS) + LOCAL_SRC_FILES := $(common_src_files) + LOCAL_CFLAGS += $(minimal_sqlite_flags) ++LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH) + LOCAL_MODULE:= libsqlite_static_minimal + LOCAL_SDK_VERSION := 23 + include $(BUILD_STATIC_LIBRARY) diff --git a/build-aux/ndk-build-helper-1.mk b/build-aux/ndk-build-helper-1.mk index 4ffe0d423e4..9035b5ca59a 100644 --- a/build-aux/ndk-build-helper-1.mk +++ b/build-aux/ndk-build-helper-1.mk @@ -77,7 +77,7 @@ endef # dependencies can be ignored while building a shared library, as they # will be linked in to the resulting shared object file later. -SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ +SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ log liblog android libandroid $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module)))) $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES) $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_LIBRARIES)),$(eval $(call add-includes,$(module)))) diff --git a/build-aux/ndk-build-helper-2.mk b/build-aux/ndk-build-helper-2.mk index 9c9e7cf09a9..8f2f397e534 100644 --- a/build-aux/ndk-build-helper-2.mk +++ b/build-aux/ndk-build-helper-2.mk @@ -87,7 +87,7 @@ endef # Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and # LOCAL_SHARED_LIBRARIES. -SYSTEM_LIBRARIES = z libz libc c libdl dl libstdc++ stdc++ +SYSTEM_LIBRARIES = z libz libc c libdl dl libstdc++ stdc++ log liblog android libandroid $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module)))) $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module)))) diff --git a/configure.ac b/configure.ac index 95bb0cfca88..879e4ab74aa 100644 --- a/configure.ac +++ b/configure.ac @@ -752,6 +752,7 @@ ANDROID= JAVAC= AAPT= JARSIGNER= +APKSIGNER= ZIPALIGN= DX= ANDROID_JAR= @@ -763,6 +764,7 @@ android_makefiles="lib/Makefile lib/gnulib.mk lib-src/Makefile src/Makefile" AC_ARG_VAR([JAVAC], [Java compiler path. Used for Android.]) AC_ARG_VAR([JARSIGNER], [Java package signer path. Used for Android.]) +AC_ARG_VAR([APKSIGNER], [Android package signer path. Used for Android.]) AC_ARG_VAR([SDK_BULD_TOOLS], [Path to the Android SDK build tools.]) if test "$with_android" = "yes"; then @@ -792,6 +794,7 @@ the path to your Java compiler before configuring Emacs, like so: JAVAC=/opt/jdk/bin/javac ./configure --with-android]) fi + AC_CHECK_PROGS([JARSIGNER], [jarsigner]) if test "$JARSIGNER" = ""; then AC_MSG_ERROR([The Java package signing utility was not found. @@ -861,6 +864,12 @@ Android 13 (Tiramisu) or later.]) Please verify that the path to the SDK build tools you specified is correct]) fi + AC_PATH_PROGS([APKSIGNER], [apksigner], [], "${SDK_BUILD_TOOLS}:$PATH") + if test "$APKSIGNER" = ""; then + AC_MSG_ERROR([The Android package signing tool was not found. +Please verify that the path to the SDK build tools you specified is correct]) + fi + AC_PATH_PROGS([D8], [d8], [], "${SDK_BUILD_TOOLS}:$PATH") if test "D8" = ""; then AC_MSG_ERROR([The Android dexer was not found. @@ -1051,6 +1060,7 @@ package will likely install on older systems but crash on startup.]) passthrough="$passthrough --with-json=$with_json" passthrough="$passthrough --with-jpeg=$with_jpeg" passthrough="$passthrough --with-xml2=$with_xml2" + passthrough="$passthrough --with-sqlite3=$with_sqlite3" AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \ ANDROID_SDK="$android_sdk" android_abi=$android_abi \ @@ -1120,10 +1130,10 @@ if test "$ANDROID" = "yes"; then with_json=no with_jpeg=no with_xml2=no + with_sqlite3=no fi with_rsvg=no - with_sqlite3=no with_lcms2=no with_libsystemd=no with_cairo=no @@ -3348,30 +3358,49 @@ fi ### Use -lsqlite3 if available, unless '--with-sqlite3=no' HAVE_SQLITE3=no +SQLITE3_LIBS= +SQLITE3_CFLAGS= if test "${with_sqlite3}" != "no"; then - AC_CHECK_LIB([sqlite3], [sqlite3_open_v2], - [HAVE_SQLITE3=yes], - [HAVE_SQLITE3=no]) - if test "$HAVE_SQLITE3" = "yes"; then - SQLITE3_LIBS=-lsqlite3 - AC_SUBST([SQLITE3_LIBS]) - LIBS="$SQLITE3_LIBS $LIBS" - AC_DEFINE([HAVE_SQLITE3], [1], - [Define to 1 if you have the libsqlite3 library (-lsqlite).]) - # Windows loads libsqlite dynamically - if test "${opsys}" = "mingw32"; then - SQLITE3_LIBS= + if test "${REALLY_ANDROID}" = "yes"; then + ndk_SEARCH_MODULE([sqlite3], [SQLITE3], [HAVE_SQLITE3=yes]) + + if test "$HAVE_SQLITE3" = "yes"; then + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $SQLITE3_CFLAGS" + AC_CHECK_DECL([sqlite3_open_v2], [HAVE_SQLITE=yes], + [HAVE_SQLITE3=no], [#include ]) + CFLAGS="$SAVE_CFLAGS" fi - AC_CHECK_LIB([sqlite3], [sqlite3_load_extension], - [HAVE_SQLITE3_LOAD_EXTENSION=yes], - [HAVE_SQLITE3_LOAD_EXTENSION=no]) - if test "$HAVE_SQLITE3_LOAD_EXTENSION" = "yes"; then - AC_DEFINE([HAVE_SQLITE3_LOAD_EXTENSION], [1], - [Define to 1 if sqlite3 supports loading extensions.]) + else + AC_CHECK_LIB([sqlite3], [sqlite3_open_v2], + [HAVE_SQLITE3=yes], + [HAVE_SQLITE3=no]) + if test "$HAVE_SQLITE3" = "yes"; then + SQLITE3_LIBS=-lsqlite3 + LIBS="$SQLITE3_LIBS $LIBS" + # Windows loads libsqlite dynamically + if test "${opsys}" = "mingw32"; then + SQLITE3_LIBS= + fi + AC_CHECK_LIB([sqlite3], [sqlite3_load_extension], + [HAVE_SQLITE3_LOAD_EXTENSION=yes], + [HAVE_SQLITE3_LOAD_EXTENSION=no]) + if test "$HAVE_SQLITE3_LOAD_EXTENSION" = "yes"; then + AC_DEFINE([HAVE_SQLITE3_LOAD_EXTENSION], [1], + [Define to 1 if sqlite3 supports loading extensions.]) + fi fi - fi + fi + + if test "$HAVE_SQLITE3" = "yes"; then + AC_DEFINE([HAVE_SQLITE3], [1], + [Define to 1 if you have the libsqlite3 library (-lsqlite).]) + fi fi +AC_SUBST([SQLITE3_LIBS]) +AC_SUBST([SQLITE3_CFLAGS]) + HAVE_IMAGEMAGICK=no if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${HAVE_W32}" = "yes" || \ test "${HAVE_BE_APP}" = "yes" || test "${window_system}" = "pgtk"; then diff --git a/cross/ndk-build/ndk-build-shared-library.mk b/cross/ndk-build/ndk-build-shared-library.mk index a4b7b47f749..b69641ba9b0 100644 --- a/cross/ndk-build/ndk-build-shared-library.mk +++ b/cross/ndk-build/ndk-build-shared-library.mk @@ -20,7 +20,12 @@ # which actually builds targets. eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) -objname = $(1)-$(subst /,_,$(2).o) + +# Objects for shared libraries are prefixed with `-shared-' in +# addition to the name of the module, because a common practice in +# Android.mk files written by Google is to define two modules with the +# same name but of different types. +objname = $(1)-shared-$(subst /,_,$(2).o) # Here are the default flags to link shared libraries with. NDK_SO_DEFAULT_LDFLAGS := -lc -lm diff --git a/cross/ndk-build/ndk-build-static-library.mk b/cross/ndk-build/ndk-build-static-library.mk index 4d16d81330c..349b9242b1f 100644 --- a/cross/ndk-build/ndk-build-static-library.mk +++ b/cross/ndk-build/ndk-build-static-library.mk @@ -20,7 +20,7 @@ # which actually builds targets. eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) -objname = $(1)-$(subst /,_,$(2).o) +objname = $(1)-static-$(subst /,_,$(2).o) define single-object-target diff --git a/cross/ndk-build/ndk-build.mk.in b/cross/ndk-build/ndk-build.mk.in index 798dcf6c19e..5b0aa82856d 100644 --- a/cross/ndk-build/ndk-build.mk.in +++ b/cross/ndk-build/ndk-build.mk.in @@ -38,7 +38,7 @@ NDK_BUILD_MODULES := $(call uniqify,$(NDK_BUILD_MODULES)) # requires the C++ standard library. ifneq ($(NDK_BUILD_ANY_CXX_MODULE),) -NDK_BUILD_SHARED += $(NDK_BUILD_ANY_CXX_SHARED) +NDK_BUILD_SHARED += $(NDK_BUILD_CXX_SHARED) endif define subr-1 diff --git a/cross/ndk-build/ndk-resolve.mk b/cross/ndk-build/ndk-resolve.mk index 910be8dab53..c2e281c53ba 100644 --- a/cross/ndk-build/ndk-resolve.mk +++ b/cross/ndk-build/ndk-resolve.mk @@ -43,32 +43,50 @@ NDK_CFLAGS_$(LOCAL_MODULE) += $(addprefix -I,$(NDK_LOCAL_EXPORT_C_INCLUDES_$(1)) # If the module happens to be zlib, then add -lz to the shared library # flags. -ifneq ($(strip $(1)),libz) +ifeq ($(strip $(1)),libz) NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lz endif -ifneq ($(strip $(1)),z) +ifeq ($(strip $(1)),z) NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lz endif # Likewise for libdl. -ifneq ($(strip $(1)),libdl) +ifeq ($(strip $(1)),libdl) NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -ldl endif -ifneq ($(strip $(1)),dl) +ifeq ($(strip $(1)),dl) NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -ldl endif # Likewise for libstdc++. -ifneq ($(strip $(1)),libstdc++) +ifeq ($(strip $(1)),libstdc++) NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lstdc++ endif -ifneq ($(strip $(1)),dl) +ifeq ($(strip $(1)),dl) NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lstdc++ endif +# Likewise for liblog. +ifeq ($(strip $(1)),liblog) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -llog +endif + +ifeq ($(strip $(1)),log) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -llog +endif + +# Likewise for libandroid. +ifeq ($(strip $(1)),libandroid) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -landroid +endif + +ifeq ($(strip $(1)),android) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -landroid +endif + ifneq ($(2),) ifneq ($(findstring lib,$(1)),) NDK_LOCAL_A_NAMES_$(LOCAL_MODULE) += $(1).a diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index e910e482ad8..98d7f1e1d9e 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -160,13 +160,35 @@ The @dfn{app library} directory. This is automatically appended to @item The @dfn{external storage} directory. This is accessible to Emacs -when the user grants the @code{Files and media} permission to Emacs -via system settings. +when the user grants the ``Files and Media'' permission to Emacs via +system settings. @end itemize -The external storage directory is found at @file{/sdcard}; the other + The external storage directory is found at @file{/sdcard}; the other directories are not found at any fixed location. +@cindex file system limitations, Android 10 + On Android 10 and later, the Android system restricts applications +from accessing files in the @file{/sdcard} directory using +file-related system calls such as @code{open} and @code{readdir}. + + This restriction is known as ``Scoped Storage'', and supposedly +makes the system more secure. Unfortunately, it also means that Emacs +cannot access files in those directories, despite holding the +necessary permissions. Thankfully, the Open Handset Alliance's +version of Android allows this restriction to be disabled on a +per-program basis; the corresponding option in the system settings +panel is: + +@indentedblock +System -> Developer Options -> App Compatibility Changes -> Emacs -> +DEFAULT_SCOPED_STORAGE +@end indentedblock + + After you disable this setting and grant Emacs the ``Files and +Media'' permission, it will be able to access files under +@file{/sdcard} as usual. + @node Android Environment @section Running Emacs under Android diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index c4a9d1f5177..527ce74c474 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in @@ -53,7 +53,7 @@ along with GNU Emacs. If not, see . --> + android:targetSdkVersion="33"/> = Build.VERSION_CODES.DONUT) EmacsApplication.findDumpFile (context); /* Start Emacs. */ - EmacsNative.initEmacs (args, EmacsApplication.dumpFileName); + EmacsNative.initEmacs (args, EmacsApplication.dumpFileName, + Build.VERSION.SDK_INT); } }; diff --git a/java/org/gnu/emacs/EmacsThread.java b/java/org/gnu/emacs/EmacsThread.java index f5e9d54044a..2724d838d41 100644 --- a/java/org/gnu/emacs/EmacsThread.java +++ b/java/org/gnu/emacs/EmacsThread.java @@ -21,6 +21,8 @@ import java.lang.Thread; +import android.os.Build; + public class EmacsThread extends Thread { /* Whether or not Emacs should be started -Q. */ @@ -45,6 +47,7 @@ public class EmacsThread extends Thread args = new String[] { "libandroid-emacs.so", "-Q", }; /* Run the native code now. */ - EmacsNative.initEmacs (args, EmacsApplication.dumpFileName); + EmacsNative.initEmacs (args, EmacsApplication.dumpFileName, + Build.VERSION.SDK_INT); } }; diff --git a/m4/ndk-build.m4 b/m4/ndk-build.m4 index 27092e4b400..bcfe0fed6fe 100644 --- a/m4/ndk-build.m4 +++ b/m4/ndk-build.m4 @@ -73,6 +73,7 @@ esac # ones. ndk_package_map="libwebpdemux:webpdemux libxml-2.0:libxml2 jansson:libjansson" +ndk_package_map="$ndk_package_map sqlite3:libsqlite_static_minimal" # Replace ndk_module with the appropriate Android module name if it is # found in ndk_package_map. diff --git a/src/Makefile.in b/src/Makefile.in index f9cfff14952..60bb9c8f3a3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -255,6 +255,7 @@ LIBXML2_LIBS = @LIBXML2_LIBS@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ SQLITE3_LIBS = @SQLITE3_LIBS@ +SQLITE3_CFLAGS = @SQLITE3_CFLAGS@ GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@ @@ -432,7 +433,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \ $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ $(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) \ - $(ANDROID_CFLAGS) $(GIF_CFLAGS) $(JPEG_CFLAGS) + $(ANDROID_CFLAGS) $(GIF_CFLAGS) $(JPEG_CFLAGS) $(SQLITE3_CFLAGS) ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ diff --git a/src/android.c b/src/android.c index 52de153eefd..1676cbf9942 100644 --- a/src/android.c +++ b/src/android.c @@ -127,6 +127,9 @@ struct android_emacs_window jmethodID window_updated; }; +/* The API level of the current device. */ +static int android_api_level; + /* The asset manager being used. */ static AAssetManager *asset_manager; @@ -999,16 +1002,16 @@ android_fstatat (int dirfd, const char *restrict pathname, return fstatat (dirfd, pathname, statbuf, flags); } -/* Return if NAME is a file that is actually an asset and is +/* Return if NAME, a file name relative to the /assets directory, is accessible, as long as !(amode & W_OK). */ -bool +static bool android_file_access_p (const char *name, int amode) { if (!asset_manager) return false; - if (!(amode & W_OK) && (name = android_get_asset_name (name))) + if (!(amode & W_OK)) { if (!strcmp (name, "") || !strcmp (name, "/")) /* /assets always exists. */ @@ -1033,42 +1036,103 @@ android_hack_asset_fd (AAsset *asset) int fd, rc; unsigned char *mem; size_t size; - - fd = open ("/dev/ashmem", O_RDWR); - - if (fd < 0) - return -1; + static int (*asharedmemory_create) (const char *, size_t); /* Assets must be small enough to fit in size_t, if off_t is larger. */ size = AAsset_getLength (asset); - /* An empty name means the memory area will exist until the file - descriptor is closed, because no other process can attach. */ - rc = ioctl (fd, ASHMEM_SET_NAME, ""); + /* Android 28 and earlier let Emacs access /dev/ashmem directly, so + prefer that over using ASharedMemory. */ - if (rc < 0) + if (android_api_level <= 28) { - __android_log_print (ANDROID_LOG_ERROR, __func__, - "ioctl ASHMEM_SET_NAME: %s", - strerror (errno)); - close (fd); - return -1; + fd = open ("/dev/ashmem", O_RDWR); + + if (fd < 0) + return -1; + + /* An empty name means the memory area will exist until the file + descriptor is closed, because no other process can + attach. */ + rc = ioctl (fd, ASHMEM_SET_NAME, ""); + + if (rc < 0) + { + __android_log_print (ANDROID_LOG_ERROR, __func__, + "ioctl ASHMEM_SET_NAME: %s", + strerror (errno)); + close (fd); + return -1; + } + + rc = ioctl (fd, ASHMEM_SET_SIZE, size); + + if (rc < 0) + { + __android_log_print (ANDROID_LOG_ERROR, __func__, + "ioctl ASHMEM_SET_SIZE: %s", + strerror (errno)); + close (fd); + return -1; + } + + if (!size) + return fd; + + /* Now map the resource. */ + mem = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + __android_log_print (ANDROID_LOG_ERROR, __func__, + "mmap: %s", strerror (errno)); + close (fd); + return -1; + } + + if (AAsset_read (asset, mem, size) != size) + { + /* Too little was read. Close the file descriptor and + report an error. */ + __android_log_print (ANDROID_LOG_ERROR, __func__, + "AAsset_read: %s", strerror (errno)); + close (fd); + return -1; + } + + /* Return anyway even if munmap fails. */ + munmap (mem, size); + return fd; } - rc = ioctl (fd, ASHMEM_SET_SIZE, size); + /* On the other hand, SELinux restrictions on Android 29 and later + require that Emacs use a system service to obtain shared memory. + Load this dynamically, as this service is not available on all + versions of the NDK. */ - if (rc < 0) + if (!asharedmemory_create) { - __android_log_print (ANDROID_LOG_ERROR, __func__, - "ioctl ASHMEM_SET_SIZE: %s", - strerror (errno)); - close (fd); - return -1; + *(void **) (&asharedmemory_create) + = dlsym (RTLD_DEFAULT, "ASharedMemory_create"); + + if (!asharedmemory_create) + { + __android_log_print (ANDROID_LOG_FATAL, __func__, + "dlsym: %s\n", + strerror (errno)); + emacs_abort (); + } } - if (!size) - return fd; + fd = asharedmemory_create ("", size); + + if (fd < 0) + { + __android_log_print (ANDROID_LOG_ERROR, __func__, + "ASharedMemory_create: %s", + strerror (errno)); + return -1; + } /* Now map the resource. */ mem = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); @@ -1082,8 +1146,8 @@ android_hack_asset_fd (AAsset *asset) if (AAsset_read (asset, mem, size) != size) { - /* Too little was read. Close the file descriptor and report an - error. */ + /* Too little was read. Close the file descriptor and + report an error. */ __android_log_print (ANDROID_LOG_ERROR, __func__, "AAsset_read: %s", strerror (errno)); close (fd); @@ -1128,6 +1192,33 @@ android_check_compressed_file (int fd) return fd; } +/* Make FD close-on-exec. If any system call fails, do not abort, but + log a warning to the system log. */ + +static void +android_close_on_exec (int fd) +{ + int flags, rc; + + flags = fcntl (fd, F_GETFD); + + if (flags < 0) + { + __android_log_print (ANDROID_LOG_WARN, __func__, + "fcntl: %s", strerror (errno)); + return; + } + + rc = fcntl (fd, F_SETFD, flags | O_CLOEXEC); + + if (rc < 0) + { + __android_log_print (ANDROID_LOG_WARN, __func__, + "fcntl: %s", strerror (errno)); + return; + } +} + /* `open' and such are modified even though they exist on Android, because Emacs treats "/assets/" as a special directory that must contain all assets in the application package. */ @@ -1139,10 +1230,6 @@ android_open (const char *filename, int oflag, int mode) AAsset *asset; int fd, oldfd; off_t out_start, out_length; - bool fd_hacked; - - /* This flag means whether or not fd should not be duplicated. */ - fd_hacked = false; if (asset_manager && (name = android_get_asset_name (filename))) { @@ -1195,25 +1282,16 @@ android_open (const char *filename, int oflag, int mode) errno = ENXIO; return -1; } - - fd_hacked = true; } - /* Duplicate the file descriptor and then close the asset, - which will close the original file descriptor. */ - - if (!fd_hacked) - { - oldfd = fd; - fd = fcntl (oldfd, F_DUPFD_CLOEXEC); - - /* Close the original file descriptor. */ - close (oldfd); - } + /* If O_CLOEXEC is specified, make the file descriptor close on + exec too. */ + if (oflag & O_CLOEXEC) + android_close_on_exec (fd); if (fd >= ANDROID_MAX_ASSET_FD || fd < 0) { - /* Too bad. You lose. */ + /* Too bad. Pretend this is an out of memory error. */ errno = ENOMEM; if (fd >= 0) @@ -1713,7 +1791,7 @@ android_init_emacs_window (void) extern JNIEXPORT void JNICALL NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, - jobject dump_file_object) + jobject dump_file_object, jint api_level) { char **c_argv; jsize nelements, i; @@ -1732,6 +1810,9 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, /* Trick GCC into not optimizing this variable away. */ unused_pointer = buffer; + /* Set the Android API level. */ + android_api_level = api_level; + android_java_env = env; nelements = (*env)->GetArrayLength (env, argv); @@ -4214,34 +4295,47 @@ android_window_updated (android_window window, unsigned long serial) -#if __ANDROID_API__ >= 16 +/* When calling the system's faccessat, make sure to clear the flag + AT_EACCESS. -/* Replace the system faccessat with one which understands AT_EACCESS. Android's faccessat simply fails upon using AT_EACCESS, so replace - it with zero here. This isn't caught during configuration. + it with zero here. This isn't caught during configuration as Emacs + is being cross compiled. This replacement is only done when building for Android 16 or later, because earlier versions use the gnulib replacement that - lacks these issues. */ + lacks these issues. + + This is unnecessary on earlier API versions, as gnulib's + rpl_faccessat will be used instead, which lacks these problems. */ + +/* Like faccessat, except it also understands DIRFD opened using + android_dirfd. */ int android_faccessat (int dirfd, const char *pathname, int mode, int flags) { + const char *asset; + + if (dirfd != AT_FDCWD) + dirfd + = android_lookup_asset_directory_fd (dirfd, &pathname, + pathname); + + /* Check if pathname is actually an asset. If that is the case, + simply fall back to android_file_access_p. */ + + if (dirfd == AT_FDCWD + && asset_manager + && (asset = android_get_asset_name (pathname))) + return !android_file_access_p (asset, mode); + +#if __ANDROID_API__ >= 16 return faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS); -} - -#else /* __ANDROID_API__ < 16 */ - -/* This is unnecessary on earlier API versions, as gnulib's - rpl_faccessat will be used instead. */ - -int -android_faccessat (int dirfd, const char *pathname, int mode, int flags) -{ +#else return faccessat (dirfd, pathname, mode, flags); -} - #endif +} @@ -4468,10 +4562,10 @@ android_closedir (struct android_dir *dir) xfree (dir); } -/* Subroutine used by android_fstatat. If DIRFD belongs to an open - asset directory and FILE is a relative file name, then return - AT_FDCWD and the absolute file name of the directory prepended to - FILE in *PATHNAME. Else, return DIRFD. */ +/* Subroutine used by android_fstatat and android_faccessat. If DIRFD + belongs to an open asset directory and FILE is a relative file + name, then return AT_FDCWD and the absolute file name of the + directory prepended to FILE in *PATHNAME. Else, return DIRFD. */ int android_lookup_asset_directory_fd (int dirfd, diff --git a/src/android.h b/src/android.h index 33fad512d4a..8234dbb07c0 100644 --- a/src/android.h +++ b/src/android.h @@ -46,7 +46,6 @@ extern int android_emacs_init (int, char **, char *); extern int android_select (int, fd_set *, fd_set *, fd_set *, struct timespec *); -extern bool android_file_access_p (const char *, int); extern int android_open (const char *, int, int); extern char *android_user_full_name (struct passwd *); extern int android_fstat (int, struct stat *); diff --git a/src/dired.c b/src/dired.c index b38416e981a..93487d552e2 100644 --- a/src/dired.c +++ b/src/dired.c @@ -888,12 +888,6 @@ file_name_completion_dirp (int fd, struct dirent *dp, ptrdiff_t len) memcpy (subdir_name, dp->d_name, len); strcpy (subdir_name + len, "/"); -#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY - /* Check if subdir_name lies in the assets directory. */ - if (android_file_access_p (subdir_name, F_OK)) - return true; -#endif - bool dirp = sys_faccessat (fd, subdir_name, F_OK, AT_EACCESS) == 0; SAFE_FREE (); diff --git a/src/fileio.c b/src/fileio.c index 6f25506dbc2..71f83ea6daf 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -182,12 +182,6 @@ file_access_p (char const *file, int amode) } #endif -#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY - /* FILE may be some kind of special Android file. */ - if (android_file_access_p (file, amode)) - return true; -#endif - if (sys_faccessat (AT_FDCWD, file, amode, AT_EACCESS) == 0) return true; @@ -3018,12 +3012,6 @@ If there is no error, returns nil. */) encoded_filename = ENCODE_FILE (absname); -#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY - /* FILE may be some kind of special Android file. */ - if (android_file_access_p (SSDATA (encoded_filename), R_OK)) - return Qnil; -#endif - if (sys_faccessat (AT_FDCWD, SSDATA (encoded_filename), R_OK, AT_EACCESS) != 0) report_file_error (SSDATA (string), filename);