Skip to content

Commit 282e9fc

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Avoid recycling recently removed user IDs." into jb-mr1.1-dev
2 parents bc0edec + ffe0cb4 commit 282e9fc

File tree

1 file changed

+42
-23
lines changed

1 file changed

+42
-23
lines changed

services/java/com/android/server/pm/UserManagerService.java

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
package com.android.server.pm;
1818

19-
import com.android.internal.util.ArrayUtils;
20-
import com.android.internal.util.FastXmlSerializer;
19+
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
2120

2221
import android.app.Activity;
2322
import android.app.ActivityManager;
@@ -26,14 +25,14 @@
2625
import android.content.BroadcastReceiver;
2726
import android.content.Context;
2827
import android.content.Intent;
29-
import android.content.SharedPreferences;
3028
import android.content.pm.PackageManager;
3129
import android.content.pm.UserInfo;
3230
import android.graphics.Bitmap;
3331
import android.graphics.BitmapFactory;
3432
import android.os.Binder;
3533
import android.os.Environment;
3634
import android.os.FileUtils;
35+
import android.os.Handler;
3736
import android.os.IUserManager;
3837
import android.os.Process;
3938
import android.os.RemoteException;
@@ -42,9 +41,17 @@
4241
import android.util.AtomicFile;
4342
import android.util.Slog;
4443
import android.util.SparseArray;
44+
import android.util.SparseBooleanArray;
4545
import android.util.TimeUtils;
4646
import android.util.Xml;
4747

48+
import com.android.internal.util.ArrayUtils;
49+
import com.android.internal.util.FastXmlSerializer;
50+
51+
import org.xmlpull.v1.XmlPullParser;
52+
import org.xmlpull.v1.XmlPullParserException;
53+
import org.xmlpull.v1.XmlSerializer;
54+
4855
import java.io.BufferedOutputStream;
4956
import java.io.File;
5057
import java.io.FileDescriptor;
@@ -54,13 +61,8 @@
5461
import java.io.IOException;
5562
import java.io.PrintWriter;
5663
import java.util.ArrayList;
57-
import java.util.HashSet;
5864
import java.util.List;
5965

60-
import org.xmlpull.v1.XmlPullParser;
61-
import org.xmlpull.v1.XmlPullParserException;
62-
import org.xmlpull.v1.XmlSerializer;
63-
6466
public class UserManagerService extends IUserManager.Stub {
6567

6668
private static final String LOG_TAG = "UserManagerService";
@@ -95,19 +97,24 @@ public class UserManagerService extends IUserManager.Stub {
9597
private final Object mInstallLock;
9698
private final Object mPackagesLock;
9799

100+
private final Handler mHandler;
101+
98102
private final File mUsersDir;
99103
private final File mUserListFile;
100104
private final File mBaseUserPath;
101105

102-
private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
103-
private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>();
106+
private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
107+
108+
/**
109+
* Set of user IDs being actively removed. Removed IDs linger in this set
110+
* for several seconds to work around a VFS caching issue.
111+
*/
112+
// @GuardedBy("mPackagesLock")
113+
private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
104114

105115
private int[] mUserIds;
106116
private boolean mGuestEnabled;
107117
private int mNextSerialNumber;
108-
// This resets on a reboot. Otherwise it keeps incrementing so that user ids are
109-
// not reused in quick succession
110-
private int mNextUserId = MIN_USER_ID;
111118
private int mUserVersion = 0;
112119

113120
private static UserManagerService sInstance;
@@ -147,6 +154,7 @@ private UserManagerService(Context context, PackageManagerService pm,
147154
mPm = pm;
148155
mInstallLock = installLock;
149156
mPackagesLock = packagesLock;
157+
mHandler = new Handler();
150158
synchronized (mInstallLock) {
151159
synchronized (mPackagesLock) {
152160
mUsersDir = new File(dataDir, USER_INFO_DIR);
@@ -190,7 +198,7 @@ public List<UserInfo> getUsers(boolean excludeDying) {
190198
if (ui.partial) {
191199
continue;
192200
}
193-
if (!excludeDying || !mRemovingUserIds.contains(ui.id)) {
201+
if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
194202
users.add(ui);
195203
}
196204
}
@@ -212,7 +220,7 @@ public UserInfo getUserInfo(int userId) {
212220
private UserInfo getUserInfoLocked(int userId) {
213221
UserInfo ui = mUsers.get(userId);
214222
// If it is partial and not in the process of being removed, return as unknown user.
215-
if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
223+
if (ui != null && ui.partial && !mRemovingUserIds.get(userId)) {
216224
Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
217225
return null;
218226
}
@@ -502,7 +510,7 @@ private void upgradeIfNecessary() {
502510

503511
private void fallbackToSingleUserLocked() {
504512
// Create the primary user
505-
UserInfo primary = new UserInfo(0,
513+
UserInfo primary = new UserInfo(0,
506514
mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
507515
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
508516
mUsers.put(0, primary);
@@ -749,7 +757,7 @@ public boolean removeUser(int userHandle) {
749757
if (userHandle == 0 || user == null) {
750758
return false;
751759
}
752-
mRemovingUserIds.add(userHandle);
760+
mRemovingUserIds.put(userHandle, true);
753761
// Set this to a partially created user, so that the user will be purged
754762
// on next startup, in case the runtime stops now before stopping and
755763
// removing the user completely.
@@ -813,13 +821,25 @@ public void run() {
813821
}
814822
}
815823

816-
private void removeUserStateLocked(int userHandle) {
824+
private void removeUserStateLocked(final int userHandle) {
817825
// Cleanup package manager settings
818826
mPm.cleanUpUserLILPw(userHandle);
819827

820828
// Remove this user from the list
821829
mUsers.remove(userHandle);
822-
mRemovingUserIds.remove(userHandle);
830+
831+
// Have user ID linger for several seconds to let external storage VFS
832+
// cache entries expire. This must be greater than the 'entry_valid'
833+
// timeout used by the FUSE daemon.
834+
mHandler.postDelayed(new Runnable() {
835+
@Override
836+
public void run() {
837+
synchronized (mPackagesLock) {
838+
mRemovingUserIds.delete(userHandle);
839+
}
840+
}
841+
}, MINUTE_IN_MILLIS);
842+
823843
// Remove user file
824844
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
825845
userFile.delete();
@@ -906,14 +926,13 @@ public void userForeground(int userId) {
906926
*/
907927
private int getNextAvailableIdLocked() {
908928
synchronized (mPackagesLock) {
909-
int i = mNextUserId;
929+
int i = MIN_USER_ID;
910930
while (i < Integer.MAX_VALUE) {
911-
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
931+
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
912932
break;
913933
}
914934
i++;
915935
}
916-
mNextUserId = i + 1;
917936
return i;
918937
}
919938
}
@@ -938,7 +957,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
938957
UserInfo user = mUsers.valueAt(i);
939958
if (user == null) continue;
940959
pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
941-
if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
960+
if (mRemovingUserIds.get(mUsers.keyAt(i))) pw.print(" <removing> ");
942961
if (user.partial) pw.print(" <partial>");
943962
pw.println();
944963
pw.print(" Created: ");

0 commit comments

Comments
 (0)