aboutsummaryrefslogtreecommitdiffstats
path: root/src/androidselect.c
diff options
context:
space:
mode:
authorPo Lu2024-05-01 11:45:53 +0800
committerPo Lu2024-05-01 11:46:31 +0800
commit2451456695d0e03b89365cbbe64effb2f99af2d5 (patch)
treeb6bcd3e227454b436ab4ee0fad447d946b5179cf /src/androidselect.c
parent294335b2304028cc97aca036bd37adf2f8e1c508 (diff)
downloademacs-2451456695d0e03b89365cbbe64effb2f99af2d5.tar.gz
emacs-2451456695d0e03b89365cbbe64effb2f99af2d5.zip
Fix compatibility issues with Android clipboards
* java/org/gnu/emacs/EmacsClipboard.java (getClipboardData): Return an AssetFileDescriptor. * java/org/gnu/emacs/EmacsContextMenu.java (onMenuItemClick): Typo corrections in commentary. * java/org/gnu/emacs/EmacsOpenActivity.java (onCreate): Raise minimum version on which to read file descriptors from ParcelFileDescriptor objects to Honeycomb. * java/org/gnu/emacs/EmacsSdk11Clipboard.java (getClipboardData): Return the asset file descriptor. * java/org/gnu/emacs/EmacsSdk8Clipboard.java (getClipboardData): Adjust return type to match. * src/android.h (struct android_parcel_file_descriptor_class): Move from androidselect.c. * src/androidselect.c (fd_class): Export function. (android_init_emacs_clipboard): Adjust signature of getClipboardData. (android_init_asset_file_descriptor, close_asset_fd) (extract_fd_offsets): New functions. (Fandroid_get_clipboard_data): Extract file descriptor and offset from the AssetFileDescriptor here, rather than in getClipboardData. (init_androidselect): Call android_init_asset_file_descriptor. * src/androidvfs.c (android_init_fd_class): Export and enable calling this function more than once.
Diffstat (limited to 'src/androidselect.c')
-rw-r--r--src/androidselect.c216
1 files changed, 191 insertions, 25 deletions
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;