aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-01-25 18:44:47 +0800
committerPo Lu2023-01-25 18:44:47 +0800
commit0900bfbcc57c555909cb75c38eb0ed26fb6964ef (patch)
tree9a2fa4328defab79f1cb3dcfac4f3c071bf0a633 /src
parent6f9a2a8f29c7faf13d0d86001b140746efc455b5 (diff)
downloademacs-0900bfbcc57c555909cb75c38eb0ed26fb6964ef.tar.gz
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) \
768 768
769android-emacs: libemacs.so android-emacs.o 769android-emacs: libemacs.so android-emacs.o
770 $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(LDFLAGS) \ 770 $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(LDFLAGS) \
771 -L. "-l:libemacs.so" android-emacs.o 771 $(LIBEGNU_ARCHIVE) -L. "-l:libemacs.so" android-emacs.o
772endif 772endif
773 773
774## The following oldxmenu-related rules are only (possibly) used if 774## 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
18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 18along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20#include <config.h> 20#include <config.h>
21#include "android.h" 21#include <stdio.h>
22#include <alloca.h>
23#include <string.h>
24#include <unistd.h>
22 25
23/* android-emacs is a wrapper around libemacs. It simply calls 26/* android-emacs is a wrapper around /system/bin/app_process(64).
24 android_emacs_init with the argv and argc given to it. */ 27 It invokes app_process(64) with the right class path and then
28 starts org.gnu.emacs.EmacsNoninteractive.
29
30 The main function in that class tries to load an activity thread
31 and obtain a context and asset manager before calling
32 android_emacs_init, which is required for Emacs to find required
33 preloaded Lisp. */
25 34
26int 35int
27main (int argc, char **argv) 36main (int argc, char **argv)
28{ 37{
29 return android_emacs_init (argc, argv); 38 char **args;
39 int i;
40 char *bootclasspath, *emacs_class_path;
41
42 /* Allocate enough to hold the arguments to app_process. */
43 args = alloca ((10 + argc) * sizeof *args);
44
45 /* Clear args. */
46 memset (args, 0, (10 + argc) * sizeof *args);
47
48 /* First, figure out what program to start. */
49#if defined __x86_64__ || defined __aarch64__
50 args[0] = (char *) "/system/bin/app_process64";
51#else
52 args[0] = (char *) "/system/bin/app_process";
53#endif
54
55 /* Next, obtain the boot class path. */
56 bootclasspath = getenv ("BOOTCLASSPATH");
57
58 /* And the Emacs class path. */
59 emacs_class_path = getenv ("EMACS_CLASS_PATH");
60
61 if (!bootclasspath)
62 {
63 fprintf (stderr, "The BOOTCLASSPATH environment variable"
64 " is not set. As a result, Emacs does not know"
65 " how to start app_process.\n"
66 "This is likely a change in the Android platform."
67 " Please report this to bug-gnu-emacs@gnu.org.\n");
68 return 1;
69 }
70
71 if (!emacs_class_path)
72 {
73 fprintf (stderr, "EMACS_CLASS_PATH not set."
74 " Please make sure Emacs is being started"
75 " from within a running copy of Emacs.\n");
76 return 1;
77 }
78
79 if (asprintf (&bootclasspath, "-Djava.class.path=%s:%s",
80 bootclasspath, emacs_class_path) < 0)
81 {
82 perror ("asprintf");
83 return 1;
84 }
85
86 args[1] = bootclasspath;
87 args[2] = (char *) "/system/bin";
88 args[3] = (char *) "--nice-name=emacs";
89 args[4] = (char *) "org.gnu.emacs.EmacsNoninteractive";
90
91 /* Arguments from here on are passed to main in
92 EmacsNoninteractive.java. */
93 args[5] = argv[0];
94
95 /* Now copy the rest of the arguments over. */
96 for (i = 1; i < argc; ++i)
97 args[5 + i] = argv[i];
98
99 /* Finally, try to start the app_process. */
100 execvp (args[0], args);
101
102 /* If exit fails, return an error indication. */
103 perror ("exec");
104 return 1;
30} 105}
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;
145/* The directory used to store temporary files. */ 145/* The directory used to store temporary files. */
146char *android_cache_dir; 146char *android_cache_dir;
147 147
148/* The list of archive files within which the Java virtual macine
149 looks for class files. */
150char *android_class_path;
151
148/* The display's pixel densities. */ 152/* The display's pixel densities. */
149double android_pixel_density_x, android_pixel_density_y; 153double android_pixel_density_x, android_pixel_density_y;
150 154
@@ -1315,6 +1319,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
1315 jobject cache_dir, 1319 jobject cache_dir,
1316 jfloat pixel_density_x, 1320 jfloat pixel_density_x,
1317 jfloat pixel_density_y, 1321 jfloat pixel_density_y,
1322 jobject class_path,
1318 jobject emacs_service_object) 1323 jobject emacs_service_object)
1319{ 1324{
1320 int pipefd[2]; 1325 int pipefd[2];
@@ -1372,19 +1377,30 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
1372 object from being deleted. */ 1377 object from being deleted. */
1373 (*env)->NewGlobalRef (env, local_asset_manager); 1378 (*env)->NewGlobalRef (env, local_asset_manager);
1374 1379
1375 /* Create a pipe and duplicate it to stdout and stderr. Next, make 1380 if (emacs_service_object)
1376 a thread that prints stderr to the system log. */ 1381 {
1382 /* Create a pipe and duplicate it to stdout and stderr. Next,
1383 make a thread that prints stderr to the system log.
1377 1384
1378 if (pipe2 (pipefd, O_CLOEXEC) < 0) 1385 Notice that this function is called in one of two ways. The
1379 emacs_abort (); 1386 first is when Emacs is being started as a GUI application by
1387 the system, and the second is when Emacs is being started by
1388 libandroid-emacs.so as an ordinary noninteractive Emacs.
1380 1389
1381 if (dup2 (pipefd[1], 2) < 0) 1390 In the second case, stderr is usually connected to a PTY, so
1382 emacs_abort (); 1391 this is unnecessary. */
1383 close (pipefd[1]);
1384 1392
1385 if (pthread_create (&thread, NULL, android_run_debug_thread, 1393 if (pipe2 (pipefd, O_CLOEXEC) < 0)
1386 (void *) (intptr_t) pipefd[0])) 1394 emacs_abort ();
1387 emacs_abort (); 1395
1396 if (dup2 (pipefd[1], 2) < 0)
1397 emacs_abort ();
1398 close (pipefd[1]);
1399
1400 if (pthread_create (&thread, NULL, android_run_debug_thread,
1401 (void *) (intptr_t) pipefd[0]))
1402 emacs_abort ();
1403 }
1388 1404
1389 /* Now set the path to the site load directory. */ 1405 /* Now set the path to the site load directory. */
1390 1406
@@ -1430,6 +1446,23 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
1430 (*env)->ReleaseStringUTFChars (env, (jstring) cache_dir, 1446 (*env)->ReleaseStringUTFChars (env, (jstring) cache_dir,
1431 java_string); 1447 java_string);
1432 1448
1449 if (class_path)
1450 {
1451 java_string = (*env)->GetStringUTFChars (env, (jstring) class_path,
1452 NULL);
1453
1454 if (!java_string)
1455 emacs_abort ();
1456
1457 android_class_path = strdup ((const char *) java_string);
1458
1459 if (!android_files_dir)
1460 emacs_abort ();
1461
1462 (*env)->ReleaseStringUTFChars (env, (jstring) class_path,
1463 java_string);
1464 }
1465
1433 /* Calculate the site-lisp path. */ 1466 /* Calculate the site-lisp path. */
1434 1467
1435 android_site_load_path = malloc (PATH_MAX + 1); 1468 android_site_load_path = malloc (PATH_MAX + 1);
@@ -1450,16 +1483,32 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
1450 "Site-lisp directory: %s\n" 1483 "Site-lisp directory: %s\n"
1451 "Files directory: %s\n" 1484 "Files directory: %s\n"
1452 "Native code directory: %s\n" 1485 "Native code directory: %s\n"
1453 "Game score path: %s\n", 1486 "Game score path: %s\n"
1487 "Class path: %s\n",
1454 android_site_load_path, 1488 android_site_load_path,
1455 android_files_dir, 1489 android_files_dir,
1456 android_lib_dir, android_game_path); 1490 android_lib_dir, android_game_path,
1491 (android_class_path
1492 ? android_class_path
1493 : "None"));
1494
1495 if (android_class_path)
1496 /* Set EMACS_CLASS_PATH to the class path where
1497 EmacsNoninteractive can be found. */
1498 setenv ("EMACS_CLASS_PATH", android_class_path, 1);
1499
1500 /* Set LD_LIBRARY_PATH to an appropriate value. */
1501 setenv ("LD_LIBRARY_PATH", android_lib_dir, 1);
1457 1502
1458 /* Make a reference to the Emacs service. */ 1503 /* Make a reference to the Emacs service. */
1459 emacs_service = (*env)->NewGlobalRef (env, emacs_service_object);
1460 1504
1461 if (!emacs_service) 1505 if (emacs_service_object)
1462 emacs_abort (); 1506 {
1507 emacs_service = (*env)->NewGlobalRef (env, emacs_service_object);
1508
1509 if (!emacs_service)
1510 emacs_abort ();
1511 }
1463 1512
1464 /* Set up events. */ 1513 /* Set up events. */
1465 android_init_events (); 1514 android_init_events ();
@@ -1660,12 +1709,14 @@ android_init_emacs_window (void)
1660} 1709}
1661 1710
1662extern JNIEXPORT void JNICALL 1711extern JNIEXPORT void JNICALL
1663NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv) 1712NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv,
1713 jobject dump_file_object)
1664{ 1714{
1665 char **c_argv; 1715 char **c_argv;
1666 jsize nelements, i; 1716 jsize nelements, i;
1667 jobject argument; 1717 jobject argument;
1668 const char *c_argument; 1718 const char *c_argument;
1719 char *dump_file;
1669 1720
1670 android_java_env = env; 1721 android_java_env = env;
1671 1722
@@ -1705,9 +1756,34 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
1705 __android_log_print (ANDROID_LOG_WARN, __func__, 1756 __android_log_print (ANDROID_LOG_WARN, __func__,
1706 "chdir: %s", strerror (errno)); 1757 "chdir: %s", strerror (errno));
1707 1758
1708 /* Initialize the Android GUI. */ 1759 /* Initialize the Android GUI as long as the service object was
1709 android_init_gui = true; 1760 set. */
1710 android_emacs_init (nelements, c_argv); 1761
1762 if (emacs_service)
1763 android_init_gui = true;
1764
1765 /* Now see if a dump file has been specified and should be used. */
1766 dump_file = NULL;
1767
1768 if (dump_file_object)
1769 {
1770 c_argument
1771 = (*env)->GetStringUTFChars (env, (jstring) dump_file_object,
1772 NULL);
1773
1774 /* Copy the Java string data once. */
1775 dump_file = strdup (c_argument);
1776
1777 /* Release the Java string data. */
1778 (*env)->ReleaseStringUTFChars (env, (jstring) dump_file_object,
1779 c_argument);
1780 }
1781
1782 /* Delete local references to objects that are no longer needed. */
1783 ANDROID_DELETE_LOCAL_REF (argv);
1784 ANDROID_DELETE_LOCAL_REF (dump_file_object);
1785
1786 android_emacs_init (nelements, c_argv, dump_file);
1711 /* android_emacs_init should never return. */ 1787 /* android_emacs_init should never return. */
1712 emacs_abort (); 1788 emacs_abort ();
1713} 1789}
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/>. */
38#include "lisp.h" 38#include "lisp.h"
39#endif 39#endif
40 40
41/* This must be used in every symbol declaration to export it to the 41extern bool android_init_gui;
42 JNI Emacs wrapper. */
43#define ANDROID_EXPORT __attribute__ ((visibility ("default")))
44
45extern bool ANDROID_EXPORT android_init_gui;
46extern int ANDROID_EXPORT android_emacs_init (int, char **);
47 42
48#ifndef ANDROID_STUBIFY 43#ifndef ANDROID_STUBIFY
49 44
45extern int android_emacs_init (int, char **, char *);
50extern int android_select (int, fd_set *, fd_set *, fd_set *, 46extern int android_select (int, fd_set *, fd_set *, fd_set *,
51 struct timespec *); 47 struct timespec *);
52 48
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)
1104void 1104void
1105init_androidfont (void) 1105init_androidfont (void)
1106{ 1106{
1107 if (!android_init_gui)
1108 return;
1109
1107 android_init_font_driver (); 1110 android_init_font_driver ();
1108 android_init_font_spec (); 1111 android_init_font_spec ();
1109 android_init_font_metrics (); 1112 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)
240 jobject tem; 240 jobject tem;
241 jmethodID make_clipboard; 241 jmethodID make_clipboard;
242 242
243 if (!android_init_gui)
244 return;
245
243 android_init_emacs_clipboard (); 246 android_init_emacs_clipboard ();
244 247
245 make_clipboard = clipboard_class.make_clipboard; 248 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)
875 } 875 }
876} 876}
877 877
878/* This function returns the Emacs executable. */ 878/* This function returns the Emacs executable. DUMP_FILE is ignored
879 outside of Android. Otherwise, it is the name of the dump file to
880 use, or NULL if Emacs should look for a ``--dump-file'' argument
881 instead. */
882
879static char * 883static char *
880load_pdump (int argc, char **argv) 884load_pdump (int argc, char **argv, char *dump_file)
881{ 885{
882#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY 886#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
883 char *dump_file = NULL;
884 int skip_args = 0, result; 887 int skip_args = 0, result;
885 888
886 while (skip_args < argc - 1) 889 while (skip_args < argc - 1)
887 { 890 {
888 if (argmatch (argv, argc, "-dump-file", "--dump-file", 6, 891 if (argmatch (argv, argc, "-dump-file", "--dump-file",
889 &dump_file, &skip_args) 892 6, &dump_file, &skip_args)
890 || argmatch (argv, argc, "--", NULL, 2, NULL, &skip_args)) 893 || argmatch (argv, argc, "--", NULL, 2, NULL,
894 &skip_args))
891 break; 895 break;
892 skip_args++; 896 skip_args++;
893 } 897 }
@@ -933,7 +937,7 @@ load_pdump (int argc, char **argv)
933 937
934 /* Look for an explicitly-specified dump file. */ 938 /* Look for an explicitly-specified dump file. */
935 const char *path_exec = PATH_EXEC; 939 const char *path_exec = PATH_EXEC;
936 char *dump_file = NULL; 940 dump_file = NULL;
937 int skip_args = 0; 941 int skip_args = 0;
938 while (skip_args < argc - 1) 942 while (skip_args < argc - 1)
939 { 943 {
@@ -1276,7 +1280,7 @@ maybe_load_seccomp (int argc, char **argv)
1276 1280
1277#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY 1281#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
1278int 1282int
1279android_emacs_init (int argc, char **argv) 1283android_emacs_init (int argc, char **argv, char *dump_file)
1280#else 1284#else
1281int 1285int
1282main (int argc, char **argv) 1286main (int argc, char **argv)
@@ -1286,6 +1290,12 @@ main (int argc, char **argv)
1286 for pointers. */ 1290 for pointers. */
1287 void *stack_bottom_variable; 1291 void *stack_bottom_variable;
1288 int old_argc; 1292 int old_argc;
1293#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
1294 char *dump_file;
1295
1296 /* This is just a dummy argument used to avoid extra defines. */
1297 dump_file = NULL;
1298#endif
1289 1299
1290 /* First, check whether we should apply a seccomp filter. This 1300 /* First, check whether we should apply a seccomp filter. This
1291 should come at the very beginning to allow the filter to protect 1301 should come at the very beginning to allow the filter to protect
@@ -1415,7 +1425,7 @@ main (int argc, char **argv)
1415 1425
1416#ifdef HAVE_PDUMPER 1426#ifdef HAVE_PDUMPER
1417 if (attempt_load_pdump) 1427 if (attempt_load_pdump)
1418 initial_emacs_executable = load_pdump (argc, argv); 1428 initial_emacs_executable = load_pdump (argc, argv, dump_file);
1419#else 1429#else
1420 ptrdiff_t bufsize; 1430 ptrdiff_t bufsize;
1421 initial_emacs_executable = find_emacs_executable (argv[0], &bufsize); 1431 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)
729void 729void
730init_sfntfont_android (void) 730init_sfntfont_android (void)
731{ 731{
732 if (!android_init_gui)
733 return;
734
732 /* Make sure to pick the right Sans Serif font depending on what 735 /* Make sure to pick the right Sans Serif font depending on what
733 version of Android the device is running. */ 736 version of Android the device is running. */
734#if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL 737#if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL