diff options
3 files changed, 127 insertions, 30 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index 702602adf1b3..1027b31b1879 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -632,6 +632,38 @@ final class DevicePolicyEngine { } /** + * Returns all the {@code policyKeys} set by any admin that share the same + * {@link PolicyKey#getIdentifier()} as the provided {@code policyDefinition}. + * + * <p>For example, getLocalPolicyKeysSetByAllAdmins(PERMISSION_GRANT) returns all permission + * grants set by any admin. + * + * <p>Note that this will always return at most one item for policies that do not require + * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs + * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}). + * + */ + @NonNull + <V> Set<PolicyKey> getLocalPolicyKeysSetByAllAdmins( + @NonNull PolicyDefinition<V> policyDefinition, + int userId) { + Objects.requireNonNull(policyDefinition); + + synchronized (mLock) { + if (policyDefinition.isGlobalOnlyPolicy() || !mLocalPolicies.contains(userId)) { + return Set.of(); + } + Set<PolicyKey> keys = new HashSet<>(); + for (PolicyKey key : mLocalPolicies.get(userId).keySet()) { + if (key.hasSameIdentifierAs(policyDefinition.getPolicyKey())) { + keys.add(key); + } + } + return keys; + } + } + + /** * Returns all user restriction policies set by the given admin. * * <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 5cad4e208b3f..1e58e2dcc6e6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -280,6 +280,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.StatusBarManager; +import android.app.admin.AccountTypePolicyKey; import android.app.admin.BooleanPolicyValue; import android.app.admin.BundlePolicyValue; import android.app.admin.ComponentNamePolicyValue; @@ -13978,16 +13979,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { caller = getCallerIdentity(who); } synchronized (getLockObject()) { - final ActiveAdmin ap; if (isPermissionCheckFlagEnabled()) { + int affectedUser = getAffectedUser(parent); EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( who, MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, caller.getPackageName(), - getAffectedUser(parent) + affectedUser ); - ap = enforcingAdmin.getActiveAdmin(); + if (disabled) { + mDevicePolicyEngine.setLocalPolicy( + PolicyDefinition.ACCOUNT_MANAGEMENT_DISABLED(accountType), + enforcingAdmin, + new BooleanPolicyValue(disabled), + affectedUser); + } else { + mDevicePolicyEngine.removeLocalPolicy( + PolicyDefinition.ACCOUNT_MANAGEMENT_DISABLED(accountType), + enforcingAdmin, + affectedUser); + } } else { + final ActiveAdmin ap; Objects.requireNonNull(who, "ComponentName is null"); /* * When called on the parent DPM instance (parent == true), affects active admin @@ -14004,13 +14017,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ap = getParentOfAdminIfRequired( getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent); } + if (disabled) { + ap.accountTypesWithManagementDisabled.add(accountType); + } else { + ap.accountTypesWithManagementDisabled.remove(accountType); + } + saveSettingsLocked(UserHandle.getCallingUserId()); } - if (disabled) { - ap.accountTypesWithManagementDisabled.add(accountType); - } else { - ap.accountTypesWithManagementDisabled.remove(accountType); - } - saveSettingsLocked(UserHandle.getCallingUserId()); } } @@ -14028,41 +14041,64 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } CallerIdentity caller; Preconditions.checkArgumentNonnegative(userId, "Invalid userId"); + final ArraySet<String> resultSet = new ArraySet<>(); if (isPermissionCheckFlagEnabled()) { + int affectedUser = parent ? getProfileParentId(userId) : userId; caller = getCallerIdentity(callerPackageName); if (!hasPermission(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, - caller.getPackageName(), userId) + callerPackageName, affectedUser) && !hasFullCrossUsersPermission(caller, userId)) { throw new SecurityException("Caller does not have permission to call this on user: " - + userId); + + affectedUser); } + Set<PolicyKey> keys = mDevicePolicyEngine.getLocalPolicyKeysSetByAllAdmins( + PolicyDefinition.GENERIC_ACCOUNT_MANAGEMENT_DISABLED, + affectedUser); + + for (PolicyKey key : keys) { + if (!(key instanceof AccountTypePolicyKey)) { + throw new IllegalStateException("PolicyKey for " + + "MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT is not of type " + + "AccountTypePolicyKey"); + } + AccountTypePolicyKey parsedKey = + (AccountTypePolicyKey) key; + String accountType = Objects.requireNonNull(parsedKey.getAccountType()); + + Boolean disabled = mDevicePolicyEngine.getResolvedPolicy( + PolicyDefinition.ACCOUNT_MANAGEMENT_DISABLED(accountType), + affectedUser); + if (disabled != null && disabled) { + resultSet.add(accountType); + } + } + } else { caller = getCallerIdentity(); Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId)); - } - - synchronized (getLockObject()) { - final ArraySet<String> resultSet = new ArraySet<>(); - if (!parent) { - final DevicePolicyData policy = getUserData(userId); - for (ActiveAdmin admin : policy.mAdminList) { - resultSet.addAll(admin.accountTypesWithManagementDisabled); + synchronized (getLockObject()) { + if (!parent) { + final DevicePolicyData policy = getUserData(userId); + for (ActiveAdmin admin : policy.mAdminList) { + resultSet.addAll(admin.accountTypesWithManagementDisabled); + } } - } - // Check if there's a profile owner of an org-owned device and the method is called for - // the parent user of this profile owner. - final ActiveAdmin orgOwnedAdmin = - getProfileOwnerOfOrganizationOwnedDeviceLocked(userId); - final boolean shouldGetParentAccounts = orgOwnedAdmin != null && (parent - || UserHandle.getUserId(orgOwnedAdmin.getUid()) != userId); - if (shouldGetParentAccounts) { - resultSet.addAll( - orgOwnedAdmin.getParentActiveAdmin().accountTypesWithManagementDisabled); + // Check if there's a profile owner of an org-owned device and the method is called + // for the parent user of this profile owner. + final ActiveAdmin orgOwnedAdmin = + getProfileOwnerOfOrganizationOwnedDeviceLocked(userId); + final boolean shouldGetParentAccounts = orgOwnedAdmin != null && (parent + || UserHandle.getUserId(orgOwnedAdmin.getUid()) != userId); + if (shouldGetParentAccounts) { + resultSet.addAll( + orgOwnedAdmin.getParentActiveAdmin() + .accountTypesWithManagementDisabled); + } } - return resultSet.toArray(new String[resultSet.size()]); } + return resultSet.toArray(new String[resultSet.size()]); } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java index 8c2468af1146..638596b5cc20 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java @@ -18,6 +18,7 @@ package com.android.server.devicepolicy; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.admin.AccountTypePolicyKey; import android.app.admin.BooleanPolicyValue; import android.app.admin.DevicePolicyIdentifiers; import android.app.admin.DevicePolicyManager; @@ -281,6 +282,32 @@ final class PolicyDefinition<V> { DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY, packageName)); } + // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the + // actual policy with the correct arguments (i.e. packageName) when reading the policies from + // xml. + static PolicyDefinition<Boolean> GENERIC_ACCOUNT_MANAGEMENT_DISABLED = + new PolicyDefinition<>( + new AccountTypePolicyKey( + DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY), + TRUE_MORE_RESTRICTIVE, + POLICY_FLAG_LOCAL_ONLY_POLICY, + // Nothing is enforced, we just need to store it + (Boolean value, Context context, Integer userId, PolicyKey policyKey) -> true, + new BooleanPolicySerializer()); + + /** + * Passing in {@code null} for {@code accountType} will return + * {@link #GENERIC_ACCOUNT_MANAGEMENT_DISABLED}. + */ + static PolicyDefinition<Boolean> ACCOUNT_MANAGEMENT_DISABLED(String accountType) { + if (accountType == null) { + return GENERIC_ACCOUNT_MANAGEMENT_DISABLED; + } + return GENERIC_ACCOUNT_MANAGEMENT_DISABLED.createPolicyDefinition( + new AccountTypePolicyKey( + DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, accountType)); + } + private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>(); private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>(); @@ -304,6 +331,8 @@ final class PolicyDefinition<V> { KEYGUARD_DISABLED_FEATURES); POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY, GENERIC_APPLICATION_HIDDEN); + POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, + GENERIC_ACCOUNT_MANAGEMENT_DISABLED); // User Restriction Policies USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0); |