emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android 22f7ad1057 1/4: Update Android port


From: Po Lu
Subject: feature/android 22f7ad1057 1/4: Update Android port
Date: Thu, 26 Jan 2023 09:19:49 -0500 (EST)

branch: feature/android
commit 22f7ad1057e1a1e20933e0a1ff2a858ecd9e3fec
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    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.
---
 INSTALL.android                             |  18 +++
 build-aux/ndk-build-helper-1.mk             |   2 +-
 build-aux/ndk-build-helper-2.mk             |   2 +-
 configure.ac                                |  69 ++++++---
 cross/ndk-build/ndk-build-shared-library.mk |   7 +-
 cross/ndk-build/ndk-build-static-library.mk |   2 +-
 cross/ndk-build/ndk-build.mk.in             |   2 +-
 cross/ndk-build/ndk-resolve.mk              |  30 +++-
 doc/emacs/android.texi                      |  28 +++-
 java/AndroidManifest.xml.in                 |   2 +-
 java/Makefile.in                            |   9 +-
 java/org/gnu/emacs/EmacsNative.java         |   7 +-
 java/org/gnu/emacs/EmacsNoninteractive.java |   3 +-
 java/org/gnu/emacs/EmacsThread.java         |   5 +-
 m4/ndk-build.m4                             |   1 +
 src/Makefile.in                             |   3 +-
 src/android.c                               | 220 ++++++++++++++++++++--------
 src/android.h                               |   1 -
 src/dired.c                                 |   6 -
 src/fileio.c                                |  12 --
 20 files changed, 305 insertions(+), 124 deletions(-)

diff --git a/INSTALL.android b/INSTALL.android
index ed0bd0f68d..06211e5ec9 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 4ffe0d423e..9035b5ca59 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 9c9e7cf09a..8f2f397e53 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 95bb0cfca8..879e4ab74a 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 <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
diff --git a/cross/ndk-build/ndk-build-shared-library.mk 
b/cross/ndk-build/ndk-build-shared-library.mk
index a4b7b47f74..b69641ba9b 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 4d16d81330..349b9242b1 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 798dcf6c19..5b0aa82856 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 910be8dab5..c2e281c53b 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 e910e482ad..98d7f1e1d9 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 c4a9d1f517..527ce74c47 100644
--- a/java/AndroidManifest.xml.in
+++ b/java/AndroidManifest.xml.in
@@ -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"
diff --git a/java/Makefile.in b/java/Makefile.in
index 755995b93b..a7bc8ac027 100644
--- a/java/Makefile.in
+++ b/java/Makefile.in
@@ -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
 
diff --git a/java/org/gnu/emacs/EmacsNative.java 
b/java/org/gnu/emacs/EmacsNative.java
index a772b96530..7bf8b5f608 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -65,8 +65,11 @@ public class EmacsNative
      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 ();
diff --git a/java/org/gnu/emacs/EmacsNoninteractive.java 
b/java/org/gnu/emacs/EmacsNoninteractive.java
index b4854d8323..4da82f2f89 100644
--- a/java/org/gnu/emacs/EmacsNoninteractive.java
+++ b/java/org/gnu/emacs/EmacsNoninteractive.java
@@ -177,6 +177,7 @@ public class EmacsNoninteractive
     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 f5e9d54044..2724d838d4 100644
--- a/java/org/gnu/emacs/EmacsThread.java
+++ b/java/org/gnu/emacs/EmacsThread.java
@@ -21,6 +21,8 @@ package org.gnu.emacs;
 
 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 27092e4b40..bcfe0fed6f 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 f9cfff1495..60bb9c8f3a 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 52de153eef..1676cbf994 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,43 +1036,104 @@ 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)
+    {
+      *(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)
@@ -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)
 {
-  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
+}
 
 
 
@@ -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 33fad512d4..8234dbb07c 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 b38416e981..93487d552e 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 6f25506dbc..71f83ea6da 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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]