Update Android port

* 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.
This commit is contained in:
Po Lu 2023-01-26 19:54:38 +08:00
parent 4255d7f051
commit 22f7ad1057
20 changed files with 309 additions and 128 deletions

View file

@ -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)

View file

@ -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))))

View file

@ -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))))

View file

@ -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 <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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -53,7 +53,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
<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"

View file

@ -33,6 +33,7 @@ AAPT = @AAPT@
D8 = @D8@
ZIPALIGN = @ZIPALIGN@
JARSIGNER = @JARSIGNER@
APKSIGNER = @APKSIGNER@
JARSIGNER_FLAGS =
ANDROID_JAR = @ANDROID_JAR@
ANDROID_ABI = @ANDROID_ABI@
@ -52,6 +53,8 @@ JARSIGNER_FLAGS =
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)
@ -196,10 +199,12 @@ $(APK_NAME): classes.dex emacs.apk-in emacs.keystore
$(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

View file

@ -65,8 +65,11 @@ public static native void setEmacsParams (AssetManager assetManager,
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 ();

View file

@ -177,6 +177,7 @@ else if (apiLevel >= Build.VERSION_CODES.DONUT)
EmacsApplication.findDumpFile (context);
/* Start Emacs. */
EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
EmacsNative.initEmacs (args, EmacsApplication.dumpFileName,
Build.VERSION.SDK_INT);
}
};

View file

@ -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);
}
};

View file

@ -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.

View file

@ -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) \

View file

@ -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,

View file

@ -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 *);

View file

@ -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 ();

View file

@ -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);