Cleanup USER_OWNER in mount service
Also removed a failing unit test and the related code which is
now deprecated.
Bug: 19913735
Bug: 24064753
Change-Id: I9b11130b52caeb0ad890cc6adaaf7fb2fc7b5db6
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c3d32c2..4d32599 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -29,6 +29,7 @@
import android.Manifest;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.IActivityManager;
@@ -90,7 +91,6 @@
import libcore.util.EmptyArray;
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;
@@ -290,7 +290,7 @@
private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
/** Map from volume ID to disk */
@GuardedBy("mLock")
- private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
+ private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
/** Map from UUID to record */
@GuardedBy("mLock")
@@ -462,11 +462,7 @@
public ObbState(String rawPath, String canonicalPath, int callingUid,
IObbActionListener token, int nonce) {
this.rawPath = rawPath;
- this.canonicalPath = canonicalPath.toString();
-
- final int userId = UserHandle.getUserId(callingUid);
- this.ownerPath = buildObbPath(canonicalPath, userId, false);
- this.voldPath = buildObbPath(canonicalPath, userId, true);
+ this.canonicalPath = canonicalPath;
this.ownerGid = UserHandle.getSharedAppGid(callingUid);
this.token = token;
@@ -475,8 +471,6 @@
final String rawPath;
final String canonicalPath;
- final String ownerPath;
- final String voldPath;
final int ownerGid;
@@ -509,8 +503,6 @@
StringBuilder sb = new StringBuilder("ObbState{");
sb.append("rawPath=").append(rawPath);
sb.append(",canonicalPath=").append(canonicalPath);
- sb.append(",ownerPath=").append(ownerPath);
- sb.append(",voldPath=").append(voldPath);
sb.append(",ownerGid=").append(ownerGid);
sb.append(",token=").append(token);
sb.append(",binder=").append(getBinder());
@@ -569,6 +561,7 @@
private static final int H_VOLUME_MOUNT = 5;
private static final int H_VOLUME_BROADCAST = 6;
private static final int H_INTERNAL_BROADCAST = 7;
+ private static final int H_VOLUME_UNMOUNT = 8;
class MountServiceHandler extends Handler {
public MountServiceHandler(Looper looper) {
@@ -649,6 +642,11 @@
}
break;
}
+ case H_VOLUME_UNMOUNT: {
+ final VolumeInfo vol = (VolumeInfo) msg.obj;
+ unmount(vol.getId());
+ break;
+ }
case H_VOLUME_BROADCAST: {
final StorageVolume userVol = (StorageVolume) msg.obj;
final String envState = userVol.getState();
@@ -683,6 +681,7 @@
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ Preconditions.checkArgument(userId >= 0);
try {
if (Intent.ACTION_USER_ADDED.equals(action)) {
@@ -690,6 +689,16 @@
final int userSerialNumber = um.getUserSerialNumber(userId);
mConnector.execute("volume", "user_added", userId, userSerialNumber);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ synchronized (mVolumes) {
+ final int size = mVolumes.size();
+ for (int i = 0; i < size; i++) {
+ final VolumeInfo vol = mVolumes.valueAt(i);
+ if (vol.mountUserId == userId) {
+ vol.mountUserId = UserHandle.USER_NULL;
+ mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
+ }
+ }
+ }
mConnector.execute("volume", "user_removed", userId);
}
} catch (NativeDaemonConnectorException e) {
@@ -757,17 +766,26 @@
* paths never changing, so we outright kill them to pick up new state.
*/
@Deprecated
- private void killMediaProvider() {
+ private void killMediaProvider(List<UserInfo> users) {
+ if (users == null) return;
+
final long token = Binder.clearCallingIdentity();
try {
- final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY, 0,
- UserHandle.USER_OWNER);
- if (provider != null) {
- final IActivityManager am = ActivityManagerNative.getDefault();
- try {
- am.killApplicationWithAppId(provider.applicationInfo.packageName,
- UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
- } catch (RemoteException e) {
+ for (UserInfo user : users) {
+ // System user does not have media provider, so skip.
+ if (user.isSystemOnly()) continue;
+
+ final ProviderInfo provider =
+ mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id);
+ if (provider != null) {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ try {
+ am.killApplicationWithAppId(provider.applicationInfo.packageName,
+ UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
+ // We only need to run this once. It will kill all users' media processes.
+ break;
+ } catch (RemoteException e) {
+ }
}
}
} finally {
@@ -788,7 +806,9 @@
Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
+ ", mDaemonConnected=" + mDaemonConnected);
if (mSystemReady && mDaemonConnected) {
- killMediaProvider();
+ final UserManager um = UserManager.get(mContext);
+ final List<UserInfo> users = um.getUsers();
+ killMediaProvider(users);
mDisks.clear();
mVolumes.clear();
@@ -799,8 +819,6 @@
mConnector.execute("volume", "reset");
// Tell vold about all existing and started users
- final UserManager um = mContext.getSystemService(UserManager.class);
- final List<UserInfo> users = um.getUsers();
for (UserInfo user : users) {
mConnector.execute("volume", "user_added", user.id, user.serialNumber);
}
@@ -1192,7 +1210,7 @@
vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
}
- vol.mountUserId = UserHandle.USER_OWNER;
+ vol.mountUserId = ActivityManager.getCurrentUser();
mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
} else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
@@ -2285,7 +2303,7 @@
final NativeDaemonEvent event;
try {
- event = mConnector.execute("obb", "path", state.voldPath);
+ event = mConnector.execute("obb", "path", state.canonicalPath);
event.checkCode(VoldResponseCode.AsecPathResult);
return event.getMessage();
} catch (NativeDaemonConnectorException e) {
@@ -3038,14 +3056,14 @@
protected ObbInfo getObbInfo() throws IOException {
ObbInfo obbInfo;
try {
- obbInfo = mContainerService.getObbInfo(mObbState.ownerPath);
+ obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
} catch (RemoteException e) {
Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
- + mObbState.ownerPath);
+ + mObbState.canonicalPath);
obbInfo = null;
}
if (obbInfo == null) {
- throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath);
+ throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
}
return obbInfo;
}
@@ -3122,7 +3140,7 @@
int rc = StorageResultCode.OperationSucceeded;
try {
- mConnector.execute("obb", "mount", mObbState.voldPath, new SensitiveArg(hashedKey),
+ mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
mObbState.ownerGid);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
@@ -3133,7 +3151,7 @@
if (rc == StorageResultCode.OperationSucceeded) {
if (DEBUG_OBB)
- Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath);
+ Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
synchronized (mObbMounts) {
addObbStateLocked(mObbState);
@@ -3194,7 +3212,7 @@
int rc = StorageResultCode.OperationSucceeded;
try {
- final Command cmd = new Command("obb", "unmount", mObbState.voldPath);
+ final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
if (mForceUnmount) {
cmd.appendArg("force");
}
@@ -3240,49 +3258,6 @@
}
}
- @VisibleForTesting
- public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
- // TODO: allow caller to provide Environment for full testing
- // TODO: extend to support OBB mounts on secondary external storage
-
- // Only adjust paths when storage is emulated
- if (!Environment.isExternalStorageEmulated()) {
- return canonicalPath;
- }
-
- String path = canonicalPath.toString();
-
- // First trim off any external storage prefix
- final UserEnvironment userEnv = new UserEnvironment(userId);
-
- // /storage/emulated/0
- final String externalPath = userEnv.getExternalStorageDirectory().getAbsolutePath();
- // /storage/emulated_legacy
- final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
- .getAbsolutePath();
-
- if (path.startsWith(externalPath)) {
- path = path.substring(externalPath.length() + 1);
- } else if (path.startsWith(legacyExternalPath)) {
- path = path.substring(legacyExternalPath.length() + 1);
- } else {
- return canonicalPath;
- }
-
- // Handle special OBB paths on emulated storage
- final String obbPath = "Android/obb";
- if (path.startsWith(obbPath)) {
- path = path.substring(obbPath.length() + 1);
-
- final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
- return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
- .getAbsolutePath();
- }
-
- // Handle normal external storage paths
- return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath();
- }
-
private static class Callbacks extends Handler {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index de106a1..9dc8875 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -130,6 +130,8 @@
private static final String XML_SUFFIX = ".xml";
private static final int MIN_USER_ID = 10;
+ // We need to keep process uid within Integer.MAX_VALUE.
+ private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
private static final int USER_VERSION = 6;
@@ -1994,14 +1996,14 @@
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
int i = MIN_USER_ID;
- while (i < Integer.MAX_VALUE) {
+ while (i < MAX_USER_ID) {
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
- break;
+ return i;
}
i++;
}
- return i;
}
+ throw new IllegalStateException("No user id available!");
}
private String packageToRestrictionsFileName(String packageName) {