From 20afcf9c0761410ec9f24ddce1fdac8cfb1585c3 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 5 Apr 2024 15:04:09 +0800 Subject: [PATCH] Enable relinquishing access to Android content directories * doc/emacs/android.texi (Android Document Providers): Document new command. * java/org/gnu/emacs/EmacsService.java (relinquishUriRights): New function. * src/Makefile.in (SOME_MACHINE_OBJECTS): Add androidvfs.c. * src/android.c (android_init_emacs_service): Link to new function. * src/android.h (struct android_emacs_service) : New field. * src/androidfns.c: * src/androidvfs.c (android_saf_tree_name) (android_saf_tree_opendir): Minor adjustments to commentary. (Fandroid_relinquish_directory_access): New function. (syms_of_androidvfs): Define new subr. (cherry picked from commit aad63f935f8737598835612b53bc3b53c124661f) --- doc/emacs/android.texi | 17 +++++---- java/org/gnu/emacs/EmacsService.java | 15 ++++++++ src/Makefile.in | 2 +- src/android.c | 2 ++ src/android.h | 1 + src/androidfns.c | 2 +- src/androidvfs.c | 54 ++++++++++++++++++++++++++-- 7 files changed, 82 insertions(+), 11 deletions(-) diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index c9f93429deb..ebc00c74ede 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -299,8 +299,8 @@ on some proprietary versions of Android. @cindex /content/storage directory, Android Android 5.0 introduces a new sort of program, the ``document -provider'': these programs are small programs that provide access to -their own files outside both the asset manager and the Unix +provider'': these programs are small services that provide access to +their own files independently of the asset manager and the Unix filesystem. Emacs supports accessing files and directories they provide, placing their files within the directory @file{/content/storage}. @@ -311,12 +311,15 @@ first request the right to access it. This is done by running the command (@pxref{M-x}) @code{android-request-directory-access}, which displays a file selection dialog. - If a directory is selected within this dialog, its contents are + If a directory is selected from this dialog, its contents are subsequently made available within a new directory named -@file{/content/storage/@var{authority}/@var{id}}, where -@var{authority} is the name of the document provider, and @var{id} is -a unique identifier assigned to the directory by the document -provider. +@file{/content/storage/@var{authority}/@var{id}}, where @var{authority} +is the name of the document provider, and @var{id} is a unique +identifier assigned to the directory by the document provider. + +@findex android-relinquish-directory-access + Such a directory can be deleted once no longer required by providing +its name to the command @code{android-relinquish-directory-access}. The same limitations applied to the @file{/assets} directory (@pxref{Android File System}) are applied when creating sub-processes diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java index 171b427b05b..34682feeedb 100644 --- a/java/org/gnu/emacs/EmacsService.java +++ b/java/org/gnu/emacs/EmacsService.java @@ -1973,6 +1973,21 @@ public final class EmacsService extends Service return false; } + /* Relinquish authorization for read and write access to the provided + URI, which is generally a reference to a directory tree. */ + + public void + relinquishUriRights (String uri) + { + Uri uri1; + int flags; + + uri1 = Uri.parse (uri); + flags = (Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + resolver.releasePersistableUriPermission (uri1, flags); + } + /* Functions for detecting and requesting storage permissions. */ diff --git a/src/Makefile.in b/src/Makefile.in index 9dd88895d27..747ec7d406f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -494,7 +494,7 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \ w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ xsettings.o xgselect.o termcap.o hbfont.o \ haikuterm.o haikufns.o haikumenu.o haikufont.o androidterm.o androidfns.o \ - androidfont.o androidselect.c sfntfont-android.c sfntfont.c + androidfont.o androidselect.c androidvfs.c sfntfont-android.c sfntfont.c ## gmalloc.o if !SYSTEM_MALLOC && !DOUG_LEA_MALLOC, else empty. GMALLOC_OBJ=@GMALLOC_OBJ@ diff --git a/src/android.c b/src/android.c index dcd5c6d99c7..507ffc458d8 100644 --- a/src/android.c +++ b/src/android.c @@ -1690,6 +1690,8 @@ android_init_emacs_service (void) "requestStorageAccess", "()V"); FIND_METHOD (cancel_notification, "cancelNotification", "(Ljava/lang/String;)V"); + FIND_METHOD (relinquish_uri_rights, + "relinquishUriRights", "(Ljava/lang/String;)V"); #undef FIND_METHOD } diff --git a/src/android.h b/src/android.h index 2ca3d7e1446..19adfa38087 100644 --- a/src/android.h +++ b/src/android.h @@ -303,6 +303,7 @@ struct android_emacs_service jmethodID external_storage_available; jmethodID request_storage_access; jmethodID cancel_notification; + jmethodID relinquish_uri_rights; }; extern JNIEnv *android_java_env; diff --git a/src/androidfns.c b/src/androidfns.c index 83cf81c1f07..9f7ac8b69b2 100644 --- a/src/androidfns.c +++ b/src/androidfns.c @@ -3146,7 +3146,7 @@ for more details about these values. */) -/* Directory access requests. */ +/* SAF directory access management. */ DEFUN ("android-request-directory-access", Fandroid_request_directory_access, Sandroid_request_directory_access, 0, 0, "", diff --git a/src/androidvfs.c b/src/androidvfs.c index 2e23ed40cf5..88ea345a298 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c @@ -4997,7 +4997,7 @@ android_saf_tree_name (struct android_vnode *vnode, char *name, root.vnode.type = ANDROID_VNODE_SAF_ROOT; root.vnode.flags = 0; - /* Find the authority from the URI. */ + /* Derive the authority from the URI. */ fill = (char *) vp->tree_uri; @@ -5647,7 +5647,7 @@ android_saf_tree_opendir (struct android_vnode *vnode) dir->vdir.closedir = android_saf_tree_closedir; dir->vdir.dirfd = android_saf_tree_dirfd; - /* Find the authority from the URI. */ + /* Derive the authority from the URI. */ fill = (char *) vp->tree_uri; @@ -7816,8 +7816,58 @@ android_closedir (struct android_vdir *dirp) +DEFUN ("android-relinquish-directory-access", + Fandroid_relinquish_directory_access, + Sandroid_relinquish_directory_access, 1, 1, + "DDirectory: ", + doc: /* Relinquish access to the provided directory. +DIRECTORY must be an inferior directory to a subdirectory of +/content/storage. Once the command completes, the parent of DIRECTORY +below that subdirectory from will cease to appear there, but no files +will be removed. */) + (Lisp_Object file) +{ + struct android_vnode *vp; + struct android_saf_tree_vnode *saf_tree; + jstring string; + jmethodID method; + + if (android_get_current_api_level () < 21) + error ("Emacs can only access or relinquish application storage on" + " Android 5.0 and later"); + + if (!android_init_gui) + return Qnil; + + file = ENCODE_FILE (Fexpand_file_name (file, Qnil)); + vp = android_name_file (SSDATA (file)); + + if (vp->type != ANDROID_VNODE_SAF_TREE) + { + (*vp->ops->close) (vp); + signal_error ("Access to this directory cannot be relinquished", + file); + } + + saf_tree = (struct android_saf_tree_vnode *) vp; + string = android_build_jstring (saf_tree->tree_uri); + method = service_class.relinquish_uri_rights; + (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, + emacs_service, + service_class.class, + method, string); + (*vp->ops->close) (vp); + android_exception_check_1 (string); + ANDROID_DELETE_LOCAL_REF (string); + return Qnil; +} + + + void syms_of_androidvfs (void) { DEFSYM (Qandroid_jni, "android-jni"); + + defsubr (&Sandroid_relinquish_directory_access); } -- 2.39.5