Toggle MANAGE_EXTERNAL_STORAGE from the host

Denying M_E_S for an app should kill the app. If we do it from the test
app it self, it would crash and the test should fail.

This CL moves the logic of allowing/denying to the host side, and just
polls in the device side to make sure it has the access.

Test: atest
  ScopedStorageHostTest#testManageExternalStorageCanDeleteOtherAppsContents
  ScopedStorageHostTest#testManageExternalStorageReaddir
  ScopedStorageHostTest#testManageExternalStorageCanRenameOtherAppsContents
  ScopedStorageHostTest#testManageExternalStorageCantReadWriteOtherAppExternalDir
  ScopedStorageHostTest#testManageExternalStorageQueryOtherAppsFile
  ScopedStorageHostTest#testWallpaperApisManageExternalStorageAppOp
Fix: 158283222
Change-Id: I72ca525c98691f8e483076d20b7cfc6f1ed235be
Merged-In: I72ca525c98691f8e483076d20b7cfc6f1ed235be
(cherry picked from commit 8e77c177ba034978600de2f1cb1d666fa338c27c)
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index c067a1c..fa42d19 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -246,27 +246,52 @@
 
     @Test
     public void testManageExternalStorageCanCreateFilesAnywhere() throws Exception {
-        runDeviceTest("testManageExternalStorageCanCreateFilesAnywhere");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageCanCreateFilesAnywhere");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
     public void testManageExternalStorageCanDeleteOtherAppsContents() throws Exception {
-        runDeviceTest("testManageExternalStorageCanDeleteOtherAppsContents");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageCanDeleteOtherAppsContents");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
     public void testManageExternalStorageReaddir() throws Exception {
-        runDeviceTest("testManageExternalStorageReaddir");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageReaddir");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
     public void testManageExternalStorageCanRenameOtherAppsContents() throws Exception {
-        runDeviceTest("testManageExternalStorageCanRenameOtherAppsContents");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageCanRenameOtherAppsContents");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
     public void testManageExternalStorageCantReadWriteOtherAppExternalDir() throws Exception {
-        runDeviceTest("testManageExternalStorageCantReadWriteOtherAppExternalDir");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageCantReadWriteOtherAppExternalDir");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
@@ -321,7 +346,12 @@
 
     @Test
     public void testManageExternalStorageQueryOtherAppsFile() throws Exception {
-        runDeviceTest("testManageExternalStorageQueryOtherAppsFile");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testManageExternalStorageQueryOtherAppsFile");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
@@ -423,7 +453,12 @@
 
     @Test
     public void testWallpaperApisManageExternalStorageAppOp() throws Exception {
-        runDeviceTest("testWallpaperApisManageExternalStorageAppOp");
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testWallpaperApisManageExternalStorageAppOp");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
     }
 
     @Test
@@ -442,4 +477,16 @@
             executeShellCommand("pm revoke android.scopedstorage.cts " + perm);
         }
     }
+
+    private void allowAppOps(String... ops) throws Exception {
+        for (String op : ops) {
+            executeShellCommand("cmd appops set --uid android.scopedstorage.cts " + op + " allow");
+        }
+    }
+
+    private void denyAppOps(String... ops) throws Exception {
+        for (String op : ops) {
+            executeShellCommand("cmd appops set --uid android.scopedstorage.cts " + op + " deny");
+        }
+    }
 }
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index 34fbe79..aa2fba6 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -1145,4 +1145,13 @@
         }
         throw new TimeoutException(errorMessage);
     }
+
+    /**
+     * Polls for all files access to be allowed.
+     */
+    public static void pollForManageExternalStorageAllowed() throws Exception {
+        pollForCondition(
+                () -> Environment.isExternalStorageManager(),
+                "Timed out while waiting for MANAGE_EXTERNAL_STORAGE");
+    }
 }
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index 7395a73..b8fe03a 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -78,6 +78,7 @@
 import static android.scopedstorage.cts.lib.TestUtils.openFileAs;
 import static android.scopedstorage.cts.lib.TestUtils.openWithMediaProvider;
 import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
+import static android.scopedstorage.cts.lib.TestUtils.pollForManageExternalStorageAllowed;
 import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
 import static android.scopedstorage.cts.lib.TestUtils.queryFile;
 import static android.scopedstorage.cts.lib.TestUtils.queryFileExcludingPending;
@@ -1638,28 +1639,26 @@
 
     @Test
     public void testManageExternalStorageCanCreateFilesAnywhere() throws Exception {
+        pollForManageExternalStorageAllowed();
+
         final File topLevelPdf = new File(getExternalStorageDir(), NONMEDIA_FILE_NAME);
         final File musicFileInMovies = new File(getMoviesDir(), AUDIO_FILE_NAME);
         final File imageFileInDcim = new File(getDcimDir(), IMAGE_FILE_NAME);
-        try {
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-            // Nothing special about this, anyone can create an image file in DCIM
-            assertCanCreateFile(imageFileInDcim);
-            // This is where we see the special powers of MANAGE_EXTERNAL_STORAGE, because it can
-            // create a top level file
-            assertCanCreateFile(topLevelPdf);
-            // It can even create a music file in Pictures
-            assertCanCreateFile(musicFileInMovies);
-        } finally {
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-        }
+
+        // Nothing special about this, anyone can create an image file in DCIM
+        assertCanCreateFile(imageFileInDcim);
+        // This is where we see the special powers of MANAGE_EXTERNAL_STORAGE, because it can
+        // create a top level file
+        assertCanCreateFile(topLevelPdf);
+        // It can even create a music file in Pictures
+        assertCanCreateFile(musicFileInMovies);
     }
 
     @Test
     public void testManageExternalStorageCantReadWriteOtherAppExternalDir() throws Exception {
-        try {
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
+        pollForManageExternalStorageAllowed();
 
+        try {
             // Install TEST_APP_A with READ_EXTERNAL_STORAGE permission.
             installAppWithStoragePermissions(TEST_APP_A);
 
@@ -1682,7 +1681,6 @@
                     () -> { otherAppExternalDataFile.createNewFile(); });
 
         } finally {
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
             uninstallApp(TEST_APP_A); // Uninstalling deletes external app dirs
         }
     }
@@ -2038,6 +2036,8 @@
 
     @Test
     public void testManageExternalStorageCanDeleteOtherAppsContents() throws Exception {
+        pollForManageExternalStorageAllowed();
+
         final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
         final File otherAppImage = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
         final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
@@ -2049,8 +2049,6 @@
             assertThat(createFileAs(TEST_APP_A, otherAppImage.getPath())).isTrue();
             assertThat(createFileAs(TEST_APP_A, otherAppMusic.getPath())).isTrue();
 
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-
             assertThat(otherAppPdf.delete()).isTrue();
             assertThat(otherAppPdf.exists()).isFalse();
 
@@ -2060,7 +2058,6 @@
             assertThat(otherAppMusic.delete()).isTrue();
             assertThat(otherAppMusic.exists()).isFalse();
         } finally {
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
             deleteFileAsNoThrow(TEST_APP_A, otherAppPdf.getAbsolutePath());
             deleteFileAsNoThrow(TEST_APP_A, otherAppImage.getAbsolutePath());
             deleteFileAsNoThrow(TEST_APP_A, otherAppMusic.getAbsolutePath());
@@ -2159,6 +2156,8 @@
 
     @Test
     public void testManageExternalStorageCanRenameOtherAppsContents() throws Exception {
+        pollForManageExternalStorageAllowed();
+
         final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
         final File pdf = new File(getDownloadDir(), NONMEDIA_FILE_NAME);
         final File pdfInObviouslyWrongPlace = new File(getPicturesDir(), NONMEDIA_FILE_NAME);
@@ -2171,7 +2170,6 @@
             assertThat(createFileAs(TEST_APP_A, otherAppPdf.getPath())).isTrue();
             assertThat(otherAppPdf.exists()).isTrue();
 
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
 
             // Write some data to the file
             try (final FileOutputStream fos = new FileOutputStream(otherAppPdf)) {
@@ -2198,7 +2196,6 @@
             pdfInObviouslyWrongPlace.delete();
             topLevelPdf.delete();
             musicFile.delete();
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
             deleteFileAsNoThrow(TEST_APP_A, otherAppPdf.getAbsolutePath());
             uninstallApp(TEST_APP_A);
         }
@@ -2221,6 +2218,8 @@
 
     @Test
     public void testManageExternalStorageReaddir() throws Exception {
+        pollForManageExternalStorageAllowed();
+
         final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
         final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
         final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
@@ -2232,8 +2231,6 @@
             executeShellCommand("touch " + otherTopLevelFile);
             MediaStore.scanFile(getContentResolver(), otherTopLevelFile);
 
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-
             // We can list other apps' files
             assertDirectoryContains(otherAppPdf.getParentFile(), otherAppPdf);
             assertDirectoryContains(otherAppImg.getParentFile(), otherAppImg);
@@ -2244,7 +2241,6 @@
             // We can also list all top level directories
             assertDirectoryContains(getExternalStorageDir(), getDefaultTopLevelDirs());
         } finally {
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
             executeShellCommand("rm " + otherTopLevelFile);
             MediaStore.scanFile(getContentResolver(), otherTopLevelFile);
             deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf);
@@ -2254,6 +2250,8 @@
 
     @Test
     public void testManageExternalStorageQueryOtherAppsFile() throws Exception {
+        pollForManageExternalStorageAllowed();
+
         final File otherAppPdf = new File(getDownloadDir(), "other" + NONMEDIA_FILE_NAME);
         final File otherAppImg = new File(getDcimDir(), "other" + IMAGE_FILE_NAME);
         final File otherAppMusic = new File(getMusicDir(), "other" + AUDIO_FILE_NAME);
@@ -2264,16 +2262,11 @@
             assertCreatePublishedFilesAs(
                     TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
 
-            // Once the test has permission to manage external storage, it can query for other
-            // apps' files and open them for read and write
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-
             assertCanQueryAndOpenFile(otherAppPdf, "rw");
             assertCanQueryAndOpenFile(otherAppImg, "rw");
             assertCanQueryAndOpenFile(otherAppMusic, "rw");
             assertCanQueryAndOpenFile(otherHiddenFile, "rw");
         } finally {
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
             deleteFilesAs(TEST_APP_A, otherAppImg, otherAppMusic, otherAppPdf, otherHiddenFile);
             uninstallApp(TEST_APP_A);
         }
@@ -2508,15 +2501,12 @@
 
     @Test
     public void testWallpaperApisManageExternalStorageAppOp() throws Exception {
-        try {
-            allowAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-            WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext());
-            wallpaperManager.getFastDrawable();
-            wallpaperManager.peekFastDrawable();
-            wallpaperManager.getWallpaperFile(WallpaperManager.FLAG_SYSTEM);
-        } finally {
-            denyAppOpsToUid(Process.myUid(), OPSTR_MANAGE_EXTERNAL_STORAGE);
-        }
+        pollForManageExternalStorageAllowed();
+
+        WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext());
+        wallpaperManager.getFastDrawable();
+        wallpaperManager.peekFastDrawable();
+        wallpaperManager.getWallpaperFile(WallpaperManager.FLAG_SYSTEM);
     }
 
     @Test