From a52dc3eb40777b055c0ca8d7885bd2c9577bcd1a Mon Sep 17 00:00:00 2001 From: Kenny Guy Date: Tue, 11 Feb 2014 15:33:14 +0000 Subject: [PATCH] Add concepts of related users and managed profiles to user manager. Related users are a group that will share things like notifications. Managed profiles are a profile of another user. Change-Id: I2d0532f1abf939810f0fa3fc7c77ad13fa567833 --- core/java/android/content/pm/UserInfo.java | 18 +++++ core/java/android/os/IUserManager.aidl | 2 + core/java/android/os/UserManager.java | 37 ++++++++++ .../android/server/pm/UserManagerService.java | 69 +++++++++++++++++++ 4 files changed, 126 insertions(+) diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 4c8783006b261..aa4a243930423 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -63,6 +63,15 @@ public class UserInfo implements Parcelable { */ public static final int FLAG_INITIALIZED = 0x00000010; + /** + * Indicates that this user is a profile of another user, for example holding a users + * corporate data. + */ + public static final int FLAG_MANAGED_PROFILE = 0x00000020; + + + public static final int NO_RELATED_GROUP_ID = -1; + public int id; public int serialNumber; public String name; @@ -70,6 +79,7 @@ public class UserInfo implements Parcelable { public int flags; public long creationTime; public long lastLoggedInTime; + public int relatedGroupId; /** User is only partially created. */ public boolean partial; @@ -83,6 +93,7 @@ public class UserInfo implements Parcelable { this.name = name; this.flags = flags; this.iconPath = iconPath; + this.relatedGroupId = NO_RELATED_GROUP_ID; } public boolean isPrimary() { @@ -101,6 +112,10 @@ public class UserInfo implements Parcelable { return (flags & FLAG_RESTRICTED) == FLAG_RESTRICTED; } + public boolean isManagedProfile() { + return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE; + } + public UserInfo() { } @@ -113,6 +128,7 @@ public class UserInfo implements Parcelable { creationTime = orig.creationTime; lastLoggedInTime = orig.lastLoggedInTime; partial = orig.partial; + relatedGroupId = orig.relatedGroupId; } public UserHandle getUserHandle() { @@ -137,6 +153,7 @@ public class UserInfo implements Parcelable { dest.writeLong(creationTime); dest.writeLong(lastLoggedInTime); dest.writeInt(partial ? 1 : 0); + dest.writeInt(relatedGroupId); } public static final Parcelable.Creator CREATOR @@ -158,5 +175,6 @@ public class UserInfo implements Parcelable { creationTime = source.readLong(); lastLoggedInTime = source.readLong(); partial = source.readInt() != 0; + relatedGroupId = source.readInt(); } } diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 3c9d0d904a6c8..6e6c06dba45a9 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -28,11 +28,13 @@ import android.graphics.Bitmap; */ interface IUserManager { UserInfo createUser(in String name, int flags); + UserInfo createRelatedUser(in String name, int flags, int relatedUserId); boolean removeUser(int userHandle); void setUserName(int userHandle, String name); void setUserIcon(int userHandle, in Bitmap icon); Bitmap getUserIcon(int userHandle); List getUsers(boolean excludeDying); + List getRelatedUsers(int userHandle); UserInfo getUserInfo(int userHandle); boolean isRestricted(); void setGuestEnabled(boolean enable); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 5d087eab01dcb..8f6dda11d68ce 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -407,6 +407,27 @@ public class UserManager { } } + /** + * Creates a user with the specified name and options. + * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * + * @param name the user's name + * @param flags flags that identify the type of user and other properties. + * @see UserInfo + * @param relatedUserId new user will be related to this user id. + * + * @return the UserInfo object for the created user, or null if the user could not be created. + * @hide + */ + public UserInfo createRelatedUser(String name, int flags, int relatedUserId) { + try { + return mService.createRelatedUser(name, flags, relatedUserId); + } catch (RemoteException re) { + Log.w(TAG, "Could not create a user", re); + return null; + } + } + /** * Return the number of users currently created on the device. */ @@ -430,6 +451,22 @@ public class UserManager { } } + /** + * Returns information for all users related to userId + * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * @param userHandle users related to this user id will be returned. + * @return the list of related users. + * @hide + */ + public List getRelatedUsers(int userHandle) { + try { + return mService.getRelatedUsers(userHandle); + } 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. diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index c33134a24d199..38a19496f4048 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -92,6 +92,7 @@ public class UserManagerService extends IUserManager.Stub { private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber"; private static final String ATTR_PARTIAL = "partial"; private static final String ATTR_USER_VERSION = "version"; + private static final String ATTR_RELATED_GROUP_ID = "relatedGroupId"; private static final String TAG_USERS = "users"; private static final String TAG_USER = "user"; private static final String TAG_RESTRICTIONS = "restrictions"; @@ -257,6 +258,29 @@ public class UserManagerService extends IUserManager.Stub { } } + @Override + public List getRelatedUsers(int userId) { + checkManageUsersPermission("query users"); + synchronized (mPackagesLock) { + UserInfo user = getUserInfoLocked(userId); + ArrayList users = new ArrayList(mUsers.size()); + for (int i = 0; i < mUsers.size(); i++) { + UserInfo ui = mUsers.valueAt(i); + if (!areRelatedUsers(user, ui)) { + continue; + } + users.add(ui); + } + return users; + } + } + + private boolean areRelatedUsers(UserInfo user1, UserInfo user2) { + return user1.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID && + user1.relatedGroupId == user2.relatedGroupId && + user1.id != user2.id; + } + @Override public UserInfo getUserInfo(int userId) { checkManageUsersPermission("query user"); @@ -662,6 +686,10 @@ public class UserManagerService extends IUserManager.Stub { if (userInfo.partial) { serializer.attribute(null, ATTR_PARTIAL, "true"); } + if (userInfo.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID) { + serializer.attribute(null, ATTR_RELATED_GROUP_ID, + Integer.toString(userInfo.relatedGroupId)); + } serializer.startTag(null, TAG_NAME); serializer.text(userInfo.name); @@ -745,6 +773,7 @@ public class UserManagerService extends IUserManager.Stub { long salt = 0L; String pinHash = null; int failedAttempts = 0; + int relatedGroupId = UserInfo.NO_RELATED_GROUP_ID; long lastAttemptTime = 0L; boolean partial = false; Bundle restrictions = new Bundle(); @@ -782,6 +811,8 @@ public class UserManagerService extends IUserManager.Stub { pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH); failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0); lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L); + relatedGroupId = readIntAttribute(parser, ATTR_RELATED_GROUP_ID, + UserInfo.NO_RELATED_GROUP_ID); String valueString = parser.getAttributeValue(null, ATTR_PARTIAL); if ("true".equals(valueString)) { partial = true; @@ -820,6 +851,7 @@ public class UserManagerService extends IUserManager.Stub { userInfo.creationTime = creationTime; userInfo.lastLoggedInTime = lastLoggedInTime; userInfo.partial = partial; + userInfo.relatedGroupId = relatedGroupId; mUserRestrictions.append(id, restrictions); if (salt != 0L) { RestrictionsPinState pinState = mRestrictionsPinStates.get(id); @@ -934,10 +966,40 @@ public class UserManagerService extends IUserManager.Stub { } } + private int getNextRelatedGroupIdLocked() { + int maxGroupId = UserInfo.NO_RELATED_GROUP_ID; + for (int i = 0; i < mUsers.size(); i++) { + UserInfo ui = mUsers.valueAt(i); + if (maxGroupId < ui.relatedGroupId) { + maxGroupId = ui.relatedGroupId; + } + } + return maxGroupId + 1; + } + + @Override + public UserInfo createRelatedUser(String name, int flags, int relatedUserId) { + checkManageUsersPermission("Only the system can create users"); + if (relatedUserId != UserHandle.USER_OWNER) { + Slog.w(LOG_TAG, "Only user owner can have related users"); + return null; + } + synchronized (mPackagesLock) { + UserInfo relatedUser = getUserInfoLocked(relatedUserId); + if (relatedUser == null) { + return null; + } + return createUserInternal(name, flags, relatedUser); + } + } + @Override public UserInfo createUser(String name, int flags) { checkManageUsersPermission("Only the system can create users"); + return createUserInternal(name, flags, null); + } + private UserInfo createUserInternal(String name, int flags, UserInfo relatedUser) { final long ident = Binder.clearCallingIdentity(); final UserInfo userInfo; try { @@ -954,6 +1016,13 @@ public class UserManagerService extends IUserManager.Stub { Environment.getUserSystemDirectory(userInfo.id).mkdirs(); mUsers.put(userId, userInfo); writeUserListLocked(); + if (relatedUser != null) { + if (relatedUser.relatedGroupId == UserInfo.NO_RELATED_GROUP_ID) { + relatedUser.relatedGroupId = getNextRelatedGroupIdLocked(); + } + userInfo.relatedGroupId = relatedUser.relatedGroupId; + writeUserLocked(relatedUser); + } writeUserLocked(userInfo); mPm.createNewUserLILPw(userId, userPath); userInfo.partial = false;