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

Commit 3f1099b0 authored by Fyodor Kupolov's avatar Fyodor Kupolov Committed by Android (Google) Code Review
Browse files

Merge "Non-system users can now have restricted profiles"

parents 762320e7 06a484ad
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ public class UserInfo implements Parcelable {
    public static final int FLAG_DISABLED = 0x00000040;


    public static final int NO_PROFILE_GROUP_ID = -1;
    public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;

    public int id;
    public int serialNumber;
@@ -87,6 +87,7 @@ public class UserInfo implements Parcelable {
    public long creationTime;
    public long lastLoggedInTime;
    public int profileGroupId;
    public int restrictedProfileParentId;

    /** User is only partially created. */
    public boolean partial;
@@ -102,6 +103,7 @@ public class UserInfo implements Parcelable {
        this.flags = flags;
        this.iconPath = iconPath;
        this.profileGroupId = NO_PROFILE_GROUP_ID;
        this.restrictedProfileParentId = NO_PROFILE_GROUP_ID;
    }

    public boolean isPrimary() {
@@ -206,6 +208,7 @@ public class UserInfo implements Parcelable {
        dest.writeInt(partial ? 1 : 0);
        dest.writeInt(profileGroupId);
        dest.writeInt(guestToRemove ? 1 : 0);
        dest.writeInt(restrictedProfileParentId);
    }

    public static final Parcelable.Creator<UserInfo> CREATOR
@@ -229,5 +232,6 @@ public class UserInfo implements Parcelable {
        partial = source.readInt() != 0;
        profileGroupId = source.readInt();
        guestToRemove = source.readInt() != 0;
        restrictedProfileParentId = source.readInt();
    }
}
+22 −0
Original line number Diff line number Diff line
@@ -926,6 +926,28 @@ public class UserManager {
        }
    }

    /**
     * Creates a restricted profile with the specified name.
     *
     * @param name profile's name
     * @return UserInfo object for the created user, or null if the user could not be created.
     * @hide
     */
    public UserInfo createRestrictedProfile(String name) {
        try {
            if (isSplitSystemUser()) {
                return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
                        UserHandle.getCallingUserId());
            } else {
                return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
                        UserHandle.USER_SYSTEM);
            }
        } catch (RemoteException e) {
            Log.w(TAG, "Could not create a restricted profile", e);
        }
        return null;
    }

    /**
     * @hide
     * Marks the guest user for deletion to allow a new guest to be created before deleting
+44 −30
Original line number Diff line number Diff line
@@ -511,10 +511,17 @@ public class AccountManagerService
        Account[] sharedAccounts = getSharedAccountsAsUser(userId);
        if (sharedAccounts == null || sharedAccounts.length == 0) return;
        Account[] accounts = getAccountsAsUser(null, userId);
        int parentUserId = UserManager.isSplitSystemUser()
                ? mUserManager.getUserInfo(userId).restrictedProfileParentId
                : UserHandle.USER_SYSTEM;
        if (parentUserId < 0) {
            Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
            return;
        }
        for (Account sa : sharedAccounts) {
            if (ArrayUtils.contains(accounts, sa)) continue;
            // Account doesn't exist. Copy it now.
            copyAccountToUser(null /*no response*/, sa, UserHandle.USER_OWNER, userId);
            copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
        }
    }

@@ -740,7 +747,7 @@ public class AccountManagerService

    @Override
    public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
            int userFrom, int userTo) {
            final int userFrom, int userTo) {
        int callingUid = Binder.getCallingUid();
        if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
            throw new SecurityException("Calling copyAccountToUser requires "
@@ -784,7 +791,7 @@ public class AccountManagerService
                    if (result != null
                            && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                        // Create a Session for the target user and pass in the bundle
                        completeCloningAccount(response, result, account, toAccounts);
                        completeCloningAccount(response, result, account, toAccounts, userFrom);
                    } else {
                        super.onResult(result);
                    }
@@ -851,7 +858,8 @@ public class AccountManagerService
    }

    private void completeCloningAccount(IAccountManagerResponse response,
            final Bundle accountCredentials, final Account account, final UserAccounts targetUser) {
            final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
            final int parentUserId){
        long id = clearCallingIdentity();
        try {
            new Session(targetUser, response, account.type, false,
@@ -866,9 +874,9 @@ public class AccountManagerService
                @Override
                public void run() throws RemoteException {
                    // Confirm that the owner's account still exists before this step.
                    UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
                    UserAccounts owner = getUserAccounts(parentUserId);
                    synchronized (owner.cacheLock) {
                        for (Account acc : getAccounts(UserHandle.USER_OWNER)) {
                        for (Account acc : getAccounts(parentUserId)) {
                            if (acc.equals(account)) {
                                mAuthenticator.addAccountFromCredentials(
                                        this, account, accountCredentials);
@@ -949,27 +957,27 @@ public class AccountManagerService
            }
            sendAccountsChangedBroadcast(accounts.userId);
        }
        if (accounts.userId == UserHandle.USER_OWNER) {
            addAccountToLimitedUsers(account);
        if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
            addAccountToLinkedRestrictedUsers(account, accounts.userId);
        }
        return true;
    }

    /**
     * Adds the account to all limited users as shared accounts. If the user is currently
     * Adds the account to all linked restricted users as shared accounts. If the user is currently
     * running, then clone the account too.
     * @param account the account to share with limited users
     *
     */
    private void addAccountToLimitedUsers(Account account) {
    private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
        List<UserInfo> users = getUserManager().getUsers();
        for (UserInfo user : users) {
            if (user.isRestricted()) {
            if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
                addSharedAccountAsUser(account, user.id);
                try {
                    if (ActivityManagerNative.getDefault().isUserRunning(user.id, false)) {
                        mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
                                MESSAGE_COPY_SHARED_ACCOUNT, UserHandle.USER_OWNER, user.id,
                                account));
                                MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
                    }
                } catch (RemoteException re) {
                    // Shouldn't happen
@@ -1172,14 +1180,16 @@ public class AccountManagerService
                          new AtomicReference<String>(accountToRename.name));
                    resultAccount = renamedAccount;

                    if (accounts.userId == UserHandle.USER_OWNER) {
                    int parentUserId = accounts.userId;
                    if (canHaveProfile(parentUserId)) {
                        /*
                         * Owner's account was renamed, rename the account for
                         * Owner or system user account was renamed, rename the account for
                         * those users with which the account was shared.
                         */
                        List<UserInfo> users = mUserManager.getUsers(true);
                        for (UserInfo user : users) {
                            if (!user.isPrimary() && user.isRestricted()) {
                            if (user.isRestricted()
                                    && (user.restrictedProfileParentId == parentUserId)) {
                                renameSharedAccountAsUser(accountToRename, newName, user.id);
                            }
                        }
@@ -1191,6 +1201,11 @@ public class AccountManagerService
        return resultAccount;
    }

    private boolean canHaveProfile(final int parentUserId) {
        final UserInfo userInfo = mUserManager.getUserInfo(parentUserId);
        return userInfo != null && userInfo.canHaveProfile();
    }

    @Override
    public void removeAccount(IAccountManagerResponse response, Account account,
            boolean expectActivityLaunch) {
@@ -1304,7 +1319,7 @@ public class AccountManagerService
        logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
        long identityToken = clearCallingIdentity();
        try {
            return removeAccountInternal(accounts, account);
            return removeAccountInternal(accounts, account, callingUid);
        } finally {
            restoreCallingIdentity(identityToken);
        }
@@ -1337,7 +1352,7 @@ public class AccountManagerService
                    && !result.containsKey(AccountManager.KEY_INTENT)) {
                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
                if (removalAllowed) {
                    removeAccountInternal(mAccounts, mAccount);
                    removeAccountInternal(mAccounts, mAccount, getCallingUid());
                }
                IAccountManagerResponse response = getResponseAndClose();
                if (response != null) {
@@ -1360,10 +1375,10 @@ public class AccountManagerService

    /* For testing */
    protected void removeAccountInternal(Account account) {
        removeAccountInternal(getUserAccountsForCaller(), account);
        removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
    }

    private boolean removeAccountInternal(UserAccounts accounts, Account account) {
    private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
        int deleted;
        synchronized (accounts.cacheLock) {
            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -1376,22 +1391,21 @@ public class AccountManagerService

            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_ACCOUNTS, accountId, accounts);
        }
        if (accounts.userId == UserHandle.USER_OWNER) {
            // Owner's account was removed, remove from any users that are sharing
            // this account.
            int callingUid = getCallingUid();
        long id = Binder.clearCallingIdentity();
        try {
            int parentUserId = accounts.userId;
            if (canHaveProfile(parentUserId)) {
                // Remove from any restricted profiles that are sharing this account.
                List<UserInfo> users = mUserManager.getUsers(true);
                for (UserInfo user : users) {
                    if (!user.isPrimary() && user.isRestricted()) {
                    if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
                        removeSharedAccountAsUser(account, user.id, callingUid);
                    }
                }
            }
        } finally {
            Binder.restoreCallingIdentity(id);
        }
        }
        return (deleted > 0);
    }

@@ -2707,7 +2721,7 @@ public class AccountManagerService
        if (r > 0) {
            logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
                    sharedTableAccountId, accounts, callingUid);
            removeAccountInternal(accounts, account);
            removeAccountInternal(accounts, account, callingUid);
        }
        return r > 0;
    }
+43 −21
Original line number Diff line number Diff line
@@ -61,7 +61,6 @@ import com.google.android.collect.Sets;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;

@@ -102,6 +101,7 @@ public class UserManagerService extends IUserManager.Stub {
    private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
    private static final String ATTR_USER_VERSION = "version";
    private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
    private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
    private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
    private static final String TAG_USERS = "users";
    private static final String TAG_USER = "user";
@@ -927,7 +927,10 @@ public class UserManagerService extends IUserManager.Stub {
                serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
                        Integer.toString(userInfo.profileGroupId));
            }

            if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
                serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
                        Integer.toString(userInfo.restrictedProfileParentId));
            }
            serializer.startTag(null, TAG_NAME);
            serializer.text(userInfo.name);
            serializer.endTag(null, TAG_NAME);
@@ -1037,6 +1040,7 @@ public class UserManagerService extends IUserManager.Stub {
        long creationTime = 0L;
        long lastLoggedInTime = 0L;
        int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
        int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
        boolean partial = false;
        boolean guestToRemove = false;
        Bundle restrictions = new Bundle();
@@ -1072,6 +1076,8 @@ public class UserManagerService extends IUserManager.Stub {
                lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
                profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
                        UserInfo.NO_PROFILE_GROUP_ID);
                restrictedProfileParentId = readIntAttribute(parser,
                        ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
                String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
                if ("true".equals(valueString)) {
                    partial = true;
@@ -1106,6 +1112,7 @@ public class UserManagerService extends IUserManager.Stub {
            userInfo.partial = partial;
            userInfo.guestToRemove = guestToRemove;
            userInfo.profileGroupId = profileGroupId;
            userInfo.restrictedProfileParentId = restrictedProfileParentId;
            mUserRestrictions.append(id, restrictions);
            return userInfo;

@@ -1262,6 +1269,7 @@ public class UserManagerService extends IUserManager.Stub {
        }
        final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
        final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
        final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
        final long ident = Binder.clearCallingIdentity();
        UserInfo userInfo = null;
        final int userId;
@@ -1286,6 +1294,24 @@ public class UserManagerService extends IUserManager.Stub {
                    if (isGuest && findCurrentGuestUserLocked() != null) {
                        return null;
                    }
                    // In legacy mode, restricted profile's parent can only be the owner user
                    if (isRestricted && !UserManager.isSplitSystemUser()
                            && (parentId != UserHandle.USER_SYSTEM)) {
                        Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
                        return null;
                    }
                    if (isRestricted && UserManager.isSplitSystemUser()) {
                        if (parent == null) {
                            Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be "
                                    + "specified");
                            return null;
                        }
                        if (!parent.canHaveProfile()) {
                            Log.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
                                    + "created for the specified parent user id " + parentId);
                            return null;
                        }
                    }
                    // In split system user mode, we assign the first human user the primary flag.
                    // And if there is no device owner, we also assign the admin flag to primary
                    // user.
@@ -1309,11 +1335,22 @@ public class UserManagerService extends IUserManager.Stub {
                    mUsers.put(userId, userInfo);
                    writeUserListLocked();
                    if (parent != null) {
                        if (isManagedProfile) {
                            if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
                                parent.profileGroupId = parent.id;
                                scheduleWriteUserLocked(parent);
                            }
                            userInfo.profileGroupId = parent.profileGroupId;
                        } else if (isRestricted) {
                            if (!parent.canHaveProfile()) {
                                Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
                            }
                            if (parent.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
                                parent.restrictedProfileParentId = parent.id;
                                scheduleWriteUserLocked(parent);
                            }
                            userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
                        }
                    }
                    final StorageManager storage = mContext.getSystemService(StorageManager.class);
                    for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
@@ -1348,24 +1385,9 @@ public class UserManagerService extends IUserManager.Stub {
        return userInfo;
    }

    private int numberOfUsersOfTypeLocked(int flags, boolean excludeDying) {
        int count = 0;
        for (int i = mUsers.size() - 1; i >= 0; i--) {
            UserInfo user = mUsers.valueAt(i);
            if (!excludeDying || !mRemovingUserIds.get(user.id)) {
                if ((user.flags & flags) != 0) {
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * Find the current guest user. If the Guest user is partial,
     * then do not include it in the results as it is about to die.
     * This is different than {@link #numberOfUsersOfTypeLocked(int, boolean)} due to
     * the special handling of Guests being removed.
     */
    private UserInfo findCurrentGuestUserLocked() {
        final int size = mUsers.size();