aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/org/gnu/emacs/EmacsClipboard.java3
-rw-r--r--java/org/gnu/emacs/EmacsContextMenu.java4
-rw-r--r--java/org/gnu/emacs/EmacsOpenActivity.java39
-rw-r--r--java/org/gnu/emacs/EmacsSdk11Clipboard.java50
-rw-r--r--java/org/gnu/emacs/EmacsSdk8Clipboard.java11
-rw-r--r--src/android.h16
-rw-r--r--src/androidselect.c216
-rw-r--r--src/androidvfs.c26
8 files changed, 251 insertions, 114 deletions
diff --git a/java/org/gnu/emacs/EmacsClipboard.java b/java/org/gnu/emacs/EmacsClipboard.java
index 9db436ca1e2..f27d96129ef 100644
--- a/java/org/gnu/emacs/EmacsClipboard.java
+++ b/java/org/gnu/emacs/EmacsClipboard.java
@@ -19,6 +19,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22import android.content.res.AssetFileDescriptor;
22import android.os.Build; 23import android.os.Build;
23 24
24/* This class provides helper code for accessing the clipboard, 25/* This class provides helper code for accessing the clipboard,
@@ -32,7 +33,7 @@ public abstract class EmacsClipboard
32 public abstract byte[] getClipboard (); 33 public abstract byte[] getClipboard ();
33 34
34 public abstract byte[][] getClipboardTargets (); 35 public abstract byte[][] getClipboardTargets ();
35 public abstract long[] getClipboardData (byte[] target); 36 public abstract AssetFileDescriptor getClipboardData (byte[] target);
36 37
37 /* Create the correct kind of clipboard for this system. */ 38 /* Create the correct kind of clipboard for this system. */
38 39
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java
index 2bbf2a313d6..0f52d45455f 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -108,8 +108,8 @@ public final class EmacsContextMenu
108 will normally confuse Emacs into thinking that the 108 will normally confuse Emacs into thinking that the
109 context menu has been dismissed. Wrong! 109 context menu has been dismissed. Wrong!
110 110
111 Setting this flag makes EmacsActivity to only handle 111 Setting this flag prompts EmacsActivity to only handle
112 SubMenuBuilder being closed, which always means the menu 112 SubMenuBuilders being closed, which always means the menu
113 has actually been dismissed. 113 has actually been dismissed.
114 114
115 However, these extraneous events aren't sent on devices 115 However, these extraneous events aren't sent on devices
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java
index 327a53bc417..cdc68aea2bf 100644
--- a/java/org/gnu/emacs/EmacsOpenActivity.java
+++ b/java/org/gnu/emacs/EmacsOpenActivity.java
@@ -19,29 +19,23 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22/* This class makes the Emacs server work reasonably on Android. 22/* Opening external documents on Android.
23 23
24 There is no way to make the Unix socket publicly available on 24 This activity is registered as an application capable of opening text
25 Android. 25 files and files in several other formats that Emacs understands, and
26 assumes responsibility for deriving file names from the files
27 provided to `onCreate', potentially copying them to temporary
28 directories in the process, and invoking `emacsclient' with suitable
29 arguments to open the same. In this respect, it fills the role of
30 `etc/emacs.desktop' on XDG systems.
26 31
27 Instead, this activity tries to connect to the Emacs server, to 32 It is also registered as a handler for mailto URIs, in which capacity
28 make it open files the system asks Emacs to open, and to emulate 33 it constructs invocations of `emacsclient' so as to start
29 some reasonable behavior when Emacs has not yet started. 34 `message-mailto' with their contents and attachments, much like
35 `etc/emacs-mail.desktop'.
30 36
31 First, Emacs registers itself as an application that can open text 37 As with all other activities, it is registered in the package
32 and image files. 38 manifest file. */
33
34 Then, when the user is asked to open a file and selects ``Emacs''
35 as the application that will open the file, the system pops up a
36 window, this activity, and calls the `onCreate' function.
37
38 `onCreate' then tries very to find the file name of the file that
39 was selected, and give it to emacsclient.
40
41 If emacsclient successfully opens the file, then this activity
42 starts EmacsActivity (to bring it on to the screen); otherwise, it
43 displays the output of emacsclient or any error message that occurs
44 and exits. */
45 39
46import android.app.AlertDialog; 40import android.app.AlertDialog;
47import android.app.Activity; 41import android.app.Activity;
@@ -628,11 +622,12 @@ public final class EmacsOpenActivity extends Activity
628 622
629 if (scheme.equals ("content") 623 if (scheme.equals ("content")
630 /* Retrieving the native file descriptor of a 624 /* Retrieving the native file descriptor of a
631 ParcelFileDescriptor requires Honeycomb, and 625 ParcelFileDescriptor requires Honeycomb MR1, and
632 proceeding without this capability is pointless on 626 proceeding without this capability is pointless on
633 systems before KitKat, since Emacs doesn't support 627 systems before KitKat, since Emacs doesn't support
634 opening content files on those. */ 628 opening content files on those. */
635 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 629 && (Build.VERSION.SDK_INT
630 >= Build.VERSION_CODES.HONEYCOMB_MR1))
636 { 631 {
637 /* This is one of the annoying Android ``content'' 632 /* This is one of the annoying Android ``content''
638 URIs. Most of the time, there is actually an 633 URIs. Most of the time, there is actually an
diff --git a/java/org/gnu/emacs/EmacsSdk11Clipboard.java b/java/org/gnu/emacs/EmacsSdk11Clipboard.java
index 850bb6c8deb..71381b0f114 100644
--- a/java/org/gnu/emacs/EmacsSdk11Clipboard.java
+++ b/java/org/gnu/emacs/EmacsSdk11Clipboard.java
@@ -207,8 +207,9 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard
207 /* Return the clipboard data for the given target, or NULL if it 207 /* Return the clipboard data for the given target, or NULL if it
208 does not exist. 208 does not exist.
209 209
210 Value is normally an array of three longs: the file descriptor, 210 Value is normally an asset file descriptor, which in turn holds
211 the start offset of the data, and its length; length may be 211 three important values: the file descriptor, the start offset of
212 the data, and its length; length may be
212 AssetFileDescriptor.UNKNOWN_LENGTH, meaning that the data extends 213 AssetFileDescriptor.UNKNOWN_LENGTH, meaning that the data extends
213 from that offset to the end of the file. 214 from that offset to the end of the file.
214 215
@@ -217,15 +218,13 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard
217 solely of a URI. */ 218 solely of a URI. */
218 219
219 @Override 220 @Override
220 public long[] 221 public AssetFileDescriptor
221 getClipboardData (byte[] target) 222 getClipboardData (byte[] target)
222 { 223 {
223 ClipData data; 224 ClipData data;
224 String mimeType; 225 String mimeType;
225 int fd;
226 AssetFileDescriptor assetFd; 226 AssetFileDescriptor assetFd;
227 Uri uri; 227 Uri uri;
228 long[] value;
229 228
230 /* Decode the target given by Emacs. */ 229 /* Decode the target given by Emacs. */
231 try 230 try
@@ -245,8 +244,6 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard
245 if (data == null || data.getItemCount () < 1) 244 if (data == null || data.getItemCount () < 1)
246 return null; 245 return null;
247 246
248 fd = -1;
249
250 try 247 try
251 { 248 {
252 uri = data.getItemAt (0).getUri (); 249 uri = data.getItemAt (0).getUri ();
@@ -257,52 +254,15 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard
257 /* Now open the file descriptor. */ 254 /* Now open the file descriptor. */
258 assetFd = resolver.openTypedAssetFileDescriptor (uri, mimeType, 255 assetFd = resolver.openTypedAssetFileDescriptor (uri, mimeType,
259 null); 256 null);
260 257 return assetFd;
261 /* Duplicate the file descriptor. */
262 fd = assetFd.getParcelFileDescriptor ().getFd ();
263 fd = EmacsNative.dup (fd);
264
265 /* Return the relevant information. */
266 value = new long[] { fd, assetFd.getStartOffset (),
267 assetFd.getLength (), };
268
269 /* Close the original offset. */
270 assetFd.close ();
271 } 258 }
272 catch (SecurityException e) 259 catch (SecurityException e)
273 { 260 {
274 /* Guarantee a file descriptor duplicated or detached is
275 ultimately closed if an error arises. */
276
277 if (fd != -1)
278 EmacsNative.close (fd);
279
280 return null; 261 return null;
281 } 262 }
282 catch (FileNotFoundException e) 263 catch (FileNotFoundException e)
283 { 264 {
284 /* Guarantee a file descriptor duplicated or detached is
285 ultimately closed if an error arises. */
286
287 if (fd != -1)
288 EmacsNative.close (fd);
289
290 return null; 265 return null;
291 } 266 }
292 catch (IOException e)
293 {
294 /* Guarantee a file descriptor duplicated or detached is
295 ultimately closed if an error arises. */
296
297 if (fd != -1)
298 EmacsNative.close (fd);
299
300 return null;
301 }
302
303 /* Don't return value if the file descriptor couldn't be
304 created. */
305
306 return fd != -1 ? value : null;
307 } 267 }
308}; 268};
diff --git a/java/org/gnu/emacs/EmacsSdk8Clipboard.java b/java/org/gnu/emacs/EmacsSdk8Clipboard.java
index 418f55c12c1..3d0504b1924 100644
--- a/java/org/gnu/emacs/EmacsSdk8Clipboard.java
+++ b/java/org/gnu/emacs/EmacsSdk8Clipboard.java
@@ -25,6 +25,8 @@ package org.gnu.emacs;
25import android.text.*; 25import android.text.*;
26 26
27import android.content.Context; 27import android.content.Context;
28import android.content.res.AssetFileDescriptor;
29
28import android.util.Log; 30import android.util.Log;
29 31
30import java.io.UnsupportedEncodingException; 32import java.io.UnsupportedEncodingException;
@@ -129,9 +131,10 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard
129 /* Return the clipboard data for the given target, or NULL if it 131 /* Return the clipboard data for the given target, or NULL if it
130 does not exist. 132 does not exist.
131 133
132 Value is normally an array of three longs: the file descriptor, 134 Value is normally an asset file descriptor, which in turn holds
133 the start offset of the data, and its length; length may be 135 three important values: the file descriptor, the start offset of
134 AssetFileDescriptor.UNKOWN_LENGTH, meaning that the data extends 136 the data, and its length; length may be
137 AssetFileDescriptor.UNKNOWN_LENGTH, meaning that the data extends
135 from that offset to the end of the file. 138 from that offset to the end of the file.
136 139
137 Do not use this function to open text targets; use `getClipboard' 140 Do not use this function to open text targets; use `getClipboard'
@@ -139,7 +142,7 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard
139 solely of a URI. */ 142 solely of a URI. */
140 143
141 @Override 144 @Override
142 public long[] 145 public AssetFileDescriptor
143 getClipboardData (byte[] target) 146 getClipboardData (byte[] target)
144 { 147 {
145 return null; 148 return null;
diff --git a/src/android.h b/src/android.h
index 19adfa38087..7074ca2630c 100644
--- a/src/android.h
+++ b/src/android.h
@@ -53,6 +53,22 @@ extern char *android_user_full_name (struct passwd *);
53 53
54 54
55 55
56/* Structure describing the android.os.ParcelFileDescriptor class used
57 to wrap file descriptors sent over IPC. */
58
59struct android_parcel_file_descriptor_class
60{
61 jclass class;
62 jmethodID close;
63 jmethodID get_fd;
64 jmethodID detach_fd;
65};
66
67/* The ParcelFileDescriptor class. */
68extern struct android_parcel_file_descriptor_class fd_class;
69
70extern void android_init_fd_class (JNIEnv *);
71
56/* File I/O operations. Many of these are defined in 72/* File I/O operations. Many of these are defined in
57 androidvfs.c. */ 73 androidvfs.c. */
58 74
diff --git a/src/androidselect.c b/src/androidselect.c
index 2f6114d0fcb..04d04d326d9 100644
--- a/src/androidselect.c
+++ b/src/androidselect.c
@@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
21#include <assert.h> 21#include <assert.h>
22#include <minmax.h> 22#include <minmax.h>
23#include <unistd.h> 23#include <unistd.h>
24#include <dlfcn.h>
24 25
25#include <boot-time.h> 26#include <boot-time.h>
26#include <sys/types.h> 27#include <sys/types.h>
@@ -100,7 +101,7 @@ android_init_emacs_clipboard (void)
100 FIND_METHOD (get_clipboard_targets, "getClipboardTargets", 101 FIND_METHOD (get_clipboard_targets, "getClipboardTargets",
101 "()[[B"); 102 "()[[B");
102 FIND_METHOD (get_clipboard_data, "getClipboardData", 103 FIND_METHOD (get_clipboard_data, "getClipboardData",
103 "([B)[J"); 104 "([B)Landroid/content/res/AssetFileDescriptor;");
104 105
105 clipboard_class.make_clipboard 106 clipboard_class.make_clipboard
106 = (*android_java_env)->GetStaticMethodID (android_java_env, 107 = (*android_java_env)->GetStaticMethodID (android_java_env,
@@ -340,6 +341,62 @@ data type available from the clipboard. */)
340 return Qnil; 341 return Qnil;
341} 342}
342 343
344
345
346struct android_asset_file_descriptor
347{
348 jclass class;
349 jmethodID close;
350 jmethodID get_length;
351 jmethodID get_start_offset;
352 jmethodID get_file_descriptor;
353 jmethodID get_parcel_file_descriptor;
354 jmethodID get_fd;
355};
356
357/* Methods associated with the AssetFileDescriptor class. */
358static struct android_asset_file_descriptor asset_fd_class;
359
360/* Initialize virtual function IDs and class pointers in connection with
361 the AssetFileDescriptor class. */
362
363static void
364android_init_asset_file_descriptor (void)
365{
366 jclass old;
367
368 asset_fd_class.class
369 = (*android_java_env)->FindClass (android_java_env,
370 "android/content/res/"
371 "AssetFileDescriptor");
372 eassert (asset_fd_class.class);
373
374 old = asset_fd_class.class;
375 asset_fd_class.class
376 = (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
377 old);
378 ANDROID_DELETE_LOCAL_REF (old);
379
380 if (!asset_fd_class.class)
381 emacs_abort ();
382
383#define FIND_METHOD(c_name, name, signature) \
384 asset_fd_class.c_name \
385 = (*android_java_env)->GetMethodID (android_java_env, \
386 asset_fd_class.class, \
387 name, signature); \
388 eassert (asset_fd_class.c_name);
389
390 FIND_METHOD (close, "close", "()V");
391 FIND_METHOD (get_length, "getLength", "()J");
392 FIND_METHOD (get_start_offset, "getStartOffset", "()J");
393 FIND_METHOD (get_file_descriptor, "getFileDescriptor",
394 "()Ljava/io/FileDescriptor;");
395 FIND_METHOD (get_parcel_file_descriptor, "getParcelFileDescriptor",
396 "()Landroid/os/ParcelFileDescriptor;");
397#undef FIND_METHOD
398}
399
343/* Free the memory inside PTR, a pointer to a char pointer. */ 400/* Free the memory inside PTR, a pointer to a char pointer. */
344 401
345static void 402static void
@@ -348,6 +405,125 @@ android_xfree_inside (void *ptr)
348 xfree (*(char **) ptr); 405 xfree (*(char **) ptr);
349} 406}
350 407
408/* Close the referent of, then delete, the local reference to an asset
409 file descriptor referenced by AFD. */
410
411static void
412close_asset_fd (void *afd)
413{
414 jobject *afd_1;
415
416 afd_1 = afd;
417 (*android_java_env)->CallVoidMethod (android_java_env, *afd_1,
418 asset_fd_class.close);
419 (*android_java_env)->ExceptionClear (android_java_env);
420 ANDROID_DELETE_LOCAL_REF (*afd_1);
421}
422
423/* Return the offset, file descriptor and length of the data contained
424 in the asset file descriptor AFD, in *FD, *OFFSET, and *LENGTH.
425 Value is 0 upon success, 1 otherwise. */
426
427static int
428extract_fd_offsets (jobject afd, int *fd, jlong *offset, jlong *length)
429{
430 jobject java_fd;
431 void *handle;
432#if __ANDROID_API__ <= 11
433 static int (*jniGetFDFromFileDescriptor) (JNIEnv *, jobject);
434#endif /* __ANDROID_API__ <= 11 */
435 static int (*AFileDescriptor_getFd) (JNIEnv *, jobject);;
436 jmethodID method;
437
438 method = asset_fd_class.get_start_offset;
439 *offset = (*android_java_env)->CallLongMethod (android_java_env,
440 afd, method);
441 android_exception_check ();
442 method = asset_fd_class.get_length;
443 *length = (*android_java_env)->CallLongMethod (android_java_env,
444 afd, method);
445 android_exception_check ();
446
447#if __ANDROID_API__ <= 11
448 if (android_get_current_api_level () <= 11)
449 {
450 /* Load libnativehelper and link to a private interface that is
451 the only means of retrieving the file descriptor from an asset
452 file descriptor on these systems. */
453
454 if (!jniGetFDFromFileDescriptor)
455 {
456 handle = dlopen ("libnativehelper.so",
457 RTLD_LAZY | RTLD_GLOBAL);
458 if (!handle)
459 goto failure;
460 jniGetFdFromFileDescriptor = dlsym (handle,
461 "jniGetFDFromFileDescriptor");
462 if (!jniGetFdFromFileDescriptor)
463 goto failure;
464 }
465
466 method = asset_fd_class.get_file_descriptor;
467 java_fd = (*android_java_env)->CallObjectMethod (android_java_env,
468 afd, method);
469 android_exception_check ();
470 *fd = (*jniGetFDFromFileDescriptor) (android_java_env, java_fd);
471 ANDROID_DELETE_LOCAL_REF (java_fd);
472
473 if (*fd >= 0)
474 return 0;
475 }
476 else
477#endif /* __ANDROID_API__ <= 11 */
478#if __ANDROID_API__ <= 30
479 if (android_get_current_api_level () <= 30)
480 {
481 /* Convert this AssetFileDescriptor into a ParcelFileDescriptor,
482 whose getFd method will return its native file descriptor. */
483 method = asset_fd_class.get_parcel_file_descriptor;
484 java_fd = (*android_java_env)->CallObjectMethod (android_java_env,
485 afd, method);
486 android_exception_check ();
487
488 /* Initialize fd_class if not already complete. */
489 android_init_fd_class (android_java_env);
490 *fd = (*android_java_env)->CallIntMethod (android_java_env,
491 java_fd,
492 fd_class.get_fd);
493 if (*fd >= 0)
494 return 0;
495 }
496 else
497#endif /* __ANDROID_API__ <= 30 */
498 {
499 /* Load libnativehelper (now a public interface) and link to
500 AFileDescriptor_getFd. */
501 if (!AFileDescriptor_getFd)
502 {
503 handle = dlopen ("libnativehelper.so",
504 RTLD_LAZY | RTLD_GLOBAL);
505 if (!handle)
506 goto failure;
507 AFileDescriptor_getFd = dlsym (handle, "AFileDescriptor_getFd");
508 if (!AFileDescriptor_getFd)
509 goto failure;
510 }
511
512 method = asset_fd_class.get_file_descriptor;
513 java_fd = (*android_java_env)->CallObjectMethod (android_java_env,
514 afd, method);
515 android_exception_check ();
516 *fd = (*AFileDescriptor_getFd) (android_java_env, java_fd);
517 ANDROID_DELETE_LOCAL_REF (java_fd);
518
519 if (*fd >= 0)
520 return 0;
521 }
522
523 failure:
524 return 1;
525}
526
351DEFUN ("android-get-clipboard-data", Fandroid_get_clipboard_data, 527DEFUN ("android-get-clipboard-data", Fandroid_get_clipboard_data,
352 Sandroid_get_clipboard_data, 1, 1, 0, 528 Sandroid_get_clipboard_data, 1, 1, 0,
353 doc: /* Return the clipboard data of the given MIME TYPE. 529 doc: /* Return the clipboard data of the given MIME TYPE.
@@ -361,12 +537,12 @@ does not have any corresponding data. In that case, use
361`android-get-clipboard' instead. */) 537`android-get-clipboard' instead. */)
362 (Lisp_Object type) 538 (Lisp_Object type)
363{ 539{
364 jlongArray array; 540 jobject afd;
365 jbyteArray bytes; 541 jbyteArray bytes;
366 jmethodID method; 542 jmethodID method;
367 int fd; 543 int fd;
368 ptrdiff_t rc; 544 ptrdiff_t rc;
369 jlong offset, length, *longs; 545 jlong offset, length;
370 specpdl_ref ref; 546 specpdl_ref ref;
371 char *buffer, *start; 547 char *buffer, *start;
372 548
@@ -387,36 +563,25 @@ does not have any corresponding data. In that case, use
387 android_exception_check (); 563 android_exception_check ();
388 564
389 method = clipboard_class.get_clipboard_data; 565 method = clipboard_class.get_clipboard_data;
390 array = (*android_java_env)->CallObjectMethod (android_java_env, 566 afd = (*android_java_env)->CallObjectMethod (android_java_env,
391 clipboard, method, 567 clipboard, method,
392 bytes); 568 bytes);
393 android_exception_check_1 (bytes); 569 android_exception_check_1 (bytes);
394 ANDROID_DELETE_LOCAL_REF (bytes); 570 ANDROID_DELETE_LOCAL_REF (bytes);
395 571
396 if (!array) 572 if (!afd)
397 goto fail; 573 goto fail;
398 574
399 longs = (*android_java_env)->GetLongArrayElements (android_java_env, 575 /* Extract the file descriptor from the AssetFileDescriptor
400 array, NULL); 576 object. */
401 android_exception_check_nonnull (longs, array); 577 ref = SPECPDL_INDEX ();
402 578 record_unwind_protect_ptr (close_asset_fd, &afd);
403 /* longs[0] is the file descriptor.
404 longs[1] is an offset to apply to the file.
405 longs[2] is either -1, or the number of bytes to read from the
406 file. */
407 fd = longs[0];
408 offset = longs[1];
409 length = longs[2];
410 579
411 (*android_java_env)->ReleaseLongArrayElements (android_java_env, 580 if (extract_fd_offsets (afd, &fd, &offset, &length))
412 array, longs, 581 return unbind_to (ref, Qnil);
413 JNI_ABORT);
414 ANDROID_DELETE_LOCAL_REF (array);
415 unblock_input (); 582 unblock_input ();
416 583
417 /* Now begin reading from longs[0]. */ 584 /* Now begin reading from fd. */
418 ref = SPECPDL_INDEX ();
419 record_unwind_protect_int (close_file_unwind, fd);
420 585
421 if (length != -1) 586 if (length != -1)
422 { 587 {
@@ -1004,6 +1169,7 @@ init_androidselect (void)
1004 return; 1169 return;
1005 1170
1006 android_init_emacs_clipboard (); 1171 android_init_emacs_clipboard ();
1172 android_init_asset_file_descriptor ();
1007 android_init_emacs_desktop_notification (); 1173 android_init_emacs_desktop_notification ();
1008 1174
1009 make_clipboard = clipboard_class.make_clipboard; 1175 make_clipboard = clipboard_class.make_clipboard;
diff --git a/src/androidvfs.c b/src/androidvfs.c
index c4b3dba4af0..38bec7d349a 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -290,17 +290,6 @@ struct emacs_directory_entry_class
290 jfieldID d_name; 290 jfieldID d_name;
291}; 291};
292 292
293/* Structure describing the android.os.ParcelFileDescriptor class used
294 to wrap file descriptors sent over IPC. */
295
296struct android_parcel_file_descriptor_class
297{
298 jclass class;
299 jmethodID close;
300 jmethodID get_fd;
301 jmethodID detach_fd;
302};
303
304/* The java.lang.String class. */ 293/* The java.lang.String class. */
305jclass java_string_class; 294jclass java_string_class;
306 295
@@ -313,7 +302,7 @@ static struct emacs_directory_entry_class entry_class;
313 302
314/* Fields and methods associated with the ParcelFileDescriptor 303/* Fields and methods associated with the ParcelFileDescriptor
315 class. */ 304 class. */
316static struct android_parcel_file_descriptor_class fd_class; 305struct android_parcel_file_descriptor_class fd_class;
317 306
318/* Global references to several exception classes. */ 307/* Global references to several exception classes. */
319static jclass file_not_found_exception, security_exception; 308static jclass file_not_found_exception, security_exception;
@@ -380,13 +369,18 @@ android_init_entry_class (JNIEnv *env)
380} 369}
381 370
382 371
383/* Initialize `fd_class' using the given JNI environment ENV. Calling 372/* Initialize `fd_class' using the given JNI environment ENV. Called on
384 this function is not necessary on Android 4.4 and earlier. */ 373 API 12 (Android 3.1) and later by androidselect.c and on 5.0 and
374 later in this file. */
385 375
386static void 376void
387android_init_fd_class (JNIEnv *env) 377android_init_fd_class (JNIEnv *env)
388{ 378{
389 jclass old; 379 jclass old;
380 static bool fd_class_initialized;
381
382 if (fd_class_initialized)
383 return;
390 384
391 fd_class.class 385 fd_class.class
392 = (*env)->FindClass (env, "android/os/ParcelFileDescriptor"); 386 = (*env)->FindClass (env, "android/os/ParcelFileDescriptor");
@@ -409,6 +403,8 @@ android_init_fd_class (JNIEnv *env)
409 FIND_METHOD (get_fd, "getFd", "()I"); 403 FIND_METHOD (get_fd, "getFd", "()I");
410 FIND_METHOD (detach_fd, "detachFd", "()I"); 404 FIND_METHOD (detach_fd, "detachFd", "()I");
411#undef FIND_METHOD 405#undef FIND_METHOD
406
407 fd_class_initialized = true;
412} 408}
413 409
414 410