aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-09-03 10:04:44 +0800
committerPo Lu2023-09-03 10:05:15 +0800
commit4debb110d70691a405a50272b3ca5d0a264e0010 (patch)
treeb6b3fa743030a6b31e1f15beaf246d78d85418bb
parent8ecc73f47a7d5473d0e3f070d85051fc85580f9d (diff)
downloademacs-4debb110d70691a405a50272b3ca5d0a264e0010.tar.gz
emacs-4debb110d70691a405a50272b3ca5d0a264e0010.zip
Move Android port internals documentation to admin/notes
* admin/notes/java: New file. Move most of its contents from README, and introduce a section on compatibility. * java/README: Move internals to admin/notes/java.
-rw-r--r--admin/notes/java1097
-rw-r--r--java/README1027
2 files changed, 1100 insertions, 1024 deletions
diff --git a/admin/notes/java b/admin/notes/java
new file mode 100644
index 00000000000..125ac0aad67
--- /dev/null
+++ b/admin/notes/java
@@ -0,0 +1,1097 @@
1Installation instructions for Android
2Copyright (C) 2023 Free Software Foundation, Inc.
3See the end of the file for license conditions.
4
5
6
7OVERVIEW OF JAVA
8
9Emacs developers do not know Java, and there is no reason they should
10have to. Thus, the code in this directory is confined to what is
11strictly necessary to support Emacs, and only uses a subset of Java
12written in a way that is easily understandable to C programmers.
13
14Java is required because the entire Android runtime is based around
15Java, and there is no way to write an Android program which runs
16without Java.
17
18This text exists to prime other Emacs developers, already familar with
19C, on the basic architecture of the Android port, and to teach them
20how to read and write the Java code found in this directory.
21
22Java is an object oriented language with automatic memory management
23compiled down to bytecode, which is then subject to interpretation by
24a Java virtual machine.
25
26What that means, is that:
27
28struct emacs_window
29{
30 int some_fields;
31 int of_emacs_window;
32};
33
34static void
35do_something_with_emacs_window (struct emacs_window *a, int n)
36{
37 a->some_fields = a->of_emacs_window + n;
38}
39
40would be written:
41
42public class EmacsWindow
43{
44 public int someFields;
45 public int ofEmacsWindow;
46
47 public void
48 doSomething (int n)
49 {
50 someFields = ofEmacsWindow + n;
51 }
52}
53
54and instead of doing:
55
56do_something_with_emacs_window (my_window, 1);
57
58you say:
59
60myWindow.doSomething (1);
61
62In addition to functions associated with an object of a given class
63(such as EmacsWindow), Java also has two other kinds of functions.
64
65The first are so-called ``static'' functions (the static means
66something entirely different from what it does in C.)
67
68A static function, while still having to be defined within a class,
69can be called without any object. Instead of the object, you write
70the name of the Java class within which it is defined. For example,
71the following C code:
72
73int
74multiply_a_with_b_and_then_add_c (int a, int b, int c)
75{
76 return a * b + c;
77}
78
79would be:
80
81public class EmacsSomething
82{
83 public static int
84 multiplyAWithBAndThenAddC (int a, int b, int c)
85 {
86 return a * b + c;
87 }
88};
89
90Then, instead of calling:
91
92int foo;
93
94foo = multiply_a_with_b_then_add_c (1, 2, 3);
95
96you say:
97
98int foo;
99
100foo = EmacsSomething.multiplyAWithBAndThenAddC (1, 2, 3);
101
102In Java, ``static'' does not mean that the function is only used
103within its compilation unit! Instead, the ``private'' qualifier is
104used to mean more or less the same thing:
105
106static void
107this_procedure_is_only_used_within_this_file (void)
108{
109 do_something ();
110}
111
112becomes
113
114public class EmacsSomething
115{
116 private static void
117 thisProcedureIsOnlyUsedWithinThisClass ()
118 {
119
120 }
121}
122
123the other kind are called ``constructors''. They are functions that
124must be called to allocate memory to hold a class:
125
126public class EmacsFoo
127{
128 int bar;
129
130 public
131 EmacsFoo (int tokenA, int tokenB)
132 {
133 bar = tokenA + tokenB;
134 }
135}
136
137now, the following statement:
138
139EmacsFoo foo;
140
141foo = new EmacsFoo (1, 2);
142
143becomes more or less equivalent to the following C code:
144
145struct emacs_foo
146{
147 int bar;
148};
149
150struct emacs_foo *
151make_emacs_foo (int token_a, int token_b)
152{
153 struct emacs_foo *foo;
154
155 foo = xmalloc (sizeof *foo);
156 foo->bar = token_a + token_b;
157
158 return foo;
159}
160
161/* ... */
162
163struct emacs_foo *foo;
164
165foo = make_emacs_foo (1, 2);
166
167A class may have any number of constructors, or no constructors at
168all, in which case the compiler inserts an empty constructor.
169
170
171
172Sometimes, you will see Java code that looks like this:
173
174 allFiles = filesDirectory.listFiles (new FileFilter () {
175 @Override
176 public boolean
177 accept (File file)
178 {
179 return (!file.isDirectory ()
180 && file.getName ().endsWith (".pdmp"));
181 }
182 });
183
184This is Java's version of GCC's nested function extension. The major
185difference is that the nested function may still be called even after
186it goes out of scope, and always retains a reference to the class and
187local variables around where it was called.
188
189Being an object-oriented language, Java also allows defining that a
190class ``extends'' another class. The following C code:
191
192struct a
193{
194 long thirty_two;
195};
196
197struct b
198{
199 struct a a;
200 long long sixty_four;
201};
202
203extern void do_something (struct a *);
204
205void
206my_function (struct b *b)
207{
208 do_something (&b->a);
209}
210
211is roughly equivalent to the following Java code, split into two
212files:
213
214 A.java
215
216public class A
217{
218 int thirtyTwo;
219
220 public void
221 doSomething ()
222 {
223 etcEtcEtc ();
224 }
225};
226
227 B.java
228
229public class B extends A
230{
231 long sixty_four;
232
233 public static void
234 myFunction (B b)
235 {
236 b.doSomething ();
237 }
238}
239
240the Java runtime has transformed the call to ``b.doSomething'' to
241``((A) b).doSomething''.
242
243However, Java also allows overriding this behavior, by specifying the
244@Override keyword:
245
246public class B extends A
247{
248 long sixty_four;
249
250 @Override
251 public void
252 doSomething ()
253 {
254 Something.doSomethingTwo ();
255 super.doSomething ();
256 }
257}
258
259now, any call to ``doSomething'' on a ``B'' created using ``new B ()''
260will end up calling ``Something.doSomethingTwo'', before calling back
261to ``A.doSomething''. This override also applies in reverse; that is
262to say, even if you write:
263
264 ((A) b).doSomething ();
265
266B's version of doSomething will still be called, if ``b'' was created
267using ``new B ()''.
268
269This mechanism is used extensively throughout the Java language and
270Android windowing APIs.
271
272Elsewhere, you will encounter Java code that defines arrays:
273
274public class EmacsFrobinicator
275{
276 public static void
277 emacsFrobinicate (int something)
278 {
279 int[] primesFromSomething;
280
281 primesFromSomething = new int[numberOfPrimes];
282 /* ... */
283 }
284}
285
286Java arrays are similar to C arrays in that they can not grow. But
287they are very much unlike C arrays in that they are always references
288(as opposed to decaying into pointers in only some situations), and
289contain information about their length.
290
291If another function named ``frobinicate1'' takes an array as an
292argument, then it need not take the length of the array.
293
294Instead, it may simply iterate over the array like so:
295
296int i, k;
297
298for (i = 0; i < array.length; ++i)
299 {
300 k = array[i];
301
302 Whatever.doSomethingWithK (k);
303 }
304
305The syntax used to define arrays is also slightly different. As
306arrays are always references, there is no way for you to tell the
307runtime to allocate an array of size N in a structure (class.)
308
309Instead, if you need an array of that size, you must declare a field
310with the type of the array, and allocate the array inside the class's
311constructor, like so:
312
313public class EmacsArrayContainer
314{
315 public int[] myArray;
316
317 public
318 EmacsArrayContainer ()
319 {
320 myArray = new array[10];
321 }
322}
323
324while in C, you could just have written:
325
326struct emacs_array_container
327{
328 int my_array[10];
329};
330
331or, possibly even better,
332
333typedef int emacs_array_container[10];
334
335Alas, Java has no equivalent of `typedef'.
336
337Like in C, Java string literals are delimited by double quotes.
338Unlike C, however, strings are not NULL-terminated arrays of
339characters, but a distinct type named ``String''. They store their
340own length, characters in Java's 16-bit ``char'' type, and are capable
341of holding NULL bytes.
342
343Instead of writing:
344
345wchar_t character;
346extern char *s;
347size_t s;
348
349 for (/* determine n, s in a loop. */)
350 s += mbstowc (&character, s, n);
351
352or:
353
354const char *byte;
355
356for (byte = my_string; *byte; ++byte)
357 /* do something with *byte. */;
358
359or perhaps even:
360
361size_t length, i;
362char foo;
363
364length = strlen (my_string);
365
366for (i = 0; i < length; ++i)
367 foo = my_string[i];
368
369you write:
370
371char foo;
372int i;
373
374for (i = 0; i < myString.length (); ++i)
375 foo = myString.charAt (0);
376
377Java also has stricter rules on what can be used as a truth value in a
378conditional. While in C, any non-zero value is true, Java requires
379that every truth value be of the boolean type ``boolean''.
380
381What this means is that instead of simply writing:
382
383 if (foo || bar)
384
385where foo can either be 1 or 0, and bar can either be NULL or a
386pointer to something, you must explicitly write:
387
388 if (foo != 0 || bar != null)
389
390in Java.
391
392JAVA NATIVE INTERFACE
393
394Java also provides an interface for C code to interface with Java.
395
396C functions exported from a shared library become static Java
397functions within a class, like so:
398
399public class EmacsNative
400{
401 /* Obtain the fingerprint of this build of Emacs. The fingerprint
402 can be used to determine the dump file name. */
403 public static native String getFingerprint ();
404
405 /* Set certain parameters before initializing Emacs.
406
407 assetManager must be the asset manager associated with the
408 context that is loading Emacs. It is saved and remains for the
409 remainder the lifetime of the Emacs process.
410
411 filesDir must be the package's data storage location for the
412 current Android user.
413
414 libDir must be the package's data storage location for native
415 libraries. It is used as PATH.
416
417 cacheDir must be the package's cache directory. It is used as
418 the `temporary-file-directory'.
419
420 pixelDensityX and pixelDensityY are the DPI values that will be
421 used by Emacs.
422
423 classPath must be the classpath of this app_process process, or
424 NULL.
425
426 emacsService must be the EmacsService singleton, or NULL. */
427 public static native void setEmacsParams (AssetManager assetManager,
428 String filesDir,
429 String libDir,
430 String cacheDir,
431 float pixelDensityX,
432 float pixelDensityY,
433 String classPath,
434 EmacsService emacsService);
435}
436
437Where the corresponding C functions are located in android.c, and
438loaded by the special invocation:
439
440 static
441 {
442 System.loadLibrary ("emacs");
443 };
444
445where ``static'' defines a section of code which will be run upon the
446object (containing class) being loaded. This is like:
447
448 __attribute__((constructor))
449
450on systems where shared object constructors are supported.
451
452See http://docs.oracle.com/en/java/javase/19/docs/specs/jni/intro.html
453for more details.
454
455
456
457OVERVIEW OF ANDROID
458
459When the Android system starts an application, it does not actually
460call the application's ``main'' function. It may not even start the
461application's process if one is already running.
462
463Instead, Android is organized around components. When the user opens
464the ``Emacs'' icon, the Android system looks up and starts the
465component associated with the ``Emacs'' icon. In this case, the
466component is called an activity, and is declared in
467the AndroidManifest.xml in this directory:
468
469 <activity android:name="org.gnu.emacs.EmacsActivity"
470 android:launchMode="singleTop"
471 android:windowSoftInputMode="adjustResize"
472 android:exported="true"
473 android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
474 <intent-filter>
475 <action android:name="android.intent.action.MAIN" />
476 <category android:name="android.intent.category.DEFAULT" />
477 <category android:name="android.intent.category.LAUNCHER" />
478 </intent-filter>
479 </activity>
480
481This tells Android to start the activity defined in ``EmacsActivity''
482(defined in org/gnu/emacs/EmacsActivity.java), a class extending the
483Android class ``Activity''.
484
485To do so, the Android system creates an instance of ``EmacsActivity''
486and the window system window associated with it, and eventually calls:
487
488 Activity activity;
489
490 activity.onCreate (...);
491
492But which ``onCreate'' is really called?
493It is actually the ``onCreate'' defined in EmacsActivity.java, as
494it overrides the ``onCreate'' defined in Android's own Activity class:
495
496 @Override
497 public void
498 onCreate (Bundle savedInstanceState)
499 {
500 FrameLayout.LayoutParams params;
501 Intent intent;
502
503Then, this is what happens step-by-step within the ``onCreate''
504function:
505
506 /* See if Emacs should be started with -Q. */
507 intent = getIntent ();
508 EmacsService.needDashQ
509 = intent.getBooleanExtra ("org.gnu.emacs.START_DASH_Q",
510 false);
511
512Here, Emacs obtains the intent (a request to start a component) which
513was used to start Emacs, and sets a special flag if it contains a
514request for Emacs to start with the ``-Q'' command-line argument.
515
516 /* Set the theme to one without a title bar. */
517
518 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
519 setTheme (android.R.style.Theme_DeviceDefault_NoActionBar);
520 else
521 setTheme (android.R.style.Theme_NoTitleBar);
522
523Next, Emacs sets an appropriate theme for the activity's associated
524window decorations.
525
526 params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
527 LayoutParams.MATCH_PARENT);
528
529 /* Make the frame layout. */
530 layout = new FrameLayout (this);
531 layout.setLayoutParams (params);
532
533 /* Set it as the content view. */
534 setContentView (layout);
535
536Then, Emacs creates a ``FrameLayout'', a widget that holds a single
537other widget, and makes it the activity's ``content view''.
538
539The activity itself is a ``FrameLayout'', so the ``layout parameters''
540here apply to the FrameLayout itself, and not its children.
541
542 /* Maybe start the Emacs service if necessary. */
543 EmacsService.startEmacsService (this);
544
545And after that, Emacs calls the static function ``startEmacsService'',
546defined in the class ``EmacsService''. This starts the Emacs service
547component if necessary.
548
549 /* Add this activity to the list of available activities. */
550 EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
551
552 super.onCreate (savedInstanceState);
553
554Finally, Emacs registers that this activity is now ready to receive
555top-level frames (windows) created from Lisp.
556
557Activities come and go, but Emacs has to stay running in the mean
558time. Thus, Emacs also defines a ``service'', which is a long-running
559component that the Android system allows to run in the background.
560
561Let us go back and review the definition of ``startEmacsService'':
562
563 public static void
564 startEmacsService (Context context)
565 {
566 if (EmacsService.SERVICE == null)
567 {
568 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
569 /* Start the Emacs service now. */
570 context.startService (new Intent (context,
571 EmacsService.class));
572 else
573 /* Display the permanant notification and start Emacs as a
574 foreground service. */
575 context.startForegroundService (new Intent (context,
576 EmacsService.class));
577 }
578 }
579
580If ``EmacsService.SERVICE'' does not yet exist, what this does is to
581tell the ``context'' (the equivalent of an Xlib Display *) to start a
582service defined by the class ``EmacsService''. Eventually, this
583results in ``EmacsService.onCreate'' being called:
584
585 @Override
586 public void
587 onCreate ()
588 {
589 AssetManager manager;
590 Context app_context;
591 String filesDir, libDir, cacheDir, classPath;
592 double pixelDensityX;
593 double pixelDensityY;
594
595Here is what this function does, step-by-step:
596
597 SERVICE = this;
598
599First, it sets the special static variable ``SERVICE'' to ``this'',
600which is a pointer to the ``EmacsService' object that was created.
601
602 handler = new Handler (Looper.getMainLooper ());
603
604Next, it creates a ``Handler'' object for the ``main looper''.
605This is a helper structure which allows executing code on the Android
606user interface thread.
607
608 manager = getAssets ();
609 app_context = getApplicationContext ();
610 metrics = getResources ().getDisplayMetrics ();
611 pixelDensityX = metrics.xdpi;
612 pixelDensityY = metrics.ydpi;
613
614Finally, it obtains:
615
616 - the asset manager, which is used to retrieve assets packaged
617 into the Emacs application package.
618
619 - the application context, used to obtain application specific
620 information.
621
622 - the display metrics, and from them, the X and Y densities in dots
623 per inch.
624
625Then, inside a ``try'' block:
626
627 try
628 {
629 /* Configure Emacs with the asset manager and other necessary
630 parameters. */
631 filesDir = app_context.getFilesDir ().getCanonicalPath ();
632 libDir = getLibraryDirectory ();
633 cacheDir = app_context.getCacheDir ().getCanonicalPath ();
634
635It obtains the names of the Emacs home, shared library, and temporary
636file directories.
637
638 /* Now provide this application's apk file, so a recursive
639 invocation of app_process (through android-emacs) can
640 find EmacsNoninteractive. */
641 classPath = getApkFile ();
642
643The name of the Emacs application package.
644
645 Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
646 + ", libDir = " + libDir + ", and classPath = " + classPath);
647
648Prints a debug message to the Android system log with this
649information.
650
651 EmacsNative.setEmacsParams (manager, filesDir, libDir,
652 cacheDir, (float) pixelDensityX,
653 (float) pixelDensityY,
654 classPath, this);
655
656And calls the native function ``setEmacsParams'' (defined in
657android.c) to configure Emacs with this information.
658
659 /* Start the thread that runs Emacs. */
660 thread = new EmacsThread (this, needDashQ);
661 thread.start ();
662
663Then, it allocates an ``EmacsThread'' object, and starts that thread.
664Inside that thread is where Emacs's C code runs.
665
666 }
667 catch (IOException exception)
668 {
669 EmacsNative.emacsAbort ();
670 return;
671
672And here is the purpose of the ``try'' block. Functions related to
673file names in Java will signal errors of various types upon failure.
674
675This ``catch'' block means that the Java virtual machine will abort
676execution of the contents of the ``try'' block as soon as an error of
677type ``IOException'' is encountered, and begin executing the contents
678of the ``catch'' block.
679
680Any failure of that type here is a crash, and
681``EmacsNative.emacsAbort'' is called to quickly abort the process to
682get a useful backtrace.
683 }
684 }
685
686Now, let us look at the definition of the class ``EmacsThread'', found
687in org/gnu/emacs/EmacsThread.java:
688
689public class EmacsThread extends Thread
690{
691 /* Whether or not Emacs should be started -Q. */
692 private boolean startDashQ;
693
694 public
695 EmacsThread (EmacsService service, boolean startDashQ)
696 {
697 super ("Emacs main thread");
698 this.startDashQ = startDashQ;
699 }
700
701 @Override
702 public void
703 run ()
704 {
705 String args[];
706
707 if (!startDashQ)
708 args = new String[] { "libandroid-emacs.so", };
709 else
710 args = new String[] { "libandroid-emacs.so", "-Q", };
711
712 /* Run the native code now. */
713 EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
714 }
715};
716
717The class itself defines a single field, ``startDashQ'', a constructor
718with an unused argument of the type ``EmacsService'' (which is useful
719while debugging) and a flag ``startDashQ'', and a single function
720``run'', overriding the same function in the class ``Thread''.
721
722When ``thread.start'' is called, the Java virtual machine creates a
723new thread, and then calls the function ``run'' within that thread.
724
725This function then computes a suitable argument vector, and calls
726``EmacsNative.initEmacs'' (defined in android.c), which then calls a
727modified version of the regular Emacs ``main'' function.
728
729At that point, Emacs initialization proceeds as usual:
730Vinitial_window_system is set, loadup.el calls `normal-top-level',
731which calls `command-line', and finally
732`window-system-initialization', which initializes the `android'
733terminal interface as usual.
734
735What happens here is the same as on other platforms. Now, here is
736what happens when the initial frame is created: Fx_create_frame calls
737`android_create_frame_window' to create a top level window:
738
739static void
740android_create_frame_window (struct frame *f)
741{
742 struct android_set_window_attributes attributes;
743 enum android_window_value_mask attribute_mask;
744
745 attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f);
746 attribute_mask = ANDROID_CW_BACK_PIXEL;
747
748 block_input ();
749 FRAME_ANDROID_WINDOW (f)
750 = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
751 f->left_pos,
752 f->top_pos,
753 FRAME_PIXEL_WIDTH (f),
754 FRAME_PIXEL_HEIGHT (f),
755 attribute_mask, &attributes);
756 unblock_input ();
757}
758
759This calls the function `android_create_window' with some arguments
760whose meanings are identical to the arguments to `XCreateWindow'.
761
762Here is the definition of `android_create_window', in android.c:
763
764android_window
765android_create_window (android_window parent, int x, int y,
766 int width, int height,
767 enum android_window_value_mask value_mask,
768 struct android_set_window_attributes *attrs)
769{
770 static jclass class;
771 static jmethodID constructor;
772 jobject object, parent_object, old;
773 android_window window;
774 android_handle prev_max_handle;
775 bool override_redirect;
776
777What does it do? First, some context:
778
779At any time, there can be at most 65535 Java objects referred to by
780the rest of Emacs through the Java native interface. Each such object
781is assigned a ``handle'' (similar to an XID on X) and given a unique
782type. The function `android_resolve_handle' returns the JNI `jobject'
783associated with a given handle.
784
785 parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
786
787Here, it is being used to look up the `jobject' associated with the
788`parent' handle.
789
790 prev_max_handle = max_handle;
791 window = android_alloc_id ();
792
793Next, `max_handle' is saved, and a new handle is allocated for
794`window'.
795
796 if (!window)
797 error ("Out of window handles!");
798
799An error is signalled if Emacs runs out of available handles.
800
801 if (!class)
802 {
803 class = (*android_java_env)->FindClass (android_java_env,
804 "org/gnu/emacs/EmacsWindow");
805 assert (class != NULL);
806
807Then, if this initialization has not yet been completed, Emacs
808proceeds to find the Java class named ``EmacsWindow''.
809
810 constructor
811 = (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
812 "(SLorg/gnu/emacs/EmacsWindow;"
813 "IIIIZ)V");
814 assert (constructor != NULL);
815
816And it tries to look up the constructor, which should take seven
817arguments:
818
819 S - a short. (the handle ID)
820 Lorg/gnu/Emacs/EmacsWindow; - an instance of the EmacsWindow
821 class. (the parent)
822 IIII - four ints. (the window geometry.)
823 Z - a boolean. (whether or not the
824 window is override-redirect; see
825 XChangeWindowAttributes.)
826
827 old = class;
828 class = (*android_java_env)->NewGlobalRef (android_java_env, class);
829 (*android_java_env)->ExceptionClear (android_java_env);
830 ANDROID_DELETE_LOCAL_REF (old);
831
832Next, it saves a global reference to the class and deletes the local
833reference. Global references will never be deallocated by the Java
834virtual machine as long as they still exist.
835
836 if (!class)
837 memory_full (0);
838 }
839
840 /* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
841 creation time. */
842 override_redirect = ((value_mask
843 & ANDROID_CW_OVERRIDE_REDIRECT)
844 && attrs->override_redirect);
845
846 object = (*android_java_env)->NewObject (android_java_env, class,
847 constructor, (jshort) window,
848 parent_object, (jint) x, (jint) y,
849 (jint) width, (jint) height,
850 (jboolean) override_redirect);
851
852Then, it creates an instance of the ``EmacsWindow'' class with the
853appropriate arguments and previously determined constructor.
854
855 if (!object)
856 {
857 (*android_java_env)->ExceptionClear (android_java_env);
858
859 max_handle = prev_max_handle;
860 memory_full (0);
861
862If creating the object fails, Emacs clears the ``pending exception''
863and signals that it is out of memory.
864 }
865
866 android_handles[window].type = ANDROID_HANDLE_WINDOW;
867 android_handles[window].handle
868 = (*android_java_env)->NewGlobalRef (android_java_env,
869 object);
870 (*android_java_env)->ExceptionClear (android_java_env);
871 ANDROID_DELETE_LOCAL_REF (object);
872
873Otherwise, it associates a new global reference to the object with the
874handle, and deletes the local reference returned from the JNI
875NewObject function.
876
877 if (!android_handles[window].handle)
878 memory_full (0);
879
880If allocating the global reference fails, Emacs signals that it is out
881of memory.
882
883 android_change_window_attributes (window, value_mask, attrs);
884 return window;
885
886Otherwise, it applies the specified window attributes and returns the
887handle of the new window.
888}
889
890
891
892DRAWABLES, CURSORS AND HANDLES
893
894Each widget created by Emacs corresponds to a single ``window'', which
895has its own backing store. This arrangement is quite similar to X.
896
897C code does not directly refer to the EmacsView widgets that implement
898the UI logic behind windows. Instead, its handles refer to
899EmacsWindow structures, which contain the state necessary to interact
900with the widgets in an orderly and synchronized manner.
901
902Like X, both pixmaps and windows are drawable resources, and the same
903graphics operations can be applied to both. Thus, a separate
904EmacsPixmap structure is used to wrap around Android Bitmap resources,
905and the Java-level graphics operation functions are capable of
906operating on them both.
907
908Finally, graphics contexts are maintained on both the C and Java
909levels; the C state recorded in `struct android_gc' is kept in sync
910with the Java state in the GContext handle's corresponding EmacsGC
911structure, and cursors are used through handles that refer to
912EmacsCursor structures that hold system PointerIcons.
913
914In all cases, the interfaces provided are identical to X.
915
916
917
918EVENT LOOP
919
920In a typical Android application, the event loop is managed by the
921operating system, and callbacks (implemented through overriding
922separate functions in widgets) are run by the event loop wherever
923necessary. The thread which runs the event loop is also the only
924thread capable of creating and manipulating widgets and activities,
925and is referred to as the ``UI thread''.
926
927These callbacks are used by Emacs to write representations of X-like
928events to a separate event queue, which are then read from Emacs's own
929event loop running in a separate thread. This is accomplished through
930replacing `select' by a function which waits for the event queue to be
931occupied, in addition to any file descriptors that `select' would
932normally wait for.
933
934Conversely, Emacs's event loop sometimes needs to send events to the
935UI thread. These events are implemented as tiny fragments of code,
936which are run as they are received by the main thread.
937
938A typical example is `displayToast', which is implemented in
939EmacsService.java:
940
941 public void
942 displayToast (final String string)
943 {
944 runOnUiThread (new Runnable () {
945 @Override
946 public void
947 run ()
948 {
949 Toast toast;
950
951 toast = Toast.makeText (getApplicationContext (),
952 string, Toast.LENGTH_SHORT);
953 toast.show ();
954 }
955 });
956 }
957
958Here, the variable `string' is used by a nested function. This nested
959function contains a copy of that variable, and is run on the main
960thread using the function `runOnUiThread', in order to display a short
961status message on the display.
962
963When Emacs needs to wait for the nested function to finish, it uses a
964mechanism implemented in `syncRunnable'. This mechanism first calls a
965deadlock avoidance mechanism, then runs a nested function on the UI
966thread, which is expected to signal itself as a condition variable
967upon completion. It is typically used to allocate resources that can
968only be allocated from the UI thread, or to obtain non-thread-safe
969information. The following function is an example; it returns a new
970EmacsView widget corresponding to the provided window:
971
972 public EmacsView
973 getEmacsView (final EmacsWindow window, final int visibility,
974 final boolean isFocusedByDefault)
975 {
976 Runnable runnable;
977 final EmacsHolder<EmacsView> view;
978
979 view = new EmacsHolder<EmacsView> ();
980
981 runnable = new Runnable () {
982 public void
983 run ()
984 {
985 synchronized (this)
986 {
987 view.thing = new EmacsView (window);
988 view.thing.setVisibility (visibility);
989
990 /* The following function is only present on Android 26
991 or later. */
992 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
993 view.thing.setFocusedByDefault (isFocusedByDefault);
994
995 notify ();
996 }
997 }
998 };
999
1000 syncRunnable (runnable);
1001 return view.thing;
1002 }
1003
1004As no value can be directly returned from the nested function, a
1005separate container object is used to hold the result after the
1006function finishes execution. Note the type name inside the angle
1007brackets: this type is substituted into the class definition as it is
1008used; a definition such as:
1009
1010public class Foo<T>
1011{
1012 T bar;
1013};
1014
1015can not be used alone:
1016
1017 Foo holder; /* Error! */
1018
1019but must have a type specified:
1020
1021 Foo<Object> holder;
1022
1023in which case the effective definition is:
1024
1025public class Foo
1026{
1027 Object bar;
1028};
1029
1030
1031
1032COMPATIBILITY
1033
1034There are three variables set within every Android application that
1035extert influence over the set of Android systems it supports, and the
1036measures it must take to function faithfully on each of those systems:
1037the minimum API level, compile SDK version and target API level.
1038
1039The minimum API level is the earliest version of Android that is
1040permitted to install and run the application. For Emacs, this is
1041established by detecting the __ANDROID_API__ preprocessor macro
1042defined within the Android C compiler.
1043
1044Before Java code executes any Android API calls that are not present
1045within Android 2.2 (API level 8), the lowest API level supported by
1046Emacs as a whole, it must first check the value of the:
1047
1048 Build.VERSION.SDK_INT
1049
1050variable, which is always set to the API level of the system Emacs is
1051presently installed within. For example, before calling
1052`dispatchKeyEventFromInputMethod', a function absent from Android 6.0
1053(API level 23) or earlier, check:
1054
1055 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
1056 view.imManager.dispatchKeyEventFromInputMethod (view, key);
1057 else
1058 {
1059
1060where `N' is a constant defined to 24.
1061
1062The compile SDK version is the version of the Android SDK headers Java
1063code is compiled against. Because Java does not provide conditional
1064compilation constructs, Emacs can't be compiled with any version of
1065these headers other than the version mentioned in `java/INSTALL', but
1066the headers used do not affect the set of supported systems provided
1067that the version checks illustrated above are performed where
1068necessary.
1069
1070The target API level is a number within java/AndroidManifest.xml.in
1071the system refers to when deciding whether to enable
1072backwards-incompatible modifications to the behavior of various system
1073APIs. For any given Android version, backwards incompatible changes
1074in that version will be disabled for applications whose target API
1075levels don't exceed its own.
1076
1077The target API should nevertheless be updated to match every major
1078Android update, as Google has stated their intentions to prohibit
1079users from installing applications targeting ``out-of-date'' versions
1080of Android, though this threat has hitherto been made good on.
1081
1082
1083
1084This file is part of GNU Emacs.
1085
1086GNU Emacs is free software: you can redistribute it and/or modify
1087it under the terms of the GNU General Public License as published by
1088the Free Software Foundation, either version 3 of the License, or
1089(at your option) any later version.
1090
1091GNU Emacs is distributed in the hope that it will be useful,
1092but WITHOUT ANY WARRANTY; without even the implied warranty of
1093MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1094GNU General Public License for more details.
1095
1096You should have received a copy of the GNU General Public License
1097along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
diff --git a/java/README b/java/README
index e518e9fbb2f..a909cdd22ef 100644
--- a/java/README
+++ b/java/README
@@ -22,1027 +22,6 @@ Please keep the Java code indented with tabs and formatted according
22to the rules for C code in the GNU coding standards. Always use 22to the rules for C code in the GNU coding standards. Always use
23C-style comments. 23C-style comments.
24 24
25====================================================================== 25Refer to the file `admin/notes/java' in the toplevel directory of the
26 26Emacs distribution or repository for specifics regarding writing Java
27OVERVIEW OF JAVA 27code for Emacs and the organization of the Android port.
28
29Emacs developers do not know Java, and there is no reason they should
30have to. Thus, the code in this directory is confined to what is
31strictly necessary to support Emacs, and only uses a subset of Java
32written in a way that is easily understandable to C programmers.
33
34Java is required because the entire Android runtime is based around
35Java, and there is no way to write an Android program which runs
36without Java.
37
38This text exists to prime other Emacs developers, already familar with
39C, on the basic architecture of the Android port, and to teach them
40how to read and write the Java code found in this directory.
41
42Java is an object oriented language with automatic memory management
43compiled down to bytecode, which is then subject to interpretation by
44a Java virtual machine.
45
46What that means, is that:
47
48struct emacs_window
49{
50 int some_fields;
51 int of_emacs_window;
52};
53
54static void
55do_something_with_emacs_window (struct emacs_window *a, int n)
56{
57 a->some_fields = a->of_emacs_window + n;
58}
59
60would be written:
61
62public class EmacsWindow
63{
64 public int someFields;
65 public int ofEmacsWindow;
66
67 public void
68 doSomething (int n)
69 {
70 someFields = ofEmacsWindow + n;
71 }
72}
73
74and instead of doing:
75
76do_something_with_emacs_window (my_window, 1);
77
78you say:
79
80myWindow.doSomething (1);
81
82In addition to functions associated with an object of a given class
83(such as EmacsWindow), Java also has two other kinds of functions.
84
85The first are so-called ``static'' functions (the static means
86something entirely different from what it does in C.)
87
88A static function, while still having to be defined within a class,
89can be called without any object. Instead of the object, you write
90the name of the Java class within which it is defined. For example,
91the following C code:
92
93int
94multiply_a_with_b_and_then_add_c (int a, int b, int c)
95{
96 return a * b + c;
97}
98
99would be:
100
101public class EmacsSomething
102{
103 public static int
104 multiplyAWithBAndThenAddC (int a, int b, int c)
105 {
106 return a * b + c;
107 }
108};
109
110Then, instead of calling:
111
112int foo;
113
114foo = multiply_a_with_b_then_add_c (1, 2, 3);
115
116you say:
117
118int foo;
119
120foo = EmacsSomething.multiplyAWithBAndThenAddC (1, 2, 3);
121
122In Java, ``static'' does not mean that the function is only used
123within its compilation unit! Instead, the ``private'' qualifier is
124used to mean more or less the same thing:
125
126static void
127this_procedure_is_only_used_within_this_file (void)
128{
129 do_something ();
130}
131
132becomes
133
134public class EmacsSomething
135{
136 private static void
137 thisProcedureIsOnlyUsedWithinThisClass ()
138 {
139
140 }
141}
142
143the other kind are called ``constructors''. They are functions that
144must be called to allocate memory to hold a class:
145
146public class EmacsFoo
147{
148 int bar;
149
150 public
151 EmacsFoo (int tokenA, int tokenB)
152 {
153 bar = tokenA + tokenB;
154 }
155}
156
157now, the following statement:
158
159EmacsFoo foo;
160
161foo = new EmacsFoo (1, 2);
162
163becomes more or less equivalent to the following C code:
164
165struct emacs_foo
166{
167 int bar;
168};
169
170struct emacs_foo *
171make_emacs_foo (int token_a, int token_b)
172{
173 struct emacs_foo *foo;
174
175 foo = xmalloc (sizeof *foo);
176 foo->bar = token_a + token_b;
177
178 return foo;
179}
180
181/* ... */
182
183struct emacs_foo *foo;
184
185foo = make_emacs_foo (1, 2);
186
187A class may have any number of constructors, or no constructors at
188all, in which case the compiler inserts an empty constructor.
189
190
191
192Sometimes, you will see Java code that looks like this:
193
194 allFiles = filesDirectory.listFiles (new FileFilter () {
195 @Override
196 public boolean
197 accept (File file)
198 {
199 return (!file.isDirectory ()
200 && file.getName ().endsWith (".pdmp"));
201 }
202 });
203
204This is Java's version of GCC's nested function extension. The major
205difference is that the nested function may still be called even after
206it goes out of scope, and always retains a reference to the class and
207local variables around where it was called.
208
209Being an object-oriented language, Java also allows defining that a
210class ``extends'' another class. The following C code:
211
212struct a
213{
214 long thirty_two;
215};
216
217struct b
218{
219 struct a a;
220 long long sixty_four;
221};
222
223extern void do_something (struct a *);
224
225void
226my_function (struct b *b)
227{
228 do_something (&b->a);
229}
230
231is roughly equivalent to the following Java code, split into two
232files:
233
234 A.java
235
236public class A
237{
238 int thirtyTwo;
239
240 public void
241 doSomething ()
242 {
243 etcEtcEtc ();
244 }
245};
246
247 B.java
248
249public class B extends A
250{
251 long sixty_four;
252
253 public static void
254 myFunction (B b)
255 {
256 b.doSomething ();
257 }
258}
259
260the Java runtime has transformed the call to ``b.doSomething'' to
261``((A) b).doSomething''.
262
263However, Java also allows overriding this behavior, by specifying the
264@Override keyword:
265
266public class B extends A
267{
268 long sixty_four;
269
270 @Override
271 public void
272 doSomething ()
273 {
274 Something.doSomethingTwo ();
275 super.doSomething ();
276 }
277}
278
279now, any call to ``doSomething'' on a ``B'' created using ``new B ()''
280will end up calling ``Something.doSomethingTwo'', before calling back
281to ``A.doSomething''. This override also applies in reverse; that is
282to say, even if you write:
283
284 ((A) b).doSomething ();
285
286B's version of doSomething will still be called, if ``b'' was created
287using ``new B ()''.
288
289This mechanism is used extensively throughout the Java language and
290Android windowing APIs.
291
292Elsewhere, you will encounter Java code that defines arrays:
293
294public class EmacsFrobinicator
295{
296 public static void
297 emacsFrobinicate (int something)
298 {
299 int[] primesFromSomething;
300
301 primesFromSomething = new int[numberOfPrimes];
302 /* ... */
303 }
304}
305
306Java arrays are similar to C arrays in that they can not grow. But
307they are very much unlike C arrays in that they are always references
308(as opposed to decaying into pointers in only some situations), and
309contain information about their length.
310
311If another function named ``frobinicate1'' takes an array as an
312argument, then it need not take the length of the array.
313
314Instead, it may simply iterate over the array like so:
315
316int i, k;
317
318for (i = 0; i < array.length; ++i)
319 {
320 k = array[i];
321
322 Whatever.doSomethingWithK (k);
323 }
324
325The syntax used to define arrays is also slightly different. As
326arrays are always references, there is no way for you to tell the
327runtime to allocate an array of size N in a structure (class.)
328
329Instead, if you need an array of that size, you must declare a field
330with the type of the array, and allocate the array inside the class's
331constructor, like so:
332
333public class EmacsArrayContainer
334{
335 public int[] myArray;
336
337 public
338 EmacsArrayContainer ()
339 {
340 myArray = new array[10];
341 }
342}
343
344while in C, you could just have written:
345
346struct emacs_array_container
347{
348 int my_array[10];
349};
350
351or, possibly even better,
352
353typedef int emacs_array_container[10];
354
355Alas, Java has no equivalent of `typedef'.
356
357Like in C, Java string literals are delimited by double quotes.
358Unlike C, however, strings are not NULL-terminated arrays of
359characters, but a distinct type named ``String''. They store their
360own length, characters in Java's 16-bit ``char'' type, and are capable
361of holding NULL bytes.
362
363Instead of writing:
364
365wchar_t character;
366extern char *s;
367size_t s;
368
369 for (/* determine n, s in a loop. */)
370 s += mbstowc (&character, s, n);
371
372or:
373
374const char *byte;
375
376for (byte = my_string; *byte; ++byte)
377 /* do something with *byte. */;
378
379or perhaps even:
380
381size_t length, i;
382char foo;
383
384length = strlen (my_string);
385
386for (i = 0; i < length; ++i)
387 foo = my_string[i];
388
389you write:
390
391char foo;
392int i;
393
394for (i = 0; i < myString.length (); ++i)
395 foo = myString.charAt (0);
396
397Java also has stricter rules on what can be used as a truth value in a
398conditional. While in C, any non-zero value is true, Java requires
399that every truth value be of the boolean type ``boolean''.
400
401What this means is that instead of simply writing:
402
403 if (foo || bar)
404
405where foo can either be 1 or 0, and bar can either be NULL or a
406pointer to something, you must explicitly write:
407
408 if (foo != 0 || bar != null)
409
410in Java.
411
412JAVA NATIVE INTERFACE
413
414Java also provides an interface for C code to interface with Java.
415
416C functions exported from a shared library become static Java
417functions within a class, like so:
418
419public class EmacsNative
420{
421 /* Obtain the fingerprint of this build of Emacs. The fingerprint
422 can be used to determine the dump file name. */
423 public static native String getFingerprint ();
424
425 /* Set certain parameters before initializing Emacs.
426
427 assetManager must be the asset manager associated with the
428 context that is loading Emacs. It is saved and remains for the
429 remainder the lifetime of the Emacs process.
430
431 filesDir must be the package's data storage location for the
432 current Android user.
433
434 libDir must be the package's data storage location for native
435 libraries. It is used as PATH.
436
437 cacheDir must be the package's cache directory. It is used as
438 the `temporary-file-directory'.
439
440 pixelDensityX and pixelDensityY are the DPI values that will be
441 used by Emacs.
442
443 classPath must be the classpath of this app_process process, or
444 NULL.
445
446 emacsService must be the EmacsService singleton, or NULL. */
447 public static native void setEmacsParams (AssetManager assetManager,
448 String filesDir,
449 String libDir,
450 String cacheDir,
451 float pixelDensityX,
452 float pixelDensityY,
453 String classPath,
454 EmacsService emacsService);
455}
456
457Where the corresponding C functions are located in android.c, and
458loaded by the special invocation:
459
460 static
461 {
462 System.loadLibrary ("emacs");
463 };
464
465where ``static'' defines a section of code which will be run upon the
466object (containing class) being loaded. This is like:
467
468 __attribute__((constructor))
469
470on systems where shared object constructors are supported.
471
472See http://docs.oracle.com/en/java/javase/19/docs/specs/jni/intro.html
473for more details.
474
475
476
477OVERVIEW OF ANDROID
478
479When the Android system starts an application, it does not actually
480call the application's ``main'' function. It may not even start the
481application's process if one is already running.
482
483Instead, Android is organized around components. When the user opens
484the ``Emacs'' icon, the Android system looks up and starts the
485component associated with the ``Emacs'' icon. In this case, the
486component is called an activity, and is declared in
487the AndroidManifest.xml in this directory:
488
489 <activity android:name="org.gnu.emacs.EmacsActivity"
490 android:launchMode="singleTop"
491 android:windowSoftInputMode="adjustResize"
492 android:exported="true"
493 android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
494 <intent-filter>
495 <action android:name="android.intent.action.MAIN" />
496 <category android:name="android.intent.category.DEFAULT" />
497 <category android:name="android.intent.category.LAUNCHER" />
498 </intent-filter>
499 </activity>
500
501This tells Android to start the activity defined in ``EmacsActivity''
502(defined in org/gnu/emacs/EmacsActivity.java), a class extending the
503Android class ``Activity''.
504
505To do so, the Android system creates an instance of ``EmacsActivity''
506and the window system window associated with it, and eventually calls:
507
508 Activity activity;
509
510 activity.onCreate (...);
511
512But which ``onCreate'' is really called?
513It is actually the ``onCreate'' defined in EmacsActivity.java, as
514it overrides the ``onCreate'' defined in Android's own Activity class:
515
516 @Override
517 public void
518 onCreate (Bundle savedInstanceState)
519 {
520 FrameLayout.LayoutParams params;
521 Intent intent;
522
523Then, this is what happens step-by-step within the ``onCreate''
524function:
525
526 /* See if Emacs should be started with -Q. */
527 intent = getIntent ();
528 EmacsService.needDashQ
529 = intent.getBooleanExtra ("org.gnu.emacs.START_DASH_Q",
530 false);
531
532Here, Emacs obtains the intent (a request to start a component) which
533was used to start Emacs, and sets a special flag if it contains a
534request for Emacs to start with the ``-Q'' command-line argument.
535
536 /* Set the theme to one without a title bar. */
537
538 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
539 setTheme (android.R.style.Theme_DeviceDefault_NoActionBar);
540 else
541 setTheme (android.R.style.Theme_NoTitleBar);
542
543Next, Emacs sets an appropriate theme for the activity's associated
544window decorations.
545
546 params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
547 LayoutParams.MATCH_PARENT);
548
549 /* Make the frame layout. */
550 layout = new FrameLayout (this);
551 layout.setLayoutParams (params);
552
553 /* Set it as the content view. */
554 setContentView (layout);
555
556Then, Emacs creates a ``FrameLayout'', a widget that holds a single
557other widget, and makes it the activity's ``content view''.
558
559The activity itself is a ``FrameLayout'', so the ``layout parameters''
560here apply to the FrameLayout itself, and not its children.
561
562 /* Maybe start the Emacs service if necessary. */
563 EmacsService.startEmacsService (this);
564
565And after that, Emacs calls the static function ``startEmacsService'',
566defined in the class ``EmacsService''. This starts the Emacs service
567component if necessary.
568
569 /* Add this activity to the list of available activities. */
570 EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
571
572 super.onCreate (savedInstanceState);
573
574Finally, Emacs registers that this activity is now ready to receive
575top-level frames (windows) created from Lisp.
576
577Activities come and go, but Emacs has to stay running in the mean
578time. Thus, Emacs also defines a ``service'', which is a long-running
579component that the Android system allows to run in the background.
580
581Let us go back and review the definition of ``startEmacsService'':
582
583 public static void
584 startEmacsService (Context context)
585 {
586 if (EmacsService.SERVICE == null)
587 {
588 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
589 /* Start the Emacs service now. */
590 context.startService (new Intent (context,
591 EmacsService.class));
592 else
593 /* Display the permanant notification and start Emacs as a
594 foreground service. */
595 context.startForegroundService (new Intent (context,
596 EmacsService.class));
597 }
598 }
599
600If ``EmacsService.SERVICE'' does not yet exist, what this does is to
601tell the ``context'' (the equivalent of an Xlib Display *) to start a
602service defined by the class ``EmacsService''. Eventually, this
603results in ``EmacsService.onCreate'' being called:
604
605 @Override
606 public void
607 onCreate ()
608 {
609 AssetManager manager;
610 Context app_context;
611 String filesDir, libDir, cacheDir, classPath;
612 double pixelDensityX;
613 double pixelDensityY;
614
615Here is what this function does, step-by-step:
616
617 SERVICE = this;
618
619First, it sets the special static variable ``SERVICE'' to ``this'',
620which is a pointer to the ``EmacsService' object that was created.
621
622 handler = new Handler (Looper.getMainLooper ());
623
624Next, it creates a ``Handler'' object for the ``main looper''.
625This is a helper structure which allows executing code on the Android
626user interface thread.
627
628 manager = getAssets ();
629 app_context = getApplicationContext ();
630 metrics = getResources ().getDisplayMetrics ();
631 pixelDensityX = metrics.xdpi;
632 pixelDensityY = metrics.ydpi;
633
634Finally, it obtains:
635
636 - the asset manager, which is used to retrieve assets packaged
637 into the Emacs application package.
638
639 - the application context, used to obtain application specific
640 information.
641
642 - the display metrics, and from them, the X and Y densities in dots
643 per inch.
644
645Then, inside a ``try'' block:
646
647 try
648 {
649 /* Configure Emacs with the asset manager and other necessary
650 parameters. */
651 filesDir = app_context.getFilesDir ().getCanonicalPath ();
652 libDir = getLibraryDirectory ();
653 cacheDir = app_context.getCacheDir ().getCanonicalPath ();
654
655It obtains the names of the Emacs home, shared library, and temporary
656file directories.
657
658 /* Now provide this application's apk file, so a recursive
659 invocation of app_process (through android-emacs) can
660 find EmacsNoninteractive. */
661 classPath = getApkFile ();
662
663The name of the Emacs application package.
664
665 Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
666 + ", libDir = " + libDir + ", and classPath = " + classPath);
667
668Prints a debug message to the Android system log with this
669information.
670
671 EmacsNative.setEmacsParams (manager, filesDir, libDir,
672 cacheDir, (float) pixelDensityX,
673 (float) pixelDensityY,
674 classPath, this);
675
676And calls the native function ``setEmacsParams'' (defined in
677android.c) to configure Emacs with this information.
678
679 /* Start the thread that runs Emacs. */
680 thread = new EmacsThread (this, needDashQ);
681 thread.start ();
682
683Then, it allocates an ``EmacsThread'' object, and starts that thread.
684Inside that thread is where Emacs's C code runs.
685
686 }
687 catch (IOException exception)
688 {
689 EmacsNative.emacsAbort ();
690 return;
691
692And here is the purpose of the ``try'' block. Functions related to
693file names in Java will signal errors of various types upon failure.
694
695This ``catch'' block means that the Java virtual machine will abort
696execution of the contents of the ``try'' block as soon as an error of
697type ``IOException'' is encountered, and begin executing the contents
698of the ``catch'' block.
699
700Any failure of that type here is a crash, and
701``EmacsNative.emacsAbort'' is called to quickly abort the process to
702get a useful backtrace.
703 }
704 }
705
706Now, let us look at the definition of the class ``EmacsThread'', found
707in org/gnu/emacs/EmacsThread.java:
708
709public class EmacsThread extends Thread
710{
711 /* Whether or not Emacs should be started -Q. */
712 private boolean startDashQ;
713
714 public
715 EmacsThread (EmacsService service, boolean startDashQ)
716 {
717 super ("Emacs main thread");
718 this.startDashQ = startDashQ;
719 }
720
721 @Override
722 public void
723 run ()
724 {
725 String args[];
726
727 if (!startDashQ)
728 args = new String[] { "libandroid-emacs.so", };
729 else
730 args = new String[] { "libandroid-emacs.so", "-Q", };
731
732 /* Run the native code now. */
733 EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
734 }
735};
736
737The class itself defines a single field, ``startDashQ'', a constructor
738with an unused argument of the type ``EmacsService'' (which is useful
739while debugging) and a flag ``startDashQ'', and a single function
740``run'', overriding the same function in the class ``Thread''.
741
742When ``thread.start'' is called, the Java virtual machine creates a
743new thread, and then calls the function ``run'' within that thread.
744
745This function then computes a suitable argument vector, and calls
746``EmacsNative.initEmacs'' (defined in android.c), which then calls a
747modified version of the regular Emacs ``main'' function.
748
749At that point, Emacs initialization proceeds as usual:
750Vinitial_window_system is set, loadup.el calls `normal-top-level',
751which calls `command-line', and finally
752`window-system-initialization', which initializes the `android'
753terminal interface as usual.
754
755What happens here is the same as on other platforms. Now, here is
756what happens when the initial frame is created: Fx_create_frame calls
757`android_create_frame_window' to create a top level window:
758
759static void
760android_create_frame_window (struct frame *f)
761{
762 struct android_set_window_attributes attributes;
763 enum android_window_value_mask attribute_mask;
764
765 attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f);
766 attribute_mask = ANDROID_CW_BACK_PIXEL;
767
768 block_input ();
769 FRAME_ANDROID_WINDOW (f)
770 = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
771 f->left_pos,
772 f->top_pos,
773 FRAME_PIXEL_WIDTH (f),
774 FRAME_PIXEL_HEIGHT (f),
775 attribute_mask, &attributes);
776 unblock_input ();
777}
778
779This calls the function `android_create_window' with some arguments
780whose meanings are identical to the arguments to `XCreateWindow'.
781
782Here is the definition of `android_create_window', in android.c:
783
784android_window
785android_create_window (android_window parent, int x, int y,
786 int width, int height,
787 enum android_window_value_mask value_mask,
788 struct android_set_window_attributes *attrs)
789{
790 static jclass class;
791 static jmethodID constructor;
792 jobject object, parent_object, old;
793 android_window window;
794 android_handle prev_max_handle;
795 bool override_redirect;
796
797What does it do? First, some context:
798
799At any time, there can be at most 65535 Java objects referred to by
800the rest of Emacs through the Java native interface. Each such object
801is assigned a ``handle'' (similar to an XID on X) and given a unique
802type. The function `android_resolve_handle' returns the JNI `jobject'
803associated with a given handle.
804
805 parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
806
807Here, it is being used to look up the `jobject' associated with the
808`parent' handle.
809
810 prev_max_handle = max_handle;
811 window = android_alloc_id ();
812
813Next, `max_handle' is saved, and a new handle is allocated for
814`window'.
815
816 if (!window)
817 error ("Out of window handles!");
818
819An error is signalled if Emacs runs out of available handles.
820
821 if (!class)
822 {
823 class = (*android_java_env)->FindClass (android_java_env,
824 "org/gnu/emacs/EmacsWindow");
825 assert (class != NULL);
826
827Then, if this initialization has not yet been completed, Emacs
828proceeds to find the Java class named ``EmacsWindow''.
829
830 constructor
831 = (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
832 "(SLorg/gnu/emacs/EmacsWindow;"
833 "IIIIZ)V");
834 assert (constructor != NULL);
835
836And it tries to look up the constructor, which should take seven
837arguments:
838
839 S - a short. (the handle ID)
840 Lorg/gnu/Emacs/EmacsWindow; - an instance of the EmacsWindow
841 class. (the parent)
842 IIII - four ints. (the window geometry.)
843 Z - a boolean. (whether or not the
844 window is override-redirect; see
845 XChangeWindowAttributes.)
846
847 old = class;
848 class = (*android_java_env)->NewGlobalRef (android_java_env, class);
849 (*android_java_env)->ExceptionClear (android_java_env);
850 ANDROID_DELETE_LOCAL_REF (old);
851
852Next, it saves a global reference to the class and deletes the local
853reference. Global references will never be deallocated by the Java
854virtual machine as long as they still exist.
855
856 if (!class)
857 memory_full (0);
858 }
859
860 /* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
861 creation time. */
862 override_redirect = ((value_mask
863 & ANDROID_CW_OVERRIDE_REDIRECT)
864 && attrs->override_redirect);
865
866 object = (*android_java_env)->NewObject (android_java_env, class,
867 constructor, (jshort) window,
868 parent_object, (jint) x, (jint) y,
869 (jint) width, (jint) height,
870 (jboolean) override_redirect);
871
872Then, it creates an instance of the ``EmacsWindow'' class with the
873appropriate arguments and previously determined constructor.
874
875 if (!object)
876 {
877 (*android_java_env)->ExceptionClear (android_java_env);
878
879 max_handle = prev_max_handle;
880 memory_full (0);
881
882If creating the object fails, Emacs clears the ``pending exception''
883and signals that it is out of memory.
884 }
885
886 android_handles[window].type = ANDROID_HANDLE_WINDOW;
887 android_handles[window].handle
888 = (*android_java_env)->NewGlobalRef (android_java_env,
889 object);
890 (*android_java_env)->ExceptionClear (android_java_env);
891 ANDROID_DELETE_LOCAL_REF (object);
892
893Otherwise, it associates a new global reference to the object with the
894handle, and deletes the local reference returned from the JNI
895NewObject function.
896
897 if (!android_handles[window].handle)
898 memory_full (0);
899
900If allocating the global reference fails, Emacs signals that it is out
901of memory.
902
903 android_change_window_attributes (window, value_mask, attrs);
904 return window;
905
906Otherwise, it applies the specified window attributes and returns the
907handle of the new window.
908}
909
910
911
912DRAWABLES, CURSORS AND HANDLES
913
914Each widget created by Emacs corresponds to a single ``window'', which
915has its own backing store. This arrangement is quite similar to X.
916
917C code does not directly refer to the EmacsView widgets that implement
918the UI logic behind windows. Instead, its handles refer to
919EmacsWindow structures, which contain the state necessary to interact
920with the widgets in an orderly and synchronized manner.
921
922Like X, both pixmaps and windows are drawable resources, and the same
923graphics operations can be applied to both. Thus, a separate
924EmacsPixmap structure is used to wrap around Android Bitmap resources,
925and the Java-level graphics operation functions are capable of
926operating on them both.
927
928Finally, graphics contexts are maintained on both the C and Java
929levels; the C state recorded in `struct android_gc' is kept in sync
930with the Java state in the GContext handle's corresponding EmacsGC
931structure, and cursors are used through handles that refer to
932EmacsCursor structures that hold system PointerIcons.
933
934In all cases, the interfaces provided are identical to X.
935
936
937
938EVENT LOOP
939
940In a typical Android application, the event loop is managed by the
941operating system, and callbacks (implemented through overriding
942separate functions in widgets) are run by the event loop wherever
943necessary. The thread which runs the event loop is also the only
944thread capable of creating and manipulating widgets and activities,
945and is referred to as the ``UI thread''.
946
947These callbacks are used by Emacs to write representations of X-like
948events to a separate event queue, which are then read from Emacs's own
949event loop running in a separate thread. This is accomplished through
950replacing `select' by a function which waits for the event queue to be
951occupied, in addition to any file descriptors that `select' would
952normally wait for.
953
954Conversely, Emacs's event loop sometimes needs to send events to the
955UI thread. These events are implemented as tiny fragments of code,
956which are run as they are received by the main thread.
957
958A typical example is `displayToast', which is implemented in
959EmacsService.java:
960
961 public void
962 displayToast (final String string)
963 {
964 runOnUiThread (new Runnable () {
965 @Override
966 public void
967 run ()
968 {
969 Toast toast;
970
971 toast = Toast.makeText (getApplicationContext (),
972 string, Toast.LENGTH_SHORT);
973 toast.show ();
974 }
975 });
976 }
977
978Here, the variable `string' is used by a nested function. This nested
979function contains a copy of that variable, and is run on the main
980thread using the function `runOnUiThread', in order to display a short
981status message on the display.
982
983When Emacs needs to wait for the nested function to finish, it uses a
984mechanism implemented in `syncRunnable'. This mechanism first calls a
985deadlock avoidance mechanism, then runs a nested function on the UI
986thread, which is expected to signal itself as a condition variable
987upon completion. It is typically used to allocate resources that can
988only be allocated from the UI thread, or to obtain non-thread-safe
989information. The following function is an example; it returns a new
990EmacsView widget corresponding to the provided window:
991
992 public EmacsView
993 getEmacsView (final EmacsWindow window, final int visibility,
994 final boolean isFocusedByDefault)
995 {
996 Runnable runnable;
997 final EmacsHolder<EmacsView> view;
998
999 view = new EmacsHolder<EmacsView> ();
1000
1001 runnable = new Runnable () {
1002 public void
1003 run ()
1004 {
1005 synchronized (this)
1006 {
1007 view.thing = new EmacsView (window);
1008 view.thing.setVisibility (visibility);
1009
1010 /* The following function is only present on Android 26
1011 or later. */
1012 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
1013 view.thing.setFocusedByDefault (isFocusedByDefault);
1014
1015 notify ();
1016 }
1017 }
1018 };
1019
1020 syncRunnable (runnable);
1021 return view.thing;
1022 }
1023
1024As no value can be directly returned from the nested function, a
1025separate container object is used to hold the result after the
1026function finishes execution. Note the type name inside the angle
1027brackets: this type is substituted into the class definition as it is
1028used; a definition such as:
1029
1030public class Foo<T>
1031{
1032 T bar;
1033};
1034
1035can not be used alone:
1036
1037 Foo holder; /* Error! */
1038
1039but must have a type specified:
1040
1041 Foo<Object> holder;
1042
1043in which case the effective definition is:
1044
1045public class Foo
1046{
1047 Object bar;
1048};