Merge "UserManager: get/set user account name"

This commit is contained in:
Xiaohui Chen
2015-12-08 21:42:22 +00:00
committed by Android (Google) Code Review
4 changed files with 147 additions and 11 deletions

View File

@@ -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);

View File

@@ -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.

View File

@@ -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:");

View File

@@ -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[]