Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13b80b23 authored by Xiaohui Chen's avatar Xiaohui Chen Committed by Android (Google) Code Review
Browse files

Merge "UserManager: get/set user account name"

parents d588e8b6 b3b9258a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
+35 −0
Original line number Diff line number Diff line
@@ -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.
+93 −11
Original line number Diff line number Diff line
@@ -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:");
+17 −0
Original line number Diff line number Diff line
@@ -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[]