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