aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-08-01 21:06:06 +0800
committerPo Lu2023-08-01 21:06:06 +0800
commite41349dd93ffec2b1e383cb4c4dfdb59f6e7edac (patch)
tree0fcd44202d335331c554ebab0730467329729ad0
parentb022398b8f0a03f0e1b3ec8df41a439cdbe5bd19 (diff)
downloademacs-e41349dd93ffec2b1e383cb4c4dfdb59f6e7edac.tar.gz
emacs-e41349dd93ffec2b1e383cb4c4dfdb59f6e7edac.zip
Update Android port
* doc/emacs/android.texi (Android File System): Describe how to access real files named /assets or /contents if so required. * java/org/gnu/emacs/EmacsService.java (validAuthority): * src/android.c (android_init_emacs_service): * src/android.h: New function. * src/androidvfs.c (android_saf_valid_authority_p): New function. Wrap the Java function. (android_saf_root_stat, android_saf_root_access): Don't return success if no authority by vp->authority's name exists. (android_saf_tree_from_name): Check validity of string data before giving it to JNI.
-rw-r--r--doc/emacs/android.texi15
-rw-r--r--java/org/gnu/emacs/EmacsService.java25
-rw-r--r--src/android.c2
-rw-r--r--src/android.h1
-rw-r--r--src/androidvfs.c91
5 files changed, 123 insertions, 11 deletions
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index 0330e9b5890..4b8f36a65eb 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -219,6 +219,15 @@ containing files provided by external programs (@pxref{Android
219Document Providers}.) 219Document Providers}.)
220@end itemize 220@end itemize
221 221
222 Despite ordinary installations of Android not having files within
223the (normally read-only) root directory named @file{content} or
224@file{assets}, you may want to access real files by these names if the
225Android installation in use has been customized. These files will
226conflict with the aformentioned special directories, but can
227nevertheless be accessed by writing their names relative to the
228``parent'' directory of the root directory, as so illustrated:
229@file{/../content}, @file{/../assets}.
230
222 The external storage directory is found at @file{/sdcard}. The 231 The external storage directory is found at @file{/sdcard}. The
223other directories are not found at any fixed location (but see below), 232other directories are not found at any fixed location (but see below),
224although the app data directory is typically symlinked to 233although the app data directory is typically symlinked to
@@ -268,10 +277,8 @@ System -> Apps -> Special App Access -> All files access -> Emacs
268 277
269 After you disable or enable this setting as appropriate and grant 278 After you disable or enable this setting as appropriate and grant
270Emacs the ``Files and Media'' permission, it will be able to access 279Emacs the ``Files and Media'' permission, it will be able to access
271files under @file{/sdcard} as usual. 280files under @file{/sdcard} as usual. These settings are not present
272 281on some proprietary versions of Android.
273 These settings are not present on many proprietary versions of
274Android.
275 282
276@node Android Document Providers 283@node Android Document Providers
277@section Accessing files from other programs under Android 284@section Accessing files from other programs under Android
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index 3c1bb0855f4..8554dadd06e 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -1769,4 +1769,29 @@ public final class EmacsService extends Service
1769 ? DocumentsContract.getDocumentId (name) 1769 ? DocumentsContract.getDocumentId (name)
1770 : null); 1770 : null);
1771 } 1771 }
1772
1773 /* Return if there is a content provider by the name of AUTHORITY
1774 supplying at least one tree URI Emacs retains persistent rights
1775 to access. */
1776
1777 public boolean
1778 validAuthority (String authority)
1779 {
1780 List<UriPermission> permissions;
1781 Uri uri;
1782
1783 permissions = resolver.getPersistedUriPermissions ();
1784
1785 for (UriPermission permission : permissions)
1786 {
1787 uri = permission.getUri ();
1788
1789 if (DocumentsContract.isTreeUri (uri)
1790 && permission.isReadPermission ()
1791 && uri.getAuthority ().equals (authority))
1792 return true;
1793 }
1794
1795 return false;
1796 }
1772}; 1797};
diff --git a/src/android.c b/src/android.c
index 2b785319549..c30d7b58979 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1592,6 +1592,8 @@ android_init_emacs_service (void)
1592 "(Ljava/lang/String;Ljava/lang/String;" 1592 "(Ljava/lang/String;Ljava/lang/String;"
1593 "Ljava/lang/String;Ljava/lang/String;" 1593 "Ljava/lang/String;Ljava/lang/String;"
1594 "Ljava/lang/String;)Ljava/lang/String;"); 1594 "Ljava/lang/String;)Ljava/lang/String;");
1595 FIND_METHOD (valid_authority, "validAuthority",
1596 "(Ljava/lang/String;)Z");
1595#undef FIND_METHOD 1597#undef FIND_METHOD
1596} 1598}
1597 1599
diff --git a/src/android.h b/src/android.h
index 8440fb9bc75..945bd649c18 100644
--- a/src/android.h
+++ b/src/android.h
@@ -284,6 +284,7 @@ struct android_emacs_service
284 jmethodID delete_document; 284 jmethodID delete_document;
285 jmethodID rename_document; 285 jmethodID rename_document;
286 jmethodID move_document; 286 jmethodID move_document;
287 jmethodID valid_authority;
287}; 288};
288 289
289extern JNIEnv *android_java_env; 290extern JNIEnv *android_java_env;
diff --git a/src/androidvfs.c b/src/androidvfs.c
index eeef5ea5db0..e3b0b895df3 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -3249,6 +3249,43 @@ static struct android_saf_root_vdir *all_saf_root_vdirs;
3249static struct android_vnode *android_saf_tree_from_name (char *, const char *, 3249static struct android_vnode *android_saf_tree_from_name (char *, const char *,
3250 const char *); 3250 const char *);
3251 3251
3252/* Forward declaration. */
3253static int android_verify_jni_string (const char *);
3254
3255/* Ascertain and return whether or not AUTHORITY designates a content
3256 provider offering at least one directory tree accessible to
3257 Emacs. */
3258
3259static bool
3260android_saf_valid_authority_p (const char *authority)
3261{
3262 jobject string;
3263 jboolean valid;
3264 jmethodID method;
3265
3266 /* Make certain AUTHORITY can actually be represented as a Java
3267 string. */
3268
3269 if (android_verify_jni_string (authority))
3270 return false;
3271
3272 /* Build a string containing AUTHORITY. */
3273
3274 string = (*android_java_env)->NewStringUTF (android_java_env,
3275 authority);
3276 android_exception_check ();
3277
3278 method = service_class.valid_authority;
3279 valid
3280 = (*android_java_env)->CallNonvirtualBooleanMethod (android_java_env,
3281 emacs_service,
3282 service_class.class,
3283 method, string);
3284 android_exception_check_1 (string);
3285 ANDROID_DELETE_LOCAL_REF (string);
3286 return valid;
3287}
3288
3252static struct android_vnode * 3289static struct android_vnode *
3253android_saf_root_name (struct android_vnode *vnode, char *name, 3290android_saf_root_name (struct android_vnode *vnode, char *name,
3254 size_t length) 3291 size_t length)
@@ -3311,9 +3348,6 @@ android_saf_root_name (struct android_vnode *vnode, char *name,
3311 return android_saf_tree_from_name (component_end, component, 3348 return android_saf_tree_from_name (component_end, component,
3312 vp->authority); 3349 vp->authority);
3313 3350
3314 /* Otherwise, find the first component of NAME and create a vnode
3315 representing it as an authority. */
3316
3317 /* Create the vnode. */ 3351 /* Create the vnode. */
3318 vp = xmalloc (sizeof *vp); 3352 vp = xmalloc (sizeof *vp);
3319 vp->vnode.ops = &saf_root_vfs_ops; 3353 vp->vnode.ops = &saf_root_vfs_ops;
@@ -3414,6 +3448,22 @@ static int
3414android_saf_root_stat (struct android_vnode *vnode, 3448android_saf_root_stat (struct android_vnode *vnode,
3415 struct stat *statb) 3449 struct stat *statb)
3416{ 3450{
3451 struct android_saf_root_vnode *vp;
3452
3453 /* Verify that the authority actually exists and return ENOENT
3454 otherwise, lest `locate-dominating-file' & co call an operation
3455 that doesn't require listing URIs under this authority, such as
3456 access. */
3457
3458 vp = (struct android_saf_root_vnode *) vnode;
3459
3460 if (vp->authority
3461 && !android_saf_valid_authority_p (vp->authority))
3462 {
3463 errno = ENOENT;
3464 return -1;
3465 }
3466
3417 /* Make up some imaginary statistics for this vnode. */ 3467 /* Make up some imaginary statistics for this vnode. */
3418 3468
3419 memset (statb, 0, sizeof *statb); 3469 memset (statb, 0, sizeof *statb);
@@ -3428,6 +3478,8 @@ android_saf_root_stat (struct android_vnode *vnode,
3428static int 3478static int
3429android_saf_root_access (struct android_vnode *vnode, int mode) 3479android_saf_root_access (struct android_vnode *vnode, int mode)
3430{ 3480{
3481 struct android_saf_root_vnode *vp;
3482
3431 /* Validate MODE. */ 3483 /* Validate MODE. */
3432 3484
3433 if (mode != F_OK && !(mode & (W_OK | X_OK | R_OK))) 3485 if (mode != F_OK && !(mode & (W_OK | X_OK | R_OK)))
@@ -3444,6 +3496,20 @@ android_saf_root_access (struct android_vnode *vnode, int mode)
3444 return -1; 3496 return -1;
3445 } 3497 }
3446 3498
3499 /* Verify that the authority actually exists and return ENOENT
3500 otherwise, lest `locate-dominating-file' & co call an operation
3501 that doesn't require listing URIs under this authority, such as
3502 access. */
3503
3504 vp = (struct android_saf_root_vnode *) vnode;
3505
3506 if (vp->authority
3507 && !android_saf_valid_authority_p (vp->authority))
3508 {
3509 errno = ENOENT;
3510 return -1;
3511 }
3512
3447 return 0; 3513 return 0;
3448} 3514}
3449 3515
@@ -5309,9 +5375,9 @@ android_saf_tree_opendir (struct android_vnode *vnode)
5309 AUTHORITY is the name of the content provider authority that is 5375 AUTHORITY is the name of the content provider authority that is
5310 offering TREE. 5376 offering TREE.
5311 5377
5312 Value is NULL if no document tree or provider by those names 5378 Value is NULL and errno is set if no document tree or provider by
5313 exists, or some other error takes place (for example, if TREE and 5379 those names exists, or some other error takes place (for example,
5314 AUTHORITY aren't encoded correctly.) */ 5380 if TREE and AUTHORITY aren't encoded correctly.) */
5315 5381
5316static struct android_vnode * 5382static struct android_vnode *
5317android_saf_tree_from_name (char *name, const char *tree, 5383android_saf_tree_from_name (char *name, const char *tree,
@@ -5323,7 +5389,18 @@ android_saf_tree_from_name (char *name, const char *tree,
5323 const char *uri; 5389 const char *uri;
5324 struct android_vnode *vp; 5390 struct android_vnode *vp;
5325 5391
5326 /* Assume that TREE and NAME are in ``modified UTF-8 format''. */ 5392 /* It's not a given that NAME and TREE are actually in the modified
5393 UTF-8 format used by the JVM to encode strings, and the JVM
5394 aborts when encountering a string that is not. Make sure they
5395 are valid before continuing. */
5396
5397 if (android_verify_jni_string (name)
5398 || android_verify_jni_string (authority))
5399 {
5400 errno = ENOENT;
5401 return NULL;
5402 }
5403
5327 tree_string = (*android_java_env)->NewStringUTF (android_java_env, 5404 tree_string = (*android_java_env)->NewStringUTF (android_java_env,
5328 tree); 5405 tree);
5329 android_exception_check (); 5406 android_exception_check ();