• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.app.admin.DevicePolicyIdentifiers.PACKAGES_SUSPENDED_POLICY;
20 import static android.app.admin.DevicePolicyIdentifiers.USER_CONTROL_DISABLED_PACKAGES_POLICY;
21 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_TARGET_USER_ID;
22 import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_UPDATE_RESULT_KEY;
23 import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_CONFLICTING_ADMIN_POLICY;
24 import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_HARDWARE_LIMITATION;
25 import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_STORAGE_LIMIT_REACHED;
26 import static android.app.admin.PolicyUpdateResult.RESULT_POLICY_CLEARED;
27 import static android.app.admin.PolicyUpdateResult.RESULT_POLICY_SET;
28 import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT;
29 
30 import android.Manifest;
31 import android.annotation.NonNull;
32 import android.annotation.Nullable;
33 import android.app.AppGlobals;
34 import android.app.BroadcastOptions;
35 import android.app.admin.BooleanPolicyValue;
36 import android.app.admin.DevicePolicyIdentifiers;
37 import android.app.admin.DevicePolicyManager;
38 import android.app.admin.DevicePolicyState;
39 import android.app.admin.IntentFilterPolicyKey;
40 import android.app.admin.PolicyKey;
41 import android.app.admin.PolicyUpdateReceiver;
42 import android.app.admin.PolicyValue;
43 import android.app.admin.TargetUser;
44 import android.app.admin.UserRestrictionPolicyKey;
45 import android.content.ComponentName;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.IntentFilter;
49 import android.content.pm.IPackageManager;
50 import android.content.pm.PackageManager;
51 import android.content.pm.ResolveInfo;
52 import android.content.pm.UserInfo;
53 import android.content.pm.UserProperties;
54 import android.os.Binder;
55 import android.os.Bundle;
56 import android.os.Environment;
57 import android.os.Parcel;
58 import android.os.RemoteException;
59 import android.os.UserHandle;
60 import android.os.UserManager;
61 import android.telephony.TelephonyManager;
62 import android.util.AtomicFile;
63 import android.util.IndentingPrintWriter;
64 import android.util.Log;
65 import android.util.SparseArray;
66 import android.util.Xml;
67 
68 import com.android.internal.annotations.GuardedBy;
69 import com.android.internal.util.XmlUtils;
70 import com.android.modules.utils.TypedXmlPullParser;
71 import com.android.modules.utils.TypedXmlSerializer;
72 import com.android.server.utils.Slogf;
73 
74 import libcore.io.IoUtils;
75 
76 import org.xmlpull.v1.XmlPullParserException;
77 
78 import java.io.File;
79 import java.io.FileOutputStream;
80 import java.io.IOException;
81 import java.io.InputStream;
82 import java.nio.file.Files;
83 import java.nio.file.Path;
84 import java.nio.file.StandardCopyOption;
85 import java.util.ArrayList;
86 import java.util.Collections;
87 import java.util.HashMap;
88 import java.util.HashSet;
89 import java.util.LinkedHashMap;
90 import java.util.List;
91 import java.util.Map;
92 import java.util.Objects;
93 import java.util.Set;
94 import java.util.concurrent.CompletableFuture;
95 
96 /**
97  * Class responsible for setting, resolving, and enforcing policies set by multiple management
98  * admins on the device.
99  */
100 final class DevicePolicyEngine {
101     static final String TAG = "DevicePolicyEngine";
102 
103     static final String DEVICE_LOCK_CONTROLLER_ROLE =
104             "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER";
105 
106     static final String SYSTEM_SUPERVISION_ROLE = "android.app.role.SYSTEM_SUPERVISION";
107 
108     private static final String CELLULAR_2G_USER_RESTRICTION_ID =
109             DevicePolicyIdentifiers.getIdentifierForUserRestriction(
110                     UserManager.DISALLOW_CELLULAR_2G);
111 
112     //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit
113     static final int DEFAULT_POLICY_SIZE_LIMIT = -1;
114 
115     private final Context mContext;
116     private final UserManager mUserManager;
117 
118     // TODO(b/256849338): add more granular locks
119     private final Object mLock;
120 
121     /**
122      * Map of <userId, Map<policyKey, policyState>>
123      */
124     @GuardedBy("mLock")
125     private final SparseArray<Map<PolicyKey, PolicyState<?>>> mLocalPolicies;
126 
127     /**
128      * Map of <policyKey, policyState>
129      */
130     @GuardedBy("mLock")
131     private final Map<PolicyKey, PolicyState<?>> mGlobalPolicies;
132 
133     /**
134      * Map containing the current set of admins in each user with active policies.
135      */
136     private final SparseArray<Set<EnforcingAdmin>> mEnforcingAdmins;
137 
138     private final SparseArray<HashMap<EnforcingAdmin, Integer>> mAdminPolicySize;
139 
140     private int mPolicySizeLimit = DEFAULT_POLICY_SIZE_LIMIT;
141 
142     private final DeviceAdminServiceController mDeviceAdminServiceController;
143 
DevicePolicyEngine( @onNull Context context, @NonNull DeviceAdminServiceController deviceAdminServiceController, @NonNull Object lock)144     DevicePolicyEngine(
145             @NonNull Context context,
146             @NonNull DeviceAdminServiceController deviceAdminServiceController,
147             @NonNull Object lock) {
148         mContext = Objects.requireNonNull(context);
149         mDeviceAdminServiceController = Objects.requireNonNull(deviceAdminServiceController);
150         mLock = Objects.requireNonNull(lock);
151         mUserManager = mContext.getSystemService(UserManager.class);
152         mLocalPolicies = new SparseArray<>();
153         mGlobalPolicies = new HashMap<>();
154         mEnforcingAdmins = new SparseArray<>();
155         mAdminPolicySize = new SparseArray<>();
156     }
157 
158     @GuardedBy("mLock")
forceEnforcementRefreshIfUserRestrictionLocked( @onNull PolicyDefinition<?> policyDefinition)159     private void forceEnforcementRefreshIfUserRestrictionLocked(
160             @NonNull PolicyDefinition<?> policyDefinition) {
161         try {
162             if (isUserRestrictionPolicy(policyDefinition)) {
163                 // This is okay because it's only true for user restrictions which are all <Boolean>
164                 forceEnforcementRefreshLocked((PolicyDefinition<Boolean>) policyDefinition);
165             }
166         } catch (Throwable e) {
167             // Catch any possible exceptions just to be on the safe side
168             Log.e(TAG, "Exception thrown during forceEnforcementRefreshIfUserRestrictionLocked", e);
169         }
170     }
171 
isUserRestrictionPolicy(@onNull PolicyDefinition<?> policyDefinition)172     private boolean isUserRestrictionPolicy(@NonNull PolicyDefinition<?> policyDefinition) {
173         // These are all "not nullable" but for the purposes of maximum safety for a lightly tested
174         // change we check here
175         if (policyDefinition == null) {
176             return false;
177         }
178         PolicyKey policyKey = policyDefinition.getPolicyKey();
179         if (policyKey == null) {
180             return false;
181         }
182 
183         if (policyKey instanceof UserRestrictionPolicyKey) {
184             // b/307481299 We must force all user restrictions to re-sync local
185             // + global on each set/clear
186             return true;
187         }
188 
189         return false;
190     }
191 
192     @GuardedBy("mLock")
forceEnforcementRefreshLocked(PolicyDefinition<Boolean> policyDefinition)193     private void forceEnforcementRefreshLocked(PolicyDefinition<Boolean> policyDefinition) {
194         Binder.withCleanCallingIdentity(() -> {
195             // Sync global state
196             PolicyValue<Boolean> globalValue = new BooleanPolicyValue(false);
197             try {
198                 PolicyState<Boolean> policyState = getGlobalPolicyStateLocked(policyDefinition);
199                 globalValue = policyState.getCurrentResolvedPolicy();
200             } catch (IllegalArgumentException e) {
201                 // Expected for local-only policies
202             }
203 
204             enforcePolicy(policyDefinition, globalValue, UserHandle.USER_ALL);
205 
206             // Loop through each user and sync that user's state
207             for (UserInfo user : mUserManager.getUsers()) {
208                 PolicyValue<Boolean> localValue = new BooleanPolicyValue(false);
209                 try {
210                     PolicyState<Boolean> localPolicyState = getLocalPolicyStateLocked(
211                             policyDefinition, user.id);
212                     localValue = localPolicyState.getCurrentResolvedPolicy();
213                 } catch (IllegalArgumentException e) {
214                     // Expected for global-only policies
215                 }
216 
217                 enforcePolicy(policyDefinition, localValue, user.id);
218             }
219         });
220     }
221 
222     /**
223      * Set the policy for the provided {@code policyDefinition} (see {@link PolicyDefinition}) and
224      * {@code enforcingAdmin} to the provided {@code value}.
225      *
226      * <p>If {@code skipEnforcePolicy} is true, it sets the policies in the internal data structure
227      * but doesn't call the enforcing logic.
228      */
setLocalPolicy( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @NonNull PolicyValue<V> value, int userId, boolean skipEnforcePolicy)229     <V> void setLocalPolicy(
230             @NonNull PolicyDefinition<V> policyDefinition,
231             @NonNull EnforcingAdmin enforcingAdmin,
232             @NonNull PolicyValue<V> value,
233             int userId,
234             boolean skipEnforcePolicy) {
235         Objects.requireNonNull(policyDefinition);
236         Objects.requireNonNull(enforcingAdmin);
237 
238         synchronized (mLock) {
239             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
240             if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value,
241                     policyDefinition, userId)) {
242                 return;
243             }
244 
245             if (policyDefinition.isNonCoexistablePolicy()) {
246                 setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
247                         enforcingAdmin, value, userId, skipEnforcePolicy);
248                 return;
249             }
250 
251             boolean hasGlobalPolicies = hasGlobalPolicyLocked(policyDefinition);
252             boolean policyChanged;
253             if (hasGlobalPolicies) {
254                 PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
255                 policyChanged = localPolicyState.addPolicy(
256                         enforcingAdmin,
257                         value,
258                         globalPolicyState.getPoliciesSetByAdmins());
259             } else {
260                 policyChanged = localPolicyState.addPolicy(enforcingAdmin, value);
261             }
262 
263             // No need to notify admins as no new policy is actually enforced, we're just filling in
264             // the data structures.
265             if (!skipEnforcePolicy) {
266                 forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
267                 if (policyChanged) {
268                     onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
269                 }
270                 boolean policyEnforced = Objects.equals(
271                         localPolicyState.getCurrentResolvedPolicy(), value);
272                 // TODO(b/285532044): remove hack and handle properly
273                 if (!policyEnforced && shouldApplyPackageSetUnionPolicyHack(policyDefinition)) {
274                     PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value;
275                     PolicyValue<Set<String>> parsedResolvedValue =
276                             (PolicyValue<Set<String>>) localPolicyState.getCurrentResolvedPolicy();
277                     policyEnforced = (parsedResolvedValue != null && parsedValue != null
278                             && parsedResolvedValue.getValue().containsAll(parsedValue.getValue()));
279                 }
280                 sendPolicyResultToAdmin(
281                         enforcingAdmin,
282                         policyDefinition,
283                         // TODO: we're always sending this for now, should properly handle errors.
284                         policyEnforced
285                                 ? RESULT_POLICY_SET : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
286                         userId);
287             }
288 
289             updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
290 
291             write();
292 
293             applyToInheritableProfiles(policyDefinition, enforcingAdmin, value, userId);
294         }
295     }
296 
297     /**
298      * Sets a non-coexistable policy, meaning it doesn't get resolved against other policies set
299      * by other admins, and no callbacks are sent to admins, this is just storing and
300      * enforcing the policy.
301      *
302      * <p>Passing a {@code null} value means the policy set by this admin should be removed.
303      */
304     @GuardedBy("mLock")
setNonCoexistableLocalPolicyLocked( PolicyDefinition<V> policyDefinition, PolicyState<V> localPolicyState, EnforcingAdmin enforcingAdmin, @Nullable PolicyValue<V> value, int userId, boolean skipEnforcePolicy)305     private <V> void setNonCoexistableLocalPolicyLocked(
306             PolicyDefinition<V> policyDefinition,
307             PolicyState<V> localPolicyState,
308             EnforcingAdmin enforcingAdmin,
309             @Nullable PolicyValue<V> value,
310             int userId,
311             boolean skipEnforcePolicy) {
312         if (value == null) {
313             localPolicyState.removePolicy(enforcingAdmin);
314         } else {
315             localPolicyState.addPolicy(enforcingAdmin, value);
316         }
317         if (!skipEnforcePolicy) {
318             enforcePolicy(policyDefinition, value, userId);
319         }
320         if (localPolicyState.getPoliciesSetByAdmins().isEmpty()) {
321             removeLocalPolicyStateLocked(policyDefinition, userId);
322         }
323         updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
324         write();
325         applyToInheritableProfiles(policyDefinition, enforcingAdmin, value, userId);
326     }
327 
328     // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values
329 
330     /**
331      * Set the policy for the provided {@code policyDefinition}
332      * (see {@link PolicyDefinition}) and {@code enforcingAdmin} to the provided {@code value}.
333      */
setLocalPolicy( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @NonNull PolicyValue<V> value, int userId)334     <V> void setLocalPolicy(
335             @NonNull PolicyDefinition<V> policyDefinition,
336             @NonNull EnforcingAdmin enforcingAdmin,
337             @NonNull PolicyValue<V> value,
338             int userId) {
339         setLocalPolicy(
340                 policyDefinition, enforcingAdmin, value, userId, /* skipEnforcePolicy= */ false);
341     }
342 
343     // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values
344 
345     /**
346      * Removes any previously set policy for the provided {@code policyDefinition}
347      * (see {@link PolicyDefinition}) and {@code enforcingAdmin}.
348      */
removeLocalPolicy( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, int userId)349     <V> void removeLocalPolicy(
350             @NonNull PolicyDefinition<V> policyDefinition,
351             @NonNull EnforcingAdmin enforcingAdmin,
352             int userId) {
353         Objects.requireNonNull(policyDefinition);
354         Objects.requireNonNull(enforcingAdmin);
355 
356         synchronized (mLock) {
357             forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
358             if (!hasLocalPolicyLocked(policyDefinition, userId)) {
359                 return;
360             }
361             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
362 
363             decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin);
364 
365             if (policyDefinition.isNonCoexistablePolicy()) {
366                 setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState,
367                         enforcingAdmin, /* value= */ null, userId, /* skipEnforcePolicy= */ false);
368                 return;
369             }
370 
371             boolean policyChanged;
372             if (hasGlobalPolicyLocked(policyDefinition)) {
373                 PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
374                 policyChanged = localPolicyState.removePolicy(
375                         enforcingAdmin,
376                         globalPolicyState.getPoliciesSetByAdmins());
377             } else {
378                 policyChanged = localPolicyState.removePolicy(enforcingAdmin);
379             }
380 
381             if (policyChanged) {
382                 onLocalPolicyChangedLocked(policyDefinition, enforcingAdmin, userId);
383             }
384 
385             // For a removePolicy to be enforced, it means no current policy exists
386             sendPolicyResultToAdmin(
387                     enforcingAdmin,
388                     policyDefinition,
389                     // TODO: we're always sending this for now, should properly handle errors.
390                     RESULT_POLICY_CLEARED,
391                     userId);
392 
393             if (localPolicyState.getPoliciesSetByAdmins().isEmpty()) {
394                 removeLocalPolicyStateLocked(policyDefinition, userId);
395             }
396 
397             updateDeviceAdminServiceOnPolicyRemoveLocked(enforcingAdmin);
398 
399             write();
400 
401             applyToInheritableProfiles(policyDefinition, enforcingAdmin, /*value */ null, userId);
402         }
403     }
404 
405     /**
406      * If any of child user has property {@link UserProperties#INHERIT_DEVICE_POLICY_FROM_PARENT}
407      * set then propagate the policy to it if value is not null
408      * else remove the policy from child.
409      */
applyToInheritableProfiles(PolicyDefinition<V> policyDefinition, EnforcingAdmin enforcingAdmin, @Nullable PolicyValue<V> value, int userId)410     private <V> void applyToInheritableProfiles(PolicyDefinition<V> policyDefinition,
411             EnforcingAdmin enforcingAdmin, @Nullable PolicyValue<V> value, int userId) {
412         if (!policyDefinition.isInheritable()) {
413             return;
414         }
415         Binder.withCleanCallingIdentity(() -> {
416             List<UserInfo> userInfos = mUserManager.getProfiles(userId);
417             for (UserInfo childUserInfo : userInfos) {
418                 int childUserId = childUserInfo.getUserHandle().getIdentifier();
419                 if (isProfileOfUser(childUserId, userId)
420                         && isInheritDevicePolicyFromParent(childUserInfo)) {
421                     if (value != null) {
422                         setLocalPolicy(policyDefinition, enforcingAdmin, value, childUserId);
423                     } else {
424                         removeLocalPolicy(policyDefinition, enforcingAdmin, childUserId);
425                     }
426                 }
427             }
428         });
429     }
430 
431     /**
432      * Checks if given parentUserId is direct parent of childUserId.
433      */
isProfileOfUser(int childUserId, int parentUserId)434     private boolean isProfileOfUser(int childUserId, int parentUserId) {
435         UserInfo parentInfo = mUserManager.getProfileParent(childUserId);
436         return childUserId != parentUserId && parentInfo != null
437                 && parentInfo.getUserHandle().getIdentifier() == parentUserId;
438     }
439 
isInheritDevicePolicyFromParent(UserInfo userInfo)440     private boolean isInheritDevicePolicyFromParent(UserInfo userInfo) {
441         UserProperties userProperties = mUserManager.getUserProperties(userInfo.getUserHandle());
442         return userProperties != null && mUserManager.getUserProperties(userInfo.getUserHandle())
443                 .getInheritDevicePolicy() == INHERIT_DEVICE_POLICY_FROM_PARENT;
444     }
445 
446     /**
447      * Enforces the new policy and notifies relevant admins.
448      */
449     @GuardedBy("mLock")
onLocalPolicyChangedLocked( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, int userId)450     private <V> void onLocalPolicyChangedLocked(
451             @NonNull PolicyDefinition<V> policyDefinition,
452             @NonNull EnforcingAdmin enforcingAdmin,
453             int userId) {
454 
455         PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
456         enforcePolicy(
457                 policyDefinition, localPolicyState.getCurrentResolvedPolicy(), userId);
458 
459         // Send policy updates to admins who've set it locally
460         sendPolicyChangedToAdminsLocked(
461                 localPolicyState,
462                 enforcingAdmin,
463                 policyDefinition,
464                 // This policy change is only relevant to a single user, not the global
465                 // policy value,
466                 userId);
467 
468         // Send policy updates to admins who've set it globally
469         if (hasGlobalPolicyLocked(policyDefinition)) {
470             PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
471             sendPolicyChangedToAdminsLocked(
472                     globalPolicyState,
473                     enforcingAdmin,
474                     policyDefinition,
475                     userId);
476         }
477         sendDevicePolicyChangedToSystem(userId);
478     }
479 
480     /**
481      * Set the policy for the provided {@code policyDefinition}
482      * (see {@link PolicyDefinition}) and {@code enforcingAdmin} to the provided {@code value}.
483      */
setGlobalPolicy( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @NonNull PolicyValue<V> value)484     <V> void setGlobalPolicy(
485             @NonNull PolicyDefinition<V> policyDefinition,
486             @NonNull EnforcingAdmin enforcingAdmin,
487             @NonNull PolicyValue<V> value) {
488         setGlobalPolicy(policyDefinition, enforcingAdmin, value, /* skipEnforcePolicy= */ false);
489     }
490 
491     // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values
492 
493     /**
494      * Set the policy for the provided {@code policyDefinition}
495      * (see {@link PolicyDefinition}) and {@code enforcingAdmin} to the provided {@code value}.
496      */
setGlobalPolicy( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @NonNull PolicyValue<V> value, boolean skipEnforcePolicy)497     <V> void setGlobalPolicy(
498             @NonNull PolicyDefinition<V> policyDefinition,
499             @NonNull EnforcingAdmin enforcingAdmin,
500             @NonNull PolicyValue<V> value,
501             boolean skipEnforcePolicy) {
502 
503         Objects.requireNonNull(policyDefinition);
504         Objects.requireNonNull(enforcingAdmin);
505         Objects.requireNonNull(value);
506 
507         synchronized (mLock) {
508             PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
509             if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value,
510                     policyDefinition, UserHandle.USER_ALL)) {
511                 return;
512             }
513             // TODO(b/270999567): Move error handling for DISALLOW_CELLULAR_2G into the code
514             //  that honors the restriction once there's an API available
515             if (checkFor2gFailure(policyDefinition, enforcingAdmin)) {
516                 Log.i(TAG,
517                         "Device does not support capabilities required to disable 2g. Not setting"
518                                 + " global policy state.");
519                 return;
520             }
521 
522             boolean policyChanged = globalPolicyState.addPolicy(enforcingAdmin, value);
523             boolean policyAppliedOnAllUsers = applyGlobalPolicyOnUsersWithLocalPoliciesLocked(
524                     policyDefinition, enforcingAdmin, value, skipEnforcePolicy);
525 
526             // No need to notify admins as no new policy is actually enforced, we're just filling in
527             // the data structures.
528             if (!skipEnforcePolicy) {
529                 forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
530                 if (policyChanged) {
531                     onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
532                 }
533 
534                 boolean policyAppliedGlobally = Objects.equals(
535                         globalPolicyState.getCurrentResolvedPolicy(), value);
536                 // TODO(b/285532044): remove hack and handle properly
537                 if (!policyAppliedGlobally
538                         && shouldApplyPackageSetUnionPolicyHack(policyDefinition)) {
539                     PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value;
540                     PolicyValue<Set<String>> parsedResolvedValue =
541                             (PolicyValue<Set<String>>) globalPolicyState.getCurrentResolvedPolicy();
542                     policyAppliedGlobally = (parsedResolvedValue != null && parsedValue != null
543                             && parsedResolvedValue.getValue().containsAll(parsedValue.getValue()));
544                 }
545 
546                 boolean policyApplied = policyAppliedGlobally && policyAppliedOnAllUsers;
547 
548                 sendPolicyResultToAdmin(
549                         enforcingAdmin,
550                         policyDefinition,
551                         // TODO: we're always sending this for now, should properly handle errors.
552                         policyApplied ? RESULT_POLICY_SET : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY,
553                         UserHandle.USER_ALL);
554             }
555 
556             updateDeviceAdminServiceOnPolicyAddLocked(enforcingAdmin);
557 
558             write();
559         }
560     }
561 
562     // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values
563 
564     /**
565      * Removes any previously set policy for the provided {@code policyDefinition}
566      * (see {@link PolicyDefinition}) and {@code enforcingAdmin}.
567      */
removeGlobalPolicy( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin)568     <V> void removeGlobalPolicy(
569             @NonNull PolicyDefinition<V> policyDefinition,
570             @NonNull EnforcingAdmin enforcingAdmin) {
571 
572         Objects.requireNonNull(policyDefinition);
573         Objects.requireNonNull(enforcingAdmin);
574 
575         synchronized (mLock) {
576             PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
577 
578             decreasePolicySizeForAdmin(policyState, enforcingAdmin);
579 
580             boolean policyChanged = policyState.removePolicy(enforcingAdmin);
581 
582             forceEnforcementRefreshIfUserRestrictionLocked(policyDefinition);
583             if (policyChanged) {
584                 onGlobalPolicyChangedLocked(policyDefinition, enforcingAdmin);
585             }
586 
587             applyGlobalPolicyOnUsersWithLocalPoliciesLocked(policyDefinition, enforcingAdmin,
588                     /* value= */ null, /* skipEnforcePolicy= */ false);
589 
590             sendPolicyResultToAdmin(
591                     enforcingAdmin,
592                     policyDefinition,
593                     // TODO: we're always sending this for now, should properly handle errors.
594                     RESULT_POLICY_CLEARED,
595                     UserHandle.USER_ALL);
596 
597             if (policyState.getPoliciesSetByAdmins().isEmpty()) {
598                 removeGlobalPolicyStateLocked(policyDefinition);
599             }
600 
601             updateDeviceAdminServiceOnPolicyRemoveLocked(enforcingAdmin);
602 
603             write();
604         }
605     }
606 
607     /**
608      * Enforces the new policy globally and notifies relevant admins.
609      */
610     @GuardedBy("mLock")
onGlobalPolicyChangedLocked( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin)611     private <V> void onGlobalPolicyChangedLocked(
612             @NonNull PolicyDefinition<V> policyDefinition,
613             @NonNull EnforcingAdmin enforcingAdmin) {
614         PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition);
615 
616         enforcePolicy(policyDefinition, policyState.getCurrentResolvedPolicy(),
617                 UserHandle.USER_ALL);
618 
619         sendPolicyChangedToAdminsLocked(
620                 policyState,
621                 enforcingAdmin,
622                 policyDefinition,
623                 UserHandle.USER_ALL);
624 
625         sendDevicePolicyChangedToSystem(UserHandle.USER_ALL);
626     }
627 
628     /**
629      * Tries to enforce the global policy locally on all users that have the same policy set
630      * locally, this is only applicable to policies that can be set locally or globally
631      * (e.g. setCameraDisabled, setScreenCaptureDisabled) rather than
632      * policies that are global by nature (e.g. setting Wifi enabled/disabled).
633      *
634      * <p> A {@code null} policy value means the policy was removed
635      *
636      * <p>Returns {@code true} if the policy is enforced successfully on all users.
637      */
638     @GuardedBy("mLock")
applyGlobalPolicyOnUsersWithLocalPoliciesLocked( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @Nullable PolicyValue<V> value, boolean skipEnforcePolicy)639     private <V> boolean applyGlobalPolicyOnUsersWithLocalPoliciesLocked(
640             @NonNull PolicyDefinition<V> policyDefinition,
641             @NonNull EnforcingAdmin enforcingAdmin,
642             @Nullable PolicyValue<V> value,
643             boolean skipEnforcePolicy) {
644         // Global only policies can't be applied locally, return early.
645         if (policyDefinition.isGlobalOnlyPolicy()) {
646             return true;
647         }
648         boolean isAdminPolicyApplied = true;
649         for (int i = 0; i < mLocalPolicies.size(); i++) {
650             int userId = mLocalPolicies.keyAt(i);
651             if (!hasLocalPolicyLocked(policyDefinition, userId)) {
652                 continue;
653             }
654 
655             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
656             PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition);
657 
658             boolean policyChanged = localPolicyState.resolvePolicy(
659                     globalPolicyState.getPoliciesSetByAdmins());
660             if (policyChanged && !skipEnforcePolicy) {
661                 enforcePolicy(
662                         policyDefinition,
663                         localPolicyState.getCurrentResolvedPolicy(),
664                         userId);
665                 sendPolicyChangedToAdminsLocked(
666                         localPolicyState,
667                         enforcingAdmin,
668                         policyDefinition,
669                         // Even though this is caused by a global policy change, admins who've set
670                         // it locally should only care about the local user state.
671                         userId);
672 
673             }
674             // TODO(b/285532044): remove hack and handle properly
675             if (shouldApplyPackageSetUnionPolicyHack(policyDefinition)) {
676                 if (!Objects.equals(value, localPolicyState.getCurrentResolvedPolicy())) {
677                     PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value;
678                     PolicyValue<Set<String>> parsedResolvedValue =
679                             (PolicyValue<Set<String>>) localPolicyState.getCurrentResolvedPolicy();
680                     isAdminPolicyApplied &= (parsedResolvedValue != null && parsedValue != null
681                             && parsedResolvedValue.getValue().containsAll(parsedValue.getValue()));
682                 }
683             } else {
684                 isAdminPolicyApplied &= Objects.equals(
685                         value, localPolicyState.getCurrentResolvedPolicy());
686             }
687         }
688         return isAdminPolicyApplied;
689     }
690 
691     /**
692      * Retrieves the resolved policy for the provided {@code policyDefinition} and {@code userId}.
693      */
694     @Nullable
getResolvedPolicy(@onNull PolicyDefinition<V> policyDefinition, int userId)695     <V> V getResolvedPolicy(@NonNull PolicyDefinition<V> policyDefinition, int userId) {
696         PolicyValue<V> resolvedValue = getResolvedPolicyValue(policyDefinition, userId);
697         return resolvedValue == null ? null : resolvedValue.getValue();
698     }
699 
getResolvedPolicyValue(@onNull PolicyDefinition<V> policyDefinition, int userId)700     private <V> PolicyValue<V> getResolvedPolicyValue(@NonNull PolicyDefinition<V> policyDefinition,
701             int userId) {
702         Objects.requireNonNull(policyDefinition);
703 
704         synchronized (mLock) {
705             PolicyValue<V> resolvedValue = null;
706             if (hasLocalPolicyLocked(policyDefinition, userId)) {
707                 resolvedValue = getLocalPolicyStateLocked(
708                         policyDefinition, userId).getCurrentResolvedPolicy();
709             } else if (hasGlobalPolicyLocked(policyDefinition)) {
710                 resolvedValue = getGlobalPolicyStateLocked(
711                         policyDefinition).getCurrentResolvedPolicy();
712             }
713             return resolvedValue;
714         }
715     }
716 
717     /**
718      * Retrieves resolved policy for the provided {@code policyDefinition} and a list of
719      * users.
720      */
721     @Nullable
getResolvedPolicyAcrossUsers(@onNull PolicyDefinition<V> policyDefinition, List<Integer> users)722     <V> V getResolvedPolicyAcrossUsers(@NonNull PolicyDefinition<V> policyDefinition,
723             List<Integer> users) {
724         Objects.requireNonNull(policyDefinition);
725 
726         List<PolicyValue<V>> adminPolicies = new ArrayList<>();
727         synchronized (mLock) {
728             for (int userId : users) {
729                 PolicyValue<V> resolvedValue = getResolvedPolicyValue(policyDefinition, userId);
730                 if (resolvedValue != null) {
731                     adminPolicies.add(resolvedValue);
732                 }
733             }
734         }
735         // We will be aggregating PolicyValue across multiple admins across multiple users,
736         // including different policies set by the same admin on different users. This is
737         // not supported by ResolutionMechanism generically, instead we need to call the special
738         // resolve() method that doesn't care about admins who set the policy. Note that not every
739         // ResolutionMechanism supports this.
740         PolicyValue<V> resolvedValue =
741                 policyDefinition.getResolutionMechanism().resolve(adminPolicies);
742         return resolvedValue == null ? null : resolvedValue.getValue();
743     }
744 
745     /**
746      * Retrieves the policy set by the admin for the provided {@code policyDefinition} and
747      * {@code userId} if one was set, otherwise returns {@code null}.
748      */
749     @Nullable
getLocalPolicySetByAdmin( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, int userId)750     <V> V getLocalPolicySetByAdmin(
751             @NonNull PolicyDefinition<V> policyDefinition,
752             @NonNull EnforcingAdmin enforcingAdmin,
753             int userId) {
754         Objects.requireNonNull(policyDefinition);
755         Objects.requireNonNull(enforcingAdmin);
756 
757         synchronized (mLock) {
758             if (!hasLocalPolicyLocked(policyDefinition, userId)) {
759                 return null;
760             }
761             PolicyValue<V> value = getLocalPolicyStateLocked(policyDefinition, userId)
762                     .getPoliciesSetByAdmins().get(enforcingAdmin);
763             return value == null ? null : value.getValue();
764         }
765     }
766 
767     /**
768      * Retrieves the global policy set by the admin for the provided {@code policyDefinition}
769      * if one was set, otherwise returns {@code null}.
770      */
771     @Nullable
getGlobalPolicySetByAdmin( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin)772     <V> V getGlobalPolicySetByAdmin(
773             @NonNull PolicyDefinition<V> policyDefinition,
774             @NonNull EnforcingAdmin enforcingAdmin) {
775         Objects.requireNonNull(policyDefinition);
776         Objects.requireNonNull(enforcingAdmin);
777 
778         synchronized (mLock) {
779             if (!hasGlobalPolicyLocked(policyDefinition)) {
780                 return null;
781             }
782             PolicyValue<V> value = getGlobalPolicyStateLocked(policyDefinition)
783                     .getPoliciesSetByAdmins().get(enforcingAdmin);
784             return value == null ? null : value.getValue();
785         }
786     }
787 
788     /**
789      * Retrieves the values set for the provided {@code policyDefinition} by each admin.
790      */
791     @NonNull
getLocalPoliciesSetByAdmins( @onNull PolicyDefinition<V> policyDefinition, int userId)792     <V> LinkedHashMap<EnforcingAdmin, PolicyValue<V>> getLocalPoliciesSetByAdmins(
793             @NonNull PolicyDefinition<V> policyDefinition,
794             int userId) {
795         Objects.requireNonNull(policyDefinition);
796 
797         synchronized (mLock) {
798             if (!hasLocalPolicyLocked(policyDefinition, userId)) {
799                 return new LinkedHashMap<>();
800             }
801             return getLocalPolicyStateLocked(policyDefinition, userId).getPoliciesSetByAdmins();
802         }
803     }
804 
805     /**
806      * Retrieves the values set for the provided {@code policyDefinition} by each admin.
807      */
808     @NonNull
getGlobalPoliciesSetByAdmins( @onNull PolicyDefinition<V> policyDefinition)809     <V> LinkedHashMap<EnforcingAdmin, PolicyValue<V>> getGlobalPoliciesSetByAdmins(
810             @NonNull PolicyDefinition<V> policyDefinition) {
811         Objects.requireNonNull(policyDefinition);
812 
813         synchronized (mLock) {
814             if (!hasGlobalPolicyLocked(policyDefinition)) {
815                 return new LinkedHashMap<>();
816             }
817             return getGlobalPolicyStateLocked(policyDefinition).getPoliciesSetByAdmins();
818         }
819     }
820 
821     /**
822      * Returns the policies set by the given admin that share the same
823      * {@link PolicyKey#getIdentifier()} as the provided {@code policyDefinition}.
824      *
825      * <p>For example, getLocalPolicyKeysSetByAdmin(PERMISSION_GRANT, admin) returns all permission
826      * grants set by the given admin.
827      *
828      * <p>Note that this will always return at most one item for policies that do not require
829      * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs
830      * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}).
831      */
832     @NonNull
getLocalPolicyKeysSetByAdmin( @onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, int userId)833     <V> Set<PolicyKey> getLocalPolicyKeysSetByAdmin(
834             @NonNull PolicyDefinition<V> policyDefinition,
835             @NonNull EnforcingAdmin enforcingAdmin,
836             int userId) {
837         Objects.requireNonNull(policyDefinition);
838         Objects.requireNonNull(enforcingAdmin);
839 
840         synchronized (mLock) {
841             if (policyDefinition.isGlobalOnlyPolicy() || !mLocalPolicies.contains(userId)) {
842                 return Set.of();
843             }
844             Set<PolicyKey> keys = new HashSet<>();
845             for (PolicyKey key : mLocalPolicies.get(userId).keySet()) {
846                 if (key.hasSameIdentifierAs(policyDefinition.getPolicyKey())
847                         && mLocalPolicies.get(userId).get(key).getPoliciesSetByAdmins()
848                         .containsKey(enforcingAdmin)) {
849                     keys.add(key);
850                 }
851             }
852             return keys;
853         }
854     }
855 
856     /**
857      * Returns all the {@code policyKeys} set by any admin that share the same
858      * {@link PolicyKey#getIdentifier()} as the provided {@code policyDefinition}.
859      *
860      * <p>For example, getLocalPolicyKeysSetByAllAdmins(PERMISSION_GRANT) returns all permission
861      * grants set by any admin.
862      *
863      * <p>Note that this will always return at most one item for policies that do not require
864      * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs
865      * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}).
866      */
867     @NonNull
getLocalPolicyKeysSetByAllAdmins( @onNull PolicyDefinition<V> policyDefinition, int userId)868     <V> Set<PolicyKey> getLocalPolicyKeysSetByAllAdmins(
869             @NonNull PolicyDefinition<V> policyDefinition,
870             int userId) {
871         Objects.requireNonNull(policyDefinition);
872 
873         synchronized (mLock) {
874             if (policyDefinition.isGlobalOnlyPolicy() || !mLocalPolicies.contains(userId)) {
875                 return Set.of();
876             }
877             Set<PolicyKey> keys = new HashSet<>();
878             for (PolicyKey key : mLocalPolicies.get(userId).keySet()) {
879                 if (key.hasSameIdentifierAs(policyDefinition.getPolicyKey())) {
880                     keys.add(key);
881                 }
882             }
883             return keys;
884         }
885     }
886 
887     /**
888      * Returns all user restriction policies set by the given admin.
889      *
890      * <p>Pass in {@link UserHandle#USER_ALL} for {@code userId} to get global restrictions set by
891      * the admin
892      */
893     @NonNull
getUserRestrictionPolicyKeysForAdmin( @onNull EnforcingAdmin admin, int userId)894     Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdmin(
895             @NonNull EnforcingAdmin admin,
896             int userId) {
897         Objects.requireNonNull(admin);
898         synchronized (mLock) {
899             if (userId == UserHandle.USER_ALL) {
900                 return getUserRestrictionPolicyKeysForAdminLocked(mGlobalPolicies, admin);
901             }
902             if (!mLocalPolicies.contains(userId)) {
903                 return Set.of();
904             }
905             return getUserRestrictionPolicyKeysForAdminLocked(mLocalPolicies.get(userId), admin);
906         }
907     }
908 
transferPolicies(EnforcingAdmin oldAdmin, EnforcingAdmin newAdmin)909     <V> void transferPolicies(EnforcingAdmin oldAdmin, EnforcingAdmin newAdmin) {
910         synchronized (mLock) {
911             Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
912             for (PolicyKey policy : globalPolicies) {
913                 PolicyState<?> policyState = mGlobalPolicies.get(policy);
914                 if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
915                     PolicyDefinition<V> policyDefinition =
916                             (PolicyDefinition<V>) policyState.getPolicyDefinition();
917                     PolicyValue<V> policyValue =
918                             (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
919                     setGlobalPolicy(policyDefinition, newAdmin, policyValue);
920                 }
921             }
922 
923             for (int i = 0; i < mLocalPolicies.size(); i++) {
924                 int userId = mLocalPolicies.keyAt(i);
925                 Set<PolicyKey> localPolicies = new HashSet<>(
926                         mLocalPolicies.get(userId).keySet());
927                 for (PolicyKey policy : localPolicies) {
928                     PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
929                     if (policyState.getPoliciesSetByAdmins().containsKey(oldAdmin)) {
930                         PolicyDefinition<V> policyDefinition =
931                                 (PolicyDefinition<V>) policyState.getPolicyDefinition();
932                         PolicyValue<V> policyValue =
933                                 (PolicyValue<V>) policyState.getPoliciesSetByAdmins().get(oldAdmin);
934                         setLocalPolicy(policyDefinition, newAdmin, policyValue, userId);
935                     }
936                 }
937             }
938         }
939         removePoliciesForAdmin(oldAdmin);
940     }
941 
942     @GuardedBy("mLock")
getUserRestrictionPolicyKeysForAdminLocked( Map<PolicyKey, PolicyState<?>> policies, EnforcingAdmin admin)943     private Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdminLocked(
944             Map<PolicyKey, PolicyState<?>> policies,
945             EnforcingAdmin admin) {
946         Set<UserRestrictionPolicyKey> keys = new HashSet<>();
947         for (PolicyKey key : policies.keySet()) {
948             if (!policies.get(key).getPolicyDefinition().isUserRestrictionPolicy()) {
949                 continue;
950             }
951             // User restriction policies are always boolean
952             PolicyValue<Boolean> value = (PolicyValue<Boolean>) policies.get(key)
953                     .getPoliciesSetByAdmins().get(admin);
954             if (value == null || !value.getValue()) {
955                 continue;
956             }
957             keys.add((UserRestrictionPolicyKey) key);
958         }
959         return keys;
960     }
961 
962     @GuardedBy("mLock")
hasLocalPolicyLocked(PolicyDefinition<V> policyDefinition, int userId)963     private <V> boolean hasLocalPolicyLocked(PolicyDefinition<V> policyDefinition, int userId) {
964         if (policyDefinition.isGlobalOnlyPolicy()) {
965             return false;
966         }
967         if (!mLocalPolicies.contains(userId)) {
968             return false;
969         }
970         if (!mLocalPolicies.get(userId).containsKey(policyDefinition.getPolicyKey())) {
971             return false;
972         }
973         return !mLocalPolicies.get(userId).get(policyDefinition.getPolicyKey())
974                 .getPoliciesSetByAdmins().isEmpty();
975     }
976 
977     @GuardedBy("mLock")
hasGlobalPolicyLocked(PolicyDefinition<V> policyDefinition)978     private <V> boolean hasGlobalPolicyLocked(PolicyDefinition<V> policyDefinition) {
979         if (policyDefinition.isLocalOnlyPolicy()) {
980             return false;
981         }
982         if (!mGlobalPolicies.containsKey(policyDefinition.getPolicyKey())) {
983             return false;
984         }
985         return !mGlobalPolicies.get(policyDefinition.getPolicyKey()).getPoliciesSetByAdmins()
986                 .isEmpty();
987     }
988 
989     @GuardedBy("mLock")
990     @NonNull
getLocalPolicyStateLocked( PolicyDefinition<V> policyDefinition, int userId)991     private <V> PolicyState<V> getLocalPolicyStateLocked(
992             PolicyDefinition<V> policyDefinition, int userId) {
993 
994         if (policyDefinition.isGlobalOnlyPolicy()) {
995             throw new IllegalArgumentException(policyDefinition.getPolicyKey() + " is a global only"
996                     + " policy.");
997         }
998 
999         if (!mLocalPolicies.contains(userId)) {
1000             mLocalPolicies.put(userId, new HashMap<>());
1001         }
1002         if (!mLocalPolicies.get(userId).containsKey(policyDefinition.getPolicyKey())) {
1003             mLocalPolicies.get(userId).put(
1004                     policyDefinition.getPolicyKey(), new PolicyState<>(policyDefinition));
1005         }
1006         return getPolicyStateLocked(mLocalPolicies.get(userId), policyDefinition);
1007     }
1008 
1009     @GuardedBy("mLock")
removeLocalPolicyStateLocked( PolicyDefinition<V> policyDefinition, int userId)1010     private <V> void removeLocalPolicyStateLocked(
1011             PolicyDefinition<V> policyDefinition, int userId) {
1012         if (!mLocalPolicies.contains(userId)) {
1013             return;
1014         }
1015         mLocalPolicies.get(userId).remove(policyDefinition.getPolicyKey());
1016     }
1017 
1018     @GuardedBy("mLock")
1019     @NonNull
getGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition)1020     private <V> PolicyState<V> getGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) {
1021         if (policyDefinition.isLocalOnlyPolicy()) {
1022             throw new IllegalArgumentException(policyDefinition.getPolicyKey() + " is a local only"
1023                     + " policy.");
1024         }
1025 
1026         if (!mGlobalPolicies.containsKey(policyDefinition.getPolicyKey())) {
1027             mGlobalPolicies.put(
1028                     policyDefinition.getPolicyKey(), new PolicyState<>(policyDefinition));
1029         }
1030         return getPolicyStateLocked(mGlobalPolicies, policyDefinition);
1031     }
1032 
1033     @GuardedBy("mLock")
removeGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition)1034     private <V> void removeGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) {
1035         mGlobalPolicies.remove(policyDefinition.getPolicyKey());
1036     }
1037 
1038     @GuardedBy("mLock")
getPolicyStateLocked( Map<PolicyKey, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition)1039     private static <V> PolicyState<V> getPolicyStateLocked(
1040             Map<PolicyKey, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition) {
1041         try {
1042             // This will not throw an exception because policyDefinition is of type V, so unless
1043             // we've created two policies with the same key but different types - we can only have
1044             // stored a PolicyState of the right type.
1045             PolicyState<V> policyState = (PolicyState<V>) policies.get(
1046                     policyDefinition.getPolicyKey());
1047             return policyState;
1048         } catch (ClassCastException exception) {
1049             // TODO: handle exception properly
1050             throw new IllegalArgumentException();
1051         }
1052     }
1053 
enforcePolicy(PolicyDefinition<V> policyDefinition, @Nullable PolicyValue<V> policyValue, int userId)1054     private <V> CompletableFuture<Boolean> enforcePolicy(PolicyDefinition<V> policyDefinition,
1055             @Nullable PolicyValue<V> policyValue, int userId) {
1056         // null policyValue means remove any enforced policies, ensure callbacks handle this
1057         // properly
1058         return policyDefinition.enforcePolicy(
1059                 policyValue == null ? null : policyValue.getValue(), mContext, userId);
1060     }
1061 
sendDevicePolicyChangedToSystem(int userId)1062     private void sendDevicePolicyChangedToSystem(int userId) {
1063         Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
1064         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
1065         Bundle options = new BroadcastOptions()
1066                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
1067                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
1068                 .toBundle();
1069         Binder.withCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(
1070                 intent,
1071                 new UserHandle(userId),
1072                 /* receiverPermissions= */ null,
1073                 options));
1074     }
1075 
sendPolicyResultToAdmin( EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, int result, int userId)1076     private <V> void sendPolicyResultToAdmin(
1077             EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, int result, int userId) {
1078         Intent intent = new Intent(PolicyUpdateReceiver.ACTION_DEVICE_POLICY_SET_RESULT);
1079         intent.setPackage(admin.getPackageName());
1080 
1081         Binder.withCleanCallingIdentity(() -> {
1082             List<ResolveInfo> receivers =
1083                     mContext.getPackageManager().queryBroadcastReceiversAsUser(
1084                             intent,
1085                             PackageManager.ResolveInfoFlags.of(PackageManager.GET_RECEIVERS),
1086                             admin.getUserId());
1087             if (receivers.isEmpty()) {
1088                 Log.i(TAG, "Couldn't find any receivers that handle ACTION_DEVICE_POLICY_SET_RESULT"
1089                         + " in package " + admin.getPackageName());
1090                 return;
1091             }
1092 
1093             Bundle extras = new Bundle();
1094             policyDefinition.getPolicyKey().writeToBundle(extras);
1095             extras.putInt(
1096                     EXTRA_POLICY_TARGET_USER_ID,
1097                     getTargetUser(admin.getUserId(), userId));
1098             extras.putInt(
1099                     EXTRA_POLICY_UPDATE_RESULT_KEY,
1100                     result);
1101 
1102             intent.putExtras(extras);
1103 
1104             maybeSendIntentToAdminReceivers(intent, UserHandle.of(admin.getUserId()), receivers);
1105         });
1106     }
1107 
1108     // TODO(b/261430877): Finalise the decision on which admins to send the updates to.
1109     @GuardedBy("mLock")
sendPolicyChangedToAdminsLocked( PolicyState<V> policyState, EnforcingAdmin callingAdmin, PolicyDefinition<V> policyDefinition, int userId)1110     private <V> void sendPolicyChangedToAdminsLocked(
1111             PolicyState<V> policyState,
1112             EnforcingAdmin callingAdmin,
1113             PolicyDefinition<V> policyDefinition,
1114             int userId) {
1115         for (EnforcingAdmin admin : policyState.getPoliciesSetByAdmins().keySet()) {
1116             // We're sending a separate broadcast for the calling admin with the result.
1117             if (admin.equals(callingAdmin)) {
1118                 continue;
1119             }
1120             int result = Objects.equals(
1121                     policyState.getPoliciesSetByAdmins().get(admin),
1122                     policyState.getCurrentResolvedPolicy())
1123                     ? RESULT_POLICY_SET : RESULT_FAILURE_CONFLICTING_ADMIN_POLICY;
1124             maybeSendOnPolicyChanged(
1125                     admin, policyDefinition, result, userId);
1126         }
1127     }
1128 
maybeSendOnPolicyChanged( EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, int reason, int userId)1129     private <V> void maybeSendOnPolicyChanged(
1130             EnforcingAdmin admin, PolicyDefinition<V> policyDefinition, int reason,
1131             int userId) {
1132         Intent intent = new Intent(PolicyUpdateReceiver.ACTION_DEVICE_POLICY_CHANGED);
1133         intent.setPackage(admin.getPackageName());
1134 
1135         Binder.withCleanCallingIdentity(() -> {
1136             List<ResolveInfo> receivers =
1137                     mContext.getPackageManager().queryBroadcastReceiversAsUser(
1138                             intent,
1139                             PackageManager.ResolveInfoFlags.of(PackageManager.GET_RECEIVERS),
1140                             admin.getUserId());
1141             if (receivers.isEmpty()) {
1142                 Log.i(TAG, "Couldn't find any receivers that handle ACTION_DEVICE_POLICY_CHANGED"
1143                         + " in package " + admin.getPackageName());
1144                 return;
1145             }
1146 
1147             Bundle extras = new Bundle();
1148             policyDefinition.getPolicyKey().writeToBundle(extras);
1149             extras.putInt(
1150                     EXTRA_POLICY_TARGET_USER_ID,
1151                     getTargetUser(admin.getUserId(), userId));
1152             extras.putInt(EXTRA_POLICY_UPDATE_RESULT_KEY, reason);
1153             intent.putExtras(extras);
1154             intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1155 
1156             maybeSendIntentToAdminReceivers(
1157                     intent, UserHandle.of(admin.getUserId()), receivers);
1158         });
1159     }
1160 
maybeSendIntentToAdminReceivers( Intent intent, UserHandle userHandle, List<ResolveInfo> receivers)1161     private void maybeSendIntentToAdminReceivers(
1162             Intent intent, UserHandle userHandle, List<ResolveInfo> receivers) {
1163         for (ResolveInfo resolveInfo : receivers) {
1164             if (!Manifest.permission.BIND_DEVICE_ADMIN.equals(
1165                     resolveInfo.activityInfo.permission)) {
1166                 Log.w(TAG, "Receiver " + resolveInfo.activityInfo + " is not protected by "
1167                         + "BIND_DEVICE_ADMIN permission!");
1168                 continue;
1169             }
1170             // TODO: If admins are always bound to, do I still need to set
1171             //  "BroadcastOptions.setBackgroundActivityStartsAllowed"?
1172             // TODO: maybe protect it with a permission that is granted to the role so that we
1173             //  don't accidentally send a broadcast to an admin that no longer holds the role.
1174             mContext.sendBroadcastAsUser(intent, userHandle);
1175         }
1176     }
1177 
getTargetUser(int adminUserId, int targetUserId)1178     private int getTargetUser(int adminUserId, int targetUserId) {
1179         if (targetUserId == UserHandle.USER_ALL) {
1180             return TargetUser.GLOBAL_USER_ID;
1181         }
1182         if (adminUserId == targetUserId) {
1183             return TargetUser.LOCAL_USER_ID;
1184         }
1185         if (getProfileParentId(adminUserId) == targetUserId) {
1186             return TargetUser.PARENT_USER_ID;
1187         }
1188         return TargetUser.UNKNOWN_USER_ID;
1189     }
1190 
getProfileParentId(int userId)1191     private int getProfileParentId(int userId) {
1192         return Binder.withCleanCallingIdentity(() -> {
1193             UserInfo parentUser = mUserManager.getProfileParent(userId);
1194             return parentUser != null ? parentUser.id : userId;
1195         });
1196     }
1197 
1198     /**
1199      * Starts/Stops the services that handle {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE}
1200      * in the enforcing admins for the given {@code userId}.
1201      */
updateDeviceAdminsServicesForUser( int userId, boolean enable, @NonNull String actionForLog)1202     private void updateDeviceAdminsServicesForUser(
1203             int userId, boolean enable, @NonNull String actionForLog) {
1204         if (!enable) {
1205             mDeviceAdminServiceController.stopServicesForUser(
1206                     userId, actionForLog);
1207         } else {
1208             for (EnforcingAdmin admin : getEnforcingAdminsOnUser(userId)) {
1209                 // DPCs are handled separately in DPMS, no need to reestablish the connection here.
1210                 if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
1211                     continue;
1212                 }
1213                 mDeviceAdminServiceController.startServiceForAdmin(
1214                         admin.getPackageName(), userId, actionForLog);
1215             }
1216         }
1217     }
1218 
1219     /**
1220      * Handles internal state related to a user getting started.
1221      */
handleStartUser(int userId)1222     void handleStartUser(int userId) {
1223         updateDeviceAdminsServicesForUser(
1224                 userId, /* enable= */ true, /* actionForLog= */ "start-user");
1225     }
1226 
1227     /**
1228      * Handles internal state related to a user getting started.
1229      */
handleUnlockUser(int userId)1230     void handleUnlockUser(int userId) {
1231         updateDeviceAdminsServicesForUser(
1232                 userId, /* enable= */ true, /* actionForLog= */ "unlock-user");
1233     }
1234 
1235     /**
1236      * Handles internal state related to a user getting stopped.
1237      */
handleStopUser(int userId)1238     void handleStopUser(int userId) {
1239         updateDeviceAdminsServicesForUser(
1240                 userId, /* enable= */ false, /* actionForLog= */ "stop-user");
1241     }
1242 
1243     /**
1244      * Handles internal state related to packages getting updated.
1245      */
handlePackageChanged( @ullable String updatedPackage, int userId, @Nullable String removedDpcPackage)1246     void handlePackageChanged(
1247             @Nullable String updatedPackage, int userId, @Nullable String removedDpcPackage) {
1248         Binder.withCleanCallingIdentity(() -> {
1249             Set<EnforcingAdmin> admins = getEnforcingAdminsOnUser(userId);
1250             if (removedDpcPackage != null) {
1251                 for (EnforcingAdmin admin : admins) {
1252                     if (removedDpcPackage.equals(admin.getPackageName())) {
1253                         removePoliciesForAdmin(admin);
1254                         return;
1255                     }
1256                 }
1257             }
1258             for (EnforcingAdmin admin : admins) {
1259                 // No need to make changes to system enforcing admins.
1260                 if (admin.isSystemAuthority()) break;
1261                 if (updatedPackage == null || updatedPackage.equals(admin.getPackageName())) {
1262                     if (!isPackageInstalled(admin.getPackageName(), userId)) {
1263                         Slogf.i(TAG, String.format(
1264                                 "Admin package %s not found for user %d, removing admin policies",
1265                                 admin.getPackageName(), userId));
1266                         // remove policies for the uninstalled package
1267                         removePoliciesForAdmin(admin);
1268                         return;
1269                     }
1270                 }
1271             }
1272             if (updatedPackage != null) {
1273                 updateDeviceAdminServiceOnPackageChanged(updatedPackage, userId);
1274                 removePersistentPreferredActivityPoliciesForPackage(updatedPackage, userId);
1275             }
1276         });
1277     }
1278 
removePersistentPreferredActivityPoliciesForPackage( @onNull String packageName, int userId)1279     private void removePersistentPreferredActivityPoliciesForPackage(
1280             @NonNull String packageName, int userId) {
1281         Set<PolicyKey> policyKeys = getLocalPolicyKeysSetByAllAdmins(
1282                 PolicyDefinition.GENERIC_PERSISTENT_PREFERRED_ACTIVITY, userId);
1283         for (PolicyKey key : policyKeys) {
1284             if (!(key instanceof IntentFilterPolicyKey)) {
1285                 throw new IllegalStateException("PolicyKey for "
1286                         + "PERSISTENT_PREFERRED_ACTIVITY is not of type "
1287                         + "IntentFilterPolicyKey");
1288             }
1289             IntentFilterPolicyKey parsedKey =
1290                     (IntentFilterPolicyKey) key;
1291             IntentFilter intentFilter = Objects.requireNonNull(parsedKey.getIntentFilter());
1292             PolicyDefinition<ComponentName> policyDefinition =
1293                     PolicyDefinition.PERSISTENT_PREFERRED_ACTIVITY(intentFilter);
1294             LinkedHashMap<EnforcingAdmin, PolicyValue<ComponentName>> policies =
1295                     getLocalPoliciesSetByAdmins(
1296                             policyDefinition,
1297                             userId);
1298             IPackageManager packageManager = AppGlobals.getPackageManager();
1299             for (EnforcingAdmin admin : policies.keySet()) {
1300                 if (policies.get(admin).getValue() != null
1301                         && policies.get(admin).getValue().getPackageName().equals(packageName)) {
1302                     try {
1303                         if (packageManager.getPackageInfo(packageName, 0, userId) == null
1304                                 || packageManager.getActivityInfo(
1305                                 policies.get(admin).getValue(), 0, userId) == null) {
1306                             Slogf.e(TAG, String.format(
1307                                     "Persistent preferred activity in package %s not found for "
1308                                             + "user %d, removing policy for admin",
1309                                     packageName, userId));
1310                             removeLocalPolicy(policyDefinition, admin, userId);
1311                         }
1312                     } catch (RemoteException re) {
1313                         // Shouldn't happen.
1314                         Slogf.wtf(TAG, "Error handling package changes", re);
1315                     }
1316                 }
1317             }
1318         }
1319     }
1320 
isPackageInstalled(String packageName, int userId)1321     private boolean isPackageInstalled(String packageName, int userId) {
1322         try {
1323             return AppGlobals.getPackageManager().getPackageInfo(
1324                     packageName, 0, userId) != null;
1325         } catch (RemoteException re) {
1326             // Shouldn't happen.
1327             Slogf.wtf(TAG, "Error handling package changes", re);
1328             return true;
1329         }
1330     }
1331 
1332     /**
1333      * Handles internal state related to a user getting removed.
1334      */
handleUserRemoved(int userId)1335     void handleUserRemoved(int userId) {
1336         removeLocalPoliciesForUser(userId);
1337         removePoliciesForAdminsOnUser(userId);
1338     }
1339 
1340     /**
1341      * Handles internal state related to a user getting created.
1342      */
handleUserCreated(UserInfo user)1343     void handleUserCreated(UserInfo user) {
1344         enforcePoliciesOnInheritableProfilesIfApplicable(user);
1345     }
1346 
1347     /**
1348      * Handles internal state related to roles getting updated.
1349      */
handleRoleChanged(@onNull String roleName, int userId)1350     void handleRoleChanged(@NonNull String roleName, int userId) {
1351         // TODO(b/256852787): handle all roles changing.
1352         if (!DEVICE_LOCK_CONTROLLER_ROLE.equals(roleName)) {
1353             // We only support device lock controller role for now.
1354             return;
1355         }
1356         String roleAuthority = EnforcingAdmin.getRoleAuthorityOf(roleName);
1357         Set<EnforcingAdmin> admins = getEnforcingAdminsOnUser(userId);
1358         for (EnforcingAdmin admin : admins) {
1359             if (admin.hasAuthority(roleAuthority)) {
1360                 admin.reloadRoleAuthorities();
1361                 // remove admin policies if role was lost
1362                 if (!admin.hasAuthority(roleAuthority)) {
1363                     removePoliciesForAdmin(admin);
1364                 }
1365             }
1366         }
1367     }
1368 
enforcePoliciesOnInheritableProfilesIfApplicable(UserInfo user)1369     private void enforcePoliciesOnInheritableProfilesIfApplicable(UserInfo user) {
1370         if (!user.isProfile()) {
1371             return;
1372         }
1373 
1374         Binder.withCleanCallingIdentity(() -> {
1375             UserProperties userProperties = mUserManager.getUserProperties(user.getUserHandle());
1376             if (userProperties == null || userProperties.getInheritDevicePolicy()
1377                     != INHERIT_DEVICE_POLICY_FROM_PARENT) {
1378                 return;
1379             }
1380 
1381             int userId = user.id;
1382             // Apply local policies present on parent to newly created child profile.
1383             UserInfo parentInfo = mUserManager.getProfileParent(userId);
1384             if (parentInfo == null || parentInfo.getUserHandle().getIdentifier() == userId) {
1385                 return;
1386             }
1387             synchronized (mLock) {
1388                 if (!mLocalPolicies.contains(parentInfo.getUserHandle().getIdentifier())) {
1389                     return;
1390                 }
1391                 for (Map.Entry<PolicyKey, PolicyState<?>> entry : mLocalPolicies.get(
1392                         parentInfo.getUserHandle().getIdentifier()).entrySet()) {
1393                     enforcePolicyOnUserLocked(userId, entry.getValue());
1394                 }
1395             }
1396         });
1397     }
1398 
1399     @GuardedBy("mLock")
enforcePolicyOnUserLocked(int userId, PolicyState<V> policyState)1400     private <V> void enforcePolicyOnUserLocked(int userId, PolicyState<V> policyState) {
1401         if (!policyState.getPolicyDefinition().isInheritable()) {
1402             return;
1403         }
1404         for (Map.Entry<EnforcingAdmin, PolicyValue<V>> enforcingAdminEntry :
1405                 policyState.getPoliciesSetByAdmins().entrySet()) {
1406             setLocalPolicy(policyState.getPolicyDefinition(),
1407                     enforcingAdminEntry.getKey(),
1408                     enforcingAdminEntry.getValue(),
1409                     userId);
1410         }
1411     }
1412 
1413     /**
1414      * Returns all current enforced policies set on the device, and the individual values set by
1415      * each admin. Global policies are returned under {@link UserHandle#ALL}.
1416      */
1417     @NonNull
getDevicePolicyState()1418     DevicePolicyState getDevicePolicyState() {
1419         synchronized (mLock) {
1420             Map<UserHandle, Map<PolicyKey, android.app.admin.PolicyState<?>>> policies =
1421                     new HashMap<>();
1422             for (int i = 0; i < mLocalPolicies.size(); i++) {
1423                 UserHandle user = UserHandle.of(mLocalPolicies.keyAt(i));
1424                 policies.put(user, new HashMap<>());
1425                 for (PolicyKey policyKey : mLocalPolicies.valueAt(i).keySet()) {
1426                     policies.get(user).put(
1427                             policyKey,
1428                             mLocalPolicies.valueAt(i).get(policyKey).getParcelablePolicyState());
1429                 }
1430             }
1431             if (!mGlobalPolicies.isEmpty()) {
1432                 policies.put(UserHandle.ALL, new HashMap<>());
1433                 for (PolicyKey policyKey : mGlobalPolicies.keySet()) {
1434                     policies.get(UserHandle.ALL).put(
1435                             policyKey,
1436                             mGlobalPolicies.get(policyKey).getParcelablePolicyState());
1437                 }
1438             }
1439             return new DevicePolicyState(policies);
1440         }
1441     }
1442 
1443     /**
1444      * Removes all local and global policies set by that admin.
1445      */
removePoliciesForAdmin(EnforcingAdmin admin)1446     void removePoliciesForAdmin(EnforcingAdmin admin) {
1447         synchronized (mLock) {
1448             Set<PolicyKey> globalPolicies = new HashSet<>(mGlobalPolicies.keySet());
1449             for (PolicyKey policy : globalPolicies) {
1450                 PolicyState<?> policyState = mGlobalPolicies.get(policy);
1451                 if (policyState.getPoliciesSetByAdmins().containsKey(admin)) {
1452                     removeGlobalPolicy(policyState.getPolicyDefinition(), admin);
1453                 }
1454             }
1455 
1456             for (int i = 0; i < mLocalPolicies.size(); i++) {
1457                 // New users are potentially added to mLocalPolicies during the loop body
1458                 // (see b/374511959).
1459                 int userId = mLocalPolicies.keyAt(i);
1460                 Set<PolicyKey> localPolicies = new HashSet<>(mLocalPolicies.get(userId).keySet());
1461                 for (PolicyKey policy : localPolicies) {
1462                     PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
1463                     if (policyState.getPoliciesSetByAdmins().containsKey(admin)) {
1464                         removeLocalPolicy(
1465                                 policyState.getPolicyDefinition(), admin, mLocalPolicies.keyAt(i));
1466                     }
1467                 }
1468             }
1469         }
1470     }
1471 
1472     /**
1473      * Removes all local policies for the provided {@code userId}.
1474      */
removeLocalPoliciesForUser(int userId)1475     private void removeLocalPoliciesForUser(int userId) {
1476         synchronized (mLock) {
1477             if (!mLocalPolicies.contains(userId)) {
1478                 // No policies on user
1479                 return;
1480             }
1481 
1482             Set<PolicyKey> localPolicies = new HashSet<>(mLocalPolicies.get(userId).keySet());
1483             for (PolicyKey policy : localPolicies) {
1484                 PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
1485                 Set<EnforcingAdmin> admins = new HashSet<>(
1486                         policyState.getPoliciesSetByAdmins().keySet());
1487                 for (EnforcingAdmin admin : admins) {
1488                     removeLocalPolicy(
1489                             policyState.getPolicyDefinition(), admin, userId);
1490                 }
1491             }
1492 
1493             mLocalPolicies.remove(userId);
1494         }
1495     }
1496 
1497     /**
1498      * Removes all local and global policies for admins installed in the provided
1499      * {@code userId}.
1500      */
removePoliciesForAdminsOnUser(int userId)1501     private void removePoliciesForAdminsOnUser(int userId) {
1502         Set<EnforcingAdmin> admins = getEnforcingAdminsOnUser(userId);
1503 
1504         for (EnforcingAdmin admin : admins) {
1505             removePoliciesForAdmin(admin);
1506         }
1507     }
1508 
1509     /**
1510      * Reestablishes the service that handles
1511      * {@link DevicePolicyManager#ACTION_DEVICE_ADMIN_SERVICE} in the enforcing admin if the package
1512      * was updated, as a package update results in the persistent connection getting reset.
1513      */
updateDeviceAdminServiceOnPackageChanged( @onNull String updatedPackage, int userId)1514     private void updateDeviceAdminServiceOnPackageChanged(
1515             @NonNull String updatedPackage, int userId) {
1516         for (EnforcingAdmin admin : getEnforcingAdminsOnUser(userId)) {
1517             // DPCs are handled separately in DPMS, no need to reestablish the connection here.
1518             if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
1519                 continue;
1520             }
1521             if (updatedPackage.equals(admin.getPackageName())) {
1522                 mDeviceAdminServiceController.startServiceForAdmin(
1523                         updatedPackage, userId, /* actionForLog= */ "package-broadcast");
1524             }
1525         }
1526     }
1527 
1528     /**
1529      * Called after an admin policy has been added to start binding to the admin if a connection
1530      * was not already established.
1531      */
1532     @GuardedBy("mLock")
updateDeviceAdminServiceOnPolicyAddLocked(@onNull EnforcingAdmin enforcingAdmin)1533     private void updateDeviceAdminServiceOnPolicyAddLocked(@NonNull EnforcingAdmin enforcingAdmin) {
1534         int userId = enforcingAdmin.getUserId();
1535 
1536         if (mEnforcingAdmins.contains(userId)
1537                 && mEnforcingAdmins.get(userId).contains(enforcingAdmin)) {
1538             return;
1539         }
1540 
1541         if (!mEnforcingAdmins.contains(enforcingAdmin.getUserId())) {
1542             mEnforcingAdmins.put(enforcingAdmin.getUserId(), new HashSet<>());
1543         }
1544         mEnforcingAdmins.get(enforcingAdmin.getUserId()).add(enforcingAdmin);
1545 
1546         // A connection is established with DPCs as soon as they are provisioned, so no need to
1547         // connect when a policy is set.
1548         if (enforcingAdmin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
1549             return;
1550         }
1551         mDeviceAdminServiceController.startServiceForAdmin(
1552                 enforcingAdmin.getPackageName(),
1553                 userId,
1554                 /* actionForLog= */ "policy-added");
1555     }
1556 
1557     /**
1558      * Called after an admin policy has been removed to stop binding to the admin if they no longer
1559      * have any policies set.
1560      */
1561     @GuardedBy("mLock")
updateDeviceAdminServiceOnPolicyRemoveLocked( @onNull EnforcingAdmin enforcingAdmin)1562     private void updateDeviceAdminServiceOnPolicyRemoveLocked(
1563             @NonNull EnforcingAdmin enforcingAdmin) {
1564         if (doesAdminHavePoliciesLocked(enforcingAdmin)) {
1565             return;
1566         }
1567         int userId = enforcingAdmin.getUserId();
1568         if (mEnforcingAdmins.contains(userId)) {
1569             mEnforcingAdmins.get(userId).remove(enforcingAdmin);
1570             if (mEnforcingAdmins.get(userId).isEmpty()) {
1571                 mEnforcingAdmins.remove(enforcingAdmin.getUserId());
1572             }
1573         }
1574 
1575         // TODO(b/263364434): centralise handling in one place.
1576         // DPCs rely on a constant connection being established as soon as they are provisioned,
1577         // so we shouldn't disconnect it even if they no longer have policies set.
1578         if (enforcingAdmin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) {
1579             return;
1580         }
1581         mDeviceAdminServiceController.stopServiceForAdmin(
1582                 enforcingAdmin.getPackageName(),
1583                 userId,
1584                 /* actionForLog= */ "policy-removed");
1585     }
1586 
1587     @GuardedBy("mLock")
doesAdminHavePoliciesLocked(@onNull EnforcingAdmin enforcingAdmin)1588     private boolean doesAdminHavePoliciesLocked(@NonNull EnforcingAdmin enforcingAdmin) {
1589         for (PolicyKey policy : mGlobalPolicies.keySet()) {
1590             PolicyState<?> policyState = mGlobalPolicies.get(policy);
1591             if (policyState.getPoliciesSetByAdmins().containsKey(enforcingAdmin)) {
1592                 return true;
1593             }
1594         }
1595         for (int i = 0; i < mLocalPolicies.size(); i++) {
1596             for (PolicyKey policy : mLocalPolicies.get(mLocalPolicies.keyAt(i)).keySet()) {
1597                 PolicyState<?> policyState = mLocalPolicies.get(
1598                         mLocalPolicies.keyAt(i)).get(policy);
1599                 if (policyState.getPoliciesSetByAdmins().containsKey(enforcingAdmin)) {
1600                     return true;
1601                 }
1602             }
1603         }
1604         return false;
1605     }
1606 
1607     @NonNull
getEnforcingAdminsOnUser(int userId)1608     private Set<EnforcingAdmin> getEnforcingAdminsOnUser(int userId) {
1609         synchronized (mLock) {
1610             return mEnforcingAdmins.contains(userId)
1611                     ? new HashSet<>(mEnforcingAdmins.get(userId)) : Collections.emptySet();
1612         }
1613     }
1614 
1615     /**
1616      * Calculate the size of a policy in bytes
1617      */
sizeOf(PolicyValue<V> value)1618     private static <V> int sizeOf(PolicyValue<V> value) {
1619         try {
1620             Parcel parcel = Parcel.obtain();
1621             parcel.writeParcelable(value, /* flags= */ 0);
1622 
1623             parcel.setDataPosition(0);
1624 
1625             byte[] bytes;
1626 
1627             bytes = parcel.marshall();
1628             return bytes.length;
1629         } catch (Exception e) {
1630             Log.e(TAG, "Error calculating size of policy: " + e);
1631             return 0;
1632         }
1633     }
1634 
1635     /**
1636      * Checks if the policy already exists and removes the current size to prevent recording the
1637      * same policy twice.
1638      *
1639      * Checks if the new sum of the size of all policies is less than the maximum sum of policies
1640      * size per admin and returns true.
1641      *
1642      * If the policy size limit is reached then send policy result to admin and return false.
1643      */
handleAdminPolicySizeLimit(PolicyState<V> policyState, EnforcingAdmin admin, PolicyValue<V> value, PolicyDefinition<V> policyDefinition, int userId)1644     private <V> boolean handleAdminPolicySizeLimit(PolicyState<V> policyState, EnforcingAdmin admin,
1645             PolicyValue<V> value, PolicyDefinition<V> policyDefinition, int userId) {
1646         int currentAdminPoliciesSize = 0;
1647         int existingPolicySize = 0;
1648         if (mAdminPolicySize.contains(admin.getUserId())
1649                 && mAdminPolicySize.get(
1650                 admin.getUserId()).containsKey(admin)) {
1651             currentAdminPoliciesSize = mAdminPolicySize.get(admin.getUserId()).get(admin);
1652         }
1653         if (policyState.getPoliciesSetByAdmins().containsKey(admin)) {
1654             existingPolicySize = sizeOf(policyState.getPoliciesSetByAdmins().get(admin));
1655         }
1656         int policySize = sizeOf(value);
1657 
1658         // Policy size limit is disabled if mPolicySizeLimit is -1.
1659         if (mPolicySizeLimit == -1
1660                 || currentAdminPoliciesSize + policySize - existingPolicySize < mPolicySizeLimit) {
1661             increasePolicySizeForAdmin(
1662                     admin, /* policySizeDiff = */ policySize - existingPolicySize);
1663             return true;
1664         } else {
1665             Log.w(TAG, "Admin " + admin + "reached max allowed storage limit.");
1666             sendPolicyResultToAdmin(
1667                     admin,
1668                     policyDefinition,
1669                     RESULT_FAILURE_STORAGE_LIMIT_REACHED,
1670                     userId);
1671             return false;
1672         }
1673     }
1674 
1675     /**
1676      * Increase the int in mAdminPolicySize representing the size of the sum of all
1677      * active policies for that admin.
1678      */
increasePolicySizeForAdmin(EnforcingAdmin admin, int policySizeDiff)1679     private <V> void increasePolicySizeForAdmin(EnforcingAdmin admin, int policySizeDiff) {
1680         if (!mAdminPolicySize.contains(admin.getUserId())) {
1681             mAdminPolicySize.put(admin.getUserId(), new HashMap<>());
1682         }
1683         if (!mAdminPolicySize.get(admin.getUserId()).containsKey(admin)) {
1684             mAdminPolicySize.get(admin.getUserId()).put(admin, /* size= */ 0);
1685         }
1686         mAdminPolicySize.get(admin.getUserId()).put(admin,
1687                 mAdminPolicySize.get(admin.getUserId()).get(admin) + policySizeDiff);
1688     }
1689 
1690     /**
1691      * Decrease the int in mAdminPolicySize representing the size of the sum of all
1692      * active policies for that admin.
1693      */
decreasePolicySizeForAdmin(PolicyState<V> policyState, EnforcingAdmin admin)1694     private <V> void decreasePolicySizeForAdmin(PolicyState<V> policyState, EnforcingAdmin admin) {
1695         if (!policyState.getPoliciesSetByAdmins().containsKey(admin)
1696                 || !mAdminPolicySize.contains(admin.getUserId())
1697                 || !mAdminPolicySize.get(admin.getUserId()).containsKey(admin)) {
1698             return;
1699         }
1700         mAdminPolicySize.get(admin.getUserId()).put(admin,
1701                 mAdminPolicySize.get(admin.getUserId()).get(admin) - sizeOf(
1702                         policyState.getPoliciesSetByAdmins().get(admin)));
1703         if (mAdminPolicySize.get(admin.getUserId()).get(admin) <= 0) {
1704             mAdminPolicySize.get(admin.getUserId()).remove(admin);
1705         }
1706         if (mAdminPolicySize.get(admin.getUserId()).isEmpty()) {
1707             mAdminPolicySize.remove(admin.getUserId());
1708         }
1709     }
1710 
1711     /**
1712      * Updates the max allowed size limit for policies per admin. Setting it to -1, disables
1713      * the limitation.
1714      */
setMaxPolicyStorageLimit(int storageLimit)1715     void setMaxPolicyStorageLimit(int storageLimit) {
1716         mPolicySizeLimit = storageLimit;
1717     }
1718 
1719     /**
1720      * Returns the max allowed size limit for policies per admin. -1 means the limitation is
1721      * disabled.
1722      */
getMaxPolicyStorageLimit()1723     int getMaxPolicyStorageLimit() {
1724         return mPolicySizeLimit;
1725     }
1726 
getPolicySizeForAdmin(EnforcingAdmin admin)1727     int getPolicySizeForAdmin(EnforcingAdmin admin) {
1728         if (mAdminPolicySize.contains(admin.getUserId())
1729                 && mAdminPolicySize.get(
1730                 admin.getUserId()).containsKey(admin)) {
1731             return mAdminPolicySize.get(admin.getUserId()).get(admin);
1732         }
1733         return 0;
1734     }
1735 
dump(IndentingPrintWriter pw)1736     public void dump(IndentingPrintWriter pw) {
1737         synchronized (mLock) {
1738             pw.println("Local Policies: ");
1739             pw.increaseIndent();
1740             for (int i = 0; i < mLocalPolicies.size(); i++) {
1741                 int userId = mLocalPolicies.keyAt(i);
1742                 pw.printf("User %d:\n", userId);
1743                 pw.increaseIndent();
1744                 for (PolicyKey policy : mLocalPolicies.get(userId).keySet()) {
1745                     PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
1746                     policyState.dump(pw);
1747                     pw.println();
1748                 }
1749                 pw.decreaseIndent();
1750             }
1751             pw.decreaseIndent();
1752             pw.println();
1753 
1754             pw.println("Global Policies: ");
1755             pw.increaseIndent();
1756             for (PolicyKey policy : mGlobalPolicies.keySet()) {
1757                 PolicyState<?> policyState = mGlobalPolicies.get(policy);
1758                 policyState.dump(pw);
1759                 pw.println();
1760             }
1761             pw.decreaseIndent();
1762             pw.println();
1763 
1764             pw.println("Default admin policy size limit: " + DEFAULT_POLICY_SIZE_LIMIT);
1765             pw.println("Current admin policy size limit: " + mPolicySizeLimit);
1766             pw.println("Admin Policies size: ");
1767             for (int i = 0; i < mAdminPolicySize.size(); i++) {
1768                 int userId = mAdminPolicySize.keyAt(i);
1769                 pw.printf("User %d:\n", userId);
1770                 pw.increaseIndent();
1771                 for (EnforcingAdmin admin : mAdminPolicySize.get(userId).keySet()) {
1772                     pw.printf("Admin : " + admin + " : " + mAdminPolicySize.get(userId).get(
1773                             admin));
1774                     pw.println();
1775                 }
1776                 pw.decreaseIndent();
1777             }
1778             pw.decreaseIndent();
1779         }
1780     }
1781 
write()1782     private void write() {
1783         synchronized (mLock) {
1784             Log.d(TAG, "Writing device policies to file.");
1785             new DevicePoliciesReaderWriter().writeToFileLocked();
1786         }
1787     }
1788 
1789     // TODO(b/256852787): trigger resolving logic after loading policies as roles are recalculated
1790     //  and could result in a different enforced policy
load()1791     void load() {
1792         Log.d(TAG, "Reading device policies from file.");
1793         synchronized (mLock) {
1794             clear();
1795             new DevicePoliciesReaderWriter().readFromFileLocked();
1796         }
1797     }
1798 
1799     /**
1800      * Create a backup of the policy engine XML file, so that we can recover previous state
1801      * in case some data-loss bug is triggered e.g. during migration.
1802      *
1803      * Backup is only created if one with the same ID does not exist yet.
1804      */
createBackup(String backupId)1805     void createBackup(String backupId) {
1806         synchronized (mLock) {
1807             DevicePoliciesReaderWriter.createBackup(backupId);
1808         }
1809     }
1810 
1811     @GuardedBy("mLock")
reapplyAllPoliciesOnBootLocked()1812     <V> void reapplyAllPoliciesOnBootLocked() {
1813         for (PolicyKey policy : mGlobalPolicies.keySet()) {
1814             PolicyState<?> policyState = mGlobalPolicies.get(policy);
1815             // Policy definition and value will always be of the same type
1816             PolicyDefinition<V> policyDefinition =
1817                     (PolicyDefinition<V>) policyState.getPolicyDefinition();
1818             if (!policyDefinition.shouldSkipEnforcementIfNotChanged()) {
1819                 PolicyValue<V> policyValue =
1820                         (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
1821                 enforcePolicy(policyDefinition, policyValue, UserHandle.USER_ALL);
1822             }
1823         }
1824         for (int i = 0; i < mLocalPolicies.size(); i++) {
1825             int userId = mLocalPolicies.keyAt(i);
1826             for (PolicyKey policy : mLocalPolicies.get(userId).keySet()) {
1827                 PolicyState<?> policyState = mLocalPolicies.get(userId).get(policy);
1828                 // Policy definition and value will always be of the same type
1829                 PolicyDefinition<V> policyDefinition =
1830                         (PolicyDefinition<V>) policyState.getPolicyDefinition();
1831                 if (!policyDefinition.shouldSkipEnforcementIfNotChanged()) {
1832                     PolicyValue<V> policyValue =
1833                             (PolicyValue<V>) policyState.getCurrentResolvedPolicy();
1834                     enforcePolicy(policyDefinition, policyValue, userId);
1835                 }
1836             }
1837         }
1838     }
1839 
1840     /**
1841      * Clear all policies set in the policy engine.
1842      *
1843      * <p>Note that this doesn't clear any enforcements, it only clears the data structures.
1844      */
clearAllPolicies()1845     void clearAllPolicies() {
1846         clear();
1847         write();
1848     }
1849 
clear()1850     private void clear() {
1851         synchronized (mLock) {
1852             mGlobalPolicies.clear();
1853             mLocalPolicies.clear();
1854             mEnforcingAdmins.clear();
1855             mAdminPolicySize.clear();
1856         }
1857     }
1858 
checkFor2gFailure(@onNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin)1859     private <V> boolean checkFor2gFailure(@NonNull PolicyDefinition<V> policyDefinition,
1860             @NonNull EnforcingAdmin enforcingAdmin) {
1861         if (!policyDefinition.getPolicyKey().getIdentifier().equals(
1862                 CELLULAR_2G_USER_RESTRICTION_ID)) {
1863             return false;
1864         }
1865 
1866         boolean isCapabilitySupported;
1867         try {
1868             isCapabilitySupported = mContext.getSystemService(
1869                     TelephonyManager.class).isRadioInterfaceCapabilitySupported(
1870                     TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK);
1871         } catch (IllegalStateException e) {
1872             // isRadioInterfaceCapabilitySupported can throw if there is no Telephony
1873             // service initialized.
1874             isCapabilitySupported = false;
1875         }
1876 
1877         if (!isCapabilitySupported) {
1878             sendPolicyResultToAdmin(
1879                     enforcingAdmin,
1880                     policyDefinition,
1881                     RESULT_FAILURE_HARDWARE_LIMITATION,
1882                     UserHandle.USER_ALL);
1883             return true;
1884         }
1885 
1886         return false;
1887     }
1888 
1889     /**
1890      * For PackageSetUnion policies, we can't simply compare the resolved policy against the admin's
1891      * policy for equality to determine if the admin has applied the policy successfully, instead
1892      * the admin's policy should be considered applied successfully as long as its policy is subset
1893      * of the resolved policy. This method controls which policies should use this special logic.
1894      */
shouldApplyPackageSetUnionPolicyHack(PolicyDefinition<V> policy)1895     private <V> boolean shouldApplyPackageSetUnionPolicyHack(PolicyDefinition<V> policy) {
1896         String policyKey = policy.getPolicyKey().getIdentifier();
1897         return policyKey.equals(USER_CONTROL_DISABLED_PACKAGES_POLICY)
1898                 || policyKey.equals(PACKAGES_SUSPENDED_POLICY);
1899     }
1900 
1901     private class DevicePoliciesReaderWriter {
1902         private static final String DEVICE_POLICIES_XML = "device_policy_state.xml";
1903         private static final String BACKUP_DIRECTORY = "device_policy_backups";
1904         private static final String BACKUP_FILENAME = "device_policy_state.%s.xml";
1905         private static final String TAG_LOCAL_POLICY_ENTRY = "local-policy-entry";
1906         private static final String TAG_GLOBAL_POLICY_ENTRY = "global-policy-entry";
1907         private static final String TAG_POLICY_STATE_ENTRY = "policy-state-entry";
1908         private static final String TAG_POLICY_KEY_ENTRY = "policy-key-entry";
1909         private static final String TAG_ENFORCING_ADMINS_ENTRY = "enforcing-admins-entry";
1910         private static final String TAG_ENFORCING_ADMIN_AND_SIZE = "enforcing-admin-and-size";
1911         private static final String TAG_ENFORCING_ADMIN = "enforcing-admin";
1912         private static final String TAG_POLICY_SUM_SIZE = "policy-sum-size";
1913         private static final String TAG_MAX_POLICY_SIZE_LIMIT = "max-policy-size-limit";
1914         private static final String ATTR_USER_ID = "user-id";
1915         private static final String ATTR_POLICY_SUM_SIZE = "size";
1916 
1917         private final File mFile;
1918 
getFileName()1919         private static File getFileName() {
1920             return new File(Environment.getDataSystemDirectory(), DEVICE_POLICIES_XML);
1921         }
1922 
DevicePoliciesReaderWriter()1923         private DevicePoliciesReaderWriter() {
1924             mFile = getFileName();
1925         }
1926 
createBackup(String backupId)1927         public static void createBackup(String backupId) {
1928             try {
1929                 File backupDirectory = new File(Environment.getDataSystemDirectory(),
1930                         BACKUP_DIRECTORY);
1931                 backupDirectory.mkdir();
1932                 Path backupPath = Path.of(backupDirectory.getPath(),
1933                         BACKUP_FILENAME.formatted(backupId));
1934                 if (backupPath.toFile().exists()) {
1935                     Log.w(TAG, "Backup already exist: " + backupPath);
1936                 } else {
1937                     Files.copy(getFileName().toPath(), backupPath,
1938                             StandardCopyOption.REPLACE_EXISTING);
1939                     Log.i(TAG, "Backup created at " + backupPath);
1940                 }
1941             } catch (Exception e) {
1942                 Log.e(TAG, "Cannot create backup " + backupId, e);
1943             }
1944         }
1945 
1946         @GuardedBy("mLock")
writeToFileLocked()1947         void writeToFileLocked() {
1948             Log.d(TAG, "Writing to " + mFile);
1949 
1950             AtomicFile f = new AtomicFile(mFile);
1951             FileOutputStream outputStream = null;
1952             try {
1953                 outputStream = f.startWrite();
1954                 TypedXmlSerializer out = Xml.resolveSerializer(outputStream);
1955 
1956                 out.startDocument(null, true);
1957 
1958                 // Actual content
1959                 writeInnerLocked(out);
1960 
1961                 out.endDocument();
1962                 out.flush();
1963 
1964                 // Commit the content.
1965                 f.finishWrite(outputStream);
1966                 outputStream = null;
1967 
1968             } catch (IOException e) {
1969                 Log.e(TAG, "Exception when writing", e);
1970                 if (outputStream != null) {
1971                     f.failWrite(outputStream);
1972                 }
1973             }
1974         }
1975 
1976         @GuardedBy("mLock")
1977         // TODO(b/256846294): Add versioning to read/write
writeInnerLocked(TypedXmlSerializer serializer)1978         void writeInnerLocked(TypedXmlSerializer serializer) throws IOException {
1979             writeLocalPoliciesInnerLocked(serializer);
1980             writeGlobalPoliciesInnerLocked(serializer);
1981             writeEnforcingAdminsInnerLocked(serializer);
1982             writeEnforcingAdminSizeInnerLocked(serializer);
1983             writeMaxPolicySizeInnerLocked(serializer);
1984         }
1985 
1986         @GuardedBy("mLock")
writeLocalPoliciesInnerLocked(TypedXmlSerializer serializer)1987         private void writeLocalPoliciesInnerLocked(TypedXmlSerializer serializer)
1988                 throws IOException {
1989             if (mLocalPolicies != null) {
1990                 for (int i = 0; i < mLocalPolicies.size(); i++) {
1991                     int userId = mLocalPolicies.keyAt(i);
1992                     for (Map.Entry<PolicyKey, PolicyState<?>> policy : mLocalPolicies.get(
1993                             userId).entrySet()) {
1994                         serializer.startTag(/* namespace= */ null, TAG_LOCAL_POLICY_ENTRY);
1995 
1996                         serializer.attributeInt(/* namespace= */ null, ATTR_USER_ID, userId);
1997 
1998                         serializer.startTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY);
1999                         policy.getKey().saveToXml(serializer);
2000                         serializer.endTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY);
2001 
2002                         serializer.startTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY);
2003                         policy.getValue().saveToXml(serializer);
2004                         serializer.endTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY);
2005 
2006                         serializer.endTag(/* namespace= */ null, TAG_LOCAL_POLICY_ENTRY);
2007                     }
2008                 }
2009             }
2010         }
2011 
2012         @GuardedBy("mLock")
writeGlobalPoliciesInnerLocked(TypedXmlSerializer serializer)2013         private void writeGlobalPoliciesInnerLocked(TypedXmlSerializer serializer)
2014                 throws IOException {
2015             if (mGlobalPolicies != null) {
2016                 for (Map.Entry<PolicyKey, PolicyState<?>> policy : mGlobalPolicies.entrySet()) {
2017                     serializer.startTag(/* namespace= */ null, TAG_GLOBAL_POLICY_ENTRY);
2018 
2019                     serializer.startTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY);
2020                     policy.getKey().saveToXml(serializer);
2021                     serializer.endTag(/* namespace= */ null, TAG_POLICY_KEY_ENTRY);
2022 
2023                     serializer.startTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY);
2024                     policy.getValue().saveToXml(serializer);
2025                     serializer.endTag(/* namespace= */ null, TAG_POLICY_STATE_ENTRY);
2026 
2027                     serializer.endTag(/* namespace= */ null, TAG_GLOBAL_POLICY_ENTRY);
2028                 }
2029             }
2030         }
2031 
2032         @GuardedBy("mLock")
writeEnforcingAdminsInnerLocked(TypedXmlSerializer serializer)2033         private void writeEnforcingAdminsInnerLocked(TypedXmlSerializer serializer)
2034                 throws IOException {
2035             if (mEnforcingAdmins != null) {
2036                 for (int i = 0; i < mEnforcingAdmins.size(); i++) {
2037                     int userId = mEnforcingAdmins.keyAt(i);
2038                     for (EnforcingAdmin admin : mEnforcingAdmins.get(userId)) {
2039                         serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMINS_ENTRY);
2040                         admin.saveToXml(serializer);
2041                         serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMINS_ENTRY);
2042                     }
2043                 }
2044             }
2045         }
2046 
2047         @GuardedBy("mLock")
writeEnforcingAdminSizeInnerLocked(TypedXmlSerializer serializer)2048         private void writeEnforcingAdminSizeInnerLocked(TypedXmlSerializer serializer)
2049                 throws IOException {
2050             if (mAdminPolicySize != null) {
2051                 for (int i = 0; i < mAdminPolicySize.size(); i++) {
2052                     int userId = mAdminPolicySize.keyAt(i);
2053                     for (EnforcingAdmin admin : mAdminPolicySize.get(
2054                             userId).keySet()) {
2055                         serializer.startTag(/* namespace= */ null,
2056                                 TAG_ENFORCING_ADMIN_AND_SIZE);
2057                         serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN);
2058                         admin.saveToXml(serializer);
2059                         serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN);
2060                         serializer.startTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE);
2061                         serializer.attributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE,
2062                                 mAdminPolicySize.get(userId).get(admin));
2063                         serializer.endTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE);
2064                         serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_AND_SIZE);
2065                     }
2066                 }
2067             }
2068         }
2069 
2070         @GuardedBy("mLock")
writeMaxPolicySizeInnerLocked(TypedXmlSerializer serializer)2071         private void writeMaxPolicySizeInnerLocked(TypedXmlSerializer serializer)
2072                 throws IOException {
2073             serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
2074             serializer.attributeInt(
2075                     /* namespace= */ null, ATTR_POLICY_SUM_SIZE, mPolicySizeLimit);
2076             serializer.endTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT);
2077         }
2078 
2079         @GuardedBy("mLock")
readFromFileLocked()2080         void readFromFileLocked() {
2081             if (!mFile.exists()) {
2082                 Log.d(TAG, "" + mFile + " doesn't exist");
2083                 return;
2084             }
2085 
2086             Log.d(TAG, "Reading from " + mFile);
2087             AtomicFile f = new AtomicFile(mFile);
2088             InputStream input = null;
2089             try {
2090                 input = f.openRead();
2091                 TypedXmlPullParser parser = Xml.resolvePullParser(input);
2092 
2093                 readInnerLocked(parser);
2094 
2095             } catch (XmlPullParserException | IOException | ClassNotFoundException e) {
2096                 Slogf.wtf(TAG, "Error parsing resources file", e);
2097             } finally {
2098                 IoUtils.closeQuietly(input);
2099             }
2100         }
2101 
2102         @GuardedBy("mLock")
readInnerLocked(TypedXmlPullParser parser)2103         private void readInnerLocked(TypedXmlPullParser parser)
2104                 throws IOException, XmlPullParserException, ClassNotFoundException {
2105             int outerDepth = parser.getDepth();
2106             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2107                 String tag = parser.getName();
2108                 switch (tag) {
2109                     case TAG_LOCAL_POLICY_ENTRY:
2110                         int userId = parser.getAttributeInt(/* namespace= */ null, ATTR_USER_ID);
2111                         if (!mLocalPolicies.contains(userId)) {
2112                             mLocalPolicies.put(userId, new HashMap<>());
2113                         }
2114                         readPoliciesInner(parser, mLocalPolicies.get(userId));
2115                         break;
2116                     case TAG_GLOBAL_POLICY_ENTRY:
2117                         readPoliciesInner(parser, mGlobalPolicies);
2118                         break;
2119                     case TAG_ENFORCING_ADMINS_ENTRY:
2120                         readEnforcingAdminsInner(parser);
2121                         break;
2122                     case TAG_ENFORCING_ADMIN_AND_SIZE:
2123                         readEnforcingAdminAndSizeInner(parser);
2124                         break;
2125                     case TAG_MAX_POLICY_SIZE_LIMIT:
2126                         readMaxPolicySizeInner(parser);
2127                         break;
2128                     default:
2129                         Slogf.wtf(TAG, "Unknown tag " + tag);
2130                 }
2131             }
2132         }
2133 
readPoliciesInner( TypedXmlPullParser parser, Map<PolicyKey, PolicyState<?>> policyStateMap)2134         private static void readPoliciesInner(
2135                 TypedXmlPullParser parser, Map<PolicyKey, PolicyState<?>> policyStateMap)
2136                 throws IOException, XmlPullParserException {
2137             PolicyKey policyKey = null;
2138             PolicyDefinition<?> policyDefinition = null;
2139             PolicyState<?> policyState = null;
2140             int outerDepth = parser.getDepth();
2141             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2142                 String tag = parser.getName();
2143                 switch (tag) {
2144                     case TAG_POLICY_KEY_ENTRY:
2145                         policyDefinition = PolicyDefinition.readFromXml(parser);
2146                         if (policyDefinition != null) {
2147                             policyKey = policyDefinition.getPolicyKey();
2148                         }
2149                         break;
2150                     case TAG_POLICY_STATE_ENTRY:
2151                         if (policyDefinition == null) {
2152                             Slogf.w(TAG, "Skipping policy state - unknown policy definition");
2153                         } else {
2154                             policyState = PolicyState.readFromXml(policyDefinition, parser);
2155                         }
2156                         break;
2157                     default:
2158                         Slogf.wtf(TAG, "Unknown tag for policy entry" + tag);
2159                 }
2160             }
2161 
2162             if (policyKey == null || policyState == null) {
2163                 Slogf.wtf(TAG, "Error parsing policy, policyKey is %s, and policyState is %s.",
2164                         policyKey, policyState);
2165                 return;
2166             }
2167 
2168             policyStateMap.put(policyKey, policyState);
2169         }
2170 
readEnforcingAdminsInner(TypedXmlPullParser parser)2171         private void readEnforcingAdminsInner(TypedXmlPullParser parser)
2172                 throws XmlPullParserException {
2173             EnforcingAdmin admin = EnforcingAdmin.readFromXml(parser);
2174             if (admin == null) {
2175                 Slogf.wtf(TAG, "Error parsing enforcingAdmins, EnforcingAdmin is null.");
2176                 return;
2177             }
2178             if (!mEnforcingAdmins.contains(admin.getUserId())) {
2179                 mEnforcingAdmins.put(admin.getUserId(), new HashSet<>());
2180             }
2181             mEnforcingAdmins.get(admin.getUserId()).add(admin);
2182         }
2183 
readEnforcingAdminAndSizeInner(TypedXmlPullParser parser)2184         private void readEnforcingAdminAndSizeInner(TypedXmlPullParser parser)
2185                 throws XmlPullParserException, IOException {
2186             int outerDepth = parser.getDepth();
2187             EnforcingAdmin admin = null;
2188             int size = 0;
2189             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2190                 String tag = parser.getName();
2191                 switch (tag) {
2192                     case TAG_ENFORCING_ADMIN:
2193                         admin = EnforcingAdmin.readFromXml(parser);
2194                         break;
2195                     case TAG_POLICY_SUM_SIZE:
2196                         size = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
2197                         break;
2198                     default:
2199                         Slogf.wtf(TAG, "Unknown tag " + tag);
2200                 }
2201             }
2202             if (admin == null) {
2203                 Slogf.wtf(TAG, "Error parsing enforcingAdmins, EnforcingAdmin is null.");
2204                 return;
2205             }
2206             if (size <= 0) {
2207                 Slogf.wtf(TAG, "Error parsing policy size, size is " + size);
2208                 return;
2209             }
2210             if (!mAdminPolicySize.contains(admin.getUserId())) {
2211                 mAdminPolicySize.put(admin.getUserId(), new HashMap<>());
2212             }
2213             mAdminPolicySize.get(admin.getUserId()).put(admin, size);
2214         }
2215 
readMaxPolicySizeInner(TypedXmlPullParser parser)2216         private void readMaxPolicySizeInner(TypedXmlPullParser parser)
2217                 throws XmlPullParserException, IOException {
2218             mPolicySizeLimit = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE);
2219         }
2220     }
2221 }
2222