Make ENSURE_VERIFY_APPS global even when set by PO.
Currently only device owner can set global user restrictions.
With this CL ENSURE_VERIFY_APPS will be global no matter who
enforces it, DO or PO.
To make it possible for system apps to check who enforces a
particular restriction in this case a new API method is added
to UserManager: getUserRestrictionSources which returns a list
of users who enforce the restriction.
Bug:31000521
Test: cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.UserRestrictionsTest (ag/1732744)
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
Test: installed M on a Nexus5x device, created a managed profile with some user restrictions, and checked that after upgrading M->O all restrictions are preserved and split correctly into base, global and local.
Change-Id: I543d3ec9ef0cf2b730da6f7406021c0bba43b785
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9b47beb..0874424 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -67,6 +67,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManager.EnforcingUser;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.storage.StorageManager;
@@ -118,6 +119,7 @@
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -162,7 +164,11 @@
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_GLOBAL_RESTRICTIONS =
+ "device_policy_global_restrictions";
+ /** Legacy name for device owner id tag. */
private static final String TAG_GLOBAL_RESTRICTION_OWNER_ID = "globalRestrictionOwnerUserId";
+ private static final String TAG_DEVICE_OWNER_USER_ID = "deviceOwnerUserId";
private static final String TAG_ENTRY = "entry";
private static final String TAG_VALUE = "value";
private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
@@ -202,7 +208,7 @@
@VisibleForTesting
static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;
- private static final int USER_VERSION = 6;
+ private static final int USER_VERSION = 7;
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
@@ -267,7 +273,7 @@
/**
* User restrictions set via UserManager. This doesn't include restrictions set by
- * device owner / profile owners.
+ * device owner / profile owners. Only non-empty restriction bundles are stored.
*
* DO NOT Change existing {@link Bundle} in it. When changing a restriction for a user,
* a new {@link Bundle} should always be created and set. This is because a {@link Bundle}
@@ -305,20 +311,21 @@
/**
* User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
- * that should be applied to all users, including guests.
+ * that should be applied to all users, including guests. Only non-empty restriction bundles are
+ * stored.
*/
@GuardedBy("mRestrictionsLock")
- private Bundle mDevicePolicyGlobalUserRestrictions;
+ private final SparseArray<Bundle> mDevicePolicyGlobalUserRestrictions = new SparseArray<>();
/**
* Id of the user that set global restrictions.
*/
@GuardedBy("mRestrictionsLock")
- private int mGlobalRestrictionOwnerUserId = UserHandle.USER_NULL;
+ private int mDeviceOwnerUserId = UserHandle.USER_NULL;
/**
* User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
- * for each user.
+ * for each user. Only non-empty restriction bundles are stored.
*/
@GuardedBy("mRestrictionsLock")
private final SparseArray<Bundle> mDevicePolicyLocalUserRestrictions = new SparseArray<>();
@@ -1176,39 +1183,36 @@
}
/**
- * See {@link UserManagerInternal#setDevicePolicyUserRestrictions(int, Bundle, Bundle)}
+ * See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
*/
- void setDevicePolicyUserRestrictionsInner(int userId, @NonNull Bundle local,
- @Nullable Bundle global) {
- Preconditions.checkNotNull(local);
- boolean globalChanged = false;
- boolean localChanged;
+ private void setDevicePolicyUserRestrictionsInner(int userId, @Nullable Bundle restrictions,
+ boolean isDeviceOwner, int cameraRestrictionScope) {
+ final Bundle global = new Bundle();
+ final Bundle local = new Bundle();
+
+ // Sort restrictions into local and global ensuring they don't overlap.
+ UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, isDeviceOwner,
+ cameraRestrictionScope, global, local);
+
+ boolean globalChanged, localChanged;
synchronized (mRestrictionsLock) {
- if (global != null) {
- // Update global.
- globalChanged = !UserRestrictionsUtils.areEqual(
- mDevicePolicyGlobalUserRestrictions, global);
- if (globalChanged) {
- mDevicePolicyGlobalUserRestrictions = global;
- }
+ // Update global and local restrictions if they were changed.
+ globalChanged = updateRestrictionsIfNeededLR(
+ userId, global, mDevicePolicyGlobalUserRestrictions);
+ localChanged = updateRestrictionsIfNeededLR(
+ userId, local, mDevicePolicyLocalUserRestrictions);
+
+ if (isDeviceOwner) {
// Remember the global restriction owner userId to be able to make a distinction
// in getUserRestrictionSource on who set local policies.
- mGlobalRestrictionOwnerUserId = userId;
+ mDeviceOwnerUserId = userId;
} else {
- if (mGlobalRestrictionOwnerUserId == userId) {
+ if (mDeviceOwnerUserId == userId) {
// When profile owner sets restrictions it passes null global bundle and we
// reset global restriction owner userId.
// This means this user used to have DO, but now the DO is gone and the user
// instead has PO.
- mGlobalRestrictionOwnerUserId = UserHandle.USER_NULL;
- }
- }
- {
- // Update local.
- final Bundle prev = mDevicePolicyLocalUserRestrictions.get(userId);
- localChanged = !UserRestrictionsUtils.areEqual(prev, local);
- if (localChanged) {
- mDevicePolicyLocalUserRestrictions.put(userId, local);
+ mDeviceOwnerUserId = UserHandle.USER_NULL;
}
}
}
@@ -1220,12 +1224,9 @@
}
// Don't call them within the mRestrictionsLock.
synchronized (mPackagesLock) {
- if (localChanged) {
+ if (localChanged || globalChanged) {
writeUserLP(getUserDataNoChecks(userId));
}
- if (globalChanged) {
- writeUserListLP();
- }
}
synchronized (mRestrictionsLock) {
@@ -1237,11 +1238,30 @@
}
}
+ /**
+ * 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.
+ */
+ private boolean updateRestrictionsIfNeededLR(int userId, @Nullable Bundle restrictions,
+ SparseArray<Bundle> restrictionsArray) {
+ final boolean changed =
+ !UserRestrictionsUtils.areEqual(restrictionsArray.get(userId), restrictions);
+ if (changed) {
+ if (!UserRestrictionsUtils.isEmpty(restrictions)) {
+ restrictionsArray.put(userId, restrictions);
+ } else {
+ restrictionsArray.delete(userId);
+ }
+ }
+ return changed;
+ }
+
@GuardedBy("mRestrictionsLock")
private Bundle computeEffectiveUserRestrictionsLR(int userId) {
final Bundle baseRestrictions =
UserRestrictionsUtils.nonNull(mBaseUserRestrictions.get(userId));
- final Bundle global = mDevicePolicyGlobalUserRestrictions;
+ final Bundle global = UserRestrictionsUtils.mergeAll(mDevicePolicyGlobalUserRestrictions);
final Bundle local = mDevicePolicyLocalUserRestrictions.get(userId);
if (UserRestrictionsUtils.isEmpty(global) && UserRestrictionsUtils.isEmpty(local)) {
@@ -1299,39 +1319,58 @@
*/
@Override
public int getUserRestrictionSource(String restrictionKey, int userId) {
- checkManageUsersPermission("getUserRestrictionSource");
+ List<EnforcingUser> enforcingUsers = getUserRestrictionSources(restrictionKey, userId);
+ // Get "bitwise or" of restriction sources for all enforcing users.
int result = UserManager.RESTRICTION_NOT_SET;
+ for (int i = enforcingUsers.size() - 1; i >= 0; i--) {
+ result |= enforcingUsers.get(i).getUserRestrictionSource();
+ }
+ return result;
+ }
+
+ @Override
+ public List<EnforcingUser> getUserRestrictionSources(
+ String restrictionKey, @UserIdInt int userId) {
+ checkManageUsersPermission("getUserRestrictionSource");
// Shortcut for the most common case
if (!hasUserRestriction(restrictionKey, userId)) {
- return result;
+ return Collections.emptyList();
}
+ final List<EnforcingUser> result = new ArrayList<>();
+
+ // Check if it is base restriction.
if (hasBaseUserRestriction(restrictionKey, userId)) {
- result |= UserManager.RESTRICTION_SOURCE_SYSTEM;
+ result.add(new EnforcingUser(
+ UserHandle.USER_NULL, UserManager.RESTRICTION_SOURCE_SYSTEM));
}
- synchronized(mRestrictionsLock) {
- Bundle localRestrictions = mDevicePolicyLocalUserRestrictions.get(userId);
- if (!UserRestrictionsUtils.isEmpty(localRestrictions)
- && localRestrictions.getBoolean(restrictionKey)) {
- // Local restrictions may have been set by device owner the userId of which is
- // stored in mGlobalRestrictionOwnerUserId.
- if (mGlobalRestrictionOwnerUserId == userId) {
- result |= UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
- } else {
- result |= UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
+ synchronized (mRestrictionsLock) {
+ // Check if it is set by profile owner.
+ Bundle profileOwnerRestrictions = mDevicePolicyLocalUserRestrictions.get(userId);
+ if (UserRestrictionsUtils.contains(profileOwnerRestrictions, restrictionKey)) {
+ result.add(getEnforcingUserLocked(userId));
+ }
+
+ // 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));
}
}
- if (!UserRestrictionsUtils.isEmpty(mDevicePolicyGlobalUserRestrictions)
- && mDevicePolicyGlobalUserRestrictions.getBoolean(restrictionKey)) {
- result |= UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
- }
}
-
return result;
}
+ 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}.
@@ -1374,28 +1413,26 @@
* Optionally updating user restrictions, calculate the effective user restrictions and also
* propagate to other services and system settings.
*
- * @param newRestrictions User restrictions to set.
+ * @param newBaseRestrictions User restrictions to set.
* If null, will not update user restrictions and only does the propagation.
* @param userId target user ID.
*/
@GuardedBy("mRestrictionsLock")
private void updateUserRestrictionsInternalLR(
- @Nullable Bundle newRestrictions, int userId) {
-
+ @Nullable Bundle newBaseRestrictions, int userId) {
final Bundle prevAppliedRestrictions = UserRestrictionsUtils.nonNull(
mAppliedUserRestrictions.get(userId));
// Update base restrictions.
- if (newRestrictions != null) {
- // If newRestrictions == the current one, it's probably a bug.
+ if (newBaseRestrictions != null) {
+ // If newBaseRestrictions == the current one, it's probably a bug.
final Bundle prevBaseRestrictions = mBaseUserRestrictions.get(userId);
- Preconditions.checkState(prevBaseRestrictions != newRestrictions);
+ Preconditions.checkState(prevBaseRestrictions != newBaseRestrictions);
Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId)
- != newRestrictions);
+ != newBaseRestrictions);
- if (!UserRestrictionsUtils.areEqual(prevBaseRestrictions, newRestrictions)) {
- mBaseUserRestrictions.put(userId, newRestrictions);
+ if (updateRestrictionsIfNeededLR(userId, newBaseRestrictions, mBaseUserRestrictions)) {
scheduleWriteUser(getUserDataNoChecks(userId));
}
}
@@ -1746,7 +1783,9 @@
}
}
- final Bundle newDevicePolicyGlobalUserRestrictions = new Bundle();
+ // Pre-O global user restriction were stored as a single bundle (as opposed to per-user
+ // currently), take care of it in case of upgrade.
+ Bundle oldDevicePolicyGlobalUserRestrictions = null;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG) {
@@ -1771,29 +1810,30 @@
if (type == XmlPullParser.START_TAG) {
if (parser.getName().equals(TAG_RESTRICTIONS)) {
synchronized (mGuestRestrictions) {
- UserRestrictionsUtils
- .readRestrictions(parser, mGuestRestrictions);
+ mGuestRestrictions.putAll(
+ UserRestrictionsUtils.readRestrictions(parser));
}
}
break;
}
}
- } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
- UserRestrictionsUtils.readRestrictions(parser,
- newDevicePolicyGlobalUserRestrictions);
- } else if (name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
+ } else if (name.equals(TAG_DEVICE_OWNER_USER_ID)
+ // Legacy name, should only be encountered when upgrading from pre-O.
+ || name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
String ownerUserId = parser.getAttributeValue(null, ATTR_ID);
if (ownerUserId != null) {
- mGlobalRestrictionOwnerUserId = Integer.parseInt(ownerUserId);
+ mDeviceOwnerUserId = Integer.parseInt(ownerUserId);
}
+ } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
+ // Should only happen when upgrading from pre-O (version < 7).
+ oldDevicePolicyGlobalUserRestrictions =
+ UserRestrictionsUtils.readRestrictions(parser);
}
}
}
- synchronized (mRestrictionsLock) {
- mDevicePolicyGlobalUserRestrictions = newDevicePolicyGlobalUserRestrictions;
- }
+
updateUserIds();
- upgradeIfNecessaryLP();
+ upgradeIfNecessaryLP(oldDevicePolicyGlobalUserRestrictions);
} catch (IOException | XmlPullParserException e) {
fallbackToSingleUserLP();
} finally {
@@ -1803,8 +1843,9 @@
/**
* Upgrade steps between versions, either for fixing bugs or changing the data format.
+ * @param oldGlobalUserRestrictions Pre-O global device policy restrictions.
*/
- private void upgradeIfNecessaryLP() {
+ private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
final int originalVersion = mUserVersion;
int userVersion = mUserVersion;
if (userVersion < 1) {
@@ -1855,6 +1896,23 @@
userVersion = 6;
}
+ if (userVersion < 7) {
+ // Previously only one user could enforce global restrictions, now it is per-user.
+ synchronized (mRestrictionsLock) {
+ if (!UserRestrictionsUtils.isEmpty(oldGlobalUserRestrictions)
+ && mDeviceOwnerUserId != UserHandle.USER_NULL) {
+ mDevicePolicyGlobalUserRestrictions.put(
+ mDeviceOwnerUserId, oldGlobalUserRestrictions);
+ }
+ // ENSURE_VERIFY_APPS is now enforced globally even if put by profile owner, so move
+ // it from local to global bundle for all users who set it.
+ UserRestrictionsUtils.moveRestriction(UserManager.ENSURE_VERIFY_APPS,
+ mDevicePolicyLocalUserRestrictions, mDevicePolicyGlobalUserRestrictions
+ );
+ }
+ userVersion = 7;
+ }
+
if (userVersion < USER_VERSION) {
Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
+ USER_VERSION);
@@ -1893,8 +1951,10 @@
Log.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e);
}
- synchronized (mRestrictionsLock) {
- mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+ if (!restrictions.isEmpty()) {
+ synchronized (mRestrictionsLock) {
+ mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+ }
}
updateUserIds();
@@ -2004,6 +2064,9 @@
UserRestrictionsUtils.writeRestrictions(serializer,
mDevicePolicyLocalUserRestrictions.get(userInfo.id),
TAG_DEVICE_POLICY_RESTRICTIONS);
+ UserRestrictionsUtils.writeRestrictions(serializer,
+ mDevicePolicyGlobalUserRestrictions.get(userInfo.id),
+ TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
}
if (userData.account != null) {
@@ -2057,13 +2120,9 @@
.writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS);
}
serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
- synchronized (mRestrictionsLock) {
- UserRestrictionsUtils.writeRestrictions(serializer,
- mDevicePolicyGlobalUserRestrictions, TAG_DEVICE_POLICY_RESTRICTIONS);
- }
- serializer.startTag(null, TAG_GLOBAL_RESTRICTION_OWNER_ID);
- serializer.attribute(null, ATTR_ID, Integer.toString(mGlobalRestrictionOwnerUserId));
- serializer.endTag(null, TAG_GLOBAL_RESTRICTION_OWNER_ID);
+ serializer.startTag(null, TAG_DEVICE_OWNER_USER_ID);
+ serializer.attribute(null, ATTR_ID, Integer.toString(mDeviceOwnerUserId));
+ serializer.endTag(null, TAG_DEVICE_OWNER_USER_ID);
int[] userIdsToWrite;
synchronized (mUsersLock) {
userIdsToWrite = new int[mUsers.size()];
@@ -2125,8 +2184,9 @@
String seedAccountName = null;
String seedAccountType = null;
PersistableBundle seedAccountOptions = null;
- Bundle baseRestrictions = new Bundle();
- Bundle localRestrictions = new Bundle();
+ Bundle baseRestrictions = null;
+ Bundle localRestrictions = null;
+ Bundle globalRestrictions = null;
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, StandardCharsets.UTF_8.name());
@@ -2187,9 +2247,11 @@
name = parser.getText();
}
} else if (TAG_RESTRICTIONS.equals(tag)) {
- UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
+ baseRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
- UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
+ localRestrictions = UserRestrictionsUtils.readRestrictions(parser);
+ } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) {
+ globalRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_ACCOUNT.equals(tag)) {
type = parser.next();
if (type == XmlPullParser.TEXT) {
@@ -2224,8 +2286,15 @@
userData.seedAccountOptions = seedAccountOptions;
synchronized (mRestrictionsLock) {
- mBaseUserRestrictions.put(id, baseRestrictions);
- mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+ if (baseRestrictions != null) {
+ mBaseUserRestrictions.put(id, baseRestrictions);
+ }
+ if (localRestrictions != null) {
+ mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+ }
+ if (globalRestrictions != null) {
+ mDevicePolicyGlobalUserRestrictions.put(id, globalRestrictions);
+ }
}
return userData;
}
@@ -2731,6 +2800,10 @@
mAppliedUserRestrictions.remove(userHandle);
mCachedEffectiveUserRestrictions.remove(userHandle);
mDevicePolicyLocalUserRestrictions.remove(userHandle);
+ if (mDevicePolicyGlobalUserRestrictions.get(userHandle) != null) {
+ mDevicePolicyGlobalUserRestrictions.remove(userHandle);
+ applyUserRestrictionsForAllUsersLR();
+ }
}
// Update the user list
synchronized (mPackagesLock) {
@@ -3420,6 +3493,9 @@
synchronized (mRestrictionsLock) {
UserRestrictionsUtils.dumpRestrictions(
pw, " ", mBaseUserRestrictions.get(userInfo.id));
+ pw.println(" Device policy global restrictions:");
+ UserRestrictionsUtils.dumpRestrictions(
+ pw, " ", mDevicePolicyGlobalUserRestrictions.get(userInfo.id));
pw.println(" Device policy local restrictions:");
UserRestrictionsUtils.dumpRestrictions(
pw, " ", mDevicePolicyLocalUserRestrictions.get(userInfo.id));
@@ -3448,13 +3524,7 @@
}
}
pw.println();
- pw.println(" Device policy global restrictions:");
- synchronized (mRestrictionsLock) {
- UserRestrictionsUtils
- .dumpRestrictions(pw, " ", mDevicePolicyGlobalUserRestrictions);
- }
- pw.println();
- pw.println(" Global restrictions owner id:" + mGlobalRestrictionOwnerUserId);
+ pw.println(" Device owner id:" + mDeviceOwnerUserId);
pw.println();
pw.println(" Guest restrictions:");
synchronized (mGuestRestrictions) {
@@ -3508,10 +3578,10 @@
private class LocalService extends UserManagerInternal {
@Override
- public void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle localRestrictions,
- @Nullable Bundle globalRestrictions) {
- UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, localRestrictions,
- globalRestrictions);
+ public void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
+ boolean isDeviceOwner, int cameraRestrictionScope) {
+ UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, restrictions,
+ isDeviceOwner, cameraRestrictionScope);
}
@Override
@@ -3525,8 +3595,10 @@
public void setBaseUserRestrictionsByDpmsForMigration(
int userId, Bundle baseRestrictions) {
synchronized (mRestrictionsLock) {
- mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions));
- invalidateEffectiveUserRestrictionsLR(userId);
+ if (updateRestrictionsIfNeededLR(
+ userId, new Bundle(baseRestrictions), mBaseUserRestrictions)) {
+ invalidateEffectiveUserRestrictionsLR(userId);
+ }
}
final UserData userData = getUserDataNoChecks(userId);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f5b8669..d301463 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -30,11 +30,13 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.service.persistentdata.PersistentDataBlockManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -117,9 +119,10 @@
);
/**
- * User restrictions that can not be set by profile owners.
+ * User restrictions that cannot be set by profile owners of secondary users. When set by DO
+ * they will be applied to all users.
*/
- private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
+ private static final Set<String> PRIMARY_USER_ONLY_RESTRICTIONS = Sets.newArraySet(
UserManager.DISALLOW_BLUETOOTH,
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_TETHERING,
@@ -163,6 +166,13 @@
UserManager.DISALLOW_ADD_MANAGED_PROFILE
);
+ /*
+ * Special user restrictions that are always applied to all users no matter who sets them.
+ */
+ private static final Set<String> PROFILE_GLOBAL_RESTRICTIONS = Sets.newArraySet(
+ UserManager.ENSURE_VERIFY_APPS
+ );
+
/**
* Throws {@link IllegalArgumentException} if the given restriction name is invalid.
*/
@@ -205,6 +215,12 @@
}
}
+ public static Bundle readRestrictions(XmlPullParser parser) {
+ final Bundle result = new Bundle();
+ readRestrictions(parser, result);
+ return result;
+ }
+
/**
* @return {@code in} itself when it's not null, or an empty bundle (which can writable).
*/
@@ -217,6 +233,14 @@
}
/**
+ * Returns {@code true} if given bundle is not null and contains {@code true} for a given
+ * restriction.
+ */
+ public static boolean contains(@Nullable Bundle in, String restriction) {
+ return in != null && in.getBoolean(restriction);
+ }
+
+ /**
* Creates a copy of the {@code in} Bundle. If {@code in} is null, it'll return an empty
* bundle.
*
@@ -241,6 +265,22 @@
}
/**
+ * Merges a sparse array of restrictions bundles into one.
+ */
+ @Nullable
+ public static Bundle mergeAll(SparseArray<Bundle> 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.
*/
public static boolean canDeviceOwnerChange(String restriction) {
@@ -254,7 +294,7 @@
public static boolean canProfileOwnerChange(String restriction, int userId) {
return !IMMUTABLE_BY_OWNERS.contains(restriction)
&& !(userId != UserHandle.USER_SYSTEM
- && DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction));
+ && PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction));
}
/**
@@ -269,8 +309,15 @@
* Takes restrictions that can be set by device owner, and sort them into what should be applied
* globally and what should be applied only on the current user.
*/
- public static void sortToGlobalAndLocal(@Nullable Bundle in, @NonNull Bundle global,
- @NonNull Bundle local) {
+ public static void sortToGlobalAndLocal(@Nullable Bundle in, boolean isDeviceOwner,
+ int cameraRestrictionScope,
+ @NonNull Bundle global, @NonNull Bundle local) {
+ // Camera restriction (as well as all others) goes to at most one bundle.
+ if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_GLOBALLY) {
+ global.putBoolean(UserManager.DISALLOW_CAMERA, true);
+ } else if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_LOCALLY) {
+ local.putBoolean(UserManager.DISALLOW_CAMERA, true);
+ }
if (in == null || in.size() == 0) {
return;
}
@@ -278,7 +325,7 @@
if (!in.getBoolean(key)) {
continue;
}
- if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)) {
+ if (isGlobal(isDeviceOwner, key)) {
global.putBoolean(key, true);
} else {
local.putBoolean(key, true);
@@ -287,6 +334,15 @@
}
/**
+ * Whether given user restriction should be enforced globally.
+ */
+ private static boolean isGlobal(boolean isDeviceOwner, String key) {
+ return (isDeviceOwner &&
+ (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key)|| GLOBAL_RESTRICTIONS.contains(key)))
+ || PROFILE_GLOBAL_RESTRICTIONS.contains(key);
+ }
+
+ /**
* @return true if two Bundles contain the same user restriction.
* A null bundle and an empty bundle are considered to be equal.
*/
@@ -485,4 +541,29 @@
pw.println(prefix + "null");
}
}
+
+ /**
+ * Moves a particular restriction from one array of bundles to another, e.g. for all users.
+ */
+ public static void moveRestriction(String restrictionKey, SparseArray<Bundle> srcRestrictions,
+ SparseArray<Bundle> destRestrictions) {
+ for (int i = 0; i < srcRestrictions.size(); i++) {
+ int key = srcRestrictions.keyAt(i);
+ 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--;
+ }
+ }
+ }
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bdd1a0f..6b4186d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -49,7 +49,6 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -180,8 +179,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -1143,7 +1140,7 @@
} else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) {
keepUninstalledPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
- UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+ userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
} else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
readAttributeValues(
parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet);
@@ -7767,7 +7764,7 @@
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- ActiveAdmin activeAdmin =
+ final ActiveAdmin activeAdmin =
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
final boolean isDeviceOwner = isDeviceOwner(who, userHandle);
@@ -7782,7 +7779,12 @@
}
// Save the restriction to ActiveAdmin.
- activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner);
+ final Bundle restrictions = activeAdmin.ensureUserRestrictions();
+ if (enabledFromThisOwner) {
+ restrictions.putBoolean(key, true);
+ } else {
+ restrictions.remove(key);
+ }
saveUserRestrictionsLocked(userHandle);
}
}
@@ -7795,39 +7797,46 @@
private void pushUserRestrictions(int userId) {
synchronized (this) {
- final Bundle global;
- final Bundle local = new Bundle();
- if (mOwners.isDeviceOwnerUserId(userId)) {
- global = new Bundle();
+ final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
+ final Bundle userRestrictions;
+ // Whether device owner enforces camera restriction.
+ boolean disallowCameraGlobally = false;
+ if (isDeviceOwner) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
if (deviceOwner == null) {
return; // Shouldn't happen.
}
-
- UserRestrictionsUtils.sortToGlobalAndLocal(deviceOwner.userRestrictions,
- global, local);
+ userRestrictions = deviceOwner.userRestrictions;
// DO can disable camera globally.
- if (deviceOwner.disableCamera) {
- global.putBoolean(UserManager.DISALLOW_CAMERA, true);
- }
+ disallowCameraGlobally = deviceOwner.disableCamera;
} else {
- global = null;
+ final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+ userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null;
+ }
- ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
- if (profileOwner != null) {
- UserRestrictionsUtils.merge(local, profileOwner.userRestrictions);
- }
- }
- // Also merge in *local* camera restriction.
- if (getCameraDisabled(/* who= */ null,
- userId, /* mergeDeviceOwnerRestriction= */ false)) {
- local.putBoolean(UserManager.DISALLOW_CAMERA, true);
- }
- mUserManagerInternal.setDevicePolicyUserRestrictions(userId, local, global);
+ // Whether any admin enforces camera restriction.
+ final int cameraRestrictionScope =
+ getCameraRestrictionScopeLocked(userId, disallowCameraGlobally);
+
+ mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions,
+ isDeviceOwner, cameraRestrictionScope);
}
}
+ /**
+ * Get the scope of camera restriction for a given user if any.
+ */
+ private int getCameraRestrictionScopeLocked(int userId, boolean disallowCameraGlobally) {
+ if (disallowCameraGlobally) {
+ return UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+ } else if (getCameraDisabled(
+ /* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) {
+ return UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+ }
+ return UserManagerInternal.CAMERA_NOT_DISABLED;
+ }
+
@Override
public Bundle getUserRestrictions(ComponentName who) {
if (!mHasFeature) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e68895e..af9caf2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -15,6 +15,10 @@
*/
package com.android.server.devicepolicy;
+import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
+
import android.Manifest.permission;
import android.app.Activity;
import android.app.admin.DeviceAdminReceiver;
@@ -39,6 +43,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.test.MoreAsserts;
@@ -928,9 +933,8 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions()
- );
+ eq(null),
+ eq(true), eq(CAMERA_NOT_DISABLED));
assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
@@ -1287,7 +1291,8 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(defaultRestrictions),
- MockUtils.checkUserRestrictions()
+ eq(true) /* isDeviceOwner */,
+ eq(CAMERA_NOT_DISABLED)
);
reset(mContext.userManagerInternal);
@@ -1296,21 +1301,21 @@
}
assertNoDeviceOwnerRestrictions();
+ reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1328,8 +1333,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- MockUtils.checkUserRestrictions()
- );
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1345,8 +1349,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions()
- );
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
assertNoDeviceOwnerRestrictions();
@@ -1358,42 +1361,38 @@
dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE)
- );
+ UserManager.DISALLOW_UNMUTE_MICROPHONE),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-
+ reset(mContext.userManagerInternal);
// More tests.
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_ADD_USER)
- );
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.setCameraDisabled(admin1, true);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
// DISALLOW_CAMERA will be applied to both local and global.
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
- );
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_DISABLED_GLOBALLY));
reset(mContext.userManagerInternal);
// Set up another DA and let it disable camera. Now DISALLOW_CAMERA will only be applied
@@ -1407,11 +1406,10 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- // DISALLOW_CAMERA will be applied to both local and global.
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+ // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_ADD_USER)
- );
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_DISABLED_LOCALLY));
reset(mContext.userManagerInternal);
// TODO Make sure restrictions are written to the file.
}
@@ -1429,8 +1427,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1438,8 +1435,7 @@
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1462,8 +1458,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1484,8 +1479,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1507,18 +1501,15 @@
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.setCameraDisabled(admin1, true);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
- UserManager.DISALLOW_ADJUST_VOLUME,
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_DISABLED_LOCALLY));
reset(mContext.userManagerInternal);
// TODO Make sure restrictions are written to the file.
@@ -1558,7 +1549,8 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(defaultRestrictions),
- MockUtils.checkUserRestrictions()
+ eq(true) /* isDeviceOwner */,
+ eq(CAMERA_NOT_DISABLED)
);
reset(mContext.userManagerInternal);
@@ -1600,7 +1592,8 @@
verify(mContext.userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
- MockUtils.checkUserRestrictions()
+ eq(true) /* isDeviceOwner */,
+ eq(CAMERA_NOT_DISABLED)
);
reset(mContext.userManagerInternal);
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 11f9ebb..480be2e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -16,13 +16,16 @@
package com.android.server.pm;
+import static com.android.server.devicepolicy.DpmTestUtils.assertRestrictions;
+import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions;
+
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.devicepolicy.DpmTestUtils;
+import android.util.SparseArray;
/**
* Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
@@ -49,14 +52,14 @@
public void testIsEmpty() {
assertTrue(UserRestrictionsUtils.isEmpty(null));
assertTrue(UserRestrictionsUtils.isEmpty(new Bundle()));
- assertFalse(UserRestrictionsUtils.isEmpty(DpmTestUtils.newRestrictions("a")));
+ assertFalse(UserRestrictionsUtils.isEmpty(newRestrictions("a")));
}
public void testClone() {
Bundle in = new Bundle();
Bundle out = UserRestrictionsUtils.clone(in);
assertNotSame(in, out);
- DpmTestUtils.assertRestrictions(out, new Bundle());
+ assertRestrictions(out, new Bundle());
out = UserRestrictionsUtils.clone(null);
assertNotNull(out);
@@ -64,16 +67,16 @@
}
public void testMerge() {
- Bundle a = DpmTestUtils.newRestrictions("a", "d");
- Bundle b = DpmTestUtils.newRestrictions("b", "d", "e");
+ Bundle a = newRestrictions("a", "d");
+ Bundle b = newRestrictions("b", "d", "e");
UserRestrictionsUtils.merge(a, b);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+ assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
UserRestrictionsUtils.merge(a, null);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+ assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
try {
UserRestrictionsUtils.merge(a, a);
@@ -114,25 +117,32 @@
final Bundle local = new Bundle();
final Bundle global = new Bundle();
- UserRestrictionsUtils.sortToGlobalAndLocal(null, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(null, false /* isDeviceOwner */,
+ UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
assertEquals(0, global.size());
assertEquals(0, local.size());
- UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false /* isDeviceOwner */,
+ UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
assertEquals(0, global.size());
assertEquals(0, local.size());
- UserRestrictionsUtils.sortToGlobalAndLocal(DpmTestUtils.newRestrictions(
+ // Restrictions set by DO.
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_OUTGOING_BEAM,
- UserManager.DISALLOW_APPS_CONTROL
- ), global, local);
+ UserManager.DISALLOW_APPS_CONTROL,
+ UserManager.ENSURE_VERIFY_APPS
+ ), true /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+ assertRestrictions(newRestrictions(
+ // This one is global no matter who sets it.
+ UserManager.ENSURE_VERIFY_APPS,
+
// These can be set by PO too, but when DO sets them, they're global.
UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
@@ -142,11 +152,117 @@
UserManager.DISALLOW_CONFIG_TETHERING
), global);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+ assertRestrictions(newRestrictions(
// They can be set by both DO/PO.
UserManager.DISALLOW_OUTGOING_BEAM,
UserManager.DISALLOW_APPS_CONTROL
), local);
+
+ local.clear();
+ global.clear();
+
+ // Restrictions set by PO.
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
+ UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE,
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_CONFIG_TETHERING,
+ UserManager.DISALLOW_OUTGOING_BEAM,
+ UserManager.DISALLOW_APPS_CONTROL,
+ UserManager.ENSURE_VERIFY_APPS
+ ), false /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+
+ assertRestrictions(newRestrictions(
+ // This one is global no matter who sets it.
+ UserManager.ENSURE_VERIFY_APPS
+ ), global);
+
+ assertRestrictions(newRestrictions(
+ // These can be set by PO too, but when PO sets them, they're local.
+ UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE,
+
+ // They can be set by both DO/PO.
+ UserManager.DISALLOW_OUTGOING_BEAM,
+ UserManager.DISALLOW_APPS_CONTROL,
+
+ // These can only be set by DO.
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_CONFIG_TETHERING
+ ), local);
+
+ }
+
+ public void testSortToLocalAndGlobalWithCameraDisabled() {
+ final Bundle local = new Bundle();
+ final Bundle global = new Bundle();
+
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+ UserManagerInternal.CAMERA_DISABLED_GLOBALLY, global, local);
+ assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
+ assertEquals(0, local.size());
+ global.clear();
+
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+ UserManagerInternal.CAMERA_DISABLED_LOCALLY, global, local);
+ assertEquals(0, global.size());
+ assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
+ }
+
+ public void testMergeAll() {
+ SparseArray<Bundle> 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<Bundle> localRestrictions = new SparseArray<>();
+ SparseArray<Bundle> globalRestrictions = new SparseArray<>();
+
+ // User 0 has only local restrictions, nothing should change.
+ localRestrictions.put(0, newRestrictions(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));
+ // 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));
+
+ UserRestrictionsUtils.moveRestriction(
+ UserManager.ENSURE_VERIFY_APPS, localRestrictions, globalRestrictions);
+
+ // Check user 0.
+ assertRestrictions(
+ newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME),
+ localRestrictions.get(0));
+ assertNull(globalRestrictions.get(0));
+
+ // Check user 1.
+ assertNull(localRestrictions.get(1));
+ assertRestrictions(
+ newRestrictions(UserManager.ENSURE_VERIFY_APPS, UserManager.DISALLOW_ADD_USER),
+ globalRestrictions.get(1));
+
+ // Check user 2.
+ assertRestrictions(
+ newRestrictions(UserManager.DISALLOW_CONFIG_VPN),
+ localRestrictions.get(2));
+ assertRestrictions(
+ newRestrictions(UserManager.ENSURE_VERIFY_APPS),
+ globalRestrictions.get(2));
}
public void testAreEqual() {
@@ -172,33 +288,33 @@
assertFalse(UserRestrictionsUtils.areEqual(
null,
- DpmTestUtils.newRestrictions("a")));
+ newRestrictions("a")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a"),
+ newRestrictions("a"),
null));
assertTrue(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a"),
- DpmTestUtils.newRestrictions("a")));
+ newRestrictions("a"),
+ newRestrictions("a")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a"),
- DpmTestUtils.newRestrictions("a", "b")));
+ newRestrictions("a"),
+ newRestrictions("a", "b")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a", "b"),
- DpmTestUtils.newRestrictions("a")));
+ newRestrictions("a", "b"),
+ newRestrictions("a")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("b", "a"),
- DpmTestUtils.newRestrictions("a", "a")));
+ newRestrictions("b", "a"),
+ newRestrictions("a", "a")));
// Make sure false restrictions are handled correctly.
- final Bundle a = DpmTestUtils.newRestrictions("a");
+ final Bundle a = newRestrictions("a");
a.putBoolean("b", true);
- final Bundle b = DpmTestUtils.newRestrictions("a");
+ final Bundle b = newRestrictions("a");
b.putBoolean("b", false);
assertFalse(UserRestrictionsUtils.areEqual(a, b));