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