]> git.eshelyaron.com Git - emacs.git/commitdiff
Update Android port
authorPo Lu <luangruo@yahoo.com>
Tue, 1 Aug 2023 13:06:06 +0000 (21:06 +0800)
committerPo Lu <luangruo@yahoo.com>
Tue, 1 Aug 2023 13:06:06 +0000 (21:06 +0800)
* 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.

doc/emacs/android.texi
java/org/gnu/emacs/EmacsService.java
src/android.c
src/android.h
src/androidvfs.c

index 0330e9b589041854171819fdd95d34a7eccdfda6..4b8f36a65eb30d555f0419adc373653eb65aa5c1 100644 (file)
@@ -219,6 +219,15 @@ containing files provided by external programs (@pxref{Android
 Document Providers}.)
 @end itemize
 
+  Despite ordinary installations of Android not having files within
+the (normally read-only) root directory named @file{content} or
+@file{assets}, you may want to access real files by these names if the
+Android installation in use has been customized.  These files will
+conflict with the aformentioned special directories, but can
+nevertheless be accessed by writing their names relative to the
+``parent'' directory of the root directory, as so illustrated:
+@file{/../content}, @file{/../assets}.
+
   The external storage directory is found at @file{/sdcard}.  The
 other directories are not found at any fixed location (but see below),
 although the app data directory is typically symlinked to
@@ -268,10 +277,8 @@ System -> Apps -> Special App Access -> All files access -> Emacs
 
   After you disable or enable this setting as appropriate and grant
 Emacs the ``Files and Media'' permission, it will be able to access
-files under @file{/sdcard} as usual.
-
-  These settings are not present on many proprietary versions of
-Android.
+files under @file{/sdcard} as usual.  These settings are not present
+on some proprietary versions of Android.
 
 @node Android Document Providers
 @section Accessing files from other programs under Android
index 3c1bb0855f47fad1b25dfcbba551d64c00b8b5c0..8554dadd06e13f2e0d90daff2d20ad3189df8177 100644 (file)
@@ -1769,4 +1769,29 @@ public final class EmacsService extends Service
            ? DocumentsContract.getDocumentId (name)
            : null);
   }
+
+  /* Return if there is a content provider by the name of AUTHORITY
+     supplying at least one tree URI Emacs retains persistent rights
+     to access.  */
+
+  public boolean
+  validAuthority (String authority)
+  {
+    List<UriPermission> permissions;
+    Uri uri;
+
+    permissions = resolver.getPersistedUriPermissions ();
+
+    for (UriPermission permission : permissions)
+      {
+       uri = permission.getUri ();
+
+       if (DocumentsContract.isTreeUri (uri)
+           && permission.isReadPermission ()
+           && uri.getAuthority ().equals (authority))
+         return true;
+      }
+
+    return false;
+  }
 };
index 2b785319549753ef56c5f85209b4988b15224a07..c30d7b58979c66493c9a950c20d5c25b075e30d4 100644 (file)
@@ -1592,6 +1592,8 @@ android_init_emacs_service (void)
               "(Ljava/lang/String;Ljava/lang/String;"
               "Ljava/lang/String;Ljava/lang/String;"
               "Ljava/lang/String;)Ljava/lang/String;");
+  FIND_METHOD (valid_authority, "validAuthority",
+              "(Ljava/lang/String;)Z");
 #undef FIND_METHOD
 }
 
index 8440fb9bc753d3d1e9c3406df7a0c058a5b861c6..945bd649c18dab49f882c527b0a266ff978f1cb1 100644 (file)
@@ -284,6 +284,7 @@ struct android_emacs_service
   jmethodID delete_document;
   jmethodID rename_document;
   jmethodID move_document;
+  jmethodID valid_authority;
 };
 
 extern JNIEnv *android_java_env;
index eeef5ea5db0eac3423b6c0d16f235bc14c9815db..e3b0b895df30153a6e1e66cec4a25103b216813f 100644 (file)
@@ -3249,6 +3249,43 @@ static struct android_saf_root_vdir *all_saf_root_vdirs;
 static struct android_vnode *android_saf_tree_from_name (char *, const char *,
                                                         const char *);
 
+/* Forward declaration.  */
+static int android_verify_jni_string (const char *);
+
+/* Ascertain and return whether or not AUTHORITY designates a content
+   provider offering at least one directory tree accessible to
+   Emacs.  */
+
+static bool
+android_saf_valid_authority_p (const char *authority)
+{
+  jobject string;
+  jboolean valid;
+  jmethodID method;
+
+  /* Make certain AUTHORITY can actually be represented as a Java
+     string.  */
+
+  if (android_verify_jni_string (authority))
+    return false;
+
+  /* Build a string containing AUTHORITY.  */
+
+  string = (*android_java_env)->NewStringUTF (android_java_env,
+                                             authority);
+  android_exception_check ();
+
+  method = service_class.valid_authority;
+  valid
+    = (*android_java_env)->CallNonvirtualBooleanMethod (android_java_env,
+                                                       emacs_service,
+                                                       service_class.class,
+                                                       method, string);
+  android_exception_check_1 (string);
+  ANDROID_DELETE_LOCAL_REF (string);
+  return valid;
+}
+
 static struct android_vnode *
 android_saf_root_name (struct android_vnode *vnode, char *name,
                       size_t length)
@@ -3311,9 +3348,6 @@ android_saf_root_name (struct android_vnode *vnode, char *name,
     return android_saf_tree_from_name (component_end, component,
                                       vp->authority);
 
-  /* Otherwise, find the first component of NAME and create a vnode
-     representing it as an authority.  */
-
   /* Create the vnode.  */
   vp = xmalloc (sizeof *vp);
   vp->vnode.ops = &saf_root_vfs_ops;
@@ -3414,6 +3448,22 @@ static int
 android_saf_root_stat (struct android_vnode *vnode,
                       struct stat *statb)
 {
+  struct android_saf_root_vnode *vp;
+
+  /* Verify that the authority actually exists and return ENOENT
+     otherwise, lest `locate-dominating-file' & co call an operation
+     that doesn't require listing URIs under this authority, such as
+     access.  */
+
+  vp = (struct android_saf_root_vnode *) vnode;
+
+  if (vp->authority
+      && !android_saf_valid_authority_p (vp->authority))
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
   /* Make up some imaginary statistics for this vnode.  */
 
   memset (statb, 0, sizeof *statb);
@@ -3428,6 +3478,8 @@ android_saf_root_stat (struct android_vnode *vnode,
 static int
 android_saf_root_access (struct android_vnode *vnode, int mode)
 {
+  struct android_saf_root_vnode *vp;
+
   /* Validate MODE.  */
 
   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)
       return -1;
     }
 
+  /* Verify that the authority actually exists and return ENOENT
+     otherwise, lest `locate-dominating-file' & co call an operation
+     that doesn't require listing URIs under this authority, such as
+     access.  */
+
+  vp = (struct android_saf_root_vnode *) vnode;
+
+  if (vp->authority
+      && !android_saf_valid_authority_p (vp->authority))
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
   return 0;
 }
 
@@ -5309,9 +5375,9 @@ android_saf_tree_opendir (struct android_vnode *vnode)
    AUTHORITY is the name of the content provider authority that is
    offering TREE.
 
-   Value is NULL if no document tree or provider by those names
-   exists, or some other error takes place (for example, if TREE and
-   AUTHORITY aren't encoded correctly.)  */
+   Value is NULL and errno is set if no document tree or provider by
+   those names exists, or some other error takes place (for example,
+   if TREE and AUTHORITY aren't encoded correctly.)  */
 
 static struct android_vnode *
 android_saf_tree_from_name (char *name, const char *tree,
@@ -5323,7 +5389,18 @@ android_saf_tree_from_name (char *name, const char *tree,
   const char *uri;
   struct android_vnode *vp;
 
-  /* Assume that TREE and NAME are in ``modified UTF-8 format''.  */
+  /* It's not a given that NAME and TREE are actually in the modified
+     UTF-8 format used by the JVM to encode strings, and the JVM
+     aborts when encountering a string that is not.  Make sure they
+     are valid before continuing.  */
+
+  if (android_verify_jni_string (name)
+      || android_verify_jni_string (authority))
+    {
+      errno = ENOENT;
+      return NULL;
+    }
+
   tree_string = (*android_java_env)->NewStringUTF (android_java_env,
                                                   tree);
   android_exception_check ();