Merge "UserManager: get/set user account name"
This commit is contained in:
@@ -48,6 +48,8 @@ interface IUserManager {
|
||||
UserInfo getProfileParent(int userHandle);
|
||||
boolean isSameProfileGroup(int userId, int otherUserId);
|
||||
UserInfo getUserInfo(int userHandle);
|
||||
String getUserAccount(int userId);
|
||||
void setUserAccount(int userId, String accountName);
|
||||
long getUserCreationTime(int userHandle);
|
||||
boolean isRestricted();
|
||||
boolean canHaveRestrictedProfile(int userId);
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
*/
|
||||
package android.os;
|
||||
|
||||
import android.Manifest;
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerNative;
|
||||
@@ -1120,6 +1122,39 @@ public class UserManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the user's account name, null if not found.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission( allOf = {
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
Manifest.permission.MANAGE_USERS
|
||||
})
|
||||
public @Nullable String getUserAccount(int userHandle) {
|
||||
try {
|
||||
return mService.getUserAccount(userHandle);
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Could not get user account", re);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set account name for the given user.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission( allOf = {
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
Manifest.permission.MANAGE_USERS
|
||||
})
|
||||
public void setUserAccount(int userHandle, @Nullable String accountName) {
|
||||
try {
|
||||
mService.setUserAccount(userHandle, accountName);
|
||||
} catch (RemoteException re) {
|
||||
Log.w(TAG, "Could not set user account", re);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information for Primary user.
|
||||
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
@@ -58,6 +59,7 @@ import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
@@ -90,6 +92,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
import libcore.util.Objects;
|
||||
|
||||
/**
|
||||
* Service for {@link UserManager}.
|
||||
@@ -107,6 +110,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
|
||||
|
||||
private static final String TAG_NAME = "name";
|
||||
private static final String TAG_ACCOUNT = "account";
|
||||
private static final String ATTR_FLAGS = "flags";
|
||||
private static final String ATTR_ICON_PATH = "icon";
|
||||
private static final String ATTR_ID = "id";
|
||||
@@ -177,6 +181,14 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
@GuardedBy("mUsersLock")
|
||||
private final SparseArray<UserInfo> mUsers = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* This collection contains each user's account name if the user chose to set one up
|
||||
* during the initial user creation process. Keeping this information separate from mUsers
|
||||
* to avoid accidentally leak it.
|
||||
*/
|
||||
@GuardedBy("mUsersLock")
|
||||
private final SparseArray<String> mUserAccounts = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* User restrictions set via UserManager. This doesn't include restrictions set by
|
||||
* device owner / profile owners.
|
||||
@@ -335,6 +347,33 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserAccount(int userId) {
|
||||
checkManageUserAndAcrossUsersFullPermission("get user account");
|
||||
synchronized (mUsersLock) {
|
||||
return mUserAccounts.get(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserAccount(int userId, String accountName) {
|
||||
checkManageUserAndAcrossUsersFullPermission("set user account");
|
||||
UserInfo userToUpdate = null;
|
||||
synchronized (mPackagesLock) {
|
||||
synchronized (mUsersLock) {
|
||||
String currentAccount = mUserAccounts.get(userId);
|
||||
if (!Objects.equal(currentAccount, accountName)) {
|
||||
mUserAccounts.put(userId, accountName);
|
||||
userToUpdate = mUsers.get(userId);
|
||||
}
|
||||
}
|
||||
|
||||
if (userToUpdate != null) {
|
||||
writeUserLP(userToUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserInfo getPrimaryUser() {
|
||||
checkManageUsersPermission("query users");
|
||||
@@ -1050,6 +1089,30 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
return aliveUserCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces that only the system UID or root's UID or apps that have the
|
||||
* {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} and
|
||||
* {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL INTERACT_ACROSS_USERS_FULL}
|
||||
* permissions can make certain calls to the UserManager.
|
||||
*
|
||||
* @param message used as message if SecurityException is thrown
|
||||
* @throws SecurityException if the caller does not have enough privilege.
|
||||
*/
|
||||
private static final void checkManageUserAndAcrossUsersFullPermission(String message) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (uid != Process.SYSTEM_UID && uid != 0
|
||||
&& ActivityManager.checkComponentPermission(
|
||||
Manifest.permission.MANAGE_USERS,
|
||||
uid, -1, true) != PackageManager.PERMISSION_GRANTED
|
||||
&& ActivityManager.checkComponentPermission(
|
||||
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
|
||||
uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException(
|
||||
"You need MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permission to: "
|
||||
+ message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces that only the system UID or root's UID or apps that have the
|
||||
* {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
|
||||
@@ -1068,13 +1131,6 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkSystemOrRoot(String message) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
if (uid != Process.SYSTEM_UID && uid != 0) {
|
||||
throw new SecurityException("Only system may call: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBitmapLP(UserInfo info, Bitmap bitmap) {
|
||||
try {
|
||||
File dir = new File(mUsersDir, Integer.toString(info.id));
|
||||
@@ -1156,11 +1212,14 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
final String name = parser.getName();
|
||||
if (name.equals(TAG_USER)) {
|
||||
String id = parser.getAttributeValue(null, ATTR_ID);
|
||||
UserInfo user = readUserLP(Integer.parseInt(id));
|
||||
Pair<UserInfo, String> userPair = readUserLP(Integer.parseInt(id));
|
||||
|
||||
if (user != null) {
|
||||
if (userPair != null) {
|
||||
UserInfo user = userPair.first;
|
||||
String account = userPair.second;
|
||||
synchronized (mUsersLock) {
|
||||
mUsers.put(user.id, user);
|
||||
mUserAccounts.put(user.id, account);
|
||||
if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
|
||||
mNextSerialNumber = user.id + 1;
|
||||
}
|
||||
@@ -1360,6 +1419,17 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
mDevicePolicyLocalUserRestrictions.get(userInfo.id),
|
||||
TAG_DEVICE_POLICY_RESTRICTIONS);
|
||||
}
|
||||
// Update the account field if it is set.
|
||||
String account;
|
||||
synchronized (mUsersLock) {
|
||||
account = mUserAccounts.get(userInfo.id);
|
||||
}
|
||||
if (account != null) {
|
||||
serializer.startTag(null, TAG_ACCOUNT);
|
||||
serializer.text(account);
|
||||
serializer.endTag(null, TAG_ACCOUNT);
|
||||
}
|
||||
|
||||
serializer.endTag(null, TAG_USER);
|
||||
|
||||
serializer.endDocument();
|
||||
@@ -1432,10 +1502,11 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private UserInfo readUserLP(int id) {
|
||||
private Pair<UserInfo, String> readUserLP(int id) {
|
||||
int flags = 0;
|
||||
int serialNumber = id;
|
||||
String name = null;
|
||||
String account = null;
|
||||
String iconPath = null;
|
||||
long creationTime = 0L;
|
||||
long lastLoggedInTime = 0L;
|
||||
@@ -1504,6 +1575,11 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
|
||||
} else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
|
||||
UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
|
||||
} else if (TAG_ACCOUNT.equals(tag)) {
|
||||
type = parser.next();
|
||||
if (type == XmlPullParser.TEXT) {
|
||||
account = parser.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1520,7 +1596,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
mBaseUserRestrictions.put(id, baseRestrictions);
|
||||
mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
|
||||
}
|
||||
return userInfo;
|
||||
return new Pair<>(userInfo, account);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
} catch (XmlPullParserException pe) {
|
||||
@@ -1947,6 +2023,7 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
// Remove this user from the list
|
||||
synchronized (mUsersLock) {
|
||||
mUsers.remove(userHandle);
|
||||
mUserAccounts.delete(userHandle);
|
||||
mIsUserManaged.delete(userHandle);
|
||||
}
|
||||
synchronized (mRestrictionsLock) {
|
||||
@@ -2507,6 +2584,11 @@ public class UserManagerService extends IUserManager.Stub {
|
||||
pw, " ", mCachedEffectiveUserRestrictions.get(user.id));
|
||||
}
|
||||
pw.println();
|
||||
String accountName = mUserAccounts.get(userId);
|
||||
if (accountName != null) {
|
||||
pw.print(" Account name: " + accountName);
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
pw.println(" Device policy global restrictions:");
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.AtomicFile;
|
||||
|
||||
@@ -29,6 +32,7 @@ import java.util.Arrays;
|
||||
public class UserManagerServiceTest extends AndroidTestCase {
|
||||
private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
|
||||
private File restrictionsFile;
|
||||
private int tempUserId = UserHandle.USER_NULL;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
@@ -40,6 +44,9 @@ public class UserManagerServiceTest extends AndroidTestCase {
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
restrictionsFile.delete();
|
||||
if (tempUserId != UserHandle.USER_NULL) {
|
||||
UserManager.get(mContext).removeUser(tempUserId);
|
||||
}
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@@ -55,6 +62,16 @@ public class UserManagerServiceTest extends AndroidTestCase {
|
||||
assertBundle(bundle);
|
||||
}
|
||||
|
||||
public void testAddUserWithAccount() {
|
||||
UserManager um = UserManager.get(mContext);
|
||||
UserInfo user = um.createUser("Test User", 0);
|
||||
assertNotNull(user);
|
||||
tempUserId = user.id;
|
||||
String accountName = "Test Account";
|
||||
um.setUserAccount(tempUserId, accountName);
|
||||
assertEquals(accountName, um.getUserAccount(tempUserId));
|
||||
}
|
||||
|
||||
private Bundle createBundle() {
|
||||
Bundle result = new Bundle();
|
||||
// Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
|
||||
|
||||
Reference in New Issue
Block a user