Create a new MOUNT_EXTERNAL_LEGACY storage mode.

Apps that are already installed on the device before isolated_storage
feature is enabled will be granted MOUNT_EXTERNAL_LEGACY mode. In this
mode, /mnt/runtime/write will be mounted at /storage giving them same
level of access as in P.

A new mount directory /mnt/runtime/full is also created which will be
used for mounting at /storage for apps started with MOUNT_EXTERNAL_FULL
mode. This will allow apps with WRITE_MEDIA_STORAGE permission to
read/write anywhere on the secondary devices without needing to bypass
sdcardfs.

Bug: 121277410
Test: manual
Test: atest android.appsecurity.cts.ExternalStorageHostTest
Change-Id: I4ec73276d7c586ae4afc482580d1eb8ee03d5be1
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 99a85ea..ec77821 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -402,6 +402,8 @@
             argsForZygote.add("--mount-external-full");
         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
             argsForZygote.add("--mount-external-installer");
+        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
+            argsForZygote.add("--mount-external-legacy");
         }
 
         argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index f5746ca..705bae4 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -82,6 +82,11 @@
     /** Read-write external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE;
     /**
+     * Mount mode for apps that are already installed on the device before the isolated_storage
+     * feature is enabled.
+     */
+    public static final int MOUNT_EXTERNAL_LEGACY = IVold.REMOUNT_MODE_LEGACY;
+    /**
      * Mount mode for package installers which should give them access to
      * all obb dirs in addition to their package sandboxes
      */
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 5990d72..ced798c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -688,8 +688,10 @@
                     mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
                 } else if (arg.equals("--mount-external-full")) {
                     mountExternal = Zygote.MOUNT_EXTERNAL_FULL;
-                }  else if (arg.equals("--mount-external-installer")) {
+                } else if (arg.equals("--mount-external-installer")) {
                     mountExternal = Zygote.MOUNT_EXTERNAL_INSTALLER;
+                } else if (arg.equals("--mount-external-legacy")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_LEGACY;
                 } else if (arg.equals("--query-abi-list")) {
                     abiListQuery = true;
                 } else if (arg.equals("--get-pid")) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 7aee833..e81b627 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -109,8 +109,9 @@
   MOUNT_EXTERNAL_DEFAULT = 1,
   MOUNT_EXTERNAL_READ = 2,
   MOUNT_EXTERNAL_WRITE = 3,
-  MOUNT_EXTERNAL_INSTALLER = 4,
-  MOUNT_EXTERNAL_FULL = 5,
+  MOUNT_EXTERNAL_LEGACY = 4,
+  MOUNT_EXTERNAL_INSTALLER = 5,
+  MOUNT_EXTERNAL_FULL = 6,
 };
 
 // Must match values in com.android.internal.os.Zygote.
@@ -548,8 +549,9 @@
     }
 
     if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, false))) {
-        if (mount_mode == MOUNT_EXTERNAL_FULL) {
-            storageSource = "/mnt/runtime/write";
+        if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) {
+            storageSource = (mount_mode == MOUNT_EXTERNAL_FULL)
+                    ? "/mnt/runtime/full" : "/mnt/runtime/write";
             if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
                     NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
                 *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s",
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index db2a733..79f8d3e 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3288,7 +3288,8 @@
         }
 
         final int mountMode = mAmInternal.getStorageMountMode(pid, uid);
-        if (mountMode == Zygote.MOUNT_EXTERNAL_FULL) {
+        if (mountMode == Zygote.MOUNT_EXTERNAL_FULL
+                || mountMode == Zygote.MOUNT_EXTERNAL_LEGACY) {
             return path;
         }
 
@@ -3663,8 +3664,7 @@
                 return Zygote.MOUNT_EXTERNAL_FULL;
             } else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid,
                     packageName) == MODE_ALLOWED) {
-                // TODO: define a specific "legacy" mount mode
-                return Zygote.MOUNT_EXTERNAL_FULL;
+                return Zygote.MOUNT_EXTERNAL_LEGACY;
             } else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
                     == PERMISSION_GRANTED || mIAppOpsService.checkOperation(
                             OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
diff --git a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
index ec5d93e..68f696b 100644
--- a/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/StorageManagerServiceTest.java
@@ -227,6 +227,22 @@
     }
 
     @Test
+    public void testPackageInLegacyMode() throws Exception {
+        setStorageMountMode(PID_RED, UID_COLORS, Zygote.MOUNT_EXTERNAL_LEGACY);
+
+        // Both app and system have the same view
+        assertTranslation(
+                "/storage/emulated/0/Android/data/com.red/foo.jpg",
+                "/storage/emulated/0/Android/data/com.red/foo.jpg",
+                PID_RED, UID_COLORS);
+
+        assertTranslation(
+                "/storage/emulated/0/Android/sandbox/com.grey/bar.jpg",
+                "/storage/emulated/0/Android/sandbox/com.grey/bar.jpg",
+                PID_RED, UID_COLORS);
+    }
+
+    @Test
     public void testInstallerPackage() throws Exception {
         setStorageMountMode(PID_GREY, UID_GREY, Zygote.MOUNT_EXTERNAL_INSTALLER);