diff options
author | Po Lu <luangruo@yahoo.com> | 2023-01-25 18:44:47 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2023-01-25 18:44:47 +0800 |
commit | 0900bfbcc57c555909cb75c38eb0ed26fb6964ef (patch) | |
tree | 9a2fa4328defab79f1cb3dcfac4f3c071bf0a633 /src | |
parent | 6f9a2a8f29c7faf13d0d86001b140746efc455b5 (diff) | |
download | emacs-0900bfbcc57c555909cb75c38eb0ed26fb6964ef.tar.gz emacs-0900bfbcc57c555909cb75c38eb0ed26fb6964ef.tar.bz2 emacs-0900bfbcc57c555909cb75c38eb0ed26fb6964ef.zip |
Update Android port
* doc/emacs/android.texi (Android Startup, Android Environment):
Document that restrictions on starting Emacs have been lifted.
* java/README: Document Java for Emacs developers and how the
Android port works.
* java/org/gnu/emacs/EmacsApplication.java (EmacsApplication)
(findDumpFile): New function.
(onCreate): Factor out dump file finding functions to there.
* java/org/gnu/emacs/EmacsNative.java (EmacsNative): Update
function declarations.
* java/org/gnu/emacs/EmacsNoninteractive.java
(EmacsNoninteractive): New class.
* java/org/gnu/emacs/EmacsService.java (EmacsService, getApkFile)
(onCreate): Pass classpath to setEmacsParams.
* java/org/gnu/emacs/EmacsThread.java (EmacsThread): Make run an
override.
* lisp/loadup.el: Don't dump on Android when noninteractive.
* lisp/shell.el (shell--command-completion-data): Handle
inaccessible directories.
* src/Makefile.in (android-emacs): Link with gnulib.
* src/android-emacs.c (main): Implement to launch app-process
and then EmacsNoninteractive.
* src/android.c (setEmacsParams): New argument `class_path'.
Don't set stuff up when running noninteractive.
* src/android.h (initEmacs): Likewise.
* src/androidfont.c (init_androidfont):
* src/androidselect.c (init_androidselect): Don't initialize
when running noninteractive.
* src/emacs.c (load_pdump): New argument `dump_file'.
(android_emacs_init): Give new argument `dump_file' to
`load_pdump'.
* src/sfntfont-android.c (init_sfntfont_android): Don't
initialize when running noninteractive.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 2 | ||||
-rw-r--r-- | src/android-emacs.c | 83 | ||||
-rw-r--r-- | src/android.c | 114 | ||||
-rw-r--r-- | src/android.h | 8 | ||||
-rw-r--r-- | src/androidfont.c | 3 | ||||
-rw-r--r-- | src/androidselect.c | 3 | ||||
-rw-r--r-- | src/emacs.c | 28 | ||||
-rw-r--r-- | src/sfntfont-android.c | 3 |
8 files changed, 205 insertions, 39 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 29beb519abb..fe745770b9f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -768,7 +768,7 @@ libemacs.so: $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ android-emacs: libemacs.so android-emacs.o $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(LDFLAGS) \ - -L. "-l:libemacs.so" android-emacs.o + $(LIBEGNU_ARCHIVE) -L. "-l:libemacs.so" android-emacs.o endif ## The following oldxmenu-related rules are only (possibly) used if diff --git a/src/android-emacs.c b/src/android-emacs.c index d4fa14e39fb..c1f2a6f43bb 100644 --- a/src/android-emacs.c +++ b/src/android-emacs.c @@ -18,13 +18,88 @@ You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <config.h> -#include "android.h" +#include <stdio.h> +#include <alloca.h> +#include <string.h> +#include <unistd.h> -/* android-emacs is a wrapper around libemacs. It simply calls - android_emacs_init with the argv and argc given to it. */ +/* android-emacs is a wrapper around /system/bin/app_process(64). + It invokes app_process(64) with the right class path and then + starts org.gnu.emacs.EmacsNoninteractive. + + The main function in that class tries to load an activity thread + and obtain a context and asset manager before calling + android_emacs_init, which is required for Emacs to find required + preloaded Lisp. */ int main (int argc, char **argv) { - return android_emacs_init (argc, argv); + char **args; + int i; + char *bootclasspath, *emacs_class_path; + + /* Allocate enough to hold the arguments to app_process. */ + args = alloca ((10 + argc) * sizeof *args); + + /* Clear args. */ + memset (args, 0, (10 + argc) * sizeof *args); + + /* First, figure out what program to start. */ +#if defined __x86_64__ || defined __aarch64__ + args[0] = (char *) "/system/bin/app_process64"; +#else + args[0] = (char *) "/system/bin/app_process"; +#endif + + /* Next, obtain the boot class path. */ + bootclasspath = getenv ("BOOTCLASSPATH"); + + /* And the Emacs class path. */ + emacs_class_path = getenv ("EMACS_CLASS_PATH"); + + if (!bootclasspath) + { + fprintf (stderr, "The BOOTCLASSPATH environment variable" + " is not set. As a result, Emacs does not know" + " how to start app_process.\n" + "This is likely a change in the Android platform." + " Please report this to bug-gnu-emacs@gnu.org.\n"); + return 1; + } + + if (!emacs_class_path) + { + fprintf (stderr, "EMACS_CLASS_PATH not set." + " Please make sure Emacs is being started" + " from within a running copy of Emacs.\n"); + return 1; + } + + if (asprintf (&bootclasspath, "-Djava.class.path=%s:%s", + bootclasspath, emacs_class_path) < 0) + { + perror ("asprintf"); + return 1; + } + + args[1] = bootclasspath; + args[2] = (char *) "/system/bin"; + args[3] = (char *) "--nice-name=emacs"; + args[4] = (char *) "org.gnu.emacs.EmacsNoninteractive"; + + /* Arguments from here on are passed to main in + EmacsNoninteractive.java. */ + args[5] = argv[0]; + + /* Now copy the rest of the arguments over. */ + for (i = 1; i < argc; ++i) + args[5 + i] = argv[i]; + + /* Finally, try to start the app_process. */ + execvp (args[0], args); + + /* If exit fails, return an error indication. */ + perror ("exec"); + return 1; } diff --git a/src/android.c b/src/android.c index c186b462360..8c4442e3397 100644 --- a/src/android.c +++ b/src/android.c @@ -145,6 +145,10 @@ char *android_game_path; /* The directory used to store temporary files. */ char *android_cache_dir; +/* The list of archive files within which the Java virtual macine + looks for class files. */ +char *android_class_path; + /* The display's pixel densities. */ double android_pixel_density_x, android_pixel_density_y; @@ -1315,6 +1319,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, jobject cache_dir, jfloat pixel_density_x, jfloat pixel_density_y, + jobject class_path, jobject emacs_service_object) { int pipefd[2]; @@ -1372,19 +1377,30 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, object from being deleted. */ (*env)->NewGlobalRef (env, local_asset_manager); - /* Create a pipe and duplicate it to stdout and stderr. Next, make - a thread that prints stderr to the system log. */ + if (emacs_service_object) + { + /* Create a pipe and duplicate it to stdout and stderr. Next, + make a thread that prints stderr to the system log. - if (pipe2 (pipefd, O_CLOEXEC) < 0) - emacs_abort (); + Notice that this function is called in one of two ways. The + first is when Emacs is being started as a GUI application by + the system, and the second is when Emacs is being started by + libandroid-emacs.so as an ordinary noninteractive Emacs. - if (dup2 (pipefd[1], 2) < 0) - emacs_abort (); - close (pipefd[1]); + In the second case, stderr is usually connected to a PTY, so + this is unnecessary. */ - if (pthread_create (&thread, NULL, android_run_debug_thread, - (void *) (intptr_t) pipefd[0])) - emacs_abort (); + if (pipe2 (pipefd, O_CLOEXEC) < 0) + emacs_abort (); + + if (dup2 (pipefd[1], 2) < 0) + emacs_abort (); + close (pipefd[1]); + + if (pthread_create (&thread, NULL, android_run_debug_thread, + (void *) (intptr_t) pipefd[0])) + emacs_abort (); + } /* Now set the path to the site load directory. */ @@ -1430,6 +1446,23 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, (*env)->ReleaseStringUTFChars (env, (jstring) cache_dir, java_string); + if (class_path) + { + java_string = (*env)->GetStringUTFChars (env, (jstring) class_path, + NULL); + + if (!java_string) + emacs_abort (); + + android_class_path = strdup ((const char *) java_string); + + if (!android_files_dir) + emacs_abort (); + + (*env)->ReleaseStringUTFChars (env, (jstring) class_path, + java_string); + } + /* Calculate the site-lisp path. */ android_site_load_path = malloc (PATH_MAX + 1); @@ -1450,16 +1483,32 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object, "Site-lisp directory: %s\n" "Files directory: %s\n" "Native code directory: %s\n" - "Game score path: %s\n", + "Game score path: %s\n" + "Class path: %s\n", android_site_load_path, android_files_dir, - android_lib_dir, android_game_path); + android_lib_dir, android_game_path, + (android_class_path + ? android_class_path + : "None")); + + if (android_class_path) + /* Set EMACS_CLASS_PATH to the class path where + EmacsNoninteractive can be found. */ + setenv ("EMACS_CLASS_PATH", android_class_path, 1); + + /* Set LD_LIBRARY_PATH to an appropriate value. */ + setenv ("LD_LIBRARY_PATH", android_lib_dir, 1); /* Make a reference to the Emacs service. */ - emacs_service = (*env)->NewGlobalRef (env, emacs_service_object); - if (!emacs_service) - emacs_abort (); + if (emacs_service_object) + { + emacs_service = (*env)->NewGlobalRef (env, emacs_service_object); + + if (!emacs_service) + emacs_abort (); + } /* Set up events. */ android_init_events (); @@ -1660,12 +1709,14 @@ android_init_emacs_window (void) } extern JNIEXPORT void JNICALL -NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) +NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv, + jobject dump_file_object) { char **c_argv; jsize nelements, i; jobject argument; const char *c_argument; + char *dump_file; android_java_env = env; @@ -1705,9 +1756,34 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) __android_log_print (ANDROID_LOG_WARN, __func__, "chdir: %s", strerror (errno)); - /* Initialize the Android GUI. */ - android_init_gui = true; - android_emacs_init (nelements, c_argv); + /* Initialize the Android GUI as long as the service object was + set. */ + + if (emacs_service) + android_init_gui = true; + + /* Now see if a dump file has been specified and should be used. */ + dump_file = NULL; + + if (dump_file_object) + { + c_argument + = (*env)->GetStringUTFChars (env, (jstring) dump_file_object, + NULL); + + /* Copy the Java string data once. */ + dump_file = strdup (c_argument); + + /* Release the Java string data. */ + (*env)->ReleaseStringUTFChars (env, (jstring) dump_file_object, + c_argument); + } + + /* Delete local references to objects that are no longer needed. */ + ANDROID_DELETE_LOCAL_REF (argv); + ANDROID_DELETE_LOCAL_REF (dump_file_object); + + android_emacs_init (nelements, c_argv, dump_file); /* android_emacs_init should never return. */ emacs_abort (); } diff --git a/src/android.h b/src/android.h index ce0ccfc4338..6c20995e4a1 100644 --- a/src/android.h +++ b/src/android.h @@ -38,15 +38,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "lisp.h" #endif -/* This must be used in every symbol declaration to export it to the - JNI Emacs wrapper. */ -#define ANDROID_EXPORT __attribute__ ((visibility ("default"))) - -extern bool ANDROID_EXPORT android_init_gui; -extern int ANDROID_EXPORT android_emacs_init (int, char **); +extern bool android_init_gui; #ifndef ANDROID_STUBIFY +extern int android_emacs_init (int, char **, char *); extern int android_select (int, fd_set *, fd_set *, fd_set *, struct timespec *); diff --git a/src/androidfont.c b/src/androidfont.c index bec5a59ca77..55f45758352 100644 --- a/src/androidfont.c +++ b/src/androidfont.c @@ -1104,6 +1104,9 @@ syms_of_androidfont (void) void init_androidfont (void) { + if (!android_init_gui) + return; + android_init_font_driver (); android_init_font_spec (); android_init_font_metrics (); diff --git a/src/androidselect.c b/src/androidselect.c index 2e2f2d7e483..4585d64b7e8 100644 --- a/src/androidselect.c +++ b/src/androidselect.c @@ -240,6 +240,9 @@ init_androidselect (void) jobject tem; jmethodID make_clipboard; + if (!android_init_gui) + return; + android_init_emacs_clipboard (); make_clipboard = clipboard_class.make_clipboard; diff --git a/src/emacs.c b/src/emacs.c index b0c19fe0070..a24f9960494 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -875,19 +875,23 @@ dump_error_to_string (int result) } } -/* This function returns the Emacs executable. */ +/* This function returns the Emacs executable. DUMP_FILE is ignored + outside of Android. Otherwise, it is the name of the dump file to + use, or NULL if Emacs should look for a ``--dump-file'' argument + instead. */ + static char * -load_pdump (int argc, char **argv) +load_pdump (int argc, char **argv, char *dump_file) { #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY - char *dump_file = NULL; int skip_args = 0, result; while (skip_args < argc - 1) { - if (argmatch (argv, argc, "-dump-file", "--dump-file", 6, - &dump_file, &skip_args) - || argmatch (argv, argc, "--", NULL, 2, NULL, &skip_args)) + if (argmatch (argv, argc, "-dump-file", "--dump-file", + 6, &dump_file, &skip_args) + || argmatch (argv, argc, "--", NULL, 2, NULL, + &skip_args)) break; skip_args++; } @@ -933,7 +937,7 @@ load_pdump (int argc, char **argv) /* Look for an explicitly-specified dump file. */ const char *path_exec = PATH_EXEC; - char *dump_file = NULL; + dump_file = NULL; int skip_args = 0; while (skip_args < argc - 1) { @@ -1276,7 +1280,7 @@ maybe_load_seccomp (int argc, char **argv) #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY int -android_emacs_init (int argc, char **argv) +android_emacs_init (int argc, char **argv, char *dump_file) #else int main (int argc, char **argv) @@ -1286,6 +1290,12 @@ main (int argc, char **argv) for pointers. */ void *stack_bottom_variable; int old_argc; +#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY) + char *dump_file; + + /* This is just a dummy argument used to avoid extra defines. */ + dump_file = NULL; +#endif /* First, check whether we should apply a seccomp filter. This should come at the very beginning to allow the filter to protect @@ -1415,7 +1425,7 @@ main (int argc, char **argv) #ifdef HAVE_PDUMPER if (attempt_load_pdump) - initial_emacs_executable = load_pdump (argc, argv); + initial_emacs_executable = load_pdump (argc, argv, dump_file); #else ptrdiff_t bufsize; initial_emacs_executable = find_emacs_executable (argv[0], &bufsize); diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index bc8f1b35b84..ab90a2e4ecd 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c @@ -729,6 +729,9 @@ syms_of_sfntfont_android_for_pdumper (void) void init_sfntfont_android (void) { + if (!android_init_gui) + return; + /* Make sure to pick the right Sans Serif font depending on what version of Android the device is running. */ #if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL |