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:
parent
4255d7f051
commit
22f7ad1057
20 changed files with 309 additions and 128 deletions
|
@ -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)
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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))))
|
||||
|
|
69
configure.ac
69
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 <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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) \
|
||||
|
|
228
src/android.c
228
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,
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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 ();
|
||||
|
|
12
src/fileio.c
12
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue