From d4c416fd7a2ee32ac89ee251f332a950f5e347b8 Mon Sep 17 00:00:00 2001 From: Alex Johnston Date: Wed, 19 Feb 2020 16:29:38 +0000 Subject: [PATCH] Change the data structure of restrictions in UM Background * In an org-owned managed profile device, two admins can set user restrictions on a user. The current data structure of local user restrictions uses a SparseArray where the key is the userId and the value is the restriction bundle. * The existing data structure cannot store both the target userId and the originating userId. Changes * Introduces RestrictionsSet data structure, which is now used as a replacement of SparseArray. * Updates the data structure of local restrictions to SparseArray. The first key is the target userId and the second key is the originating userId. * targetUserId -> originatingUserId -> restrictionBundle * Numerous methods in UserManagerService and UserRestrictionsUtils had to be changed to support this. There will be follow up changes to move the logic of sorting the restrictions into local and global restrictions to DPMS. Bug: 149743941 Test: atest com.android.server.pm.UserManagerTest atest com.android.server.pm.RestrictionsSetTest atest com.android.server.pm.UserRestrictionsUtilsTest atest com.android.cts.devicepolicy.UserRestrictionsTest Change-Id: I08c9d60aa7a5e7cc3c661aaa4ba6dcd4f218323b --- .../android/server/pm/RestrictionsSet.java | 256 ++++++++++++++++ .../android/server/pm/UserManagerService.java | 274 ++++++++++++------ .../server/pm/UserRestrictionsUtils.java | 44 +-- .../server/devicepolicy/DpmTestUtils.java | 21 +- .../server/pm/RestrictionsSetTest.java | 191 ++++++++++++ .../server/pm/UserRestrictionsUtilsTest.java | 45 +-- 6 files changed, 674 insertions(+), 157 deletions(-) create mode 100644 services/core/java/com/android/server/pm/RestrictionsSet.java create mode 100644 services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java diff --git a/services/core/java/com/android/server/pm/RestrictionsSet.java b/services/core/java/com/android/server/pm/RestrictionsSet.java new file mode 100644 index 0000000000000..5aff6bbe002e6 --- /dev/null +++ b/services/core/java/com/android/server/pm/RestrictionsSet.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.os.Bundle; +import android.os.UserManager; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +/** + * Data structure that contains the mapping of users to user restrictions (either the user + * restrictions that apply to them, or the user restrictions that they set, depending on the + * circumstances). + * + * @hide + */ +public class RestrictionsSet { + + private static final String USER_ID = "user_id"; + private static final String TAG_RESTRICTIONS = "restrictions"; + private static final String TAG_RESTRICTIONS_USER = "restrictions_user"; + + /** + * Mapping of user restrictions. + * Only non-empty restriction bundles are stored. + * The key is the user id of the user. + * userId -> restrictionBundle + */ + private final SparseArray mUserRestrictions = new SparseArray<>(0); + + public RestrictionsSet() { + } + + public RestrictionsSet(@UserIdInt int userId, @NonNull Bundle restrictions) { + if (restrictions.isEmpty()) { + throw new IllegalArgumentException("empty restriction bundle cannot be added."); + } + mUserRestrictions.put(userId, restrictions); + } + + /** + * Updates restriction bundle for a given user. + * If new bundle is empty, record is removed from the array. + * + * @return whether restrictions bundle is different from the old one. + */ + public boolean updateRestrictions(@UserIdInt int userId, @Nullable Bundle restrictions) { + final boolean changed = + !UserRestrictionsUtils.areEqual(mUserRestrictions.get(userId), restrictions); + if (!changed) { + return false; + } + if (!UserRestrictionsUtils.isEmpty(restrictions)) { + mUserRestrictions.put(userId, restrictions); + } else { + mUserRestrictions.delete(userId); + } + return true; + } + + /** + * Moves a particular restriction from one restriction set to another, e.g. for all users. + */ + public void moveRestriction(@NonNull RestrictionsSet destRestrictions, String restriction) { + for (int i = 0; i < mUserRestrictions.size(); i++) { + final int userId = mUserRestrictions.keyAt(i); + final Bundle from = mUserRestrictions.valueAt(i); + + if (UserRestrictionsUtils.contains(from, restriction)) { + from.remove(restriction); + Bundle to = destRestrictions.getRestrictions(userId); + if (to == null) { + to = new Bundle(); + to.putBoolean(restriction, true); + destRestrictions.updateRestrictions(userId, to); + } else { + to.putBoolean(restriction, true); + } + // Don't keep empty bundles. + if (from.isEmpty()) { + mUserRestrictions.removeAt(i); + i--; + } + } + } + } + + /** + * @return whether restrictions set has no restrictions. + */ + public boolean isEmpty() { + return mUserRestrictions.size() == 0; + } + + /** + * Merge all restrictions in restrictions set into one bundle. The original user restrictions + * set does not get modified, instead a new bundle is returned. + * + * @return restrictions bundle containing all user restrictions. + */ + public @NonNull Bundle mergeAll() { + final Bundle result = new Bundle(); + for (int i = 0; i < mUserRestrictions.size(); i++) { + UserRestrictionsUtils.merge(result, mUserRestrictions.valueAt(i)); + } + return result; + } + + /** + * @return list of enforcing users that enforce a particular restriction. + */ + public @NonNull List getEnforcingUsers(String restriction, + @UserIdInt int deviceOwnerUserId) { + final List result = new ArrayList<>(); + for (int i = 0; i < mUserRestrictions.size(); i++) { + if (UserRestrictionsUtils.contains(mUserRestrictions.valueAt(i), restriction)) { + result.add(getEnforcingUser(mUserRestrictions.keyAt(i), deviceOwnerUserId)); + } + } + return result; + } + + private UserManager.EnforcingUser getEnforcingUser(@UserIdInt int userId, + @UserIdInt int deviceOwnerUserId) { + int source = deviceOwnerUserId == userId + ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER + : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER; + return new UserManager.EnforcingUser(userId, source); + } + + /** + * @return list of user restrictions for a given user. Null is returned if the user does not + * have any restrictions. + */ + public @Nullable Bundle getRestrictions(@UserIdInt int userId) { + return mUserRestrictions.get(userId); + } + + /** + * Removes a given user from the restrictions set, returning true if the user has non-empty + * restrictions before removal. + */ + public boolean remove(@UserIdInt int userId) { + boolean hasUserRestriction = mUserRestrictions.contains(userId); + mUserRestrictions.remove(userId); + return hasUserRestriction; + } + + /** + * Remove list of users and user restrictions. + */ + public void removeAllRestrictions() { + mUserRestrictions.clear(); + } + + /** + * Serialize a given {@link RestrictionsSet} to XML. + */ + public void writeRestrictions(@NonNull XmlSerializer serializer, @NonNull String outerTag) + throws IOException { + serializer.startTag(null, outerTag); + for (int i = 0; i < mUserRestrictions.size(); i++) { + serializer.startTag(null, TAG_RESTRICTIONS_USER); + serializer.attribute(null, USER_ID, String.valueOf(mUserRestrictions.keyAt(i))); + UserRestrictionsUtils.writeRestrictions(serializer, mUserRestrictions.valueAt(i), + TAG_RESTRICTIONS); + serializer.endTag(null, TAG_RESTRICTIONS_USER); + } + serializer.endTag(null, outerTag); + } + + /** + * Read restrictions from XML. + */ + public static RestrictionsSet readRestrictions(@NonNull XmlPullParser parser, + @NonNull String outerTag) throws IOException, XmlPullParserException { + RestrictionsSet restrictionsSet = new RestrictionsSet(); + int userId = 0; + int type; + + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + String tag = parser.getName(); + if (type == XmlPullParser.END_TAG && outerTag.equals(tag)) { + return restrictionsSet; + } else if (type == XmlPullParser.START_TAG && TAG_RESTRICTIONS_USER.equals(tag)) { + userId = Integer.parseInt(parser.getAttributeValue(null, USER_ID)); + } else if (type == XmlPullParser.START_TAG && TAG_RESTRICTIONS.equals(tag)) { + Bundle restrictions = UserRestrictionsUtils.readRestrictions(parser); + restrictionsSet.updateRestrictions(userId, restrictions); + } + } + throw new XmlPullParserException("restrictions cannot be read as xml is malformed."); + } + + /** + * Dumps {@link RestrictionsSet}. + */ + public void dumpRestrictions(PrintWriter pw, String prefix) { + boolean noneSet = true; + for (int i = 0; i < mUserRestrictions.size(); i++) { + pw.println(prefix + "User Id: " + mUserRestrictions.keyAt(i)); + UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", mUserRestrictions.valueAt(i)); + noneSet = false; + } + if (noneSet) { + pw.println(prefix + "none"); + } + } + + public boolean containsKey(@UserIdInt int userId) { + return mUserRestrictions.contains(userId); + } + + @VisibleForTesting + public int size() { + return mUserRestrictions.size(); + } + + @VisibleForTesting + public int keyAt(int index) { + return mUserRestrictions.keyAt(index); + } + + @VisibleForTesting + public Bundle valueAt(int index) { + return mUserRestrictions.valueAt(index); + } + +} diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index df3c83aec85ad..4b9d2600f8dab 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -182,6 +182,8 @@ public class UserManagerService extends IUserManager.Stub { private static final String TAG_USER = "user"; private static final String TAG_RESTRICTIONS = "restrictions"; private static final String TAG_DEVICE_POLICY_RESTRICTIONS = "device_policy_restrictions"; + private static final String TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS = + "device_policy_local_restrictions"; private static final String TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS = "device_policy_global_restrictions"; /** Legacy name for device owner id tag. */ @@ -329,7 +331,7 @@ public class UserManagerService extends IUserManager.Stub { * {@link #updateUserRestrictionsInternalLR}. */ @GuardedBy("mRestrictionsLock") - private final SparseArray mBaseUserRestrictions = new SparseArray<>(); + private final RestrictionsSet mBaseUserRestrictions = new RestrictionsSet(); /** * Cached user restrictions that are in effect -- i.e. {@link #mBaseUserRestrictions} combined @@ -344,7 +346,7 @@ public class UserManagerService extends IUserManager.Stub { * {@link #updateUserRestrictionsInternalLR}. */ @GuardedBy("mRestrictionsLock") - private final SparseArray mCachedEffectiveUserRestrictions = new SparseArray<>(); + private final RestrictionsSet mCachedEffectiveUserRestrictions = new RestrictionsSet(); /** * User restrictions that have already been applied in @@ -353,7 +355,7 @@ public class UserManagerService extends IUserManager.Stub { * {@link #updateUserRestrictionsInternalLR(Bundle, int)} call. */ @GuardedBy("mRestrictionsLock") - private final SparseArray mAppliedUserRestrictions = new SparseArray<>(); + private final RestrictionsSet mAppliedUserRestrictions = new RestrictionsSet(); /** * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService} @@ -362,7 +364,7 @@ public class UserManagerService extends IUserManager.Stub { * The key is the user id of the user whom the restriction originated from. */ @GuardedBy("mRestrictionsLock") - private final SparseArray mDevicePolicyGlobalUserRestrictions = new SparseArray<>(); + private final RestrictionsSet mDevicePolicyGlobalUserRestrictions = new RestrictionsSet(); /** * Id of the user that set global restrictions. @@ -372,11 +374,15 @@ public class UserManagerService extends IUserManager.Stub { /** * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService} - * for each user. Only non-empty restriction bundles are stored. - * The key is the user id of the user whom the restriction originated from. + * for each user. + * The key is the user id of the user whom the restrictions are targeting. + * The key inside the restrictionsSet is the user id of the user whom the restriction + * originated from. + * targetUserId -> originatingUserId -> restrictionBundle */ @GuardedBy("mRestrictionsLock") - private final SparseArray mDevicePolicyLocalUserRestrictions = new SparseArray<>(); + private final SparseArray mDevicePolicyLocalUserRestrictions = + new SparseArray<>(); @GuardedBy("mGuestRestrictions") private final Bundle mGuestRestrictions = new Bundle(); @@ -1709,9 +1715,6 @@ public class UserManagerService extends IUserManager.Stub { } } - /** - * See {@link UserManagerInternal#setDevicePolicyUserRestrictions} - */ private void setDevicePolicyUserRestrictionsInner(@UserIdInt int originatingUserId, @Nullable Bundle restrictions, @UserManagerInternal.OwnerType int restrictionOwnerType) { @@ -1721,16 +1724,36 @@ public class UserManagerService extends IUserManager.Stub { // Sort restrictions into local and global ensuring they don't overlap. UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, restrictionOwnerType, global, local); + boolean isDeviceOwner = restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; + RestrictionsSet localRestrictionsSet; + if (UserRestrictionsUtils.isEmpty(local)) { + localRestrictionsSet = new RestrictionsSet(); + } else { + localRestrictionsSet = new RestrictionsSet(originatingUserId, local); + } + setDevicePolicyUserRestrictionsInner(originatingUserId, global, localRestrictionsSet, + isDeviceOwner); + } + + /** + * See {@link UserManagerInternal#setDevicePolicyUserRestrictions} + */ + private void setDevicePolicyUserRestrictionsInner(@UserIdInt int originatingUserId, + @NonNull Bundle global, @NonNull RestrictionsSet local, + boolean isDeviceOwner) { boolean globalChanged, localChanged; + List updatedLocalTargetUserIds; synchronized (mRestrictionsLock) { // Update global and local restrictions if they were changed. - globalChanged = updateRestrictionsIfNeededLR( - originatingUserId, global, mDevicePolicyGlobalUserRestrictions); - localChanged = updateRestrictionsIfNeededLR( - originatingUserId, local, mDevicePolicyLocalUserRestrictions); + globalChanged = mDevicePolicyGlobalUserRestrictions + .updateRestrictions(originatingUserId, global); + updatedLocalTargetUserIds = getUpdatedTargetUserIdsFromLocalRestrictions( + originatingUserId, local); + localChanged = updateLocalRestrictionsForTargetUsersLR(originatingUserId, local, + updatedLocalTargetUserIds); - if (restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) { + if (isDeviceOwner) { // Remember the global restriction owner userId to be able to make a distinction // in getUserRestrictionSource on who set local policies. mDeviceOwnerUserId = originatingUserId; @@ -1753,8 +1776,20 @@ public class UserManagerService extends IUserManager.Stub { } // Don't call them within the mRestrictionsLock. synchronized (mPackagesLock) { - if (localChanged || globalChanged) { - writeUserLP(getUserDataNoChecks(originatingUserId)); + if (globalChanged || localChanged) { + if (updatedLocalTargetUserIds.size() == 1 + && updatedLocalTargetUserIds.contains(originatingUserId)) { + writeUserLP(getUserDataNoChecks(originatingUserId)); + } else { + if (globalChanged) { + writeUserLP(getUserDataNoChecks(originatingUserId)); + } + if (localChanged) { + for (int targetUserId : updatedLocalTargetUserIds) { + writeAllTargetUsersLP(targetUserId); + } + } + } } } @@ -1762,44 +1797,88 @@ public class UserManagerService extends IUserManager.Stub { if (globalChanged) { applyUserRestrictionsForAllUsersLR(); } else if (localChanged) { - applyUserRestrictionsLR(originatingUserId); + for (int targetUserId : updatedLocalTargetUserIds) { + applyUserRestrictionsLR(targetUserId); + } } } } /** - * Updates restriction bundle for a given user in a given restriction array. If new bundle is - * empty, record is removed from the array. - * @return whether restrictions bundle is different from the old one. + * @return the list of updated target user ids in device policy local restrictions for a + * given originating user id. */ - private boolean updateRestrictionsIfNeededLR(@UserIdInt int userId, - @Nullable Bundle restrictions, SparseArray restrictionsArray) { - final boolean changed = - !UserRestrictionsUtils.areEqual(restrictionsArray.get(userId), restrictions); - if (changed) { - if (!UserRestrictionsUtils.isEmpty(restrictions)) { - restrictionsArray.put(userId, restrictions); - } else { - restrictionsArray.delete(userId); + private List getUpdatedTargetUserIdsFromLocalRestrictions(int originatingUserId, + @NonNull RestrictionsSet local) { + List targetUserIds = new ArrayList<>(); + // Update all the target user ids from the local restrictions set + for (int i = 0; i < local.size(); i++) { + targetUserIds.add(local.keyAt(i)); + } + // Update the target user id from device policy local restrictions if the local + // restrictions set does not contain the target user id. + for (int i = 0; i < mDevicePolicyLocalUserRestrictions.size(); i++) { + int targetUserId = mDevicePolicyLocalUserRestrictions.keyAt(i); + RestrictionsSet restrictionsSet = mDevicePolicyLocalUserRestrictions.valueAt(i); + if (!local.containsKey(targetUserId) + && restrictionsSet.containsKey(originatingUserId)) { + targetUserIds.add(targetUserId); + } + } + return targetUserIds; + } + + /** + * Update restrictions for all target users in the restriction set. If a target user does not + * exist in device policy local restrictions, remove the restrictions bundle for that target + * user originating from the specified originating user. + */ + private boolean updateLocalRestrictionsForTargetUsersLR(int originatingUserId, + RestrictionsSet local, List updatedTargetUserIds) { + boolean changed = false; + for (int targetUserId : updatedTargetUserIds) { + Bundle restrictions = local.getRestrictions(targetUserId); + if (restrictions == null) { + restrictions = new Bundle(); + } + if (getDevicePolicyLocalRestrictionsForTargetUserLR(targetUserId) + .updateRestrictions(originatingUserId, restrictions)) { + changed = true; } } return changed; } + /** + * A new restriction set is created if a restriction set does not already exist for a given + * target user. + * + * @return restrictions set for a given target user. + */ + private @NonNull RestrictionsSet getDevicePolicyLocalRestrictionsForTargetUserLR( + int targetUserId) { + RestrictionsSet result = mDevicePolicyLocalUserRestrictions.get(targetUserId); + if (result == null) { + result = new RestrictionsSet(); + mDevicePolicyLocalUserRestrictions.put(targetUserId, result); + } + return result; + } + @GuardedBy("mRestrictionsLock") private Bundle computeEffectiveUserRestrictionsLR(@UserIdInt int userId) { final Bundle baseRestrictions = - UserRestrictionsUtils.nonNull(mBaseUserRestrictions.get(userId)); - final Bundle global = UserRestrictionsUtils.mergeAll(mDevicePolicyGlobalUserRestrictions); - final Bundle local = mDevicePolicyLocalUserRestrictions.get(userId); + UserRestrictionsUtils.nonNull(mBaseUserRestrictions.getRestrictions(userId)); + final Bundle global = mDevicePolicyGlobalUserRestrictions.mergeAll(); + final RestrictionsSet local = getDevicePolicyLocalRestrictionsForTargetUserLR(userId); - if (UserRestrictionsUtils.isEmpty(global) && UserRestrictionsUtils.isEmpty(local)) { + if (UserRestrictionsUtils.isEmpty(global) && local.isEmpty()) { // Common case first. return baseRestrictions; } final Bundle effective = UserRestrictionsUtils.clone(baseRestrictions); UserRestrictionsUtils.merge(effective, global); - UserRestrictionsUtils.merge(effective, local); + UserRestrictionsUtils.merge(effective, local.mergeAll()); return effective; } @@ -1814,10 +1893,10 @@ public class UserManagerService extends IUserManager.Stub { private Bundle getEffectiveUserRestrictions(@UserIdInt int userId) { synchronized (mRestrictionsLock) { - Bundle restrictions = mCachedEffectiveUserRestrictions.get(userId); + Bundle restrictions = mCachedEffectiveUserRestrictions.getRestrictions(userId); if (restrictions == null) { restrictions = computeEffectiveUserRestrictionsLR(userId); - mCachedEffectiveUserRestrictions.put(userId, restrictions); + mCachedEffectiveUserRestrictions.updateRestrictions(userId, restrictions); } return restrictions; } @@ -1920,31 +1999,17 @@ public class UserManagerService extends IUserManager.Stub { } synchronized (mRestrictionsLock) { - // Check if it is set by profile owner. - Bundle profileOwnerRestrictions = mDevicePolicyLocalUserRestrictions.get(userId); - if (UserRestrictionsUtils.contains(profileOwnerRestrictions, restrictionKey)) { - result.add(getEnforcingUserLocked(userId)); - } + // Check if it is set as a local restriction. + result.addAll(getDevicePolicyLocalRestrictionsForTargetUserLR(userId).getEnforcingUsers( + restrictionKey, mDeviceOwnerUserId)); - // Iterate over all users who enforce global restrictions. - for (int i = mDevicePolicyGlobalUserRestrictions.size() - 1; i >= 0; i--) { - Bundle globalRestrictions = mDevicePolicyGlobalUserRestrictions.valueAt(i); - int profileUserId = mDevicePolicyGlobalUserRestrictions.keyAt(i); - if (UserRestrictionsUtils.contains(globalRestrictions, restrictionKey)) { - result.add(getEnforcingUserLocked(profileUserId)); - } - } + // Check if it is set as a global restriction. + result.addAll(mDevicePolicyGlobalUserRestrictions.getEnforcingUsers(restrictionKey, + mDeviceOwnerUserId)); } return result; } - @GuardedBy("mRestrictionsLock") - private EnforcingUser getEnforcingUserLocked(@UserIdInt int userId) { - int source = mDeviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER - : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER; - return new EnforcingUser(userId, source); - } - /** * @return UserRestrictions that are in effect currently. This always returns a new * {@link Bundle}. @@ -1962,7 +2027,7 @@ public class UserManagerService extends IUserManager.Stub { return false; } synchronized (mRestrictionsLock) { - Bundle bundle = mBaseUserRestrictions.get(userId); + Bundle bundle = mBaseUserRestrictions.getRestrictions(userId); return (bundle != null && bundle.getBoolean(restrictionKey, false)); } } @@ -1977,7 +2042,7 @@ public class UserManagerService extends IUserManager.Stub { // Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create // a copy. final Bundle newRestrictions = UserRestrictionsUtils.clone( - mBaseUserRestrictions.get(userId)); + mBaseUserRestrictions.getRestrictions(userId)); newRestrictions.putBoolean(key, value); updateUserRestrictionsInternalLR(newRestrictions, userId); @@ -1996,25 +2061,25 @@ public class UserManagerService extends IUserManager.Stub { private void updateUserRestrictionsInternalLR( @Nullable Bundle newBaseRestrictions, @UserIdInt int userId) { final Bundle prevAppliedRestrictions = UserRestrictionsUtils.nonNull( - mAppliedUserRestrictions.get(userId)); + mAppliedUserRestrictions.getRestrictions(userId)); // Update base restrictions. if (newBaseRestrictions != null) { // If newBaseRestrictions == the current one, it's probably a bug. - final Bundle prevBaseRestrictions = mBaseUserRestrictions.get(userId); + final Bundle prevBaseRestrictions = mBaseUserRestrictions.getRestrictions(userId); Preconditions.checkState(prevBaseRestrictions != newBaseRestrictions); - Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId) + Preconditions.checkState(mCachedEffectiveUserRestrictions.getRestrictions(userId) != newBaseRestrictions); - if (updateRestrictionsIfNeededLR(userId, newBaseRestrictions, mBaseUserRestrictions)) { + if (mBaseUserRestrictions.updateRestrictions(userId, newBaseRestrictions)) { scheduleWriteUser(getUserDataNoChecks(userId)); } } final Bundle effective = computeEffectiveUserRestrictionsLR(userId); - mCachedEffectiveUserRestrictions.put(userId, effective); + mCachedEffectiveUserRestrictions.updateRestrictions(userId, effective); // Apply the new restrictions. if (DBG) { @@ -2037,7 +2102,7 @@ public class UserManagerService extends IUserManager.Stub { propagateUserRestrictionsLR(userId, effective, prevAppliedRestrictions); - mAppliedUserRestrictions.put(userId, new Bundle(effective)); + mAppliedUserRestrictions.updateRestrictions(userId, new Bundle(effective)); } private void propagateUserRestrictionsLR(final int userId, @@ -2089,7 +2154,7 @@ public class UserManagerService extends IUserManager.Stub { debug("applyUserRestrictionsForAllUsersLR"); } // First, invalidate all cached values. - mCachedEffectiveUserRestrictions.clear(); + mCachedEffectiveUserRestrictions.removeAllRestrictions(); // We don't want to call into ActivityManagerService while taking a lock, so we'll call // it on a handler. @@ -2565,7 +2630,7 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mRestrictionsLock) { if (!UserRestrictionsUtils.isEmpty(oldGlobalUserRestrictions) && mDeviceOwnerUserId != UserHandle.USER_NULL) { - mDevicePolicyGlobalUserRestrictions.put( + mDevicePolicyGlobalUserRestrictions.updateRestrictions( mDeviceOwnerUserId, oldGlobalUserRestrictions); } // ENSURE_VERIFY_APPS is now enforced globally even if put by profile owner, so move @@ -2690,7 +2755,8 @@ public class UserManagerService extends IUserManager.Stub { if (!restrictions.isEmpty()) { synchronized (mRestrictionsLock) { - mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions); + mBaseUserRestrictions.updateRestrictions(UserHandle.USER_SYSTEM, + restrictions); } } @@ -2717,6 +2783,16 @@ public class UserManagerService extends IUserManager.Stub { } } + private void writeAllTargetUsersLP(int originatingUserId) { + for (int i = 0; i < mDevicePolicyLocalUserRestrictions.size(); i++) { + int targetUserId = mDevicePolicyLocalUserRestrictions.keyAt(i); + RestrictionsSet restrictionsSet = mDevicePolicyLocalUserRestrictions.valueAt(i); + if (restrictionsSet.containsKey(originatingUserId)) { + writeUserLP(getUserDataNoChecks(targetUserId)); + } + } + } + private void writeUserLP(UserData userData) { if (DBG) { debug("writeUserLP " + userData); @@ -2801,12 +2877,11 @@ public class UserManagerService extends IUserManager.Stub { } synchronized (mRestrictionsLock) { UserRestrictionsUtils.writeRestrictions(serializer, - mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS); + mBaseUserRestrictions.getRestrictions(userInfo.id), TAG_RESTRICTIONS); + getDevicePolicyLocalRestrictionsForTargetUserLR(userInfo.id).writeRestrictions( + serializer, TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS); UserRestrictionsUtils.writeRestrictions(serializer, - mDevicePolicyLocalUserRestrictions.get(userInfo.id), - TAG_DEVICE_POLICY_RESTRICTIONS); - UserRestrictionsUtils.writeRestrictions(serializer, - mDevicePolicyGlobalUserRestrictions.get(userInfo.id), + mDevicePolicyGlobalUserRestrictions.getRestrictions(userInfo.id), TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS); } @@ -2936,7 +3011,8 @@ public class UserManagerService extends IUserManager.Stub { String seedAccountType = null; PersistableBundle seedAccountOptions = null; Bundle baseRestrictions = null; - Bundle localRestrictions = null; + Bundle legacyLocalRestrictions = null; + RestrictionsSet localRestrictions = null; Bundle globalRestrictions = null; XmlPullParser parser = Xml.newPullParser(); @@ -3006,7 +3082,10 @@ public class UserManagerService extends IUserManager.Stub { } else if (TAG_RESTRICTIONS.equals(tag)) { baseRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) { - localRestrictions = UserRestrictionsUtils.readRestrictions(parser); + legacyLocalRestrictions = UserRestrictionsUtils.readRestrictions(parser); + } else if (TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS.equals(tag)) { + localRestrictions = RestrictionsSet.readRestrictions(parser, + TAG_DEVICE_POLICY_LOCAL_RESTRICTIONS); } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) { globalRestrictions = UserRestrictionsUtils.readRestrictions(parser); } else if (TAG_ACCOUNT.equals(tag)) { @@ -3051,13 +3130,20 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mRestrictionsLock) { if (baseRestrictions != null) { - mBaseUserRestrictions.put(id, baseRestrictions); + mBaseUserRestrictions.updateRestrictions(id, baseRestrictions); } if (localRestrictions != null) { mDevicePolicyLocalUserRestrictions.put(id, localRestrictions); + if (legacyLocalRestrictions != null) { + Slog.wtf(LOG_TAG, "Seeing both legacy and current local restrictions in xml"); + } + } else if (legacyLocalRestrictions != null) { + mDevicePolicyLocalUserRestrictions.put(id, + new RestrictionsSet(id, legacyLocalRestrictions)); } if (globalRestrictions != null) { - mDevicePolicyGlobalUserRestrictions.put(id, globalRestrictions); + mDevicePolicyGlobalUserRestrictions.updateRestrictions(id, + globalRestrictions); } } return userData; @@ -3373,7 +3459,7 @@ public class UserManagerService extends IUserManager.Stub { userTypeDetails.addDefaultRestrictionsTo(restrictions); } synchronized (mRestrictionsLock) { - mBaseUserRestrictions.append(userId, restrictions); + mBaseUserRestrictions.updateRestrictions(userId, restrictions); } t.traceBegin("PM.onNewUserCreated-" + userId); @@ -3844,9 +3930,17 @@ public class UserManagerService extends IUserManager.Stub { mBaseUserRestrictions.remove(userId); mAppliedUserRestrictions.remove(userId); mCachedEffectiveUserRestrictions.remove(userId); - mDevicePolicyLocalUserRestrictions.remove(userId); - if (mDevicePolicyGlobalUserRestrictions.get(userId) != null) { - mDevicePolicyGlobalUserRestrictions.remove(userId); + // Remove local restrictions affecting user + mDevicePolicyLocalUserRestrictions.delete(userId); + // Remove local restrictions set by user + boolean changed = false; + for (int i = 0; i < mDevicePolicyLocalUserRestrictions.size(); i++) { + int targetUserId = mDevicePolicyLocalUserRestrictions.keyAt(i); + changed |= getDevicePolicyLocalRestrictionsForTargetUserLR(targetUserId) + .remove(userId); + } + changed |= mDevicePolicyGlobalUserRestrictions.remove(userId); + if (changed) { applyUserRestrictionsForAllUsersLR(); } } @@ -4539,16 +4633,18 @@ public class UserManagerService extends IUserManager.Stub { pw.println(" Restrictions:"); synchronized (mRestrictionsLock) { UserRestrictionsUtils.dumpRestrictions( - pw, " ", mBaseUserRestrictions.get(userInfo.id)); + pw, " ", mBaseUserRestrictions.getRestrictions(userInfo.id)); pw.println(" Device policy global restrictions:"); UserRestrictionsUtils.dumpRestrictions( - pw, " ", mDevicePolicyGlobalUserRestrictions.get(userInfo.id)); + pw, " ", + mDevicePolicyGlobalUserRestrictions.getRestrictions(userInfo.id)); pw.println(" Device policy local restrictions:"); - UserRestrictionsUtils.dumpRestrictions( - pw, " ", mDevicePolicyLocalUserRestrictions.get(userInfo.id)); + getDevicePolicyLocalRestrictionsForTargetUserLR( + userInfo.id).dumpRestrictions(pw, " "); pw.println(" Effective restrictions:"); UserRestrictionsUtils.dumpRestrictions( - pw, " ", mCachedEffectiveUserRestrictions.get(userInfo.id)); + pw, " ", + mCachedEffectiveUserRestrictions.getRestrictions(userInfo.id)); } if (userData.account != null) { @@ -4664,7 +4760,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public Bundle getBaseUserRestrictions(@UserIdInt int userId) { synchronized (mRestrictionsLock) { - return mBaseUserRestrictions.get(userId); + return mBaseUserRestrictions.getRestrictions(userId); } } @@ -4672,8 +4768,8 @@ public class UserManagerService extends IUserManager.Stub { public void setBaseUserRestrictionsByDpmsForMigration( @UserIdInt int userId, Bundle baseRestrictions) { synchronized (mRestrictionsLock) { - if (updateRestrictionsIfNeededLR( - userId, new Bundle(baseRestrictions), mBaseUserRestrictions)) { + if (mBaseUserRestrictions.updateRestrictions(userId, + new Bundle(baseRestrictions))) { invalidateEffectiveUserRestrictionsLR(userId); } } diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 8d3f32aab9c5e..eec6e024fef27 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -394,22 +394,6 @@ public class UserRestrictionsUtils { } } - /** - * Merges a sparse array of restrictions bundles into one. - */ - @Nullable - public static Bundle mergeAll(SparseArray restrictions) { - if (restrictions.size() == 0) { - return null; - } else { - final Bundle result = new Bundle(); - for (int i = 0; i < restrictions.size(); i++) { - merge(result, restrictions.valueAt(i)); - } - return result; - } - } - /** * @return true if a restriction is settable by device owner. */ @@ -864,27 +848,15 @@ public class UserRestrictionsUtils { } /** - * Moves a particular restriction from one array of bundles to another, e.g. for all users. + * Moves a particular restriction from one array of restrictions sets to a restriction set, + * e.g. for all users. */ - public static void moveRestriction(String restrictionKey, SparseArray srcRestrictions, - SparseArray destRestrictions) { - for (int i = 0; i < srcRestrictions.size(); i++) { - final int key = srcRestrictions.keyAt(i); - final Bundle from = srcRestrictions.valueAt(i); - if (contains(from, restrictionKey)) { - from.remove(restrictionKey); - Bundle to = destRestrictions.get(key); - if (to == null) { - to = new Bundle(); - destRestrictions.append(key, to); - } - to.putBoolean(restrictionKey, true); - // Don't keep empty bundles. - if (from.isEmpty()) { - srcRestrictions.removeAt(i); - i--; - } - } + public static void moveRestriction(String restrictionKey, + SparseArray sourceRestrictionsSets, + RestrictionsSet destRestrictionSet) { + for (int i = 0; i < sourceRestrictionsSets.size(); i++) { + final RestrictionsSet sourceRestrictionsSet = sourceRestrictionsSets.valueAt(i); + sourceRestrictionsSet.moveRestriction(destRestrictionSet, restrictionKey); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java index 2882b88460c9e..afb5e55004232 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java @@ -25,6 +25,8 @@ import android.test.AndroidTestCase; import android.util.Log; import android.util.Printer; +import com.android.server.pm.RestrictionsSet; + import libcore.io.Streams; import com.google.android.collect.Lists; @@ -35,7 +37,6 @@ import org.junit.Assert; import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; @@ -58,6 +59,13 @@ public class DpmTestUtils extends AndroidTestCase { return list == null ? 0 : list.size(); } + public static RestrictionsSet newRestrictions(int userId, String... restrictions) { + Bundle localRestrictionsBundle = newRestrictions(restrictions); + RestrictionsSet localRestrictions = new RestrictionsSet(); + localRestrictions.updateRestrictions(userId, localRestrictionsBundle); + return localRestrictions; + } + public static Bundle newRestrictions(String... restrictions) { final Bundle ret = new Bundle(); for (String restriction : restrictions) { @@ -66,6 +74,17 @@ public class DpmTestUtils extends AndroidTestCase { return ret; } + public static void assertRestrictions(RestrictionsSet expected, RestrictionsSet actual) { + assertEquals(expected.size(), actual.size()); + + for (int i = 0; i < expected.size(); i++) { + int originatingUserId = expected.keyAt(i); + Bundle actualRestrictions = actual.getRestrictions(originatingUserId); + assertFalse(actualRestrictions.isEmpty()); + assertRestrictions(expected.getRestrictions(originatingUserId), actualRestrictions); + } + } + public static void assertRestrictions(Bundle expected, Bundle actual) { final ArrayList elist; if (expected == null) { diff --git a/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java b/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java new file mode 100644 index 0000000000000..b73c9ea949b83 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/RestrictionsSetTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import static com.android.server.devicepolicy.DpmTestUtils.assertRestrictions; +import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; + +/** Test for {@link RestrictionsSet}. */ +@RunWith(AndroidJUnit4.class) +public class RestrictionsSetTest { + + private RestrictionsSet mRestrictionsSet = new RestrictionsSet(); + private final int originatingUserId = 0; + + @Test + public void testUpdateRestrictions_addRestrictions() { + Bundle restrictions = newRestrictions(UserManager.ENSURE_VERIFY_APPS); + + assertTrue(mRestrictionsSet.updateRestrictions(originatingUserId, restrictions)); + + assertRestrictions(restrictions, mRestrictionsSet.getRestrictions(originatingUserId)); + } + + @Test + public void testUpdateRestrictions_removeRestrictions() { + Bundle restrictions = newRestrictions(UserManager.ENSURE_VERIFY_APPS); + mRestrictionsSet.updateRestrictions(originatingUserId, restrictions); + + assertTrue(mRestrictionsSet.updateRestrictions(originatingUserId, new Bundle())); + + assertNull(mRestrictionsSet.getRestrictions(originatingUserId)); + } + + @Test + public void testUpdateRestrictions_noChange() { + Bundle restrictions = newRestrictions(UserManager.ENSURE_VERIFY_APPS); + mRestrictionsSet.updateRestrictions(originatingUserId, restrictions); + + assertFalse(mRestrictionsSet.updateRestrictions(originatingUserId, restrictions)); + } + + @Test + public void testMoveRestriction_containsRestriction() { + RestrictionsSet destRestrictionsSet = new RestrictionsSet(); + + String restriction = UserManager.DISALLOW_CONFIG_DATE_TIME; + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(restriction)); + + mRestrictionsSet.moveRestriction(destRestrictionsSet, restriction); + + assertNull(mRestrictionsSet.getRestrictions(originatingUserId)); + assertNotNull(destRestrictionsSet.getRestrictions(originatingUserId)); + assertRestrictions(newRestrictions(restriction), + destRestrictionsSet.getRestrictions(originatingUserId)); + } + + @Test + public void testMoveRestriction_doesNotContainRestriction() { + RestrictionsSet destRestrictionsSet = new RestrictionsSet(); + + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(UserManager.ENSURE_VERIFY_APPS)); + + mRestrictionsSet.moveRestriction(destRestrictionsSet, + UserManager.DISALLOW_CONFIG_DATE_TIME); + + assertRestrictions(newRestrictions(UserManager.ENSURE_VERIFY_APPS), + mRestrictionsSet.getRestrictions(originatingUserId)); + assertNull(destRestrictionsSet.getRestrictions(originatingUserId)); + } + + @Test + public void testIsEmpty_noRestrictions() { + assertTrue(mRestrictionsSet.isEmpty()); + } + + @Test + public void testIsEmpty_hasRestrictions() { + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(UserManager.ENSURE_VERIFY_APPS, + UserManager.DISALLOW_CONFIG_DATE_TIME)); + + assertFalse(mRestrictionsSet.isEmpty()); + } + + @Test + public void testMergeAll_noRestrictions() { + assertTrue(mRestrictionsSet.mergeAll().isEmpty()); + } + + @Test + public void testMergeAll_hasRestrictions() { + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(UserManager.ENSURE_VERIFY_APPS, + UserManager.DISALLOW_CONFIG_DATE_TIME)); + mRestrictionsSet.updateRestrictions(10, + newRestrictions(UserManager.DISALLOW_ADD_USER, + UserManager.DISALLOW_AIRPLANE_MODE)); + + Bundle actual = mRestrictionsSet.mergeAll(); + assertRestrictions(newRestrictions(UserManager.ENSURE_VERIFY_APPS, + UserManager.DISALLOW_CONFIG_DATE_TIME, UserManager.DISALLOW_ADD_USER, + UserManager.DISALLOW_AIRPLANE_MODE), actual); + } + + @Test + public void testGetEnforcingUsers_hasEnforcingUser() { + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(UserManager.ENSURE_VERIFY_APPS)); + mRestrictionsSet.updateRestrictions(10, + newRestrictions(UserManager.DISALLOW_ADD_USER)); + + List enforcingUsers = mRestrictionsSet.getEnforcingUsers( + UserManager.ENSURE_VERIFY_APPS, originatingUserId); + + UserManager.EnforcingUser enforcingUser1 = enforcingUsers.get(0); + assertEquals(UserHandle.of(originatingUserId), enforcingUser1.getUserHandle()); + assertEquals(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER, + enforcingUser1.getUserRestrictionSource()); + } + + @Test + public void testGetEnforcingUsers_hasMultipleEnforcingUsers() { + int originatingUserId2 = 10; + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(UserManager.ENSURE_VERIFY_APPS)); + mRestrictionsSet.updateRestrictions(originatingUserId2, + newRestrictions(UserManager.ENSURE_VERIFY_APPS)); + + List enforcingUsers = mRestrictionsSet.getEnforcingUsers( + UserManager.ENSURE_VERIFY_APPS, originatingUserId); + + assertEquals(2, enforcingUsers.size()); + for (UserManager.EnforcingUser enforcingUser : enforcingUsers) { + int userId = enforcingUser.getUserHandle().getIdentifier(); + assertTrue((userId == originatingUserId) || (userId == originatingUserId2)); + if (userId == originatingUserId) { + assertEquals(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER, + enforcingUser.getUserRestrictionSource()); + } + if (userId == originatingUserId2) { + assertEquals(UserManager.RESTRICTION_SOURCE_PROFILE_OWNER, + enforcingUser.getUserRestrictionSource()); + } + } + } + + @Test + public void testGetEnforcingUsers_noEnforcingUsers() { + mRestrictionsSet.updateRestrictions(originatingUserId, + newRestrictions(UserManager.DISALLOW_USER_SWITCH)); + + List enforcingUsers = mRestrictionsSet.getEnforcingUsers( + UserManager.ENSURE_VERIFY_APPS, originatingUserId); + + assertTrue(enforcingUsers.isEmpty()); + } + +} diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java index 1a630ffa70970..1c2313e3e32f2 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java @@ -247,60 +247,43 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase { assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local); } - public void testMergeAll() { - SparseArray restrictions = new SparseArray<>(); - assertNull(UserRestrictionsUtils.mergeAll(restrictions)); - - restrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME)); - restrictions.put(1, newRestrictions(UserManager.DISALLOW_USB_FILE_TRANSFER)); - restrictions.put(2, newRestrictions(UserManager.DISALLOW_APPS_CONTROL)); - - Bundle result = UserRestrictionsUtils.mergeAll(restrictions); - assertRestrictions( - newRestrictions( - UserManager.DISALLOW_ADJUST_VOLUME, - UserManager.DISALLOW_USB_FILE_TRANSFER, - UserManager.DISALLOW_APPS_CONTROL), - result); - } - public void testMoveRestriction() { - SparseArray localRestrictions = new SparseArray<>(); - SparseArray globalRestrictions = new SparseArray<>(); + SparseArray localRestrictions = new SparseArray<>(); + RestrictionsSet globalRestrictions = new RestrictionsSet(); // User 0 has only local restrictions, nothing should change. - localRestrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME)); + localRestrictions.put(0, newRestrictions(0, UserManager.DISALLOW_ADJUST_VOLUME)); // User 1 has a local restriction to be moved to global and some global already. Local // restrictions should be removed for this user. - localRestrictions.put(1, newRestrictions(UserManager.ENSURE_VERIFY_APPS)); - globalRestrictions.put(1, newRestrictions(UserManager.DISALLOW_ADD_USER)); + localRestrictions.put(1, newRestrictions(1, UserManager.ENSURE_VERIFY_APPS)); + globalRestrictions.updateRestrictions(1, + newRestrictions(UserManager.DISALLOW_ADD_USER)); // User 2 has a local restriction to be moved and one to leave local. - localRestrictions.put(2, newRestrictions( - UserManager.ENSURE_VERIFY_APPS, - UserManager.DISALLOW_CONFIG_VPN)); + localRestrictions.put(2, newRestrictions(2, + UserManager.ENSURE_VERIFY_APPS, UserManager.DISALLOW_CONFIG_VPN)); UserRestrictionsUtils.moveRestriction( UserManager.ENSURE_VERIFY_APPS, localRestrictions, globalRestrictions); // Check user 0. assertRestrictions( - newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME), + newRestrictions(0, UserManager.DISALLOW_ADJUST_VOLUME), localRestrictions.get(0)); - assertNull(globalRestrictions.get(0)); + assertNull(globalRestrictions.getRestrictions(0)); // Check user 1. - assertNull(localRestrictions.get(1)); + assertTrue(localRestrictions.get(1).isEmpty()); assertRestrictions( newRestrictions(UserManager.ENSURE_VERIFY_APPS, UserManager.DISALLOW_ADD_USER), - globalRestrictions.get(1)); + globalRestrictions.getRestrictions(1)); // Check user 2. assertRestrictions( - newRestrictions(UserManager.DISALLOW_CONFIG_VPN), + newRestrictions(2, UserManager.DISALLOW_CONFIG_VPN), localRestrictions.get(2)); assertRestrictions( newRestrictions(UserManager.ENSURE_VERIFY_APPS), - globalRestrictions.get(2)); + globalRestrictions.getRestrictions(2)); } public void testAreEqual() {