Merge "Grant file managers full access to files table"
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 57ac286..6b60565 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -5656,6 +5656,11 @@
return true;
}
+ // Apps that have permission to manage external storage can work with all files
+ if (mCallingIdentity.get().hasPermission(PERMISSION_MANAGE_EXTERNAL_STORAGE)) {
+ return true;
+ }
+
// Check if caller is known to be owner of this item, to speed up
// performance of our permission checks
final int table = matchUri(uri, true);
diff --git a/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java b/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java
index 4fba34b..b3ee227 100644
--- a/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java
+++ b/tests/jni/FuseDaemonTest/host/src/com/android/tests/fused/host/FuseDaemonHostTest.java
@@ -223,4 +223,9 @@
public void testCanCreateHiddenFile() throws Exception {
runDeviceTest("testCanCreateHiddenFile");
}
+
+ @Test
+ public void testManageExternalStorageQueryOtherAppsFile() throws Exception {
+ runDeviceTest("testManageExternalStorageQueryOtherAppsFile");
+ }
}
diff --git a/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java b/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java
index 3bbdcdd..878d1ec 100644
--- a/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java
+++ b/tests/jni/FuseDaemonTest/src/com/android/tests/fused/FilePathAccessTest.java
@@ -39,6 +39,7 @@
import static com.android.tests.fused.lib.TestUtils.getContentResolver;
import static com.android.tests.fused.lib.TestUtils.getFileMimeTypeFromDatabase;
import static com.android.tests.fused.lib.TestUtils.getFileRowIdFromDatabase;
+import static com.android.tests.fused.lib.TestUtils.getFileUri;
import static com.android.tests.fused.lib.TestUtils.installApp;
import static com.android.tests.fused.lib.TestUtils.listAs;
import static com.android.tests.fused.lib.TestUtils.openWithMediaProvider;
@@ -59,6 +60,7 @@
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.database.Cursor;
+import android.net.Uri;
import android.os.Environment;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -1377,6 +1379,53 @@
}
}
+ @Test
+ public void testManageExternalStorageQueryOtherAppsFile() throws Exception {
+ final File otherAppPdf = new File(DOWNLOAD_DIR, "other" + NONMEDIA_FILE_NAME);
+ final File otherAppImg = new File(DCIM_DIR, "other" + IMAGE_FILE_NAME);
+ final File otherAppMusic = new File(MUSIC_DIR, "other" + MUSIC_FILE_NAME);
+ try {
+ installApp(TEST_APP_A, false);
+ assertCreateFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
+
+ // Once we have permission to manage external storage, we can query for other apps'
+ // files and open them for read and write
+ adoptShellPermissionIdentity(Manifest.permission.MANAGE_EXTERNAL_STORAGE);
+
+ assertCanQueryAndOpenFile(otherAppPdf, "rw");
+ assertCanQueryAndOpenFile(otherAppImg, "rw");
+ assertCanQueryAndOpenFile(otherAppMusic, "rw");
+ } finally {
+ dropShellPermissionIdentity();
+ deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
+ uninstallApp(TEST_APP_A);
+ }
+ }
+
+ private static void assertCreateFilesAs(TestApp testApp, File... files) throws Exception {
+ for (File file : files) {
+ assertThat(createFileAs(testApp, file.getPath())).isTrue();
+ }
+ }
+
+ private static void deleteFilesAs(TestApp testApp, File... files) throws Exception {
+ for (File file : files) {
+ deleteFileAs(testApp, file.getPath());
+ }
+ }
+
+ private static void assertCanQueryAndOpenFile(File file, String mode) throws IOException {
+ // This call performs the query
+ final Uri fileUri = getFileUri(file);
+ // The query succeeds iff it didn't return null
+ assertThat(fileUri).isNotNull();
+ // Now we assert that we can open the file through ContentResolver
+ try (final ParcelFileDescriptor pfd =
+ getContentResolver().openFileDescriptor(fileUri, mode)) {
+ assertThat(pfd).isNotNull();
+ }
+ }
+
/**
* Assert that the last read in: read - write - read using {@code readFd} and {@code writeFd}
* see the last write. {@code readFd} and {@code writeFd} are fds pointing to the same