diff options
-rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 1 | ||||
-rw-r--r-- | core/java/android/os/Process.java | 11 | ||||
-rw-r--r-- | core/java/android/os/storage/IMountService.java | 26 | ||||
-rw-r--r-- | core/java/android/os/storage/StorageManager.java | 9 | ||||
-rw-r--r-- | core/java/com/android/internal/os/Zygote.java | 6 | ||||
-rw-r--r-- | core/java/com/android/internal/os/ZygoteConnection.java | 4 | ||||
-rw-r--r-- | core/jni/com_android_internal_os_Zygote.cpp | 71 | ||||
-rw-r--r-- | data/etc/platform.xml | 15 | ||||
-rw-r--r-- | services/core/java/com/android/server/MountService.java | 47 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 35 |
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 |