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