1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.devicepolicy;
18 
19 import static com.android.server.devicepolicy.DevicePolicyEngine.DEVICE_LOCK_CONTROLLER_ROLE;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.app.admin.AccountTypePolicyKey;
24 import android.app.admin.BooleanPolicyValue;
25 import android.app.admin.DevicePolicyIdentifiers;
26 import android.app.admin.DevicePolicyManager;
27 import android.app.admin.IntegerPolicyValue;
28 import android.app.admin.IntentFilterPolicyKey;
29 import android.app.admin.LockTaskPolicy;
30 import android.app.admin.NoArgsPolicyKey;
31 import android.app.admin.PackagePermissionPolicyKey;
32 import android.app.admin.PackagePolicyKey;
33 import android.app.admin.PolicyKey;
34 import android.app.admin.PolicyValue;
35 import android.app.admin.UserRestrictionPolicyKey;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.IntentFilter;
39 import android.os.Bundle;
40 import android.os.UserManager;
41 
42 import com.android.internal.util.function.QuadFunction;
43 import com.android.modules.utils.TypedXmlPullParser;
44 import com.android.modules.utils.TypedXmlSerializer;
45 import com.android.server.utils.Slogf;
46 
47 import org.xmlpull.v1.XmlPullParserException;
48 
49 import java.io.IOException;
50 import java.util.HashMap;
51 import java.util.LinkedHashMap;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Set;
55 
56 final class PolicyDefinition<V> {
57 
58     static final String TAG = "PolicyDefinition";
59 
60     private static final int POLICY_FLAG_NONE = 0;
61 
62     // Only use this flag if a policy can not be applied locally.
63     private static final int POLICY_FLAG_GLOBAL_ONLY_POLICY = 1;
64 
65     // Only use this flag if a policy can not be applied globally.
66     private static final int POLICY_FLAG_LOCAL_ONLY_POLICY = 1 << 1;
67 
68     // Only use this flag if a policy is inheritable by child profile from parent.
69     private static final int POLICY_FLAG_INHERITABLE = 1 << 2;
70 
71     // Use this flag if admin policies should be treated independently of each other and should not
72     // have any resolution logic applied, this should only be used for very limited policies were
73     // this would make sense and the enforcing logic should handle it appropriately, e.g.
74     // application restrictions set by different admins for a single package should not be merged,
75     // but saved and queried independent of each other.
76     // Currently, support is  added for local only policies, if you need to add a non coexistable
77     // global policy please add support.
78     private static final int POLICY_FLAG_NON_COEXISTABLE_POLICY = 1 << 3;
79 
80     // Add this flag to any policy that is a user restriction, the reason for this is that there
81     // are some special APIs to handle user restriction policies and this is the way we can identify
82     // them.
83     private static final int POLICY_FLAG_USER_RESTRICTION_POLICY = 1 << 4;
84 
85     private static final MostRestrictive<Boolean> FALSE_MORE_RESTRICTIVE = new MostRestrictive<>(
86             List.of(new BooleanPolicyValue(false), new BooleanPolicyValue(true)));
87 
88     private static final MostRestrictive<Boolean> TRUE_MORE_RESTRICTIVE = new MostRestrictive<>(
89             List.of(new BooleanPolicyValue(true), new BooleanPolicyValue(false)));
90 
91     static PolicyDefinition<Boolean> AUTO_TIMEZONE = new PolicyDefinition<>(
92             new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY),
93             // auto timezone is disabled by default, hence enabling it is more restrictive.
94             TRUE_MORE_RESTRICTIVE,
95             POLICY_FLAG_GLOBAL_ONLY_POLICY,
96             (Boolean value, Context context, Integer userId, PolicyKey policyKey) ->
97                     PolicyEnforcerCallbacks.setAutoTimezoneEnabled(value, context),
98             new BooleanPolicySerializer());
99 
100     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
101     // actual policy with the correct arguments (packageName and permission name)
102     // when reading the policies from xml.
103     static final PolicyDefinition<Integer> GENERIC_PERMISSION_GRANT =
104             new PolicyDefinition<>(
105                     new PackagePermissionPolicyKey(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY),
106                     // TODO: is this really the best mechanism, what makes denied more
107                     //  restrictive than
108                     //  granted?
109                     new MostRestrictive<>(
110                             List.of(
111                                     new IntegerPolicyValue(
112                                             DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED),
113                                     new IntegerPolicyValue(
114                                             DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED),
115                                     new IntegerPolicyValue(
116                                             DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT))),
117                     POLICY_FLAG_LOCAL_ONLY_POLICY,
118                     PolicyEnforcerCallbacks::setPermissionGrantState,
119                     new IntegerPolicySerializer());
120 
121     /**
122      * Passing in {@code null} for {@code packageName} or {@code permissionName} will return a
123      * {@link #GENERIC_PERMISSION_GRANT}.
124      */
PERMISSION_GRANT( @onNull String packageName, @NonNull String permissionName)125     static PolicyDefinition<Integer> PERMISSION_GRANT(
126             @NonNull String packageName, @NonNull String permissionName) {
127         if (packageName == null || permissionName == null) {
128             return GENERIC_PERMISSION_GRANT;
129         }
130         return GENERIC_PERMISSION_GRANT.createPolicyDefinition(
131                 new PackagePermissionPolicyKey(
132                         DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
133                         packageName,
134                         permissionName));
135     }
136 
137     static PolicyDefinition<LockTaskPolicy> LOCK_TASK = new PolicyDefinition<>(
138             new NoArgsPolicyKey(DevicePolicyIdentifiers.LOCK_TASK_POLICY),
139             new TopPriority<>(List.of(
140                     EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
141                     EnforcingAdmin.DPC_AUTHORITY)),
142             POLICY_FLAG_LOCAL_ONLY_POLICY,
143             (LockTaskPolicy value, Context context, Integer userId, PolicyKey policyKey) ->
144                     PolicyEnforcerCallbacks.setLockTask(value, context, userId),
145             new LockTaskPolicySerializer());
146 
147     static PolicyDefinition<Set<String>> USER_CONTROLLED_DISABLED_PACKAGES =
148             new PolicyDefinition<>(
149                     new NoArgsPolicyKey(
150                             DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY),
151                     new StringSetUnion(),
152                     (Set<String> value, Context context, Integer userId, PolicyKey policyKey) ->
153                             PolicyEnforcerCallbacks.setUserControlDisabledPackages(value, userId),
154                     new StringSetPolicySerializer());
155 
156     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
157     // actual policy with the correct arguments (i.e. packageName) when reading the policies from
158     // xml.
159     static PolicyDefinition<ComponentName> GENERIC_PERSISTENT_PREFERRED_ACTIVITY =
160             new PolicyDefinition<>(
161                     new IntentFilterPolicyKey(
162                             DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY),
163             new TopPriority<>(List.of(
164                     EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE),
165                     EnforcingAdmin.DPC_AUTHORITY)),
166             POLICY_FLAG_LOCAL_ONLY_POLICY,
167             PolicyEnforcerCallbacks::addPersistentPreferredActivity,
168             new ComponentNamePolicySerializer());
169 
170     /**
171      * Passing in {@code null} for {@code intentFilter} will return
172      * {@link #GENERIC_PERSISTENT_PREFERRED_ACTIVITY}.
173      */
PERSISTENT_PREFERRED_ACTIVITY( IntentFilter intentFilter)174     static PolicyDefinition<ComponentName> PERSISTENT_PREFERRED_ACTIVITY(
175             IntentFilter intentFilter) {
176         if (intentFilter == null) {
177             return GENERIC_PERSISTENT_PREFERRED_ACTIVITY;
178         }
179         return GENERIC_PERSISTENT_PREFERRED_ACTIVITY.createPolicyDefinition(
180                 new IntentFilterPolicyKey(
181                         DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
182                         intentFilter));
183     }
184 
185     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
186     // actual policy with the correct arguments (i.e. packageName) when reading the policies from
187     // xml.
188     static PolicyDefinition<Boolean> GENERIC_PACKAGE_UNINSTALL_BLOCKED =
189             new PolicyDefinition<>(
190                     new PackagePolicyKey(
191                             DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY),
192                     TRUE_MORE_RESTRICTIVE,
193                     POLICY_FLAG_LOCAL_ONLY_POLICY,
194                     PolicyEnforcerCallbacks::setUninstallBlocked,
195                     new BooleanPolicySerializer());
196 
197     /**
198      * Passing in {@code null} for {@code packageName} will return
199      * {@link #GENERIC_PACKAGE_UNINSTALL_BLOCKED}.
200      */
PACKAGE_UNINSTALL_BLOCKED( String packageName)201     static PolicyDefinition<Boolean> PACKAGE_UNINSTALL_BLOCKED(
202             String packageName) {
203         if (packageName == null) {
204             return GENERIC_PACKAGE_UNINSTALL_BLOCKED;
205         }
206         return GENERIC_PACKAGE_UNINSTALL_BLOCKED.createPolicyDefinition(
207                 new PackagePolicyKey(
208                         DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY, packageName));
209     }
210 
211     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
212     // actual policy with the correct arguments (i.e. packageName) when reading the policies from
213     // xml.
214     static PolicyDefinition<Bundle> GENERIC_APPLICATION_RESTRICTIONS =
215             new PolicyDefinition<>(
216                     new PackagePolicyKey(
217                             DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY),
218                     // Don't need to take in a resolution mechanism since its never used, but might
219                     // need some refactoring to not always assume a non-null mechanism.
220                     new MostRecent<>(),
221                     POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
222                     // Application restrictions are now stored and retrieved from DPMS, so no
223                     // enforcing is required, however DPMS calls into UM to set restrictions for
224                     // backwards compatibility.
225                     (Bundle value, Context context, Integer userId, PolicyKey policyKey) -> true,
226                     new BundlePolicySerializer());
227 
228     /**
229      * Passing in {@code null} for {@code packageName} will return
230      * {@link #GENERIC_APPLICATION_RESTRICTIONS}.
231      */
APPLICATION_RESTRICTIONS(String packageName)232     static PolicyDefinition<Bundle> APPLICATION_RESTRICTIONS(String packageName) {
233         if (packageName == null) {
234             return GENERIC_APPLICATION_RESTRICTIONS;
235         }
236         return GENERIC_APPLICATION_RESTRICTIONS.createPolicyDefinition(
237                 new PackagePolicyKey(
238                         DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY, packageName));
239     }
240 
241     static PolicyDefinition<Long> RESET_PASSWORD_TOKEN = new PolicyDefinition<>(
242             new NoArgsPolicyKey(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY),
243             // Don't need to take in a resolution mechanism since its never used, but might
244             // need some refactoring to not always assume a non-null mechanism.
245             new MostRecent<>(),
246             POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_NON_COEXISTABLE_POLICY,
247             // DevicePolicyManagerService handles the enforcement, this just takes care of storage
248             (Long value, Context context, Integer userId, PolicyKey policyKey) -> true,
249             new LongPolicySerializer());
250 
251     static PolicyDefinition<Integer> KEYGUARD_DISABLED_FEATURES = new PolicyDefinition<>(
252             new NoArgsPolicyKey(DevicePolicyIdentifiers.KEYGUARD_DISABLED_FEATURES_POLICY),
253             new FlagUnion(),
254             POLICY_FLAG_LOCAL_ONLY_POLICY,
255             // Nothing is enforced for keyguard features, we just need to store it
256             (Integer value, Context context, Integer userId, PolicyKey policyKey) -> true,
257             new IntegerPolicySerializer());
258 
259     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
260     // actual policy with the correct arguments (i.e. packageName) when reading the policies from
261     // xml.
262     static PolicyDefinition<Boolean> GENERIC_APPLICATION_HIDDEN =
263             new PolicyDefinition<>(
264                     new PackagePolicyKey(
265                             DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY),
266                     // TODO(b/276713779): Don't need to take in a resolution mechanism since its
267                     //  never used, but might need some refactoring to not always assume a non-null
268                     //  mechanism.
269                     TRUE_MORE_RESTRICTIVE,
270                     POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
271                     PolicyEnforcerCallbacks::setApplicationHidden,
272                     new BooleanPolicySerializer());
273 
274     /**
275      * Passing in {@code null} for {@code packageName} will return
276      * {@link #GENERIC_APPLICATION_HIDDEN}.
277      */
APPLICATION_HIDDEN(String packageName)278     static PolicyDefinition<Boolean> APPLICATION_HIDDEN(String packageName) {
279         if (packageName == null) {
280             return GENERIC_APPLICATION_HIDDEN;
281         }
282         return GENERIC_APPLICATION_HIDDEN.createPolicyDefinition(
283                 new PackagePolicyKey(
284                         DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY, packageName));
285     }
286 
287     // This is saved in the static map sPolicyDefinitions so that we're able to reconstruct the
288     // actual policy with the correct arguments (i.e. packageName) when reading the policies from
289     // xml.
290     static PolicyDefinition<Boolean> GENERIC_ACCOUNT_MANAGEMENT_DISABLED =
291             new PolicyDefinition<>(
292                     new AccountTypePolicyKey(
293                             DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY),
294                     TRUE_MORE_RESTRICTIVE,
295                     POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
296                     // Nothing is enforced, we just need to store it
297                     (Boolean value, Context context, Integer userId, PolicyKey policyKey) -> true,
298                     new BooleanPolicySerializer());
299 
300     /**
301      * Passing in {@code null} for {@code accountType} will return
302      * {@link #GENERIC_ACCOUNT_MANAGEMENT_DISABLED}.
303      */
ACCOUNT_MANAGEMENT_DISABLED(String accountType)304     static PolicyDefinition<Boolean> ACCOUNT_MANAGEMENT_DISABLED(String accountType) {
305         if (accountType == null) {
306             return GENERIC_ACCOUNT_MANAGEMENT_DISABLED;
307         }
308         return GENERIC_ACCOUNT_MANAGEMENT_DISABLED.createPolicyDefinition(
309                 new AccountTypePolicyKey(
310                         DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, accountType));
311     }
312 
313     static PolicyDefinition<Set<String>> PERMITTED_INPUT_METHODS = new PolicyDefinition<>(
314             new NoArgsPolicyKey(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY),
315             new MostRecent<>(),
316             POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
317             (Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true,
318             new StringSetPolicySerializer());
319 
320 
321     static PolicyDefinition<Boolean> SCREEN_CAPTURE_DISABLED = new PolicyDefinition<>(
322             new NoArgsPolicyKey(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY),
323             TRUE_MORE_RESTRICTIVE,
324             POLICY_FLAG_INHERITABLE,
325             PolicyEnforcerCallbacks::setScreenCaptureDisabled,
326             new BooleanPolicySerializer());
327 
328     static PolicyDefinition<Boolean> PERSONAL_APPS_SUSPENDED = new PolicyDefinition<>(
329             new NoArgsPolicyKey(DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY),
330             new MostRecent<>(),
331             POLICY_FLAG_LOCAL_ONLY_POLICY | POLICY_FLAG_INHERITABLE,
332             PolicyEnforcerCallbacks::setPersonalAppsSuspended,
333             new BooleanPolicySerializer());
334 
335 
336     private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
337     private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
338 
339     // TODO(b/277218360): Revisit policies that should be marked as global-only.
340     static {
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE)341         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY, AUTO_TIMEZONE);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY, GENERIC_PERMISSION_GRANT)342         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMISSION_GRANT_POLICY,
343                 GENERIC_PERMISSION_GRANT);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK)344         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.LOCK_TASK_POLICY, LOCK_TASK);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY, USER_CONTROLLED_DISABLED_PACKAGES)345         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY,
346                 USER_CONTROLLED_DISABLED_PACKAGES);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY, GENERIC_PERSISTENT_PREFERRED_ACTIVITY)347         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSISTENT_PREFERRED_ACTIVITY_POLICY,
348                 GENERIC_PERSISTENT_PREFERRED_ACTIVITY);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY, GENERIC_PACKAGE_UNINSTALL_BLOCKED)349         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PACKAGE_UNINSTALL_BLOCKED_POLICY,
350                 GENERIC_PACKAGE_UNINSTALL_BLOCKED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY, GENERIC_APPLICATION_RESTRICTIONS)351         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_RESTRICTIONS_POLICY,
352                 GENERIC_APPLICATION_RESTRICTIONS);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY, RESET_PASSWORD_TOKEN)353         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.RESET_PASSWORD_TOKEN_POLICY,
354                 RESET_PASSWORD_TOKEN);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.KEYGUARD_DISABLED_FEATURES_POLICY, KEYGUARD_DISABLED_FEATURES)355         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.KEYGUARD_DISABLED_FEATURES_POLICY,
356                 KEYGUARD_DISABLED_FEATURES);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY, GENERIC_APPLICATION_HIDDEN)357         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.APPLICATION_HIDDEN_POLICY,
358                 GENERIC_APPLICATION_HIDDEN);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, GENERIC_ACCOUNT_MANAGEMENT_DISABLED)359         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY,
360                 GENERIC_ACCOUNT_MANAGEMENT_DISABLED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY, PERMITTED_INPUT_METHODS)361         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY,
362                 PERMITTED_INPUT_METHODS);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY, SCREEN_CAPTURE_DISABLED)363         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY,
364                 SCREEN_CAPTURE_DISABLED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY, PERSONAL_APPS_SUSPENDED)365         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERSONAL_APPS_SUSPENDED_POLICY,
366                 PERSONAL_APPS_SUSPENDED);
367 
368         // User Restriction Policies
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, 0)369         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_WIFI, 0)370         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_WIFI, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_CHANGE_WIFI_STATE, POLICY_FLAG_GLOBAL_ONLY_POLICY)371         USER_RESTRICTION_FLAGS.put(
372                 UserManager.DISALLOW_CHANGE_WIFI_STATE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_WIFI_TETHERING, POLICY_FLAG_GLOBAL_ONLY_POLICY)373         USER_RESTRICTION_FLAGS.put(
374                 UserManager.DISALLOW_WIFI_TETHERING, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_GRANT_ADMIN, 0)375         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_GRANT_ADMIN, /* flags= */ 0);
376         // TODO: set as global only once we get rid of the mapping
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, 0)377         USER_RESTRICTION_FLAGS.put(
378                 UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_WIFI_DIRECT, POLICY_FLAG_GLOBAL_ONLY_POLICY)379         USER_RESTRICTION_FLAGS.put(
380                 UserManager.DISALLOW_WIFI_DIRECT, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_ADD_WIFI_CONFIG, POLICY_FLAG_GLOBAL_ONLY_POLICY)381         USER_RESTRICTION_FLAGS.put(
382                 UserManager.DISALLOW_ADD_WIFI_CONFIG, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCALE, 0)383         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCALE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_APPS, 0)384         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_APPS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNINSTALL_APPS, 0)385         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNINSTALL_APPS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_LOCATION, 0)386         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_LOCATION, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_AIRPLANE_MODE, POLICY_FLAG_GLOBAL_ONLY_POLICY)387         USER_RESTRICTION_FLAGS.put(
388                 UserManager.DISALLOW_AIRPLANE_MODE, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BRIGHTNESS, 0)389         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BRIGHTNESS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AMBIENT_DISPLAY, 0)390         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AMBIENT_DISPLAY, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, 0)391         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, 0)392         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)393         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,
394                 POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BLUETOOTH, 0)395         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_BLUETOOTH, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH, 0)396         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH_SHARING, 0)397         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BLUETOOTH_SHARING, /* flags= */ 0);
398         // This effectively always applies globally, but it can be set on the profile
399         // parent, check the javadocs on the restriction for more info.
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_USB_FILE_TRANSFER, 0)400         USER_RESTRICTION_FLAGS.put(
401                 UserManager.DISALLOW_USB_FILE_TRANSFER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CREDENTIALS, 0)402         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CREDENTIALS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_USER, 0)403         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_USER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, 0)404         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DEBUGGING_FEATURES, 0)405         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DEBUGGING_FEATURES, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_VPN, 0)406         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_VPN, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCATION, 0)407         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_LOCATION, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DATE_TIME, 0)408         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DATE_TIME, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_CONFIG_TETHERING, 0)409         USER_RESTRICTION_FLAGS.put(
410                 UserManager.DISALLOW_CONFIG_TETHERING, /* flags= */ 0);
411         // This effectively always applies globally, but it can be set on the profile
412         // parent, check the javadocs on the restriction for more info.
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_NETWORK_RESET, 0)413         USER_RESTRICTION_FLAGS.put(
414                 UserManager.DISALLOW_NETWORK_RESET, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FACTORY_RESET, 0)415         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FACTORY_RESET, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, 0)416         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, 0)417         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, 0)418         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY)419         USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, 0)420         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, 0)421         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_APPS_CONTROL, 0)422         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_APPS_CONTROL, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, 0)423         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_MICROPHONE, 0)424         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_MICROPHONE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADJUST_VOLUME, 0)425         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADJUST_VOLUME, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_CALLS, 0)426         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_CALLS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SMS, 0)427         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SMS, /* flags= */ 0);
428         // TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FUN, 0)429         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_FUN, /* flags= */ 0);
430         // TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CREATE_WINDOWS, 0)431         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CREATE_WINDOWS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, 0)432         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, 0)433         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, /* flags= */ 0);
434         // TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_BEAM, 0)435         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OUTGOING_BEAM, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_WALLPAPER, 0)436         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_WALLPAPER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_WALLPAPER, 0)437         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_WALLPAPER, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SAFE_BOOT, 0)438         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SAFE_BOOT, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RECORD_AUDIO, 0)439         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RECORD_AUDIO, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RUN_IN_BACKGROUND, 0)440         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_RUN_IN_BACKGROUND, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA, 0)441         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_DEVICE, 0)442         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNMUTE_DEVICE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DATA_ROAMING, 0)443         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_DATA_ROAMING, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_USER_ICON, 0)444         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SET_USER_ICON, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, 0)445         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_OEM_UNLOCK, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNIFIED_PASSWORD, 0)446         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_UNIFIED_PASSWORD, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, 0)447         USER_RESTRICTION_FLAGS.put(UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AUTOFILL, 0)448         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_AUTOFILL, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_CAPTURE, 0)449         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_CAPTURE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_SUGGESTIONS, 0)450         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONTENT_SUGGESTIONS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_USER_SWITCH, POLICY_FLAG_GLOBAL_ONLY_POLICY)451         USER_RESTRICTION_FLAGS.put(
452                 UserManager.DISALLOW_USER_SWITCH, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, 0)453         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_PRINTING, 0)454         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_PRINTING, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_CONFIG_PRIVATE_DNS, POLICY_FLAG_GLOBAL_ONLY_POLICY)455         USER_RESTRICTION_FLAGS.put(
456                 UserManager.DISALLOW_CONFIG_PRIVATE_DNS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MICROPHONE_TOGGLE, 0)457         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MICROPHONE_TOGGLE, /* flags= */ 0);
458         // TODO: According the UserRestrictionsUtils, this is global only, need to confirm.
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA_TOGGLE, 0)459         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CAMERA_TOGGLE, /* flags= */ 0);
460         // TODO: check if its global only
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BIOMETRIC, 0)461         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_BIOMETRIC, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, 0)462         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_DEFAULT_APPS, /* flags= */ 0);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_CELLULAR_2G, POLICY_FLAG_GLOBAL_ONLY_POLICY)463         USER_RESTRICTION_FLAGS.put(
464                 UserManager.DISALLOW_CELLULAR_2G, POLICY_FLAG_GLOBAL_ONLY_POLICY);
USER_RESTRICTION_FLAGS.put( UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, POLICY_FLAG_GLOBAL_ONLY_POLICY)465         USER_RESTRICTION_FLAGS.put(
466                 UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, POLICY_FLAG_GLOBAL_ONLY_POLICY);
467 
468         for (String key : USER_RESTRICTION_FLAGS.keySet()) {
createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key))469             createAndAddUserRestrictionPolicyDefinition(key, USER_RESTRICTION_FLAGS.get(key));
470         }
471     }
472 
473     private final PolicyKey mPolicyKey;
474     private final ResolutionMechanism<V> mResolutionMechanism;
475     private final int mPolicyFlags;
476     // A function that accepts  policy to apple, context, userId, callback arguments, and returns
477     // true if the policy has been enforced successfully.
478     private final QuadFunction<V, Context, Integer, PolicyKey, Boolean> mPolicyEnforcerCallback;
479     private final PolicySerializer<V> mPolicySerializer;
480 
createPolicyDefinition(PolicyKey key)481     private PolicyDefinition<V> createPolicyDefinition(PolicyKey key) {
482         return new PolicyDefinition<>(key, mResolutionMechanism, mPolicyFlags,
483                 mPolicyEnforcerCallback, mPolicySerializer);
484     }
485 
getPolicyDefinitionForUserRestriction( @serManager.UserRestrictionKey String restriction)486     static PolicyDefinition<Boolean> getPolicyDefinitionForUserRestriction(
487             @UserManager.UserRestrictionKey String restriction) {
488         String key = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
489 
490         if (!POLICY_DEFINITIONS.containsKey(key)) {
491             throw new IllegalArgumentException("Unsupported user restriction " + restriction);
492         }
493         // All user restrictions are of type boolean
494         return (PolicyDefinition<Boolean>) POLICY_DEFINITIONS.get(key);
495     }
496 
497     @NonNull
getPolicyKey()498     PolicyKey getPolicyKey() {
499         return mPolicyKey;
500     }
501 
502     @NonNull
getResolutionMechanism()503     ResolutionMechanism<V> getResolutionMechanism() {
504         return mResolutionMechanism;
505     }
506     /**
507      * Returns {@code true} if the policy is a global policy by nature and can't be applied locally.
508      */
isGlobalOnlyPolicy()509     boolean isGlobalOnlyPolicy() {
510         return (mPolicyFlags & POLICY_FLAG_GLOBAL_ONLY_POLICY) != 0;
511     }
512 
513     /**
514      * Returns {@code true} if the policy is a local policy by nature and can't be applied globally.
515      */
isLocalOnlyPolicy()516     boolean isLocalOnlyPolicy() {
517         return (mPolicyFlags & POLICY_FLAG_LOCAL_ONLY_POLICY) != 0;
518     }
519 
520     /**
521      * Returns {@code true} if the policy is inheritable by child profiles.
522      */
isInheritable()523     boolean isInheritable() {
524         return (mPolicyFlags & POLICY_FLAG_INHERITABLE) != 0;
525     }
526 
527     /**
528      * Returns {@code true} if the policy engine should not try to resolve policies set by different
529      * admins and should just store it and pass it on to the enforcing logic.
530      */
isNonCoexistablePolicy()531     boolean isNonCoexistablePolicy() {
532         return (mPolicyFlags & POLICY_FLAG_NON_COEXISTABLE_POLICY) != 0;
533     }
534 
isUserRestrictionPolicy()535     boolean isUserRestrictionPolicy() {
536         return (mPolicyFlags & POLICY_FLAG_USER_RESTRICTION_POLICY) != 0;
537     }
538 
539     @Nullable
resolvePolicy(LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminsPolicy)540     PolicyValue<V> resolvePolicy(LinkedHashMap<EnforcingAdmin, PolicyValue<V>> adminsPolicy) {
541         return mResolutionMechanism.resolve(adminsPolicy);
542     }
543 
enforcePolicy(@ullable V value, Context context, int userId)544     boolean enforcePolicy(@Nullable V value, Context context, int userId) {
545         return mPolicyEnforcerCallback.apply(value, context, userId, mPolicyKey);
546     }
547 
createAndAddUserRestrictionPolicyDefinition( String restriction, int flags)548     private static void createAndAddUserRestrictionPolicyDefinition(
549             String restriction, int flags) {
550         String identifier = DevicePolicyIdentifiers.getIdentifierForUserRestriction(restriction);
551         UserRestrictionPolicyKey key = new UserRestrictionPolicyKey(identifier, restriction);
552         flags |= (POLICY_FLAG_USER_RESTRICTION_POLICY | POLICY_FLAG_INHERITABLE);
553         PolicyDefinition<Boolean> definition = new PolicyDefinition<>(
554                 key,
555                 TRUE_MORE_RESTRICTIVE,
556                 flags,
557                 PolicyEnforcerCallbacks::setUserRestriction,
558                 new BooleanPolicySerializer());
559         POLICY_DEFINITIONS.put(key.getIdentifier(), definition);
560     }
561 
562 
563     /**
564      * Callers must ensure that {@code policyType} have implemented an appropriate
565      * {@link Object#equals} implementation.
566      */
PolicyDefinition( PolicyKey key, ResolutionMechanism<V> resolutionMechanism, QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback, PolicySerializer<V> policySerializer)567     private PolicyDefinition(
568             PolicyKey key,
569             ResolutionMechanism<V> resolutionMechanism,
570             QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
571             PolicySerializer<V> policySerializer) {
572         this(key, resolutionMechanism, POLICY_FLAG_NONE, policyEnforcerCallback, policySerializer);
573     }
574 
575     /**
576      * Callers must ensure that custom {@code policyKeys} and {@code V} have an appropriate
577      * {@link Object#equals} and {@link Object#hashCode()} implementation.
578      */
PolicyDefinition( PolicyKey policyKey, ResolutionMechanism<V> resolutionMechanism, int policyFlags, QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback, PolicySerializer<V> policySerializer)579     private PolicyDefinition(
580             PolicyKey policyKey,
581             ResolutionMechanism<V> resolutionMechanism,
582             int policyFlags,
583             QuadFunction<V, Context, Integer, PolicyKey, Boolean> policyEnforcerCallback,
584             PolicySerializer<V> policySerializer) {
585         mPolicyKey = policyKey;
586         mResolutionMechanism = resolutionMechanism;
587         mPolicyFlags = policyFlags;
588         mPolicyEnforcerCallback = policyEnforcerCallback;
589         mPolicySerializer = policySerializer;
590 
591         if (isNonCoexistablePolicy() && !isLocalOnlyPolicy()) {
592             throw new UnsupportedOperationException("Non-coexistable global policies not supported,"
593                     + "please add support.");
594         }
595         // TODO: maybe use this instead of manually adding to the map
596 //        sPolicyDefinitions.put(policyDefinitionKey, this);
597     }
598 
saveToXml(TypedXmlSerializer serializer)599     void saveToXml(TypedXmlSerializer serializer) throws IOException {
600         mPolicyKey.saveToXml(serializer);
601     }
602 
603     @Nullable
readFromXml(TypedXmlPullParser parser)604     static <V> PolicyDefinition<V> readFromXml(TypedXmlPullParser parser)
605             throws XmlPullParserException, IOException {
606         // TODO: can we avoid casting?
607         PolicyKey policyKey = readPolicyKeyFromXml(parser);
608         if (policyKey == null) {
609             Slogf.wtf(TAG, "Error parsing PolicyDefinition, PolicyKey is null.");
610             return null;
611         }
612         PolicyDefinition<V> genericPolicyDefinition =
613                 (PolicyDefinition<V>) POLICY_DEFINITIONS.get(policyKey.getIdentifier());
614         if (genericPolicyDefinition == null) {
615             Slogf.wtf(TAG, "Unknown generic policy key: " + policyKey);
616             return null;
617         }
618         return genericPolicyDefinition.createPolicyDefinition(policyKey);
619     }
620 
621     @Nullable
readPolicyKeyFromXml(TypedXmlPullParser parser)622     static <V> PolicyKey readPolicyKeyFromXml(TypedXmlPullParser parser)
623             throws XmlPullParserException, IOException {
624         // TODO: can we avoid casting?
625         PolicyKey policyKey = PolicyKey.readGenericPolicyKeyFromXml(parser);
626         if (policyKey == null) {
627             Slogf.wtf(TAG, "Error parsing PolicyKey, GenericPolicyKey is null");
628             return null;
629         }
630         PolicyDefinition<PolicyValue<V>> genericPolicyDefinition =
631                 (PolicyDefinition<PolicyValue<V>>) POLICY_DEFINITIONS.get(
632                         policyKey.getIdentifier());
633         if (genericPolicyDefinition == null) {
634             Slogf.wtf(TAG, "Error parsing PolicyKey, Unknown generic policy key: " + policyKey);
635             return null;
636         }
637         return genericPolicyDefinition.mPolicyKey.readFromXml(parser);
638     }
639 
savePolicyValueToXml(TypedXmlSerializer serializer, V value)640     void savePolicyValueToXml(TypedXmlSerializer serializer, V value)
641             throws IOException {
642         mPolicySerializer.saveToXml(mPolicyKey, serializer, value);
643     }
644 
645     @Nullable
readPolicyValueFromXml(TypedXmlPullParser parser)646     PolicyValue<V> readPolicyValueFromXml(TypedXmlPullParser parser) {
647         return mPolicySerializer.readFromXml(parser);
648     }
649 
650     @Override
toString()651     public String toString() {
652         return "PolicyDefinition{ mPolicyKey= " + mPolicyKey + ", mResolutionMechanism= "
653                 + mResolutionMechanism + ", mPolicyFlags= " + mPolicyFlags + " }";
654     }
655 }
656