aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-02-21 15:28:06 +0800
committerPo Lu2023-02-21 15:28:06 +0800
commit7aa4ffddd842e495d1ae388afff12075317ecb07 (patch)
tree9ba8cb2c232665ee59113494f7e35eeb33ab8619
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.
-rw-r--r--doc/emacs/android.texi12
-rwxr-xr-xjava/debug.sh2
-rw-r--r--java/org/gnu/emacs/EmacsNative.java4
-rw-r--r--java/org/gnu/emacs/EmacsOpenActivity.java42
-rw-r--r--java/org/gnu/emacs/EmacsService.java119
-rw-r--r--src/android.c213
6 files changed, 379 insertions, 13 deletions
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index d070199d325..f176d68ae67 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -129,9 +129,15 @@ file, it invokes @command{emacsclient} with the options
129and the name of the file being opened. Then, upon success, the focus 129and the name of the file being opened. Then, upon success, the focus
130is transferred to any open Emacs frame. 130is transferred to any open Emacs frame.
131 131
132It is sadly impossible to open certain kinds of files which are 132@cindex /content directory, android
133provided by a ``content provider''. When that is the case, a dialog 133 Some files are given to Emacs as ``content identifiers'', which the
134is displayed with an explanation of the error. 134system provides access to outside the normal filesystem APIs. Emacs
135internally supports a temporary @file{/content} directory which is
136used to access those files. Do not make any assumptions about the
137contents of this directory, or try to open files in it yourself.
138
139 This feature is not provided on Android 4.3 and earlier, in which
140case the file is copied to a temporary directory instead.
135 141
136@node Android File System 142@node Android File System
137@section What files Emacs can access under Android 143@section What files Emacs can access under Android
diff --git a/java/debug.sh b/java/debug.sh
index 30e5a94eee5..f07bb98ed7d 100755
--- a/java/debug.sh
+++ b/java/debug.sh
@@ -281,7 +281,7 @@ else
281 # Upload the specified gdbserver binary to the device. 281 # Upload the specified gdbserver binary to the device.
282 adb -s $device push "$gdbserver" "$gdbserver_bin" 282 adb -s $device push "$gdbserver" "$gdbserver_bin"
283 283
284 if (adb -s $device pull /system/bin/tee /dev/null &> /dev/null); then 284 if adb -s $device shell ls /system/bin/tee; then
285 # Copy it to the user directory. 285 # Copy it to the user directory.
286 adb -s $device shell "$gdbserver_cat" 286 adb -s $device shell "$gdbserver_cat"
287 adb -s $device shell "run-as $package chmod +x gdbserver" 287 adb -s $device shell "run-as $package chmod +x gdbserver"
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
index ef1a0e75a5c..f0917a68120 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -31,6 +31,10 @@ public class EmacsNative
31 initialization. */ 31 initialization. */
32 private static final String[] libraryDeps; 32 private static final String[] libraryDeps;
33 33
34
35 /* Like `dup' in C. */
36 public static native int dup (int fd);
37
34 /* Obtain the fingerprint of this build of Emacs. The fingerprint 38 /* Obtain the fingerprint of this build of Emacs. The fingerprint
35 can be used to determine the dump file name. */ 39 can be used to determine the dump file name. */
36 public static native String getFingerprint (); 40 public static native String getFingerprint ();
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java
index c8501d91025..87ce454a816 100644
--- a/java/org/gnu/emacs/EmacsOpenActivity.java
+++ b/java/org/gnu/emacs/EmacsOpenActivity.java
@@ -57,6 +57,8 @@ import android.os.Build;
57import android.os.Bundle; 57import android.os.Bundle;
58import android.os.ParcelFileDescriptor; 58import android.os.ParcelFileDescriptor;
59 59
60import android.util.Log;
61
60import java.io.File; 62import java.io.File;
61import java.io.FileInputStream; 63import java.io.FileInputStream;
62import java.io.FileNotFoundException; 64import java.io.FileNotFoundException;
@@ -69,6 +71,8 @@ import java.io.UnsupportedEncodingException;
69public class EmacsOpenActivity extends Activity 71public class EmacsOpenActivity extends Activity
70 implements DialogInterface.OnClickListener 72 implements DialogInterface.OnClickListener
71{ 73{
74 private static final String TAG = "EmacsOpenActivity";
75
72 private class EmacsClientThread extends Thread 76 private class EmacsClientThread extends Thread
73 { 77 {
74 private ProcessBuilder builder; 78 private ProcessBuilder builder;
@@ -178,12 +182,16 @@ public class EmacsOpenActivity extends Activity
178 dialog.show (); 182 dialog.show ();
179 } 183 }
180 184
181 /* Check that the specified FILE is readable. If it is not, then 185 /* Check that the specified FILE is readable. If Android 4.4 or
182 copy the file in FD to a location in the system cache 186 later is being used, return URI formatted into a `/content/' file
183 directory and return the name of that file. */ 187 name.
188
189 If it is not, then copy the file in FD to a location in the
190 system cache directory and return the name of that file. */
184 191
185 private String 192 private String
186 checkReadableOrCopy (String file, ParcelFileDescriptor fd) 193 checkReadableOrCopy (String file, ParcelFileDescriptor fd,
194 Uri uri)
187 throws IOException, FileNotFoundException 195 throws IOException, FileNotFoundException
188 { 196 {
189 File inFile; 197 File inFile;
@@ -191,12 +199,34 @@ public class EmacsOpenActivity extends Activity
191 InputStream stream; 199 InputStream stream;
192 byte buffer[]; 200 byte buffer[];
193 int read; 201 int read;
202 String content;
203
204 Log.d (TAG, "checkReadableOrCopy: " + file);
194 205
195 inFile = new File (file); 206 inFile = new File (file);
196 207
197 if (inFile.setReadable (true)) 208 if (inFile.canRead ())
198 return file; 209 return file;
199 210
211 Log.d (TAG, "checkReadableOrCopy: NO");
212
213 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
214 {
215 content = "/content/" + uri.getEncodedAuthority ();
216
217 for (String segment : uri.getPathSegments ())
218 content += "/" + Uri.encode (segment);
219
220 /* Append the URI query. */
221
222 if (uri.getEncodedQuery () != null)
223 content += "?" + uri.getEncodedQuery ();
224
225 Log.d (TAG, "checkReadableOrCopy: " + content);
226
227 return content;
228 }
229
200 /* inFile is now the file being written to. */ 230 /* inFile is now the file being written to. */
201 inFile = new File (getCacheDir (), inFile.getName ()); 231 inFile = new File (getCacheDir (), inFile.getName ());
202 buffer = new byte[4098]; 232 buffer = new byte[4098];
@@ -398,7 +428,7 @@ public class EmacsOpenActivity extends Activity
398 if (names != null) 428 if (names != null)
399 fileName = new String (names, "UTF-8"); 429 fileName = new String (names, "UTF-8");
400 430
401 fileName = checkReadableOrCopy (fileName, fd); 431 fileName = checkReadableOrCopy (fileName, fd, uri);
402 } 432 }
403 catch (FileNotFoundException exception) 433 catch (FileNotFoundException exception)
404 { 434 {
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index ba6ec485d62..c9701ff2990 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -19,7 +19,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
19 19
20package org.gnu.emacs; 20package org.gnu.emacs;
21 21
22import java.io.FileNotFoundException;
22import java.io.IOException; 23import java.io.IOException;
24import java.io.UnsupportedEncodingException;
25
23import java.util.List; 26import java.util.List;
24import java.util.ArrayList; 27import java.util.ArrayList;
25 28
@@ -41,22 +44,31 @@ import android.app.Service;
41 44
42import android.content.ClipboardManager; 45import android.content.ClipboardManager;
43import android.content.Context; 46import android.content.Context;
47import android.content.ContentResolver;
44import android.content.Intent; 48import android.content.Intent;
45import android.content.pm.ApplicationInfo; 49import android.content.pm.ApplicationInfo;
46import android.content.pm.PackageManager.ApplicationInfoFlags; 50import android.content.pm.PackageManager.ApplicationInfoFlags;
47import android.content.pm.PackageManager; 51import android.content.pm.PackageManager;
48import android.content.res.AssetManager; 52import android.content.res.AssetManager;
49 53
54import android.database.Cursor;
55import android.database.MatrixCursor;
56
57
50import android.net.Uri; 58import android.net.Uri;
51 59
52import android.os.Build; 60import android.os.Build;
53import android.os.Looper; 61import android.os.Looper;
54import android.os.IBinder; 62import android.os.IBinder;
55import android.os.Handler; 63import android.os.Handler;
64import android.os.ParcelFileDescriptor;
56import android.os.Vibrator; 65import android.os.Vibrator;
57import android.os.VibratorManager; 66import android.os.VibratorManager;
58import android.os.VibrationEffect; 67import android.os.VibrationEffect;
59 68
69import android.provider.DocumentsContract;
70import android.provider.DocumentsContract.Document;
71
60import android.util.Log; 72import android.util.Log;
61import android.util.DisplayMetrics; 73import android.util.DisplayMetrics;
62 74
@@ -79,6 +91,7 @@ public class EmacsService extends Service
79 91
80 private EmacsThread thread; 92 private EmacsThread thread;
81 private Handler handler; 93 private Handler handler;
94 private ContentResolver resolver;
82 95
83 /* Keep this in synch with androidgui.h. */ 96 /* Keep this in synch with androidgui.h. */
84 public static final int IC_MODE_NULL = 0; 97 public static final int IC_MODE_NULL = 0;
@@ -193,6 +206,7 @@ public class EmacsService extends Service
193 metrics = getResources ().getDisplayMetrics (); 206 metrics = getResources ().getDisplayMetrics ();
194 pixelDensityX = metrics.xdpi; 207 pixelDensityX = metrics.xdpi;
195 pixelDensityY = metrics.ydpi; 208 pixelDensityY = metrics.ydpi;
209 resolver = getContentResolver ();
196 210
197 try 211 try
198 { 212 {
@@ -643,4 +657,109 @@ public class EmacsService extends Service
643 window.view.setICMode (icMode); 657 window.view.setICMode (icMode);
644 window.view.imManager.restartInput (window.view); 658 window.view.imManager.restartInput (window.view);
645 } 659 }
660
661 /* Open a content URI described by the bytes BYTES, a non-terminated
662 string; make it writable if WRITABLE, and readable if READABLE.
663 Truncate the file if TRUNCATE.
664
665 Value is the resulting file descriptor or -1 upon failure. */
666
667 public int
668 openContentUri (byte[] bytes, boolean writable, boolean readable,
669 boolean truncate)
670 {
671 String name, mode;
672 ParcelFileDescriptor fd;
673 int i;
674
675 /* Figure out the file access mode. */
676
677 mode = "";
678
679 if (readable)
680 mode += "r";
681
682 if (writable)
683 mode += "w";
684
685 if (truncate)
686 mode += "t";
687
688 /* Try to open an associated ParcelFileDescriptor. */
689
690 try
691 {
692 /* The usual file name encoding question rears its ugly head
693 again. */
694 name = new String (bytes, "UTF-8");
695 Log.d (TAG, "openContentUri: " + Uri.parse (name));
696
697 fd = resolver.openFileDescriptor (Uri.parse (name), mode);
698
699 /* Use detachFd on newer versions of Android or plain old
700 dup. */
701
702 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1)
703 {
704 i = fd.detachFd ();
705 fd.close ();
706
707 return i;
708 }
709 else
710 {
711 i = EmacsNative.dup (fd.getFd ());
712 fd.close ();
713
714 return i;
715 }
716 }
717 catch (Exception exception)
718 {
719 return -1;
720 }
721 }
722
723 public boolean
724 checkContentUri (byte[] string, boolean readable, boolean writable)
725 {
726 String mode, name;
727 ParcelFileDescriptor fd;
728
729 /* Decode this into a URI. */
730
731 try
732 {
733 /* The usual file name encoding question rears its ugly head
734 again. */
735 name = new String (string, "UTF-8");
736 Log.d (TAG, "checkContentUri: " + Uri.parse (name));
737 }
738 catch (UnsupportedEncodingException exception)
739 {
740 name = null;
741 throw new RuntimeException (exception);
742 }
743
744 mode = "r";
745
746 if (writable)
747 mode += "w";
748
749 try
750 {
751 fd = resolver.openFileDescriptor (Uri.parse (name), mode);
752 fd.close ();
753
754 Log.d (TAG, "checkContentUri: YES");
755
756 return true;
757 }
758 catch (Exception exception)
759 {
760 Log.d (TAG, "checkContentUri: NO");
761 Log.d (TAG, exception.toString ());
762 return false;
763 }
764 }
646}; 765};
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);