OSDN Git Service

Teach storage appops.
authorSvet Ganov <svetoslavganov@google.com>
Fri, 10 Jul 2015 21:29:33 +0000 (14:29 -0700)
committerSvetoslav <svetoslavganov@google.com>
Tue, 14 Jul 2015 01:22:30 +0000 (18:22 -0700)
For modern apps targeting M SDK and up the external storage state
is deterined by granted permissions. For apps targeting older SDK
the storage access is determined by app ops correspning to the
storage permissions as the latter are always granted.

When app ops change we do not remount as we kill the app process
in both cases enabling and disabling an app op since legacy code
is not prepared for dynamic behavior where an operation that failed
may next succeed. Hence, we remount when we start the app.

For modern apps we don't kill the app process on a permission
grant, therefore we synchronously remount the app storage.

bug:22104923

Change-Id: I601c19c764a74c2d15bea6630d0f5fdc52bf6a5a

core/java/android/content/pm/IPackageManager.aidl
core/java/android/os/storage/IMountService.java
core/java/android/os/storage/MountServiceInternal.java [new file with mode: 0644]
core/java/android/os/storage/StorageManager.java
core/java/android/os/storage/VolumeInfo.java
services/core/java/com/android/server/AppOpsService.java
services/core/java/com/android/server/MountService.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/pm/PackageManagerService.java

index 103ee29..ceb610a 100644 (file)
@@ -502,9 +502,6 @@ interface IPackageManager {
 
     void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
     void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
-
-    int getMountExternalMode(int uid);
-
     void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
 
     boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
index 84a879c..c3b098b 100644 (file)
@@ -758,13 +758,15 @@ public interface IMountService extends IInterface {
                 return _result;
             }
 
-            public StorageVolume[] getVolumeList(int userId) throws RemoteException {
+            public StorageVolume[] getVolumeList(int uid, String packageName)
+                    throws RemoteException {
                 Parcel _data = Parcel.obtain();
                 Parcel _reply = Parcel.obtain();
                 StorageVolume[] _result;
                 try {
                     _data.writeInterfaceToken(DESCRIPTOR);
-                    _data.writeInt(userId);
+                    _data.writeInt(uid);
+                    _data.writeString(packageName);
                     mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
                     _reply.readException();
                     _result = _reply.createTypedArray(StorageVolume.CREATOR);
@@ -1177,21 +1179,6 @@ public interface IMountService extends IInterface {
                     _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";
@@ -1307,8 +1294,6 @@ public interface IMountService extends IInterface {
         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.
@@ -1622,8 +1607,9 @@ public interface IMountService extends IInterface {
                 }
                 case TRANSACTION_getVolumeList: {
                     data.enforceInterface(DESCRIPTOR);
-                    int userId = data.readInt();
-                    StorageVolume[] result = getVolumeList(userId);
+                    int uid = data.readInt();
+                    String packageName = data.readString();
+                    StorageVolume[] result = getVolumeList(uid, packageName);
                     reply.writeNoException();
                     reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                     return true;
@@ -1862,13 +1848,6 @@ public interface IMountService extends IInterface {
                     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);
         }
@@ -2080,11 +2059,11 @@ public interface IMountService extends IInterface {
     /**
      * Returns list of all mountable volumes.
      */
-    public StorageVolume[] getVolumeList(int userId) throws RemoteException;
+    public StorageVolume[] getVolumeList(int uid, String packageName) throws RemoteException;
 
     /**
      * Gets the path on the filesystem for the ASEC container itself.
-     * 
+     *
      * @param cid ASEC container ID
      * @return path to filesystem or {@code null} if it's not found
      * @throws RemoteException
@@ -2178,6 +2157,4 @@ public interface IMountService extends IInterface {
     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/MountServiceInternal.java b/core/java/android/os/storage/MountServiceInternal.java
new file mode 100644 (file)
index 0000000..17aaef9
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+/**
+ * Mount service local interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class MountServiceInternal {
+
+    /**
+     * Policy that influences how external storage is mounted and reported.
+     */
+    public interface ExternalStorageMountPolicy {
+        /**
+         * Gets the external storage mount mode for the given uid.
+         *
+         * @param uid The UID for which to determine mount mode.
+         * @param packageName The package in the UID for making the call.
+         * @return The mount mode.
+         *
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_NONE
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_DEFAULT
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_READ
+         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_WRITE
+         */
+        public int getMountMode(int uid, String packageName);
+
+        /**
+         * Gets whether external storage should be reported to the given UID.
+         *
+         * @param uid The UID for which to determine whether it has external storage.
+         * @param packageName The package in the UID for making the call.
+         * @return Weather to report external storage.
+         * @return True to report the state of external storage, false to
+         *     report it as unmounted.
+         */
+        public boolean hasExternalStorage(int uid, String packageName);
+    }
+
+    /**
+     * Adds a policy for determining how external storage is mounted and reported.
+     * The mount mode is the most conservative result from querying all registered
+     * policies. Similarly, the reported state is the most conservative result from
+     * querying all registered policies.
+     *
+     * @param policy The policy to add.
+     */
+    public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy);
+
+    /**
+     * Notify the mount service that the mount policy for a UID changed.
+     * @param uid The UID for which policy changed.
+     * @param packageName The package in the UID for making the call.
+     */
+    public abstract void onExternalStoragePolicyChanged(int uid, String packageName);
+
+    /**
+     * Gets the mount mode to use for a given UID as determined by consultin all
+     * policies.
+     *
+     * @param uid The UID for which to get mount mode.
+     * @param packageName The package in the UID for making the call.
+     * @return The mount mode.
+     */
+    public abstract int getExternalStorageMountMode(int uid, String packageName);
+}
index f03e04e..140f317 100644 (file)
@@ -20,6 +20,7 @@ import static android.net.TrafficStats.MB_IN_BYTES;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.IPackageMoveObserver;
@@ -857,7 +858,9 @@ public class StorageManager {
         final IMountService mountService = IMountService.Stub.asInterface(
                 ServiceManager.getService("mount"));
         try {
-            return mountService.getVolumeList(userId);
+            final String packageName = ActivityThread.currentOpPackageName();
+            final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
+            return mountService.getVolumeList(uid, packageName);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -894,15 +897,6 @@ public class StorageManager {
     }
 
     /** {@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;
index 32f7bc9..8d603a1 100644 (file)
@@ -298,14 +298,14 @@ public class VolumeInfo implements Parcelable {
         }
     }
 
-    public StorageVolume buildStorageVolume(Context context, int userId) {
+    public StorageVolume buildStorageVolume(Context context, int userId, boolean reportUnmounted) {
         final StorageManager storage = context.getSystemService(StorageManager.class);
 
         final boolean removable;
         final boolean emulated;
         final boolean allowMassStorage = false;
-        final String envState = getEnvironmentForState(state);
-
+        final String envState = reportUnmounted
+                ? Environment.MEDIA_UNMOUNTED : getEnvironmentForState(state);
         File userPath = getPathForUser(userId);
         if (userPath == null) {
             userPath = new File("/dev/null");
index f0fc399..417f18d 100644 (file)
@@ -48,6 +48,7 @@ import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.storage.MountServiceInternal;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -60,6 +61,7 @@ import android.util.Xml;
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.os.Zygote;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
@@ -245,6 +247,34 @@ public class AppOpsService extends IAppOpsService.Stub {
                 scheduleFastWriteLocked();
             }
         }
+
+        MountServiceInternal mountServiceInternal = LocalServices.getService(
+                MountServiceInternal.class);
+        mountServiceInternal.addExternalStoragePolicy(
+                new MountServiceInternal.ExternalStorageMountPolicy() {
+                    @Override
+                    public int getMountMode(int uid, String packageName) {
+                        if (Process.isIsolated(uid)) {
+                            return Zygote.MOUNT_EXTERNAL_NONE;
+                        }
+                        if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
+                                packageName) != AppOpsManager.MODE_ALLOWED) {
+                            return Zygote.MOUNT_EXTERNAL_NONE;
+                        }
+                        if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
+                                packageName) != AppOpsManager.MODE_ALLOWED) {
+                            return Zygote.MOUNT_EXTERNAL_READ;
+                        }
+                        return Zygote.MOUNT_EXTERNAL_WRITE;
+                    }
+
+                    @Override
+                    public boolean hasExternalStorage(int uid, String packageName) {
+                        final int mountMode = getMountMode(uid, packageName);
+                        return mountMode == Zygote.MOUNT_EXTERNAL_READ
+                                || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
+                    }
+                });
     }
 
     public void packageRemoved(int uid, String packageName) {
index da552dd..bc61c3d 100644 (file)
@@ -68,6 +68,8 @@ import android.os.storage.IMountService;
 import android.os.storage.IMountServiceListener;
 import android.os.storage.IMountShutdownObserver;
 import android.os.storage.IObbActionListener;
+import android.os.storage.MountServiceInternal;
+import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy;
 import android.os.storage.OnObbStateChangeListener;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageResultCode;
@@ -127,6 +129,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -307,16 +310,6 @@ class MountService extends IMountService.Stub
     @GuardedBy("mLock")
     private String mMoveTargetUuid;
 
-    private DiskInfo findDiskById(String id) {
-        synchronized (mLock) {
-            final DiskInfo disk = mDisks.get(id);
-            if (disk != null) {
-                return disk;
-            }
-        }
-        throw new IllegalArgumentException("No disk found for ID " + id);
-    }
-
     private VolumeInfo findVolumeByIdOrThrow(String id) {
         synchronized (mLock) {
             final VolumeInfo vol = mVolumes.get(id);
@@ -456,6 +449,9 @@ class MountService extends IMountService.Stub
     /** Map from raw paths to {@link ObbState}. */
     final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
 
+    // Not guarded by a lock.
+    private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
+
     class ObbState implements IBinder.DeathRecipient {
         public ObbState(String rawPath, String canonicalPath, int callingUid,
                 IObbActionListener token, int nonce) {
@@ -807,7 +803,7 @@ class MountService extends IMountService.Stub
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
 
                     final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
@@ -1250,7 +1246,7 @@ class MountService extends IMountService.Stub
             // user-specific broadcasts.
             for (int userId : mStartedUsers) {
                 if (vol.isVisibleToUser(userId)) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
 
                     mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
@@ -1370,6 +1366,8 @@ class MountService extends IMountService.Stub
             readSettingsLocked();
         }
 
+        LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
+
         /*
          * Create the connection to vold with a maximum queue of twice the
          * amount of containers we'd ever expect to have. This keeps an
@@ -1787,27 +1785,28 @@ class MountService extends IMountService.Stub
         }
     }
 
-    @Override
-    public void remountUid(int uid) {
-        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+    private void remountUidExternalStorage(int uid, int mode) {
         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";
+        String modeName = "none";
+        switch (mode) {
+            case Zygote.MOUNT_EXTERNAL_DEFAULT: {
+                modeName = "default";
+            } break;
+
+            case Zygote.MOUNT_EXTERNAL_READ: {
+                modeName = "read";
+            } break;
+
+            case Zygote.MOUNT_EXTERNAL_WRITE: {
+                modeName = "write";
+            } break;
         }
 
         try {
-            mConnector.execute("volume", "remount_uid", uid, mode);
+            mConnector.execute("volume", "remount_uid", uid, modeName);
         } catch (NativeDaemonConnectorException e) {
-            Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e);
+            Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
         }
     }
 
@@ -2598,15 +2597,20 @@ class MountService extends IMountService.Stub
     }
 
     @Override
-    public StorageVolume[] getVolumeList(int userId) {
+    public StorageVolume[] getVolumeList(int uid, String packageName) {
         final ArrayList<StorageVolume> res = new ArrayList<>();
         boolean foundPrimary = false;
 
+        final int userId = UserHandle.getUserId(uid);
+        final boolean reportUnmounted = !mMountServiceInternal.hasExternalStorage(
+                uid, packageName);
+
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleToUser(userId)) {
-                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
+                            reportUnmounted);
                     if (vol.isPrimary()) {
                         res.add(0, userVol);
                         foundPrimary = true;
@@ -3379,4 +3383,50 @@ class MountService extends IMountService.Stub
             mCryptConnector.monitor();
         }
     }
+
+    private final class MountServiceInternalImpl extends MountServiceInternal {
+        // Not guarded by a lock.
+        private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
+                new CopyOnWriteArrayList<>();
+
+        @Override
+        public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
+            // No locking - CopyOnWriteArrayList
+            mPolicies.add(policy);
+        }
+
+        @Override
+        public void onExternalStoragePolicyChanged(int uid, String packageName) {
+            final int mountMode = getExternalStorageMountMode(uid, packageName);
+            remountUidExternalStorage(uid, mountMode);
+        }
+
+        @Override
+        public int getExternalStorageMountMode(int uid, String packageName) {
+            // No locking - CopyOnWriteArrayList
+            int mountMode = Integer.MAX_VALUE;
+            for (ExternalStorageMountPolicy policy : mPolicies) {
+                final int policyMode = policy.getMountMode(uid, packageName);
+                if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
+                    return Zygote.MOUNT_EXTERNAL_NONE;
+                }
+                mountMode = Math.min(mountMode, policyMode);
+            }
+            if (mountMode == Integer.MAX_VALUE) {
+                return Zygote.MOUNT_EXTERNAL_NONE;
+            }
+            return mountMode;
+        }
+
+        public boolean hasExternalStorage(int uid, String packageName) {
+            // No locking - CopyOnWriteArrayList
+            for (ExternalStorageMountPolicy policy : mPolicies) {
+                final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
+                if (!policyHasStorage) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
 }
index 6e94647..5bfca10 100644 (file)
@@ -18,7 +18,10 @@ package com.android.server.am;
 
 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.Manifest.permission.WRITE_MEDIA_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;
@@ -62,6 +65,7 @@ import android.os.Trace;
 import android.os.TransactionTooLargeException;
 import android.os.WorkSource;
 import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
 import android.os.storage.StorageManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
@@ -3219,7 +3223,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                     checkTime(startTime, "startProcess: getting gids from package manager");
                     final IPackageManager pm = AppGlobals.getPackageManager();
                     permGids = pm.getPackageGids(app.info.packageName, app.userId);
-                    mountExternal = pm.getMountExternalMode(uid);
+                    MountServiceInternal mountServiceInternal = LocalServices.getService(
+                            MountServiceInternal.class);
+                    mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
+                            app.info.packageName);
                 } catch (RemoteException e) {
                     throw e.rethrowAsRuntimeException();
                 }
index 13aca79..6d76832 100644 (file)
@@ -62,6 +62,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
 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_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Process.PACKAGE_INFO_GID;
@@ -166,6 +167,7 @@ import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
@@ -2727,23 +2729,6 @@ public class PackageManagerService extends IPackageManager.Stub {
         return null;
     }
 
-    @Override
-    public int getMountExternalMode(int uid) {
-        if (Process.isIsolated(uid)) {
-            return Zygote.MOUNT_EXTERNAL_NONE;
-        } else {
-            if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
-                return Zygote.MOUNT_EXTERNAL_DEFAULT;
-            } 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) {
@@ -3466,8 +3451,9 @@ public class PackageManagerService extends IPackageManager.Stub {
             final long token = Binder.clearCallingIdentity();
             try {
                 if (sUserManager.isInitialized(userId)) {
-                    final StorageManager storage = mContext.getSystemService(StorageManager.class);
-                    storage.remountUid(uid);
+                    MountServiceInternal mountServiceInternal = LocalServices.getService(
+                            MountServiceInternal.class);
+                    mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -14439,6 +14425,33 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         mInstallerService.systemReady();
         mPackageDexOptimizer.systemReady();
+
+        MountServiceInternal mountServiceInternal = LocalServices.getService(
+                MountServiceInternal.class);
+        mountServiceInternal.addExternalStoragePolicy(
+                new MountServiceInternal.ExternalStorageMountPolicy() {
+            @Override
+            public int getMountMode(int uid, String packageName) {
+                if (Process.isIsolated(uid)) {
+                    return Zygote.MOUNT_EXTERNAL_NONE;
+                }
+                if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
+                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
+                }
+                if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
+                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
+                }
+                if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
+                    return Zygote.MOUNT_EXTERNAL_READ;
+                }
+                return Zygote.MOUNT_EXTERNAL_WRITE;
+            }
+
+            @Override
+            public boolean hasExternalStorage(int uid, String packageName) {
+                return true;
+            }
+        });
     }
 
     @Override