Merge "Use AppOp value from local identity cache." into mainline-prod
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 7917cc6..93218cf 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -4,7 +4,12 @@
             "name": "MediaProviderTests"
         },
         {
-            "name": "MediaProviderClientTests"
+            "name": "MediaProviderClientTests",
+            "options": [
+                {
+                  "exclude-annotation": "androidx.test.filters.LargeTest"
+                }
+            ]
         },
         {
             "name": "CtsProviderTestCases",
@@ -28,5 +33,10 @@
         {
             "name": "fuse_node_test"
         }
+    ],
+    "postsubmit": [
+        {
+            "name": "MediaProviderClientTests"
+        }
     ]
 }
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
old mode 100644
new mode 100755
index 9d3d280..234d5ff
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -1383,7 +1383,8 @@
                 // Ignore lookup errors on
                 // 1. non-existing files returned from MediaProvider database.
                 // 2. path that doesn't match FuseDaemon UID and calling uid.
-                if (error_code == ENOENT || error_code == EPERM || error_code == EACCES) continue;
+                if (error_code == ENOENT || error_code == EPERM || error_code == EACCES
+                    || error_code == EIO) continue;
                 fuse_reply_err(req, error_code);
                 return;
             }
diff --git a/tests/client/src/com/android/providers/media/client/PerformanceTest.java b/tests/client/src/com/android/providers/media/client/PerformanceTest.java
index b0ae33d..21cdb8b 100644
--- a/tests/client/src/com/android/providers/media/client/PerformanceTest.java
+++ b/tests/client/src/com/android/providers/media/client/PerformanceTest.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
@@ -40,6 +41,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -238,32 +240,49 @@
 
     @Test
     public void testDirOperations_10() throws Exception {
-        Timer createTimer = new Timer("mkdir");
-        Timer readTimer = new Timer("readdir");
-        Timer deleteTimer = new Timer("rmdir");
-        for (int i = 0; i < COUNT_REPEAT; i++ ){
-            doDirOperations(10, createTimer, readTimer, deleteTimer);
-        }
-        createTimer.dumpResults();
-        readTimer.dumpResults();
-        deleteTimer.dumpResults();
+        testDirOperations_size(10);
     }
 
     @Test
     public void testDirOperations_100() throws Exception {
+        testDirOperations_size(100);
+    }
+
+    @Test
+    public void testDirOperations_500() throws Exception {
+        testDirOperations_size(500);
+    }
+
+    @LargeTest
+    @Test
+    public void testDirOperations_1000() throws Exception {
+        testDirOperations_size(1000);
+    }
+
+    private void testDirOperations_size(int size) throws Exception {
         Timer createTimer = new Timer("mkdir");
         Timer readTimer = new Timer("readdir");
+        // We have different timers for rename dir only and rename files as we want to track the
+        // performance for both of the following:
+        // 1. Renaming a directory is significantly faster (for file managers) as we do not update
+        // DB entries for all the files within it. (it takes ~10ms for a dir of 1000 files)
+        // 2. Renaming files is faster as well (for file managers), as we do not do DB operations
+        // on each rename.
+        Timer renameDirTimer = new Timer("renamedir");
+        Timer renameFilesTimer = new Timer("renamefiles");
         Timer deleteTimer = new Timer("rmdir");
-        for (int i = 0; i < COUNT_REPEAT; i++ ){
-            doDirOperations(100, createTimer, readTimer, deleteTimer);
+        for (int i = 0; i < COUNT_REPEAT; i++ ) {
+            doDirOperations(size, createTimer, readTimer, renameDirTimer, renameFilesTimer,
+                    deleteTimer);
         }
         createTimer.dumpResults();
         readTimer.dumpResults();
+        renameDirTimer.dumpResults();
+        renameFilesTimer.dumpResults();
         deleteTimer.dumpResults();
     }
-
-    private void doDirOperations(int size, Timer createTimer, Timer readTimer, Timer deleteTimer)
-            throws Exception {
+    private void doDirOperations(int size, Timer createTimer, Timer readTimer,
+            Timer renameDirTimer, Timer renameFilesTimer, Timer deleteTimer) throws Exception {
         createTimer.start();
         File testDir = new File(new File(Environment.getExternalStorageDirectory(),
                 "Download"), "test_dir_" + System.nanoTime());
@@ -276,12 +295,34 @@
         }
         createTimer.stop();
 
+        File renamedTestDir = new File(new File(Environment.getExternalStorageDirectory(),
+                "Download"), "renamed_test_dir_" + System.nanoTime());
         try {
             readTimer.start();
             File[] result = testDir.listFiles();
             readTimer.stop();
             assertEquals(size, result.length);
 
+            renameDirTimer.start();
+            assertTrue(testDir.renameTo(renamedTestDir));
+            renameDirTimer.stop();
+            testDir = renamedTestDir;
+
+            // renameTo for files will fail as the old files are not valid files as the dir name
+            // is changed, update the files to be valid.
+            files = Arrays.asList(renamedTestDir.listFiles());
+
+            renameFilesTimer.start();
+            List<File> renamedFiles = new ArrayList<>();
+            for (File file : files) {
+                File newFile = new File(testDir, "file_" + System.nanoTime());
+                assertTrue(file.renameTo(newFile));
+                renamedFiles.add(newFile);
+            }
+            renameFilesTimer.stop();
+            // This is essential for the finally block to delete valid files.
+            files = renamedFiles;
+
         } finally {
             deleteTimer.start();
             for (File file : files) {