diff options
13 files changed, 143 insertions, 27 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index e0f54fb..5f898c2 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -1025,7 +1025,7 @@ public final class Pm { public void runListUsers() { try { - List<UserInfo> users = mUm.getUsers(); + List<UserInfo> users = mUm.getUsers(false); if (users == null) { System.err.println("Error: couldn't get users"); } else { diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index a06aba9..ab32523 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -68,6 +68,8 @@ public class UserInfo implements Parcelable { public String name; public String iconPath; public int flags; + public long creationTime; + public long lastLoggedInTime; public UserInfo(int id, String name, int flags) { this(id, name, null, flags); @@ -101,6 +103,8 @@ public class UserInfo implements Parcelable { id = orig.id; flags = orig.flags; serialNumber = orig.serialNumber; + creationTime = orig.creationTime; + lastLoggedInTime = orig.lastLoggedInTime; } public UserHandle getUserHandle() { @@ -122,6 +126,8 @@ public class UserInfo implements Parcelable { dest.writeString(iconPath); dest.writeInt(flags); dest.writeInt(serialNumber); + dest.writeLong(creationTime); + dest.writeLong(lastLoggedInTime); } public static final Parcelable.Creator<UserInfo> CREATOR @@ -140,5 +146,7 @@ public class UserInfo implements Parcelable { iconPath = source.readString(); flags = source.readInt(); serialNumber = source.readInt(); + creationTime = source.readLong(); + lastLoggedInTime = source.readLong(); } } diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 0798913..ec02ae0 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -30,7 +30,7 @@ interface IUserManager { void setUserName(int userHandle, String name); void setUserIcon(int userHandle, in Bitmap icon); Bitmap getUserIcon(int userHandle); - List<UserInfo> getUsers(); + List<UserInfo> getUsers(boolean excludeDying); UserInfo getUserInfo(int userHandle); void setGuestEnabled(boolean enable); boolean isGuestEnabled(); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index b532966..2a5c1aa 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -116,7 +116,23 @@ public class UserManager { */ public List<UserInfo> getUsers() { try { - return mService.getUsers(); + return mService.getUsers(false); + } catch (RemoteException re) { + Log.w(TAG, "Could not get user list", re); + return null; + } + } + + /** + * Returns information for all users on this device. + * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * @param excludeDying specify if the list should exclude users being removed. + * @return the list of users that were created. + * @hide + */ + public List<UserInfo> getUsers(boolean excludeDying) { + try { + return mService.getUsers(excludeDying); } catch (RemoteException re) { Log.w(TAG, "Could not get user list", re); return null; @@ -271,6 +287,4 @@ public class UserManager { } return -1; } - - } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index bbd07a3..4e47770 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -703,7 +703,7 @@ public class KeyguardHostView extends KeyguardViewBase { // if there are multiple users, we need to add the multi-user switcher widget to the // keyguard. UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - List<UserInfo> users = mUm.getUsers(); + List<UserInfo> users = mUm.getUsers(true); if (users.size() > 1) { KeyguardWidgetFrame userSwitcher = (KeyguardWidgetFrame) diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java index b3cd8a2..e4096b9 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java @@ -76,7 +76,7 @@ public class KeyguardMultiUserSelectorView extends FrameLayout implements View.O } UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUm.getUsers()); + ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUm.getUsers(true)); Collections.sort(users, mOrderAddedComparator); for (UserInfo user: users) { diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java index 50a7134..416a0bb 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java @@ -792,7 +792,7 @@ public class KeyguardViewMediator { return; } - if (mUserManager.getUsers().size() < 2 + if (mUserManager.getUsers(true).size() < 2 && mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); return; diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index ba758e5..fe2f8d8 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -1176,7 +1176,7 @@ class MountService extends IMountService.Stub true, mtpReserve, false, maxFileSize, null); final UserManagerService userManager = UserManagerService.getInstance(); - for (UserInfo user : userManager.getUsers()) { + for (UserInfo user : userManager.getUsers(false)) { createEmulatedVolumeForUserLocked(user.getUserHandle()); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index cd3aeff..f162dae 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -14034,6 +14034,7 @@ public final class ActivityManagerService extends ActivityManagerNative startHomeActivityLocked(userId); } + getUserManagerLocked().userForeground(userId); sendUserSwitchBroadcastsLocked(oldUserId, userId); } } finally { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index df50d89..05ff379 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -3038,11 +3038,6 @@ final class ActivityStack { // Collect information about the target of the Intent. ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profileFile, profileFd, userId); - if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0 - && mService.isSingleton(aInfo.processName, aInfo.applicationInfo, null, 0)) { - userId = 0; - } - aInfo = mService.getActivityInfoForUser(aInfo, userId); synchronized (mService) { int callingPid; diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index f3de8a4..739caa0 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1029,7 +1029,7 @@ public class PackageManagerService extends IPackageManager.Stub { readPermissions(); - mRestoredSettings = mSettings.readLPw(sUserManager.getUsers()); + mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false)); long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index b075da3..23e54678 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -2477,7 +2477,7 @@ final class Settings { private List<UserInfo> getAllUsers() { long id = Binder.clearCallingIdentity(); try { - return UserManagerService.getInstance().getUsers(); + return UserManagerService.getInstance().getUsers(false); } catch (NullPointerException npe) { // packagemanager not yet initialized } finally { diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index 2dc9a6a..2edc700 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -43,15 +43,19 @@ import android.os.UserManager; import android.util.AtomicFile; import android.util.Slog; import android.util.SparseArray; +import android.util.TimeUtils; import android.util.Xml; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; 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; @@ -66,6 +70,8 @@ public class UserManagerService extends IUserManager.Stub { private static final String ATTR_FLAGS = "flags"; private static final String ATTR_ICON_PATH = "icon"; private static final String ATTR_ID = "id"; + private static final String ATTR_CREATION_TIME = "created"; + private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn"; private static final String ATTR_SERIAL_NO = "serialNumber"; private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber"; private static final String TAG_USERS = "users"; @@ -75,6 +81,8 @@ public class UserManagerService extends IUserManager.Stub { private static final String USER_LIST_FILENAME = "userlist.xml"; private static final String USER_PHOTO_FILENAME = "photo.png"; + private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms + private final Context mContext; private final PackageManagerService mPm; private final Object mInstallLock; @@ -85,6 +93,7 @@ public class UserManagerService extends IUserManager.Stub { private final File mBaseUserPath; private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); + private HashSet<Integer> mRemovingUserIds = new HashSet<Integer>(); private int[] mUserIds; private boolean mGuestEnabled; @@ -145,12 +154,14 @@ public class UserManagerService extends IUserManager.Stub { } @Override - public List<UserInfo> getUsers() { + public List<UserInfo> getUsers(boolean excludeDying) { checkManageUsersPermission("query users"); synchronized (mPackagesLock) { ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); for (int i = 0; i < mUsers.size(); i++) { - users.add(mUsers.valueAt(i)); + if (!excludeDying || !mRemovingUserIds.contains(mUsers.keyAt(i))) { + users.add(mUsers.valueAt(i)); + } } return users; } @@ -436,6 +447,9 @@ public class UserManagerService extends IUserManager.Stub { serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id)); serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber)); serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags)); + serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime)); + serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME, + Long.toString(userInfo.lastLoggedInTime)); if (userInfo.iconPath != null) { serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath); } @@ -500,6 +514,8 @@ public class UserManagerService extends IUserManager.Stub { int serialNumber = id; String name = null; String iconPath = null; + long creationTime = 0L; + long lastLoggedInTime = 0L; FileInputStream fis = null; try { @@ -520,18 +536,16 @@ public class UserManagerService extends IUserManager.Stub { } if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) { - String storedId = parser.getAttributeValue(null, ATTR_ID); - if (Integer.parseInt(storedId) != id) { + int storedId = readIntAttribute(parser, ATTR_ID, -1); + if (storedId != id) { Slog.e(LOG_TAG, "User id does not match the file name"); return null; } - String serialNumberValue = parser.getAttributeValue(null, ATTR_SERIAL_NO); - if (serialNumberValue != null) { - serialNumber = Integer.parseInt(serialNumberValue); - } - String flagString = parser.getAttributeValue(null, ATTR_FLAGS); - flags = Integer.parseInt(flagString); + serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id); + flags = readIntAttribute(parser, ATTR_FLAGS, 0); iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH); + creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0); + lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0); while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { @@ -546,6 +560,8 @@ public class UserManagerService extends IUserManager.Stub { UserInfo userInfo = new UserInfo(id, name, iconPath, flags); userInfo.serialNumber = serialNumber; + userInfo.creationTime = creationTime; + userInfo.lastLoggedInTime = lastLoggedInTime; return userInfo; } catch (IOException ioe) { @@ -561,6 +577,26 @@ public class UserManagerService extends IUserManager.Stub { return null; } + private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) { + String valueString = parser.getAttributeValue(null, attr); + if (valueString == null) return defaultValue; + try { + return Integer.parseInt(valueString); + } catch (NumberFormatException nfe) { + return defaultValue; + } + } + + private long readLongAttribute(XmlPullParser parser, String attr, long defaultValue) { + String valueString = parser.getAttributeValue(null, attr); + if (valueString == null) return defaultValue; + try { + return Long.parseLong(valueString); + } catch (NumberFormatException nfe) { + return defaultValue; + } + } + @Override public UserInfo createUser(String name, int flags) { checkManageUsersPermission("Only the system can create users"); @@ -575,6 +611,8 @@ public class UserManagerService extends IUserManager.Stub { userInfo = new UserInfo(userId, name, null, flags); File userPath = new File(mBaseUserPath, Integer.toString(userId)); userInfo.serialNumber = mNextSerialNumber++; + long now = System.currentTimeMillis(); + userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0; mUsers.put(userId, userInfo); writeUserListLocked(); writeUserLocked(userInfo); @@ -607,6 +645,7 @@ public class UserManagerService extends IUserManager.Stub { if (userHandle == 0 || user == null) { return false; } + mRemovingUserIds.add(userHandle); } int res; @@ -636,6 +675,7 @@ public class UserManagerService extends IUserManager.Stub { // Remove this user from the list mUsers.remove(userHandle); + mRemovingUserIds.remove(userHandle); // Remove user file AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml")); userFile.delete(); @@ -700,6 +740,21 @@ public class UserManagerService extends IUserManager.Stub { } /** + * Make a note of the last started time of a user. + * @param userId the user that was just foregrounded + */ + public void userForeground(int userId) { + synchronized (mPackagesLock) { + UserInfo user = mUsers.get(userId); + long now = System.currentTimeMillis(); + if (user != null && now > EPOCH_PLUS_30_YEARS) { + user.lastLoggedInTime = now; + writeUserLocked(user); + } + } + } + + /** * Returns the next available user id, filling in any holes in the ids. * TODO: May not be a good idea to recycle ids, in case it results in confusion * for data and battery stats collection, or unexpected cross-talk. @@ -709,7 +764,7 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mPackagesLock) { int i = 10; while (i < Integer.MAX_VALUE) { - if (mUsers.indexOfKey(i) < 0) { + if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) { break; } i++; @@ -717,4 +772,47 @@ public class UserManagerService extends IUserManager.Stub { return i; } } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump UserManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " without permission " + + android.Manifest.permission.DUMP); + return; + } + + long now = System.currentTimeMillis(); + StringBuilder sb = new StringBuilder(); + synchronized (mPackagesLock) { + pw.println("Users:"); + for (int i = 0; i < mUsers.size(); i++) { + UserInfo user = mUsers.valueAt(i); + if (user == null) continue; + pw.print(" "); pw.print(user); + pw.println(mRemovingUserIds.contains(mUsers.keyAt(i)) ? " <removing> " : ""); + pw.print(" Created: "); + if (user.creationTime == 0) { + pw.println("<unknown>"); + } else { + sb.setLength(0); + TimeUtils.formatDuration(now - user.creationTime, sb); + sb.append(" ago"); + pw.println(sb); + } + pw.print(" Last logged in: "); + if (user.lastLoggedInTime == 0) { + pw.println("<unknown>"); + } else { + sb.setLength(0); + TimeUtils.formatDuration(now - user.lastLoggedInTime, sb); + sb.append(" ago"); + pw.println(sb); + } + } + } + } } |