summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2023-01-25 18:44:47 +0800
committerPo Lu <luangruo@yahoo.com>2023-01-25 18:44:47 +0800
commit0900bfbcc57c555909cb75c38eb0ed26fb6964ef (patch)
tree9a2fa4328defab79f1cb3dcfac4f3c071bf0a633 /src
parent6f9a2a8f29c7faf13d0d86001b140746efc455b5 (diff)
downloademacs-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.in2
-rw-r--r--src/android-emacs.c83
-rw-r--r--src/android.c114
-rw-r--r--src/android.h8
-rw-r--r--src/androidfont.c3
-rw-r--r--src/androidselect.c3
-rw-r--r--src/emacs.c28
-rw-r--r--src/sfntfont-android.c3
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