am d2c41457: Merge "Let\'s reinvent storage, yet again!" into mnc-dev

* commit 'd2c414573242fc59a2d34f66f1dfb610ec7d59a3':
  Let's reinvent storage, yet again!
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index cb68d74..c9853df 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -504,4 +504,5 @@
 
     void grantDefaultPermissions(int userId);
     void setCarrierAppPackagesProvider(in IPackagesProvider provider);
+    int getMountExternalMode(int uid);
 }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f9c50f3..7234e98 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -643,6 +643,10 @@
             }
             if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
                 argsForZygote.add("--mount-external-default");
+            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
+                argsForZygote.add("--mount-external-read");
+            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
+                argsForZygote.add("--mount-external-write");
             }
             argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
 
@@ -802,7 +806,12 @@
      * @hide
      */
     public static final boolean isIsolated() {
-        int uid = UserHandle.getAppId(myUid());
+        return isIsolated(myUid());
+    }
+
+    /** {@hide} */
+    public static final boolean isIsolated(int uid) {
+        uid = UserHandle.getAppId(uid);
         return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
     }
 
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index e55ae99..84a879c 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1177,6 +1177,21 @@
                     _data.recycle();
                 }
             }
+
+            @Override
+            public void remountUid(int uid) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeInt(uid);
+                    mRemote.transact(Stub.TRANSACTION_remountUid, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
         }
 
         private static final String DESCRIPTOR = "IMountService";
@@ -1292,6 +1307,8 @@
         static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
         static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;
 
+        static final int TRANSACTION_remountUid = IBinder.FIRST_CALL_TRANSACTION + 61;
+
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -1845,6 +1862,13 @@
                     reply.writeNoException();
                     return true;
                 }
+                case TRANSACTION_remountUid: {
+                    data.enforceInterface(DESCRIPTOR);
+                    int uid = data.readInt();
+                    remountUid(uid);
+                    reply.writeNoException();
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -2154,4 +2178,6 @@
     public String getPrimaryStorageUuid() throws RemoteException;
     public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
             throws RemoteException;
+
+    public void remountUid(int uid) throws RemoteException;
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9b26f24..aab68e9 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -871,6 +871,15 @@
     }
 
     /** {@hide} */
+    public void remountUid(int uid) {
+        try {
+            mMountService.remountUid(uid);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
     private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
     private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
     private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index c97fdf4..197004c 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -46,8 +46,12 @@
 
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = 0;
-    /** Default user-specific external storage should be mounted. */
+    /** Default external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_DEFAULT = 1;
+    /** Read-only external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_READ = 2;
+    /** Read-write external storage should be mounted. */
+    public static final int MOUNT_EXTERNAL_WRITE = 3;
 
     private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
 
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index fa870b9..3e86fac 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -519,6 +519,10 @@
                     niceName = arg.substring(arg.indexOf('=') + 1);
                 } else if (arg.equals("--mount-external-default")) {
                     mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
+                } else if (arg.equals("--mount-external-read")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_READ;
+                } else if (arg.equals("--mount-external-write")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
                 } else if (arg.equals("--query-abi-list")) {
                     abiListQuery = true;
                 } else if (arg.startsWith("--instruction-set=")) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 76db5d3..f7cfe0e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -66,6 +66,8 @@
 enum MountExternalKind {
   MOUNT_EXTERNAL_NONE = 0,
   MOUNT_EXTERNAL_DEFAULT = 1,
+  MOUNT_EXTERNAL_READ = 2,
+  MOUNT_EXTERNAL_WRITE = 3,
 };
 
 static void RuntimeAbort(JNIEnv* env) {
@@ -249,38 +251,49 @@
 
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
-static bool MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace) {
-  if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
+        bool force_mount_namespace) {
+    // See storage config details at http://source.android.com/tech/storage/
+
+    // Create a second private mount namespace for our process
+    if (unshare(CLONE_NEWNS) == -1) {
+        ALOGW("Failed to unshare(): %s", strerror(errno));
+        return false;
+    }
+
+    // Unmount storage provided by root namespace and mount requested view
+    umount2("/storage", MNT_FORCE);
+
+    String8 storageSource;
+    if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
+        storageSource = "/mnt/runtime_default";
+    } else if (mount_mode == MOUNT_EXTERNAL_READ) {
+        storageSource = "/mnt/runtime_read";
+    } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
+        storageSource = "/mnt/runtime_write";
+    } else {
+        // Sane default of no storage visible
+        return true;
+    }
+    if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
+            NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+        ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
+        return false;
+    }
+
+    // Mount user-specific symlink helpers into place
+    userid_t user_id = multiuser_get_user_id(uid);
+    const String8 userSource(String8::format("/mnt/user/%d", user_id));
+    if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+        return false;
+    }
+    if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
+            NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
+        return false;
+    }
+
     return true;
-  }
-
-  // Create a second private mount namespace for our process
-  if (unshare(CLONE_NEWNS) == -1) {
-      ALOGW("Failed to unshare(): %s", strerror(errno));
-      return false;
-  }
-
-  if (mount_mode == MOUNT_EXTERNAL_NONE) {
-    return true;
-  }
-
-  // See storage config details at http://source.android.com/tech/storage/
-  userid_t user_id = multiuser_get_user_id(uid);
-
-  // Bind mount user-specific storage into place
-  const String8 source(String8::format("/mnt/user/%d", user_id));
-  const String8 target(String8::format("/storage/self"));
-
-  if (fs_prepare_dir(source.string(), 0755, 0, 0) == -1) {
-    return false;
-  }
-
-  if (TEMP_FAILURE_RETRY(mount(source.string(), target.string(), NULL, MS_BIND, NULL)) == -1) {
-    ALOGW("Failed to mount %s to %s: %s", source.string(), target.string(), strerror(errno));
-    return false;
-  }
-
-  return true;
 }
 
 static bool NeedsNoRandomizeWorkaround() {
@@ -543,7 +556,7 @@
   pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                       debug_flags, rlimits,
                                       permittedCapabilities, effectiveCapabilities,
-                                      MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
+                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                       NULL, NULL);
   if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index c517201..377e6a16 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,21 +58,6 @@
         <group gid="log" />
     </permission>
 
-    <permission name="android.permission.READ_EXTERNAL_STORAGE" perUser="true" >
-        <group gid="sdcard_r" />
-    </permission>
-
-    <permission name="android.permission.WRITE_EXTERNAL_STORAGE" perUser="true" >
-        <group gid="sdcard_r" />
-        <group gid="sdcard_rw" />
-    </permission>
-
-    <permission name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" >
-        <group gid="sdcard_r" />
-        <group gid="sdcard_rw" />
-        <group gid="sdcard_all" />
-    </permission>
-
     <permission name="android.permission.WRITE_MEDIA_STORAGE" >
         <group gid="media_rw" />
     </permission>
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 4fe8fb9..45a7767 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -50,7 +50,9 @@
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -84,6 +86,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
@@ -675,13 +678,15 @@
     }
 
     private void handleSystemReady() {
-        resetIfReadyAndConnected();
+        synchronized (mLock) {
+            resetIfReadyAndConnectedLocked();
+        }
 
         // Start scheduling nominally-daily fstrim operations
         MountServiceIdler.scheduleIdlePass(mContext);
     }
 
-    private void resetIfReadyAndConnected() {
+    private void resetIfReadyAndConnectedLocked() {
         Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mSystemReady && mDaemonConnected) {
@@ -780,7 +785,9 @@
     }
 
     private void handleDaemonConnected() {
-        resetIfReadyAndConnected();
+        synchronized (mLock) {
+            resetIfReadyAndConnectedLocked();
+        }
 
         /*
          * Now that we've done our initialization, release
@@ -1600,7 +1607,7 @@
             // reset vold so we bind into new volume into place.
             if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
                 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
-                resetIfReadyAndConnected();
+                resetIfReadyAndConnectedLocked();
             }
 
             writeSettingsLocked();
@@ -1628,7 +1635,7 @@
             }
 
             writeSettingsLocked();
-            resetIfReadyAndConnected();
+            resetIfReadyAndConnectedLocked();
         }
     }
 
@@ -1641,6 +1648,30 @@
     }
 
     @Override
+    public void remountUid(int uid) {
+        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+        waitForReady();
+
+        final int mountExternal = mPms.getMountExternalMode(uid);
+        final String mode;
+        if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
+            mode = "default";
+        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
+            mode = "read";
+        } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
+            mode = "write";
+        } else {
+            mode = "none";
+        }
+
+        try {
+            mConnector.execute("volume", "remount_uid", uid, mode);
+        } catch (NativeDaemonConnectorException e) {
+            Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e);
+        }
+    }
+
+    @Override
     public void setDebugFlags(int flags, int mask) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
@@ -1651,7 +1682,7 @@
             }
 
             writeSettingsLocked();
-            resetIfReadyAndConnected();
+            resetIfReadyAndConnectedLocked();
         }
     }
 
@@ -1688,7 +1719,7 @@
                 Slog.d(TAG, "Skipping move to/from primary physical");
                 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
                 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
-                resetIfReadyAndConnected();
+                resetIfReadyAndConnectedLocked();
 
             } else {
                 final VolumeInfo from = Preconditions.checkNotNull(
@@ -2022,7 +2053,7 @@
 
     @Override
     public void finishMediaUpdate() {
-        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("no permission to call finishMediaUpdate()");
         }
         if (mUnmountSignal != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f031694..7204a6e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,9 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -3209,13 +3211,14 @@
 
             int uid = app.uid;
             int[] gids = null;
-            int mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
+            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
             if (!app.isolated) {
                 int[] permGids = null;
                 try {
                     checkTime(startTime, "startProcess: getting gids from package manager");
-                    permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName,
-                            app.userId);
+                    final IPackageManager pm = AppGlobals.getPackageManager();
+                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
+                    mountExternal = pm.getMountExternalMode(uid);
                 } catch (RemoteException e) {
                     throw e.rethrowAsRuntimeException();
                 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index be1afa8..40ff3f4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -54,6 +55,7 @@
 import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
 import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
@@ -196,6 +198,7 @@
 import com.android.internal.content.PackageHelper;
 import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
@@ -208,8 +211,8 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
-import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.pm.PermissionsState.PermissionState;
+import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -2562,6 +2565,21 @@
         return null;
     }
 
+    @Override
+    public int getMountExternalMode(int uid) {
+        if (Process.isIsolated(uid)) {
+            return Zygote.MOUNT_EXTERNAL_NONE;
+        } else {
+            if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
+                return Zygote.MOUNT_EXTERNAL_WRITE;
+            } else if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
+                return Zygote.MOUNT_EXTERNAL_READ;
+            } else {
+                return Zygote.MOUNT_EXTERNAL_DEFAULT;
+            }
+        }
+    }
+
     static PermissionInfo generatePermissionInfo(
             BasePermission bp, int flags) {
         if (bp.perm != null) {
@@ -3201,6 +3219,7 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
                 "grantRuntimePermission");
 
+        final int uid;
         final SettingBase sb;
 
         synchronized (mPackages) {
@@ -3216,6 +3235,7 @@
 
             enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
 
+            uid = pkg.applicationInfo.uid;
             sb = (SettingBase) pkg.mExtras;
             if (sb == null) {
                 throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -3245,11 +3265,22 @@
                 } break;
             }
 
-            mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+            mOnPermissionChangeListeners.onPermissionsChanged(uid);
 
             // Not critical if that is lost - app has to request again.
             mSettings.writeRuntimePermissionsForUserLPr(userId, false);
         }
+
+        if (READ_EXTERNAL_STORAGE.equals(name)
+                || WRITE_EXTERNAL_STORAGE.equals(name)) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final StorageManager storage = mContext.getSystemService(StorageManager.class);
+                storage.remountUid(uid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
     }
 
     @Override