Fix ContentResolver opening with O_DIRECT

To ensure upper and lower fs cache consistency, when we return fds to
the lower fs via ContentResolver, we hold a lock on the file so that
subsequent file path opens will use direct_io and the latest writes
will be visible across upper and lower fs, see:
I7726a75a51869c0e3ea3856103dd501b1aa19d14

Ideally, we only need to hold a read lock but we cannot grab a read
lock when the fd is opened 'w' only.

Previously, we would grab a read lock for 'r' or 'rw' and a write lock
for 'w' only.

Now, we convert 'w' to 'rw'. This allows us always grab a read lock
and fixes the following scenario:

1. App opens file for 'w' via ContentResolver: Gets fd to the lower fs
2. App opens file for 'w' again. Gets fd to FUSE but with
O_DIRECT (because we set the write) lock in (1). This second fd cannot
be used with mmap(PROT_SHARED) for instance.

Test: atest ScopedStorageTest#testVfsCacheConsistency
Bug: 158226779
Change-Id: Iaf8054bf56bdc3bb1f71a1ee543ebb261fd58fbd
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 42f7bfe..0836cc0 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -5659,8 +5659,13 @@
      */
     private ParcelFileDescriptor openFileAndEnforcePathPermissionsHelper(Uri uri, int match,
             String mode, CancellationSignal signal) throws FileNotFoundException {
-        final int modeBits = ParcelFileDescriptor.parseMode(mode);
-        final boolean forWrite = (modeBits & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0;
+        int modeBits = ParcelFileDescriptor.parseMode(mode);
+        boolean forWrite = (modeBits & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0;
+        if (forWrite) {
+            // Upgrade 'w' only to 'rw'. This allows us acquire a WR_LOCK when calling
+            // #shouldOpenWithFuse
+            modeBits |= ParcelFileDescriptor.MODE_READ_WRITE;
+        }
 
         final boolean hasOwnerPackageName = hasOwnerPackageName(uri);
         final String[] projection = new String[] {
@@ -5773,9 +5778,10 @@
                 } catch (FileNotFoundException ignored) {
                 }
                 ParcelFileDescriptor lowerFsFd = FileUtils.openSafely(file, modeBits);
-                boolean forRead = (modeBits & ParcelFileDescriptor.MODE_READ_ONLY) != 0;
+                // Always acquire a readLock. This allows us make multiple opens via lower
+                // filesystem
                 boolean shouldOpenWithFuse = daemon != null
-                        && daemon.shouldOpenWithFuse(filePath, forRead, lowerFsFd.getFd());
+                        && daemon.shouldOpenWithFuse(filePath, true /* forRead */, lowerFsFd.getFd());
 
                 if (SystemProperties.getBoolean(PROP_FUSE, false) && shouldOpenWithFuse) {
                     // If the file is already opened on the FUSE mount with VFS caching enabled