summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/content/pm/UserInfo.java8
-rw-r--r--core/java/android/os/IUserManager.aidl2
-rw-r--r--core/java/android/os/UserManager.java20
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java2
-rw-r--r--services/java/com/android/server/MountService.java2
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java1
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java5
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java2
-rw-r--r--services/java/com/android/server/pm/Settings.java2
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java120
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);
+ }
+ }
+ }
+ }
}