blob: 260264d0fb9cff4d7c3d0b1a0b7b1e2c64f6f095 [file] [log] [blame]
/*
* Copyright (C) 2022 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.devicepolicy;
import static com.android.server.devicepolicy.DevicePolicyEngine.DEVICE_LOCK_CONTROLLER_ROLE;
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;
import android.app.admin.IntegerPolicyValue;
import android.app.admin.IntentFilterPolicyKey;
import android.app.admin.LockTaskPolicy;
import android.app.admin.NoArgsPolicyKey;
import android.app.admin.PackagePermissionPolicyKey;
import android.app.admin.PackagePolicyKey;
import android.app.admin.PolicyKey;
import android.app.admin.PolicyValue;
import android.app.admin.UserRestrictionPolicyKey;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.UserManager;
import com.android.internal.util.function.QuadFunction;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.utils.Slogf;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
final class PolicyDefinition<V> {
static final String TAG = "PolicyDefinition";
private static final int POLICY_FLAG_NONE = 0;
// Only use this flag if a policy can not be applied locally.
private static final int POLICY_FLAG_GLOBAL_ONLY_POLICY = 1;
// Only use this flag if a policy can not be applied globally.
private static final int POLICY_FLAG_LOCAL_ONLY_POLICY = 1 << 1;
// Only use this flag if a policy is inheritable by child profile from parent.
private static final int POLICY_FLAG_INHERITABLE = 1 << 2;
// Use this flag if admin policies should be treated independently of each other and should not
// have any resolution logic applied, this should only be used for very limited policies were
// this would make sense and the enforcing logic should handle it appropriately, e.g.
// application restrictions set by different admins for a single package should not be merged,
// but saved and queried independent of each other.
// Currently, support is added for local only policies, if you need to add a non coexistable
// global policy please add support.
private static final int POLICY_FLAG_NON_COEXISTABLE_POLICY = 1 << 3;
// Add this flag to any policy that is a user restriction, the reason for this is that there
// are some special APIs to handle user restriction policies and this is the way we can identify
// them.
private static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
List.of(new BooleanPolicyValue(false), new BooleanPolicyValue(true)));
private static final MostRestrictive<Boolean> TRUE_MORE_RESTRICTIVE = new MostRestrictive<>(
List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY),
// auto timezone is disabled by default, hence enabling it is more restrictive.
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
(Boolean value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setAutoTimezoneEnabled(value, context),
new BooleanPolicySerializer());
// This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
// actual policy with the correct arguments (packageName and permission name)
// when reading the policies from xml.
static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
new PolicyDefinition<>(
new PackagePermissionPolicyKey(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY),
// TODO: is this really the best mechanism, what makes denied more
// restrictive than
// granted?
new MostRestrictive<>(
List.of(
new IntegerPolicyValue(
DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED),
new IntegerPolicyValue(
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED),
new IntegerPolicyValue(
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT))),
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::setPermissionGrantState,
new IntegerPolicySerializer());
/**
* Passing in {@code null} for {@code packageName} or {@code permissionName} will return a
* {@link #GENERIC_PERMISSION_GRANT}.
*/
static PolicyDefinition<Integer> PERMISSION_GRANT(
@NonNull String packageName, @NonNull String permissionName) {
if (packageName == null || permissionName == null) {
return GENERIC_PERMISSION_GRANT;
}
return GENERIC_PERMISSION_GRANT.createPolicyDefinition(
new PackagePermissionPolicyKey(
DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
packageName,
permissionName));
}
static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
new TopPriority<>(List.of(
EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
(LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setLockTask(value, context, userId),
new LockTaskPolicySerializer());
static PolicyDefinition<Set<String>> USER_CONTROLLED_DISABLED_PACKAGES =
new PolicyDefinition<>(
new NoArgsPolicyKey(
DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY),
new StringSetUnion(),
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setUserControlDisabledPackages(value, userId),
new StringSetPolicySerializer());
// 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<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
new PolicyDefinition<>(
new IntentFilterPolicyKey(
DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
new TopPriority<>(List.of(
EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
EnforcingAdmin.DPC_AUTHORITY)),
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::addPersistentPreferredActivity,
new ComponentNamePolicySerializer());
/**
* Passing in {@code null} for {@code intentFilter} will return
* {@link #GENERIC_PERSISTENT_PREFERRED_ACTIVITY}.
*/
static PolicyDefinition<ComponentName> PERSISTENT_PREFERRED_ACTIVITY(
IntentFilter intentFilter) {
if (intentFilter == null) {
return GENERIC_PERSISTENT_PREFERRED_ACTIVITY;
}
return GENERIC_PERSISTENT_PREFERRED_ACTIVITY.createPolicyDefinition(
new IntentFilterPolicyKey(
DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
intentFilter));
}
// 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_PACKAGE_UNINSTALL_BLOCKED =
new PolicyDefinition<>(
new PackagePolicyKey(
DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY),
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_LOCAL_ONLY_POLICY,
PolicyEnforcerCallbacks::setUninstallBlocked,
new BooleanPolicySerializer());
/**
* Passing in {@code null} for {@code packageName} will return
* {@link #GENERIC_PACKAGE_UNINSTALL_BLOCKED}.
*/
static PolicyDefinition<Boolean> PACKAGE_UNINSTALL_BLOCKED(
String packageName) {
if (packageName == null) {
return GENERIC_PACKAGE_UNINSTALL_BLOCKED;
}
return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
new PackagePolicyKey(
DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_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<Bundle> GENERIC_APPLICATION_RESTRICTIONS =
new PolicyDefinition<>(
new PackagePolicyKey(
DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY),
// Don't need to take in a resolution mechanism since its never used, but might
// need some refactoring to not always assume a non-null mechanism.
new MostRecent<>(),
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
// Application restrictions are now stored and retrieved from DPMS, so no
// enforcing is required, however DPMS calls into UM to set restrictions for
// backwards compatibility.
(Bundle value, Context context, Integer userId, PolicyKey policyKey) -> true,
new BundlePolicySerializer());
/**
* Passing in {@code null} for {@code packageName} will return
* {@link #GENERIC_APPLICATION_RESTRICTIONS}.
*/
static PolicyDefinition<Bundle> APPLICATION_RESTRICTIONS(String packageName) {
if (packageName == null) {
return GENERIC_APPLICATION_RESTRICTIONS;
}
return GENERIC_APPLICATION_RESTRICTIONS.createPolicyDefinition(
new PackagePolicyKey(
DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY, packageName));
}
static PolicyDefinition<Long> RESET_PASSWORD_TOKEN = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY),
// Don't need to take in a resolution mechanism since its never used, but might
// need some refactoring to not always assume a non-null mechanism.
new MostRecent<>(),
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
// DevicePolicyManagerService handles the enforcement, this just takes care of storage
(Long value, Context context, Integer userId, PolicyKey policyKey) -> true,
new LongPolicySerializer());
static PolicyDefinition<Integer> KEYGUARD_DISABLED_FEATURES = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.KEYGUARD_DISABLED_FEATURES_POLICY),
new FlagUnion(),
POLICY_FLAG_LOCAL_ONLY_POLICY,
// Nothing is enforced for keyguard features, we just need to store it
(Integer value, Context context, Integer userId, PolicyKey policyKey) -> true,
new IntegerPolicySerializer());
// 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_APPLICATION_HIDDEN =
new PolicyDefinition<>(
new PackagePolicyKey(
DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY),
// TODO(b/276713779): Don't need to take in a resolution mechanism since its
// never used, but might need some refactoring to not always assume a non-null
// mechanism.
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
PolicyEnforcerCallbacks::setApplicationHidden,
new BooleanPolicySerializer());
/**
* Passing in {@code null} for {@code packageName} will return
* {@link #GENERIC_APPLICATION_HIDDEN}.
*/
static PolicyDefinition<Boolean> APPLICATION_HIDDEN(String packageName) {
if (packageName == null) {
return GENERIC_APPLICATION_HIDDEN;
}
return GENERIC_APPLICATION_HIDDEN.createPolicyDefinition(
new PackagePolicyKey(
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 | POLICY_FLAG_INHERITABLE,
// 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));
}
static PolicyDefinition<Set<String>> PERMITTED_INPUT_METHODS = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY),
new MostRecent<>(),
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true,
new StringSetPolicySerializer());
static PolicyDefinition<Boolean> SCREEN_CAPTURE_DISABLED = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY),
TRUE_MORE_RESTRICTIVE,
POLICY_FLAG_INHERITABLE,
PolicyEnforcerCallbacks::setScreenCaptureDisabled,
new BooleanPolicySerializer());
static PolicyDefinition<Boolean> PERSONAL_APPS_SUSPENDED = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY),
new MostRecent<>(),
POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
PolicyEnforcerCallbacks::setPersonalAppsSuspended,
new BooleanPolicySerializer());
static PolicyDefinition<Boolean> USB_DATA_SIGNALING = new PolicyDefinition<>(
new NoArgsPolicyKey(DevicePolicyIdentifiers.USB_DATA_SIGNALING_POLICY),
// usb data signaling is enabled by default, hence disabling it is more restrictive.
FALSE_MORE_RESTRICTIVE,
POLICY_FLAG_GLOBAL_ONLY_POLICY,
(Boolean value, Context context, Integer userId, PolicyKey policyKey) ->
PolicyEnforcerCallbacks.setUsbDataSignalingEnabled(value, context),
new BooleanPolicySerializer());
private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
// TODO(b/277218360): Revisit policies that should be marked as global-only.
static {
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
GENERIC_PERMISSION_GRANT);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
USER_CONTROLLED_DISABLED_PACKAGES);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
GENERIC_PERSISTENT_PREFERRED_ACTIVITY);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
GENERIC_PACKAGE_UNINSTALL_BLOCKED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
GENERIC_APPLICATION_RESTRICTIONS);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
RESET_PASSWORD_TOKEN);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.KEYGUARD_DISABLED_FEATURES_POLICY,
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);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY,
PERMITTED_INPUT_METHODS);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY,
SCREEN_CAPTURE_DISABLED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY,
PERSONAL_APPS_SUSPENDED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USB_DATA_SIGNALING_POLICY,
USB_DATA_SIGNALING);
// User Restriction Policies
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_WIFI, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_CHANGE_WIFI_STATE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_WIFI_TETHERING, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_GRANT_ADMIN, /* flags= */ 0);
// TODO: set as global only once we get rid of the mapping
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_WIFI_DIRECT, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_ADD_WIFI_CONFIG, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCALE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_APPS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNINSTALL_APPS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_LOCATION, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_AIRPLANE_MODE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BRIGHTNESS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AMBIENT_DISPLAY, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BLUETOOTH, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH_SHARING, /* flags= */ 0);
// This effectively always applies globally, but it can be set on the profile
// parent, check the javadocs on the restriction for more info.
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_USB_FILE_TRANSFER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CREDENTIALS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_USER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DEBUGGING_FEATURES, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_VPN, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCATION, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DATE_TIME, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_CONFIG_TETHERING, /* flags= */ 0);
// This effectively always applies globally, but it can be set on the profile
// parent, check the javadocs on the restriction for more info.
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_NETWORK_RESET, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FACTORY_RESET, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_APPS_CONTROL, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_MICROPHONE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADJUST_VOLUME, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_CALLS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SMS, /* flags= */ 0);
// TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FUN, /* flags= */ 0);
// TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CREATE_WINDOWS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, /* flags= */ 0);
// TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_BEAM, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_WALLPAPER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_WALLPAPER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SAFE_BOOT, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RECORD_AUDIO, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RUN_IN_BACKGROUND, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_DEVICE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DATA_ROAMING, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_USER_ICON, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNIFIED_PASSWORD, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AUTOFILL, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_CAPTURE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_SUGGESTIONS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_USER_SWITCH, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_PRINTING, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_CONFIG_PRIVATE_DNS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MICROPHONE_TOGGLE, /* flags= */ 0);
// TODO: According the UserRestrictionsUtils, this is global only, need to confirm.
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA_TOGGLE, /* flags= */ 0);
// TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BIOMETRIC, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_CELLULAR_2G, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, POLICY_FLAG_GLOBAL_ONLY_POLICY);
if (com.android.net.thread.platform.flags.Flags.threadUserRestrictionEnabled()) {
USER_RESTRICTION_FLAGS.put(
UserManager.DISALLOW_THREAD_NETWORK, POLICY_FLAG_GLOBAL_ONLY_POLICY);
}
for (String key : USER_RESTRICTION_FLAGS.keySet()) {
createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key));
}
}
private final PolicyKey mPolicyKey;
private final ResolutionMechanism<V> mResolutionMechanism;
private final int mPolicyFlags;
// A function that accepts policy to apple, context, userId, callback arguments, and returns
// true if the policy has been enforced successfully.
private final QuadFunction<V, Context, Integer, PolicyKey, Boolean> mPolicyEnforcerCallback;
private final PolicySerializer<V> mPolicySerializer;
private PolicyDefinition<V> createPolicyDefinition(PolicyKey key) {
return new PolicyDefinition<>(key, mResolutionMechanism, mPolicyFlags,
mPolicyEnforcerCallback, mPolicySerializer);
}
static PolicyDefinition<Boolean> getPolicyDefinitionForUserRestriction(
@UserManager.UserRestrictionKey String restriction) {
String key = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
if (!POLICY_DEFINITIONS.containsKey(key)) {
throw new IllegalArgumentException("Unsupported user restriction " + restriction);
}
// All user restrictions are of type boolean
return (PolicyDefinition<Boolean>) POLICY_DEFINITIONS.get(key);
}
@NonNull
PolicyKey getPolicyKey() {
return mPolicyKey;
}
@NonNull
ResolutionMechanism<V> getResolutionMechanism() {
return mResolutionMechanism;
}
/**
* Returns {@code true} if the policy is a global policy by nature and can't be applied locally.
*/
boolean isGlobalOnlyPolicy() {
return (mPolicyFlags & POLICY_FLAG_GLOBAL_ONLY_POLICY) != 0;
}
/**
* Returns {@code true} if the policy is a local policy by nature and can't be applied globally.
*/
boolean isLocalOnlyPolicy() {
return (mPolicyFlags & POLICY_FLAG_LOCAL_ONLY_POLICY) != 0;
}
/**
* Returns {@code true} if the policy is inheritable by child profiles.
*/
boolean isInheritable() {
return (mPolicyFlags & POLICY_FLAG_INHERITABLE) != 0;
}
/**
* Returns {@code true} if the policy engine should not try to resolve policies set by different
* admins and should just store it and pass it on to the enforcing logic.
*/
boolean isNonCoexistablePolicy() {
return (mPolicyFlags & POLICY_FLAG_NON_COEXISTABLE_POLICY) != 0;
}
boolean isUserRestrictionPolicy() {
return (mPolicyFlags & POLICY_FLAG_USER_RESTRICTION_POLICY) != 0;
}
@Nullable
PolicyValue<V> resolvePolicy(LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminsPolicy) {
return mResolutionMechanism.resolve(adminsPolicy);
}
boolean enforcePolicy(@Nullable V value, Context context, int userId) {
return mPolicyEnforcerCallback.apply(value, context, userId, mPolicyKey);
}
private static void createAndAddUserRestrictionPolicyDefinition(
String restriction, int flags) {
String identifier = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
UserRestrictionPolicyKey key = new UserRestrictionPolicyKey(identifier, restriction);
flags |= (POLICY_FLAG_USER_RESTRICTION_POLICY | POLICY_FLAG_INHERITABLE);
PolicyDefinition<Boolean> definition = new PolicyDefinition<>(
key,
TRUE_MORE_RESTRICTIVE,
flags,
PolicyEnforcerCallbacks::setUserRestriction,
new BooleanPolicySerializer());
POLICY_DEFINITIONS.put(key.getIdentifier(), definition);
}
/**
* Callers must ensure that {@code policyType} have implemented an appropriate
* {@link Object#equals} implementation.
*/
private PolicyDefinition(
PolicyKey key,
ResolutionMechanism<V> resolutionMechanism,
QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
PolicySerializer<V> policySerializer) {
this(key, resolutionMechanism, POLICY_FLAG_NONE, policyEnforcerCallback, policySerializer);
}
/**
* Callers must ensure that custom {@code policyKeys} and {@code V} have an appropriate
* {@link Object#equals} and {@link Object#hashCode()} implementation.
*/
private PolicyDefinition(
PolicyKey policyKey,
ResolutionMechanism<V> resolutionMechanism,
int policyFlags,
QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
PolicySerializer<V> policySerializer) {
mPolicyKey = policyKey;
mResolutionMechanism = resolutionMechanism;
mPolicyFlags = policyFlags;
mPolicyEnforcerCallback = policyEnforcerCallback;
mPolicySerializer = policySerializer;
if (isNonCoexistablePolicy() && !isLocalOnlyPolicy()) {
throw new UnsupportedOperationException("Non-coexistable global policies not supported,"
+ "please add support.");
}
// TODO: maybe use this instead of manually adding to the map
// sPolicyDefinitions.put(policyDefinitionKey, this);
}
void saveToXml(TypedXmlSerializer serializer) throws IOException {
mPolicyKey.saveToXml(serializer);
}
@Nullable
static <V> PolicyDefinition<V> readFromXml(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
// TODO: can we avoid casting?
PolicyKey policyKey = readPolicyKeyFromXml(parser);
if (policyKey == null) {
Slogf.wtf(TAG, "Error parsing PolicyDefinition, PolicyKey is null.");
return null;
}
PolicyDefinition<V> genericPolicyDefinition =
(PolicyDefinition<V>) POLICY_DEFINITIONS.get(policyKey.getIdentifier());
if (genericPolicyDefinition == null) {
Slogf.wtf(TAG, "Unknown generic policy key: " + policyKey);
return null;
}
return genericPolicyDefinition.createPolicyDefinition(policyKey);
}
@Nullable
static <V> PolicyKey readPolicyKeyFromXml(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
// TODO: can we avoid casting?
PolicyKey policyKey = PolicyKey.readGenericPolicyKeyFromXml(parser);
if (policyKey == null) {
Slogf.wtf(TAG, "Error parsing PolicyKey, GenericPolicyKey is null");
return null;
}
PolicyDefinition<PolicyValue<V>> genericPolicyDefinition =
(PolicyDefinition<PolicyValue<V>>) POLICY_DEFINITIONS.get(
policyKey.getIdentifier());
if (genericPolicyDefinition == null) {
Slogf.wtf(TAG, "Error parsing PolicyKey, Unknown generic policy key: " + policyKey);
return null;
}
return genericPolicyDefinition.mPolicyKey.readFromXml(parser);
}
void savePolicyValueToXml(TypedXmlSerializer serializer, V value)
throws IOException {
mPolicySerializer.saveToXml(mPolicyKey, serializer, value);
}
@Nullable
PolicyValue<V> readPolicyValueFromXml(TypedXmlPullParser parser) {
return mPolicySerializer.readFromXml(parser);
}
@Override
public String toString() {
return "PolicyDefinition{ mPolicyKey= " + mPolicyKey + ", mResolutionMechanism= "
+ mResolutionMechanism + ", mPolicyFlags= " + mPolicyFlags + " }";
}
}