* INSTALL.android: Document how to install sqlite3.
* build-aux/ndk-build-helper-1.mk (SYSTEM_LIBRARIES):
* build-aux/ndk-build-helper-2.mk (SYSTEM_LIBRARIES): Add liblog
and libandroid.
* configure.ac (SQLITE3_LIBS, HAVE_SQLITE3)
(HAVE_SQLITE3_LOAD_EXTENSION): Support on Android.
(APKSIGNER): Look for this new required binary.
* cross/ndk-build/ndk-build-shared-library.mk (objname):
* cross/ndk-build/ndk-build-static-library.mk (objname): Avoid
duplicate rules by prefixing objects with module type.
* cross/ndk-build/ndk-build.mk.in (NDK_BUILD_SHARED): Fix
definition.
* cross/ndk-build/ndk-resolve.mk:
(NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE)): Handle new system
libraries.
* doc/emacs/android.texi (Android File System): Document Android
10 system restriction.
* java/AndroidManifest.xml.in: Target Android 33, not 28.
* java/Makefile.in (SIGN_EMACS_V2, APKSIGNER): New variables.
($(APK_NAME)): Make sure to apply a ``version 2 signature'' to
the package as well.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): New
argument apiLevel.
* java/org/gnu/emacs/EmacsNoninteractive.java (main):
* java/org/gnu/emacs/EmacsThread.java (run): Pass API level.
* m4/ndk-build.m4 (ndk_package_mape): Add package mapping for
sqlite3.
* src/Makefile.in (SQLITE3_CFLAGS): New substition.
(EMACS_CFLAGS): Add that variable.
* src/android.c (android_api_level): New variable.
(initEmacs): Set it.
(android_file_access_p): Make static.
(android_hack_asset_fd): Adjust for restrictions in Android 29
and later.
(android_close_on_exec): New function.
(android_open): Adjust to not duplicate file descriptor even if
CLOEXEC.
(android_faccessat): Use fstatat at-func emulation.
* src/android.h: Update prototypes.
* src/dired.c (file_name_completion_dirp):
* src/fileio.c (file_access_p, Faccess_file): Now that
sys_faccessat takes care of everything, stop calling
android_file_access_p.
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.
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)
# 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))))
# 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))))
JAVAC=
AAPT=
JARSIGNER=
+APKSIGNER=
ZIPALIGN=
DX=
ANDROID_JAR=
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
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.
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.
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 \
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
### 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 <sqlite3.h>])
+ 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
# 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
# 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
# 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
# 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
@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
<uses-permission android:name="android.permission.CAMERA" />
<uses-sdk android:minSdkVersion="@ANDROID_MIN_SDK@"
- android:targetSdkVersion="28"/>
+ android:targetSdkVersion="33"/>
<application android:name="org.gnu.emacs.EmacsApplication"
android:label="Emacs"
D8 = @D8@
ZIPALIGN = @ZIPALIGN@
JARSIGNER = @JARSIGNER@
+APKSIGNER = @APKSIGNER@
JARSIGNER_FLAGS =
ANDROID_JAR = @ANDROID_JAR@
ANDROID_ABI = @ANDROID_ABI@
endif
SIGN_EMACS = -keystore emacs.keystore -storepass emacs1 $(JARSIGNER_FLAGS)
+SIGN_EMACS_V2 = sign --v2-signing-enabled --ks emacs.keystore \
+ --debuggable-apk-permitted --ks-pass pass:emacs1
JAVA_FILES = $(shell find . -type f -name *.java)
CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
$(AAPT) add $@.unaligned classes.dex
$(JARSIGNER) $(SIGN_EMACS) $@.unaligned "Emacs keystore"
$(ZIPALIGN) -f 4 $@.unaligned $@
- rm -f $@.unaligned
+# Signing must happen after alignment!
+ $(APKSIGNER) $(SIGN_EMACS_V2) $@
+ rm -f $@.unaligned *.idsig
clean:
- rm -f *.apk emacs.apk-in *.dex *.unaligned *.class
+ rm -f *.apk emacs.apk-in *.dex *.unaligned *.class *.idsig
rm -rf install-temp
find . -name '*.class' -delete
undefined.
DUMPFILE is the dump file to use, or NULL if Emacs is to load
- loadup.el itself. */
- public static native void initEmacs (String argv[], String dumpFile);
+ loadup.el itself.
+
+ APILEVEL is the version of Android being used. */
+ public static native void initEmacs (String argv[], String dumpFile,
+ int apiLevel);
/* Abort and generate a native core dump. */
public static native void emacsAbort ();
EmacsApplication.findDumpFile (context);
/* Start Emacs. */
- EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
+ EmacsNative.initEmacs (args, EmacsApplication.dumpFileName,
+ Build.VERSION.SDK_INT);
}
};
import java.lang.Thread;
+import android.os.Build;
+
public class EmacsThread extends Thread
{
/* Whether or not Emacs should be started -Q. */
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);
}
};
# 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.
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
SQLITE3_LIBS = @SQLITE3_LIBS@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@
$(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) \
jmethodID window_updated;
};
+/* The API level of the current device. */
+static int android_api_level;
+
/* The asset manager being used. */
static AAssetManager *asset_manager;
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. */
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)
+ {
+ *(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 ();
+ }
+ }
+
+ fd = asharedmemory_create ("", size);
+
+ if (fd < 0)
{
__android_log_print (ANDROID_LOG_ERROR, __func__,
- "ioctl ASHMEM_SET_SIZE: %s",
+ "ASharedMemory_create: %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)
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);
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. */
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)))
{
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)
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;
/* 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);
\f
-#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)
{
- return faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);
-}
+ const char *asset;
-#else /* __ANDROID_API__ < 16 */
+ if (dirfd != AT_FDCWD)
+ dirfd
+ = android_lookup_asset_directory_fd (dirfd, &pathname,
+ pathname);
-/* This is unnecessary on earlier API versions, as gnulib's
- rpl_faccessat will be used instead. */
+ /* Check if pathname is actually an asset. If that is the case,
+ simply fall back to android_file_access_p. */
-int
-android_faccessat (int dirfd, const char *pathname, int mode, int flags)
-{
- return faccessat (dirfd, pathname, mode, flags);
-}
+ 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
+ return faccessat (dirfd, pathname, mode, flags);
#endif
+}
\f
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,
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 *);
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 ();
}
#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;
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);