summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2015-06-24 15:24:48 -0700
committerJeff Sharkey <jsharkey@android.com>2015-06-25 22:25:48 -0700
commit9527b223a9d4a4d149bb005afc77148dbeeff785 (patch)
tree5e3839f65f6dad7f402c280ef5de091238648159
parent9206d6a0e69ef0f60e20464796d4a2da6f7c42f4 (diff)
downloadframeworks_base-9527b223a9d4a4d149bb005afc77148dbeeff785.zip
frameworks_base-9527b223a9d4a4d149bb005afc77148dbeeff785.tar.gz
frameworks_base-9527b223a9d4a4d149bb005afc77148dbeeff785.tar.bz2
Let's reinvent storage, yet again!
Now that we're treating storage as a runtime permission, we need to grant read/write access without killing the app. This is really tricky, since we had been using GIDs for access control, and they're set in stone once Zygote drops privileges. The only thing left that can change dynamically is the filesystem itself, so let's do that. This means changing the FUSE daemon to present itself as three different views: /mnt/runtime_default/foo - view for apps with no access /mnt/runtime_read/foo - view for apps with read access /mnt/runtime_write/foo - view for apps with write access There is still a single location for all the backing files, and filesystem permissions are derived the same way for each view, but the file modes are masked off differently for each mountpoint. During Zygote fork, it wires up the appropriate storage access into an isolated mount namespace based on the current app permissions. When the app is granted permissions dynamically at runtime, the system asks vold to jump into the existing mount namespace and bind mount the newly granted access model into place. Bug: 21858077 Change-Id: I62fb25d126dd815aea699b33d580e3afb90f8fd2
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/os/Process.java11
-rw-r--r--core/java/android/os/storage/IMountService.java26
-rw-r--r--core/java/android/os/storage/StorageManager.java9
-rw-r--r--core/java/com/android/internal/os/Zygote.java6
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java4
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp71
-rw-r--r--data/etc/platform.xml15
-rw-r--r--services/core/java/com/android/server/MountService.java47
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java35
11 files changed, 175 insertions, 59 deletions
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 @@ interface IPackageManager {
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 @@ public class Process {
}
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 @@ public class Process {
* @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 @@ 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";
@@ -1292,6 +1307,8 @@ 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.
@@ -1845,6 +1862,13 @@ 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);
}
@@ -2154,4 +2178,6 @@ 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/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 @@ 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;
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 @@ public final class Zygote {
/** 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 @@ class ZygoteConnection {
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 @@ static jmethodID gCallPostForkChildHooks;
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 @@ static void SetSchedulerPolicy(JNIEnv* env) {
// 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) {
- 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;
- }
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
+ bool force_mount_namespace) {
+ // See storage config details at http://source.android.com/tech/storage/
- 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"));
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ ALOGW("Failed to unshare(): %s", strerror(errno));
+ return false;
+ }
- if (fs_prepare_dir(source.string(), 0755, 0, 0) == -1) {
- 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;
+ }
- 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;
- }
+ // 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;
+ return true;
}
static bool NeedsNoRandomizeWorkaround() {
@@ -543,7 +556,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
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.Handler;
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.GuardedBy;
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 @@ class MountService extends IMountService.Stub
}
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 @@ class MountService extends IMountService.Stub
}
private void handleDaemonConnected() {
- resetIfReadyAndConnected();
+ synchronized (mLock) {
+ resetIfReadyAndConnectedLocked();
+ }
/*
* Now that we've done our initialization, release
@@ -1600,7 +1607,7 @@ class MountService extends IMountService.Stub
// reset vold so we bind into new volume into place.
if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
- resetIfReadyAndConnected();
+ resetIfReadyAndConnectedLocked();
}
writeSettingsLocked();
@@ -1628,7 +1635,7 @@ class MountService extends IMountService.Stub
}
writeSettingsLocked();
- resetIfReadyAndConnected();
+ resetIfReadyAndConnectedLocked();
}
}
@@ -1641,6 +1648,30 @@ class MountService extends IMountService.Stub
}
@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 @@ class MountService extends IMountService.Stub
}
writeSettingsLocked();
- resetIfReadyAndConnected();
+ resetIfReadyAndConnectedLocked();
}
}
@@ -1688,7 +1719,7 @@ class MountService extends IMountService.Stub
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 @@ class MountService extends IMountService.Stub
@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 @@ 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.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 @@ public final class ActivityManagerService extends ActivityManagerNative
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 @@ package com.android.server.pm;
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_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_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.NativeLibraryHelper;
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.LocalServices;
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 @@ 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_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 @@ public class PackageManagerService extends IPackageManager.Stub {
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"grantRuntimePermission");
+ final int uid;
final SettingBase sb;
synchronized (mPackages) {
@@ -3216,6 +3235,7 @@ public class PackageManagerService extends IPackageManager.Stub {
enforceDeclaredAsUsedAndRuntimePermission(pkg, bp);
+ uid = pkg.applicationInfo.uid;
sb = (SettingBase) pkg.mExtras;
if (sb == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -3245,11 +3265,22 @@ public class PackageManagerService extends IPackageManager.Stub {
} 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