Merge "Avoid recycling recently removed user IDs." into jb-mr1.1-dev

This commit is contained in:
Jeff Sharkey
2012-11-12 10:30:00 -08:00
committed by Android (Google) Code Review

View File

@ -16,8 +16,7 @@
package com.android.server.pm;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.app.Activity;
import android.app.ActivityManager;
@ -26,7 +25,6 @@ import android.app.IStopUserCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@ -34,6 +32,7 @@ import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IUserManager;
import android.os.Process;
import android.os.RemoteException;
@ -42,9 +41,17 @@ import android.os.UserManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
@ -54,13 +61,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
@ -95,19 +97,24 @@ public class UserManagerService extends IUserManager.Stub {
private final Object mInstallLock;
private final Object mPackagesLock;
private final Handler mHandler;
private final File mUsersDir;
private final File mUserListFile;
private final File mBaseUserPath;
private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();
private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
/**
* Set of user IDs being actively removed. Removed IDs linger in this set
* for several seconds to work around a VFS caching issue.
*/
// @GuardedBy("mPackagesLock")
private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
// This resets on a reboot. Otherwise it keeps incrementing so that user ids are
// not reused in quick succession
private int mNextUserId = MIN_USER_ID;
private int mUserVersion = 0;
private static UserManagerService sInstance;
@ -147,6 +154,7 @@ public class UserManagerService extends IUserManager.Stub {
mPm = pm;
mInstallLock = installLock;
mPackagesLock = packagesLock;
mHandler = new Handler();
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
mUsersDir = new File(dataDir, USER_INFO_DIR);
@ -190,7 +198,7 @@ public class UserManagerService extends IUserManager.Stub {
if (ui.partial) {
continue;
}
if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
users.add(ui);
}
}
@ -212,7 +220,7 @@ public class UserManagerService extends IUserManager.Stub {
private UserInfo getUserInfoLocked(int userId) {
UserInfo ui = mUsers.get(userId);
// If it is partial and not in the process of being removed, return as unknown user.
if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
return null;
}
@ -502,7 +510,7 @@ public class UserManagerService extends IUserManager.Stub {
private void fallbackToSingleUserLocked() {
// Create the primary user
UserInfo primary = new UserInfo(0,
UserInfo primary = new UserInfo(0,
mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
mUsers.put(0, primary);
@ -749,7 +757,7 @@ public class UserManagerService extends IUserManager.Stub {
if (userHandle == 0 || user == null) {
return false;
}
mRemovingUserIds.add(userHandle);
mRemovingUserIds.put(userHandle, true);
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
@ -813,13 +821,25 @@ public class UserManagerService extends IUserManager.Stub {
}
}
private void removeUserStateLocked(int userHandle) {
private void removeUserStateLocked(final int userHandle) {
// Cleanup package manager settings
mPm.cleanUpUserLILPw(userHandle);
// Remove this user from the list
mUsers.remove(userHandle);
mRemovingUserIds.remove(userHandle);
// Have user ID linger for several seconds to let external storage VFS
// cache entries expire. This must be greater than the 'entry_valid'
// timeout used by the FUSE daemon.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
synchronized (mPackagesLock) {
mRemovingUserIds.delete(userHandle);
}
}
}, MINUTE_IN_MILLIS);
// Remove user file
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
userFile.delete();
@ -906,14 +926,13 @@ public class UserManagerService extends IUserManager.Stub {
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
int i = mNextUserId;
int i = MIN_USER_ID;
while (i < Integer.MAX_VALUE) {
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
break;
}
i++;
}
mNextUserId = i + 1;
return i;
}
}
@ -938,7 +957,7 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> ");
if (user.partial) pw.print(" <partial>");
pw.println();
pw.print(" Created: ");