Ensure MediaProvider Fuse is ready after Vold reset

I99cfe7d4dba0aae2e0f39bc7e881b21fd45ac150 can make cts fail for some
OEMs of which devices don't support adoptable storage.

I99cfe7d4dba0aae2e0f39bc7e881b21fd45ac150 just checks whether primary
and secondary storages are ready. It not only does not wait until
MediaProvider Fuse is ready, but also misinterprets unmounted state as
mounted state.

Even Vold kills MediaProvider as some TCs don't close opened FDs.

Bug: 222217635
Test: run cts -m CtsScopedStorageDeviceOnlyTest
Change-Id: Ic6e05e8c903b6bb0d3c3a91e75402d89c4d10841
diff --git a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
index a93aeee..549179d 100644
--- a/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
+++ b/hostsidetests/scopedstorage/ScopedStorageTestHelper/src/android/scopedstorage/cts/ScopedStorageTestHelper.java
@@ -50,6 +50,7 @@
 import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
 import android.provider.MediaStore;
 
 import androidx.annotation.Nullable;
@@ -155,10 +156,11 @@
         try {
             final String mode = queryType.equals(IS_URI_REDACTED_VIA_FILE_DESCRIPTOR_FOR_WRITE)
                     ? "w" : "r";
-            FileDescriptor fd = getContentResolver().openFileDescriptor(uri,
-                    mode).getFileDescriptor();
-            ExifInterface exifInterface = new ExifInterface(fd);
-            intent.putExtra(queryType, exifInterface.getGpsDateTime() == -1);
+            try (ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(uri, mode)) {
+                FileDescriptor fd = pfd.getFileDescriptor();
+                ExifInterface exifInterface = new ExifInterface(fd);
+                intent.putExtra(queryType, exifInterface.getGpsDateTime() == -1);
+            }
         } catch (Exception e) {
             intent.putExtra(INTENT_EXCEPTION, e);
         }
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java
index f0be82f..a122110 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/RedactUriDeviceTest.java
@@ -50,6 +50,7 @@
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
 import android.provider.MediaStore;
 
 import androidx.test.filters.SdkSuppress;
@@ -449,9 +450,10 @@
         try {
             assertUriIsUnredacted(img);
 
-            InputStream is = getContentResolver().openInputStream(redactedUri);
-            ExifInterface redactedExifInf = new ExifInterface(is);
-            assertUriIsRedacted(redactedExifInf);
+            try (InputStream is = getContentResolver().openInputStream(redactedUri)) {
+                ExifInterface redactedExifInf = new ExifInterface(is);
+                assertUriIsRedacted(redactedExifInf);
+            }
         } finally {
             img.delete();
         }
@@ -464,10 +466,12 @@
         try {
             assertUriIsUnredacted(img);
 
-            FileDescriptor fd = getContentResolver().openFileDescriptor(redactedUri,
-                    "r").getFileDescriptor();
-            ExifInterface redactedExifInf = new ExifInterface(fd);
-            assertUriIsRedacted(redactedExifInf);
+            try (ParcelFileDescriptor pfd =
+                    getContentResolver().openFileDescriptor(redactedUri, "r")) {
+                FileDescriptor fd = pfd.getFileDescriptor();
+                ExifInterface redactedExifInf = new ExifInterface(fd);
+                assertUriIsRedacted(redactedExifInf);
+            }
         } finally {
             img.delete();
         }
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index 605f85c..ad480e2 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -889,11 +889,11 @@
         try {
             assertThat(file.createNewFile()).isTrue();
 
-            ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-            ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
-
-            assertRWR(readPfd, writePfd);
-            assertUpperFsFd(writePfd); // With cache
+            try (ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+                 ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw")) {
+                assertRWR(readPfd, writePfd);
+                assertUpperFsFd(writePfd); // With cache
+            }
         } finally {
             file.delete();
         }
@@ -907,11 +907,11 @@
         try {
             assertThat(file.createNewFile()).isTrue();
 
-            ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
-            ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-
-            assertRWR(readPfd, writePfd);
-            assertLowerFsFdWithPassthrough(writePfd);
+            try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+                 ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+                assertRWR(readPfd, writePfd);
+                assertLowerFsFdWithPassthrough(writePfd);
+            }
         } finally {
             file.delete();
         }
@@ -925,11 +925,11 @@
         try {
             assertThat(file.createNewFile()).isTrue();
 
-            ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-            ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-
-            assertRWR(readPfd, writePfd);
-            assertUpperFsFd(readPfd); // With cache
+            try (ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
+                 ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw")) {
+                assertRWR(readPfd, writePfd);
+                assertUpperFsFd(readPfd); // With cache
+            }
         } finally {
             file.delete();
         }
@@ -943,11 +943,11 @@
         try {
             assertThat(file.createNewFile()).isTrue();
 
-            ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-            ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-
-            assertRWR(readPfd, writePfd);
-            assertLowerFsFdWithPassthrough(readPfd);
+            try (ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
+                 ParcelFileDescriptor writePfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+                assertRWR(readPfd, writePfd);
+                assertLowerFsFdWithPassthrough(readPfd);
+            }
         } finally {
             file.delete();
         }
@@ -962,13 +962,13 @@
             assertThat(file.createNewFile()).isTrue();
 
             // We upgrade 'w' only to 'rw'
-            ParcelFileDescriptor writePfd = openWithMediaProvider(file, "w");
-            ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw");
-
-            assertRWR(readPfd, writePfd);
-            assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
-            assertLowerFsFdWithPassthrough(writePfd);
-            assertLowerFsFdWithPassthrough(readPfd);
+            try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "w");
+                 ParcelFileDescriptor readPfd = openWithMediaProvider(file, "rw")) {
+                assertRWR(readPfd, writePfd);
+                assertRWR(writePfd, readPfd); // Can read on 'w' only pfd
+                assertLowerFsFdWithPassthrough(writePfd);
+                assertLowerFsFdWithPassthrough(readPfd);
+            }
         } finally {
             file.delete();
         }
@@ -985,15 +985,13 @@
 
             // Even if we close the original fd, since we have a dup open
             // the FUSE IO should still bypass the cache
-            try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw")) {
-                try (ParcelFileDescriptor writePfdDup = writePfd.dup();
-                     ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(
-                             file, MODE_READ_WRITE)) {
-                    writePfd.close();
+            try (ParcelFileDescriptor writePfd = openWithMediaProvider(file, "rw");
+                 ParcelFileDescriptor writePfdDup = writePfd.dup();
+                 ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+                writePfd.close();
 
-                    assertRWR(readPfd, writePfdDup);
-                    assertLowerFsFdWithPassthrough(writePfdDup);
-                }
+                assertRWR(readPfd, writePfdDup);
+                assertLowerFsFdWithPassthrough(writePfdDup);
             }
         } finally {
             file.delete();
@@ -1020,12 +1018,13 @@
             writePfd.close();
 
             // Upper fs open and read without direct_io
-            ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE);
-            Os.pread(readPfd.getFileDescriptor(), readBuffer, 0, 10, 0);
+            try (ParcelFileDescriptor readPfd = ParcelFileDescriptor.open(file, MODE_READ_WRITE)) {
+                Os.pread(readPfd.getFileDescriptor(), readBuffer, 0, 10, 0);
 
-            // Last write on lower fs is visible via upper fs
-            assertThat(readBuffer).isEqualTo(writeBuffer);
-            assertThat(readPfd.getStatSize()).isEqualTo(writeBuffer.length);
+                // Last write on lower fs is visible via upper fs
+                assertThat(readBuffer).isEqualTo(writeBuffer);
+                assertThat(readPfd.getStatSize()).isEqualTo(writeBuffer.length);
+            }
         } finally {
             file.delete();
         }
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 041e5ce..a04b5d8 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
@@ -854,8 +854,7 @@
      * Returns whether we can open the file.
      */
     public static boolean canOpen(File file, boolean forWrite) {
-        try {
-            openWithFilePath(file, forWrite);
+        try (ParcelFileDescriptor ignore = openWithFilePath(file, forWrite)) {
             return true;
         } catch (IOException expected) {
             return false;
@@ -1578,7 +1577,7 @@
     private static boolean isVolumeMounted(String type) {
         try {
             final String volume = executeShellCommand("sm list-volumes " + type).trim();
-            return volume != null && volume.contains("mounted");
+            return volume != null && volume.contains(" mounted");
         } catch (Exception e) {
             return false;
         }
@@ -1592,6 +1591,18 @@
         return isVolumeMounted("emulated");
     }
 
+    private static boolean isFuseReady() {
+        for (String volumeName : MediaStore.getExternalVolumeNames(getContext())) {
+            final Uri uri = MediaStore.Files.getContentUri(volumeName);
+            try (Cursor c = getContentResolver().query(uri, null, null, null)) {
+                assertThat(c).isNotNull();
+            } catch (IllegalArgumentException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * Prepare or create a public volume for testing
      */
@@ -1610,6 +1621,8 @@
                     "Timed out while waiting for public volume");
             pollForCondition(TestUtils::isEmulatedVolumeMounted,
                     "Timed out while waiting for emulated volume");
+            pollForCondition(TestUtils::isFuseReady,
+                    "Timed out while waiting for fuse");
         }
     }
 
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index c915235..4f62a91 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -680,7 +680,9 @@
             assertCanQueryAndOpenFile(otherPendingFile, "r");
 
             // We can also read other app's pending file via MediaStore API
-            assertNotNull(openWithMediaProvider(otherPendingFile, "r"));
+            try (ParcelFileDescriptor pfd = openWithMediaProvider(otherPendingFile, "r")) {
+                assertNotNull(pfd);
+            }
         } finally {
             deleteFileAsNoThrow(APP_B_NO_PERMS, otherPendingFile.getAbsolutePath());
         }