aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-02-21 15:28:06 +0800
committerPo Lu2023-02-21 15:28:06 +0800
commit7aa4ffddd842e495d1ae388afff12075317ecb07 (patch)
tree9ba8cb2c232665ee59113494f7e35eeb33ab8619 /src
parentd197d7349121b972d50e37d66017567bf6cba652 (diff)
downloademacs-7aa4ffddd842e495d1ae388afff12075317ecb07.tar.gz
emacs-7aa4ffddd842e495d1ae388afff12075317ecb07.zip
Update Android port
* doc/emacs/android.texi (Android Startup): Document `content' special directory. * java/debug.sh (is_root): Improve /bin/tee detection. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): New function `dup'. * java/org/gnu/emacs/EmacsOpenActivity.java (EmacsOpenActivity) (checkReadableOrCopy, onCreate): Create content directory names when the file is not readable. * java/org/gnu/emacs/EmacsService.java (EmacsService) (openContentUri, checkContentUri): New functions. * src/android.c (struct android_emacs_service): New methods. (android_content_name_p, android_get_content_name) (android_check_content_access): New function. (android_fstatat, android_open): Implement opening content URIs. (dup): Export to Java. (android_init_emacs_service): Initialize new methods. (android_faccessat): Implement content file names.
Diffstat (limited to 'src')
-rw-r--r--src/android.c213
1 files changed, 210 insertions, 3 deletions
diff --git a/src/android.c b/src/android.c
index fc5e6d278ed..75a97f9db33 100644
--- a/src/android.c
+++ b/src/android.c
@@ -108,6 +108,8 @@ struct android_emacs_service
108 jmethodID restart_emacs; 108 jmethodID restart_emacs;
109 jmethodID update_ic; 109 jmethodID update_ic;
110 jmethodID reset_ic; 110 jmethodID reset_ic;
111 jmethodID open_content_uri;
112 jmethodID check_content_uri;
111}; 113};
112 114
113struct android_emacs_pixmap 115struct android_emacs_pixmap
@@ -941,6 +943,102 @@ android_get_asset_name (const char *filename)
941 return NULL; 943 return NULL;
942} 944}
943 945
946/* Return whether or not the specified FILENAME actually resolves to a
947 content resolver URI. */
948
949static bool
950android_content_name_p (const char *filename)
951{
952 return (!strcmp (filename, "/content")
953 || !strncmp (filename, "/content/",
954 sizeof "/content/" - 1));
955}
956
957/* Return the content URI corresponding to a `/content' file name,
958 or NULL if it is not a content URI.
959
960 This function is not reentrant. */
961
962static const char *
963android_get_content_name (const char *filename)
964{
965 static char buffer[PATH_MAX + 1];
966 char *head, *token, *saveptr, *copy;
967 size_t n;
968
969 n = PATH_MAX;
970
971 /* First handle content ``URIs'' without a provider. */
972
973 if (!strcmp (filename, "/content")
974 || !strcmp (filename, "/content/"))
975 return "content://";
976
977 /* Next handle ordinary file names. */
978
979 if (strncmp (filename, "/content/", sizeof "/content/" - 1))
980 return NULL;
981
982 /* Forward past the first directory specifying the schema. */
983
984 copy = xstrdup (filename + sizeof "/content");
985 token = saveptr = NULL;
986 head = stpcpy (buffer, "content:/");
987
988 /* Split FILENAME by slashes. */
989
990 while ((token = strtok_r (!token ? copy : NULL,
991 "/", &saveptr)))
992 {
993 head = stpncpy (head, "/", n--);
994 head = stpncpy (head, token, n);
995 assert ((head - buffer) >= PATH_MAX);
996
997 n = PATH_MAX - (head - buffer);
998 }
999
1000 /* Make sure the given buffer ends up NULL terminated. */
1001 buffer[PATH_MAX] = '\0';
1002 xfree (copy);
1003
1004 return buffer;
1005}
1006
1007/* Return whether or not the specified FILENAME is an accessible
1008 content URI. MODE specifies what to check. */
1009
1010static bool
1011android_check_content_access (const char *filename, int mode)
1012{
1013 const char *name;
1014 jobject string;
1015 size_t length;
1016 jboolean rc;
1017
1018 name = android_get_content_name (filename);
1019 length = strlen (name);
1020
1021 string = (*android_java_env)->NewByteArray (android_java_env,
1022 length);
1023 android_exception_check ();
1024
1025 (*android_java_env)->SetByteArrayRegion (android_java_env,
1026 string, 0, length,
1027 (jbyte *) name);
1028 rc = (*android_java_env)->CallBooleanMethod (android_java_env,
1029 emacs_service,
1030 service_class.check_content_uri,
1031 string,
1032 (jboolean) ((mode & R_OK)
1033 != 0),
1034 (jboolean) ((mode & W_OK)
1035 != 0));
1036 android_exception_check ();
1037 ANDROID_DELETE_LOCAL_REF (string);
1038
1039 return rc;
1040}
1041
944/* Like fstat. However, look up the asset corresponding to the file 1042/* Like fstat. However, look up the asset corresponding to the file
945 descriptor. If it exists, return the right information. */ 1043 descriptor. If it exists, return the right information. */
946 1044
@@ -976,6 +1074,7 @@ android_fstatat (int dirfd, const char *restrict pathname,
976 AAsset *asset_desc; 1074 AAsset *asset_desc;
977 const char *asset; 1075 const char *asset;
978 const char *asset_dir; 1076 const char *asset_dir;
1077 int fd, rc;
979 1078
980 /* Look up whether or not DIRFD belongs to an open struct 1079 /* Look up whether or not DIRFD belongs to an open struct
981 android_dir. */ 1080 android_dir. */
@@ -1027,6 +1126,23 @@ android_fstatat (int dirfd, const char *restrict pathname,
1027 return 0; 1126 return 0;
1028 } 1127 }
1029 1128
1129 if (dirfd == AT_FDCWD
1130 && android_init_gui
1131 && android_content_name_p (pathname))
1132 {
1133 /* This is actually a content:// URI. Open that file and call
1134 stat on it. */
1135
1136 fd = android_open (pathname, O_RDONLY, 0);
1137
1138 if (fd < 0)
1139 return -1;
1140
1141 rc = fstat (fd, statbuf);
1142 android_close (fd);
1143 return rc;
1144 }
1145
1030 return fstatat (dirfd, pathname, statbuf, flags); 1146 return fstatat (dirfd, pathname, statbuf, flags);
1031} 1147}
1032 1148
@@ -1316,6 +1432,8 @@ android_open (const char *filename, int oflag, int mode)
1316 AAsset *asset; 1432 AAsset *asset;
1317 int fd; 1433 int fd;
1318 off_t out_start, out_length; 1434 off_t out_start, out_length;
1435 size_t length;
1436 jobject string;
1319 1437
1320 if (asset_manager && (name = android_get_asset_name (filename))) 1438 if (asset_manager && (name = android_get_asset_name (filename)))
1321 { 1439 {
@@ -1329,7 +1447,7 @@ android_open (const char *filename, int oflag, int mode)
1329 1447
1330 if (oflag & O_DIRECTORY) 1448 if (oflag & O_DIRECTORY)
1331 { 1449 {
1332 errno = EINVAL; 1450 errno = ENOTSUP;
1333 return -1; 1451 return -1;
1334 } 1452 }
1335 1453
@@ -1396,7 +1514,7 @@ android_open (const char *filename, int oflag, int mode)
1396 /* Fill in some information that will be reported to 1514 /* Fill in some information that will be reported to
1397 callers of android_fstat, among others. */ 1515 callers of android_fstat, among others. */
1398 android_table[fd].statb.st_mode 1516 android_table[fd].statb.st_mode
1399 = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;; 1517 = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
1400 1518
1401 /* Owned by root. */ 1519 /* Owned by root. */
1402 android_table[fd].statb.st_uid = 0; 1520 android_table[fd].statb.st_uid = 0;
@@ -1411,6 +1529,64 @@ android_open (const char *filename, int oflag, int mode)
1411 return fd; 1529 return fd;
1412 } 1530 }
1413 1531
1532 if (android_init_gui && android_content_name_p (filename))
1533 {
1534 /* This is a content:// URI. Ask the system for a descriptor to
1535 that file. */
1536
1537 name = android_get_content_name (filename);
1538 length = strlen (name);
1539
1540 /* Check if the mode is valid. */
1541
1542 if (oflag & O_DIRECTORY)
1543 {
1544 errno = ENOTSUP;
1545 return -1;
1546 }
1547
1548 /* Allocate a buffer to hold the file name. */
1549 string = (*android_java_env)->NewByteArray (android_java_env,
1550 length);
1551 if (!string)
1552 {
1553 (*android_java_env)->ExceptionClear (android_java_env);
1554 errno = ENOMEM;
1555 return -1;
1556 }
1557 (*android_java_env)->SetByteArrayRegion (android_java_env,
1558 string, 0, length,
1559 (jbyte *) name);
1560
1561 /* Try to open the file descriptor. */
1562
1563 fd
1564 = (*android_java_env)->CallIntMethod (android_java_env,
1565 emacs_service,
1566 service_class.open_content_uri,
1567 string,
1568 (jboolean) ((mode & O_WRONLY
1569 || mode & O_RDWR)
1570 != 0),
1571 (jboolean) !(mode & O_WRONLY),
1572 (jboolean) ((mode & O_TRUNC)
1573 != 0));
1574
1575 if ((*android_java_env)->ExceptionCheck (android_java_env))
1576 {
1577 (*android_java_env)->ExceptionClear (android_java_env);
1578 errno = ENOMEM;
1579 ANDROID_DELETE_LOCAL_REF (string);
1580 return -1;
1581 }
1582
1583 if (mode & O_CLOEXEC)
1584 android_close_on_exec (fd);
1585
1586 ANDROID_DELETE_LOCAL_REF (string);
1587 return fd;
1588 }
1589
1414 return open (filename, oflag, mode); 1590 return open (filename, oflag, mode);
1415} 1591}
1416 1592
@@ -1488,6 +1664,12 @@ android_proc_name (int fd, char *buffer, size_t size)
1488#pragma GCC diagnostic ignored "-Wmissing-prototypes" 1664#pragma GCC diagnostic ignored "-Wmissing-prototypes"
1489#endif 1665#endif
1490 1666
1667JNIEXPORT jint JNICALL
1668NATIVE_NAME (dup) (JNIEnv *env, jobject object, jint fd)
1669{
1670 return dup (fd);
1671}
1672
1491JNIEXPORT jstring JNICALL 1673JNIEXPORT jstring JNICALL
1492NATIVE_NAME (getFingerprint) (JNIEnv *env, jobject object) 1674NATIVE_NAME (getFingerprint) (JNIEnv *env, jobject object)
1493{ 1675{
@@ -1795,6 +1977,10 @@ android_init_emacs_service (void)
1795 "(Lorg/gnu/emacs/EmacsWindow;IIII)V"); 1977 "(Lorg/gnu/emacs/EmacsWindow;IIII)V");
1796 FIND_METHOD (reset_ic, "resetIC", 1978 FIND_METHOD (reset_ic, "resetIC",
1797 "(Lorg/gnu/emacs/EmacsWindow;I)V"); 1979 "(Lorg/gnu/emacs/EmacsWindow;I)V");
1980 FIND_METHOD (open_content_uri, "openContentUri",
1981 "([BZZZ)I");
1982 FIND_METHOD (check_content_uri, "checkContentUri",
1983 "([BZZ)Z");
1798#undef FIND_METHOD 1984#undef FIND_METHOD
1799} 1985}
1800 1986
@@ -4577,7 +4763,28 @@ android_faccessat (int dirfd, const char *pathname, int mode, int flags)
4577 if (dirfd == AT_FDCWD 4763 if (dirfd == AT_FDCWD
4578 && asset_manager 4764 && asset_manager
4579 && (asset = android_get_asset_name (pathname))) 4765 && (asset = android_get_asset_name (pathname)))
4580 return !android_file_access_p (asset, mode); 4766 {
4767 if (android_file_access_p (asset, mode))
4768 return 0;
4769
4770 /* Set errno to an appropriate value. */
4771 errno = ENOENT;
4772 return 1;
4773 }
4774
4775 /* Check if pathname is actually a content resolver URI. */
4776
4777 if (dirfd == AT_FDCWD
4778 && android_init_gui
4779 && android_content_name_p (pathname))
4780 {
4781 if (android_check_content_access (pathname, mode))
4782 return 0;
4783
4784 /* Set errno to an appropriate value. */
4785 errno = ENOENT;
4786 return 1;
4787 }
4581 4788
4582#if __ANDROID_API__ >= 16 4789#if __ANDROID_API__ >= 16
4583 return faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS); 4790 return faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);