• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.bedstead.nene.devicepolicy;
18 
19 import static android.Manifest.permission.CREATE_USERS;
20 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
21 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
22 import static android.app.role.RoleManager.ROLE_DEVICE_POLICY_MANAGEMENT;
23 import static android.os.Build.VERSION.SDK_INT;
24 import static android.os.Build.VERSION_CODES.TIRAMISU;
25 import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
26 
27 import static com.android.bedstead.nene.permissions.CommonPermissions.FORCE_DEVICE_POLICY_MANAGER_LOGS;
28 import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_DEVICE_ADMINS;
29 import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_PROFILE_AND_DEVICE_OWNERS;
30 import static com.android.bedstead.nene.permissions.CommonPermissions.MANAGE_ROLE_HOLDERS;
31 import static com.android.bedstead.nene.permissions.CommonPermissions.QUERY_ADMIN_POLICY;
32 
33 import android.annotation.TargetApi;
34 import android.app.admin.DevicePolicyManager;
35 import android.content.ComponentName;
36 import android.content.Intent;
37 import android.content.pm.PackageManager;
38 import android.content.pm.ResolveInfo;
39 import android.os.Build;
40 import android.os.PersistableBundle;
41 import android.os.UserHandle;
42 import android.util.Log;
43 
44 import androidx.annotation.Nullable;
45 
46 import com.android.bedstead.nene.TestApis;
47 import com.android.bedstead.nene.annotations.Experimental;
48 import com.android.bedstead.nene.exceptions.AdbException;
49 import com.android.bedstead.nene.exceptions.AdbParseException;
50 import com.android.bedstead.nene.exceptions.NeneException;
51 import com.android.bedstead.nene.logcat.BlockingLogcatListener;
52 import com.android.bedstead.nene.packages.ComponentReference;
53 import com.android.bedstead.nene.packages.Package;
54 import com.android.bedstead.nene.permissions.CommonPermissions;
55 import com.android.bedstead.nene.permissions.PermissionContext;
56 import com.android.bedstead.nene.roles.RoleContext;
57 import com.android.bedstead.nene.users.UserReference;
58 import com.android.bedstead.nene.utils.Poll;
59 import com.android.bedstead.nene.utils.Retry;
60 import com.android.bedstead.nene.utils.ShellCommand;
61 import com.android.bedstead.nene.utils.ShellCommandUtils;
62 import com.android.bedstead.nene.utils.Versions;
63 
64 import java.lang.reflect.InvocationTargetException;
65 import java.time.Duration;
66 import java.util.HashSet;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Set;
70 import java.util.stream.Collectors;
71 
72 /**
73  * Test APIs related to device policy.
74  */
75 public final class DevicePolicy {
76 
77     public static final DevicePolicy sInstance = new DevicePolicy();
78 
79     private static final String LOG_TAG = "DevicePolicy";
80 
81     private final AdbDevicePolicyParser mParser;
82 
83     private DeviceOwner mCachedDeviceOwner;
84     private Map<UserReference, ProfileOwner> mCachedProfileOwners;
85 
86     private static final DevicePolicyManager sDevicePolicyManager =
87             TestApis.context().instrumentedContext()
88                     .getSystemService(DevicePolicyManager.class);
89 
DevicePolicy()90     private DevicePolicy() {
91         mParser = AdbDevicePolicyParser.get(SDK_INT);
92     }
93 
94     /**
95      * Set the profile owner for a given {@link UserReference}.
96      */
setProfileOwner(UserReference user, ComponentName profileOwnerComponent)97     public ProfileOwner setProfileOwner(UserReference user, ComponentName profileOwnerComponent) {
98         if (user == null || profileOwnerComponent == null) {
99             throw new NullPointerException();
100         }
101 
102         ShellCommand.Builder command =
103                 ShellCommand.builderForUser(user, "dpm set-profile-owner")
104                 .addOperand(profileOwnerComponent.flattenToShortString())
105                 .validate(ShellCommandUtils::startsWithSuccess);
106 
107         // TODO(b/187925230): If it fails, we check for terminal failure states - and if not
108         //  we retry because if the profile owner was recently removed, it can take some time
109         //  to be allowed to set it again
110         try {
111             Retry.logic(command::execute)
112                     .terminalException((ex) -> {
113 
114                         if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
115                             return false; // Just retry on old versions as we don't have stderr
116                         }
117                         if (ex instanceof AdbException) {
118                             String error = ((AdbException) ex).error();
119                             if (error != null && error.contains("is already set")) {
120                                 // This can happen for a while when it is being tidied up
121                                 return false;
122                             }
123 
124                             if (error != null && error.contains("is being removed")) {
125                                 return false;
126                             }
127                         }
128 
129                         // Assume all other errors are terminal
130                         return true;
131                     })
132                     .timeout(Duration.ofMinutes(5))
133                     .run();
134         } catch (Throwable e) {
135             throw new NeneException("Could not set profile owner for user "
136                     + user + " component " + profileOwnerComponent, e);
137         }
138 
139         Poll.forValue("Profile Owner", () -> TestApis.devicePolicy().getProfileOwner(user))
140                 .toNotBeNull()
141                 .errorOnFail()
142                 .await();
143 
144         return new ProfileOwner(user,
145                 TestApis.packages().find(
146                         profileOwnerComponent.getPackageName()), profileOwnerComponent);
147     }
148 
149     /**
150      * Get the organization owned profile owner for the device, if any, otherwise null.
151      */
getOrganizationOwnedProfileOwner()152     public ProfileOwner getOrganizationOwnedProfileOwner() {
153         for (UserReference user : TestApis.users().all()) {
154             ProfileOwner profileOwner = getProfileOwner(user);
155             if (profileOwner != null && profileOwner.isOrganizationOwned()) {
156                 return profileOwner;
157             }
158         }
159 
160         return null;
161     }
162 
163 
164     /**
165      * Get the profile owner for the instrumented user.
166      */
getProfileOwner()167     public ProfileOwner getProfileOwner() {
168         return getProfileOwner(TestApis.users().instrumented());
169     }
170 
171     /**
172      * Get the profile owner for a given {@link UserHandle}.
173      */
getProfileOwner(UserHandle user)174     public ProfileOwner getProfileOwner(UserHandle user) {
175         return getProfileOwner(UserReference.of(user));
176     }
177 
178     /**
179      * Get the profile owner for a given {@link UserReference}.
180      */
getProfileOwner(UserReference user)181     public ProfileOwner getProfileOwner(UserReference user) {
182         if (user == null) {
183             throw new NullPointerException();
184         }
185         fillCache();
186         return mCachedProfileOwners.get(user);
187     }
188 
189     /**
190      * Set the device owner.
191      */
setDeviceOwner(ComponentName deviceOwnerComponent)192     public DeviceOwner setDeviceOwner(ComponentName deviceOwnerComponent) {
193         if (deviceOwnerComponent == null) {
194             throw new NullPointerException();
195         }
196 
197         if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
198             return setDeviceOwnerPreS(deviceOwnerComponent);
199         } else if (!Versions.meetsMinimumSdkVersionRequirement(Versions.U)) {
200             return setDeviceOwnerPreU(deviceOwnerComponent);
201         }
202 
203         UserReference user = TestApis.users().system();
204 
205         try (PermissionContext p =
206                      TestApis.permissions().withPermission(
207                              MANAGE_PROFILE_AND_DEVICE_OWNERS, MANAGE_DEVICE_ADMINS,
208                              INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS)) {
209 
210             ShellCommand.Builder command = ShellCommand.builderForUser(
211                             user, "dpm set-device-owner --device-owner-only")
212                     .addOperand(deviceOwnerComponent.flattenToShortString())
213                     .validate(ShellCommandUtils::startsWithSuccess);
214             // TODO(b/187925230): If it fails, we check for terminal failure states - and if not
215             //  we retry because if the DO/PO was recently removed, it can take some time
216             //  to be allowed to set it again
217             Retry.logic(command::execute)
218                     .terminalException(
219                             (e) -> checkForTerminalDeviceOwnerFailures(
220                                     user,
221                                     deviceOwnerComponent,
222                                     /* allowAdditionalUsers= */ false,
223                                     e))
224                     .timeout(Duration.ofMinutes(5))
225                     .run();
226         } catch (Throwable e) {
227             throw new NeneException("Error setting device owner.", e);
228         }
229 
230         Package deviceOwnerPackage = TestApis.packages().find(
231                 deviceOwnerComponent.getPackageName());
232 
233         Poll.forValue("Device Owner", () -> TestApis.devicePolicy().getDeviceOwner())
234                 .toNotBeNull()
235                 .errorOnFail()
236                 .await();
237 
238         return new DeviceOwner(user, deviceOwnerPackage, deviceOwnerComponent);
239     }
240 
241     /**
242      * Set Device Owner without changing any other device state.
243      *
244      * <p>This is used instead of {@link DevicePolicyManager#setDeviceOwner(ComponentName)} directly
245      * because on S_V2 and above, that method can also set profile owners and install packages in
246      * some circumstances.
247      */
setDeviceOwnerOnly(DevicePolicyManager devicePolicyManager, ComponentName component, int deviceOwnerUserId)248     private void setDeviceOwnerOnly(DevicePolicyManager devicePolicyManager,
249             ComponentName component, int deviceOwnerUserId) {
250         if (Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
251             devicePolicyManager.setDeviceOwnerOnly(component, deviceOwnerUserId);
252         } else if (Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S_V2)) {
253             try {
254                 DevicePolicyManager.class.getMethod(
255                         "setDeviceOwnerOnly", ComponentName.class, String.class, int.class)
256                         .invoke(devicePolicyManager, component, null, deviceOwnerUserId);
257             } catch (IllegalAccessException | InvocationTargetException
258                     | NoSuchMethodException e) {
259                 throw new NeneException("Error executing setDeviceOwnerOnly", e);
260             }
261         } else {
262             try {
263                 DevicePolicyManager.class.getMethod(
264                         "setDeviceOwner", ComponentName.class, String.class, int.class)
265                         .invoke(devicePolicyManager, component, null, deviceOwnerUserId);
266             } catch (IllegalAccessException | InvocationTargetException
267                     | NoSuchMethodException e) {
268                 throw new NeneException("Error executing setDeviceOwner", e);
269             }
270         }
271     }
272 
273     /**
274      * Resets organization ID via @TestApi.
275      * @param user whose organization ID to clear
276      */
clearOrganizationId(UserReference user)277     public void clearOrganizationId(UserReference user) {
278         try (PermissionContext p =
279                      TestApis.permissions().withPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)) {
280             devicePolicyManager(user).clearOrganizationId();
281         }
282     }
283 
devicePolicyManager(UserReference user)284     private DevicePolicyManager devicePolicyManager(UserReference user) {
285         return TestApis.context().instrumentedContextAsUser(user)
286                 .getSystemService(DevicePolicyManager.class);
287     }
288 
setDeviceOwnerPreU(ComponentName deviceOwnerComponent)289     private DeviceOwner setDeviceOwnerPreU(ComponentName deviceOwnerComponent) {
290         UserReference user = TestApis.users().system();
291 
292         boolean dpmUserSetupComplete = user.getSetupComplete();
293         Boolean currentUserSetupComplete = null;
294 
295         try {
296             user.setSetupComplete(false);
297 
298             try (PermissionContext p =
299                          TestApis.permissions().withPermission(
300                                  MANAGE_PROFILE_AND_DEVICE_OWNERS, MANAGE_DEVICE_ADMINS,
301                                  INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS)) {
302 
303                 // TODO(b/187925230): If it fails, we check for terminal failure states - and if not
304                 //  we retry because if the DO/PO was recently removed, it can take some time
305                 //  to be allowed to set it again
306                 Retry.logic(
307                         () -> {
308                             sDevicePolicyManager.setActiveAdmin(
309                                     deviceOwnerComponent,
310                                     /* refreshing= */ true,
311                                     user.id());
312                             setDeviceOwnerOnly(
313                                     sDevicePolicyManager, deviceOwnerComponent, user.id());
314                         })
315                         .terminalException(
316                                 (e) -> checkForTerminalDeviceOwnerFailures(
317                                         user,
318                                         deviceOwnerComponent,
319                                         /* allowAdditionalUsers= */ true,
320                                         e))
321                         .timeout(Duration.ofMinutes(5))
322                         .run();
323             } catch (Throwable e) {
324                 throw new NeneException("Error setting device owner", e);
325             }
326         } finally {
327             user.setSetupComplete(dpmUserSetupComplete);
328             if (currentUserSetupComplete != null) {
329                 TestApis.users().current().setSetupComplete(currentUserSetupComplete);
330             }
331         }
332 
333         Poll.forValue("Device Owner", () -> TestApis.devicePolicy().getDeviceOwner())
334                 .toNotBeNull()
335                 .errorOnFail()
336                 .await();
337 
338         return new DeviceOwner(user,
339                 TestApis.packages().find(deviceOwnerComponent.getPackageName()),
340                 deviceOwnerComponent);
341     }
342 
setDeviceOwnerPreS(ComponentName deviceOwnerComponent)343     private DeviceOwner setDeviceOwnerPreS(ComponentName deviceOwnerComponent) {
344         UserReference user = TestApis.users().system();
345 
346         ShellCommand.Builder command = ShellCommand.builderForUser(
347                 user, "dpm set-device-owner")
348                 .addOperand(deviceOwnerComponent.flattenToShortString())
349                 .validate(ShellCommandUtils::startsWithSuccess);
350         // TODO(b/187925230): If it fails, we check for terminal failure states - and if not
351         //  we retry because if the device owner was recently removed, it can take some time
352         //  to be allowed to set it again
353 
354         try {
355             Retry.logic(command::execute)
356                     .terminalException(
357                             (e) ->
358                                     checkForTerminalDeviceOwnerFailures(
359                                             user,
360                                             deviceOwnerComponent,
361                                             /* allowAdditionalUsers= */ false,
362                                             e))
363                     .timeout(Duration.ofMinutes(5))
364                     .run();
365         } catch (Throwable e) {
366             throw new NeneException("Error setting device owner", e);
367         }
368 
369         return new DeviceOwner(user,
370                 TestApis.packages().find(
371                         deviceOwnerComponent.getPackageName()), deviceOwnerComponent);
372     }
373 
checkForTerminalDeviceOwnerFailures( UserReference user, ComponentName deviceOwnerComponent, boolean allowAdditionalUsers, Throwable e)374     private boolean checkForTerminalDeviceOwnerFailures(
375             UserReference user,
376             ComponentName deviceOwnerComponent,
377             boolean allowAdditionalUsers,
378             Throwable e) {
379         DeviceOwner deviceOwner = getDeviceOwner();
380         if (deviceOwner != null) {
381             // TODO(scottjonathan): Should we actually fail here if the component name is the
382             //  same?
383 
384             throw new NeneException(
385                     "Could not set device owner for user "
386                             + user
387                             + " as a device owner is already set: "
388                             + deviceOwner,
389                     e);
390         }
391 
392         Package pkg = TestApis.packages().find(
393                 deviceOwnerComponent.getPackageName());
394         if (!TestApis.packages().installedForUser(user).contains(pkg)) {
395             throw new NeneException(
396                     "Could not set device owner for user "
397                             + user
398                             + " as the package "
399                             + pkg
400                             + " is not installed",
401                     e);
402         }
403 
404         if (!componentCanBeSetAsDeviceAdmin(deviceOwnerComponent, user)) {
405             throw new NeneException(
406                     "Could not set device owner for user "
407                             + user
408                             + " as component "
409                             + deviceOwnerComponent
410                             + " is not valid",
411                     e);
412         }
413 
414         if (!allowAdditionalUsers && nonTestNonPrecreatedUsersExist()) {
415             throw new NeneException(
416                     "Could not set device owner for user "
417                             + user
418                             + " as there are already additional non-test on the device",
419                     e);
420         }
421         // TODO(scottjonathan): Check accounts
422 
423         return false;
424     }
425 
componentCanBeSetAsDeviceAdmin(ComponentName component, UserReference user)426     private boolean componentCanBeSetAsDeviceAdmin(ComponentName component, UserReference user) {
427         PackageManager packageManager =
428                 TestApis.context().instrumentedContext().getPackageManager();
429         Intent intent = new Intent("android.app.action.DEVICE_ADMIN_ENABLED");
430         intent.setComponent(component);
431 
432         try (PermissionContext p =
433                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) {
434             List<ResolveInfo> r =
435                     packageManager.queryBroadcastReceiversAsUser(
436                             intent, /* flags= */ 0, user.userHandle());
437             return (!r.isEmpty());
438         }
439     }
440 
441     /**
442      * Get the device owner.
443      */
444     @Nullable
getDeviceOwner()445     public DeviceOwner getDeviceOwner() {
446         fillCache();
447         return mCachedDeviceOwner;
448     }
449 
fillCache()450     private void fillCache() {
451         int retries = 5;
452         while (true) {
453             try {
454                 // TODO: Replace use of adb on supported versions of Android
455                 String devicePolicyDumpsysOutput =
456                         ShellCommand.builder("dumpsys device_policy").execute();
457                 AdbDevicePolicyParser.ParseResult result = mParser.parse(devicePolicyDumpsysOutput);
458 
459                 mCachedDeviceOwner = result.mDeviceOwner;
460                 mCachedProfileOwners = result.mProfileOwners;
461 
462                 return;
463             } catch (AdbParseException e) {
464                 if (e.adbOutput().contains("DUMP TIMEOUT") && retries-- > 0) {
465                     // Sometimes this call times out - just retry
466                     Log.e(LOG_TAG, "Dump timeout when filling cache, retrying", e);
467                 } else {
468                     throw new NeneException("Error filling cache", e);
469                 }
470             } catch (AdbException e) {
471                 throw new NeneException("Error filling cache", e);
472             }
473         }
474     }
475 
476     /** See {@link android.app.admin.DevicePolicyManager#getPolicyExemptApps()}. */
477     @Experimental
getPolicyExemptApps()478     public Set<String> getPolicyExemptApps() {
479         try (PermissionContext p = TestApis.permissions().withPermission(MANAGE_DEVICE_ADMINS)) {
480             return TestApis.context()
481                     .instrumentedContext()
482                     .getSystemService(DevicePolicyManager.class)
483                     .getPolicyExemptApps();
484         }
485     }
486 
487     @Experimental
forceNetworkLogs()488     public void forceNetworkLogs() {
489         try (PermissionContext p = TestApis.permissions().withPermission(FORCE_DEVICE_POLICY_MANAGER_LOGS)) {
490             long throttle = TestApis.context()
491                     .instrumentedContext()
492                     .getSystemService(DevicePolicyManager.class)
493                     .forceNetworkLogs();
494 
495             if (throttle == -1) {
496                 throw new NeneException("Error forcing network logs: returned -1");
497             }
498             if (throttle == 0) {
499                 return;
500             }
501             try {
502                 Thread.sleep(throttle);
503             } catch (InterruptedException e) {
504                 throw new NeneException("Error waiting for network log throttle", e);
505             }
506 
507             forceNetworkLogs();
508         }
509     }
510 
511     /**
512      * Sets the provided {@code packageName} as a device policy management role holder.
513      */
514     @TargetApi(Build.VERSION_CODES.TIRAMISU)
515     @Experimental
setDevicePolicyManagementRoleHolder(Package pkg, UserReference user)516     public RoleContext setDevicePolicyManagementRoleHolder(Package pkg, UserReference user) {
517         Versions.requireMinimumVersion(TIRAMISU);
518 
519         if (!Versions.meetsMinimumSdkVersionRequirement(Versions.U)) {
520             if (TestApis.users().all().size() > 1) {
521                 throw new NeneException("Could not set device policy management role holder as"
522                         + " more than one user is on the device");
523             }
524         }
525 
526         if (nonTestNonPrecreatedUsersExist()) {
527             throw new NeneException("Could not set device policy management role holder as"
528                     + " non-test users already exist");
529         }
530 
531         TestApis.roles().setBypassingRoleQualification(true);
532 
533         return pkg.setAsRoleHolder(ROLE_DEVICE_POLICY_MANAGEMENT, user);
534     }
535 
nonTestNonPrecreatedUsersExist()536     private boolean nonTestNonPrecreatedUsersExist() {
537         int expectedPrecreatedUsers = TestApis.users().isHeadlessSystemUserMode() ? 2 : 1;
538 
539         return TestApis.users().all().stream()
540                 .filter(u -> !u.isForTesting())
541                 .count() > expectedPrecreatedUsers;
542     }
543 
544     /**
545      * Unsets the provided {@code packageName} as a device policy management role holder.
546      */
547     @TargetApi(Build.VERSION_CODES.TIRAMISU)
548     @Experimental
unsetDevicePolicyManagementRoleHolder(Package pkg, UserReference user)549     public void unsetDevicePolicyManagementRoleHolder(Package pkg, UserReference user) {
550         Versions.requireMinimumVersion(TIRAMISU);
551 
552         pkg.removeAsRoleHolder(ROLE_DEVICE_POLICY_MANAGEMENT, user);
553     }
554 
555     /**
556      * Returns true if the AutoTimeRequired policy is set to true for the given user.
557      */
558     @Experimental
autoTimeRequired(UserReference user)559     public boolean autoTimeRequired(UserReference user) {
560         return TestApis.context().androidContextAsUser(user)
561                 .getSystemService(DevicePolicyManager.class)
562                 .getAutoTimeRequired();
563     }
564 
565     /**
566      * Returns true if the AutoTimeRequired policy is set to true for the instrumented user.
567      */
568     @Experimental
autoTimeRequired()569     public boolean autoTimeRequired() {
570         return autoTimeRequired(TestApis.users().instrumented());
571     }
572 
573     /**
574      * See {@code DevicePolicyManager#isNewUserDisclaimerAcknowledged}.
575      */
576     @Experimental
isNewUserDisclaimerAcknowledged(UserReference user)577     public boolean isNewUserDisclaimerAcknowledged(UserReference user) {
578         try (PermissionContext p = TestApis.permissions().withPermission(
579                 CommonPermissions.INTERACT_ACROSS_USERS)) {
580             return TestApis.context().androidContextAsUser(user).getSystemService(
581                     DevicePolicyManager.class).isNewUserDisclaimerAcknowledged();
582         }
583     }
584 
585     /**
586      * See {@code DevicePolicyManager#isNewUserDisclaimerAcknowledged}.
587      */
588     @Experimental
isNewUserDisclaimerAcknowledged()589     public boolean isNewUserDisclaimerAcknowledged() {
590         return isNewUserDisclaimerAcknowledged(TestApis.users().instrumented());
591     }
592 
593     /**
594      * Access APIs related to Device Policy resource overriding.
595      */
596     @TargetApi(TIRAMISU)
resources()597     public DevicePolicyResources resources() {
598         Versions.requireMinimumVersion(TIRAMISU);
599         return DevicePolicyResources.sInstance;
600     }
601 
602     /**
603      * Get active admins on the instrumented user.
604      */
getActiveAdmins()605     public Set<ComponentReference> getActiveAdmins() {
606         return getActiveAdmins(TestApis.users().instrumented());
607     }
608 
609     /**
610      * Get active admins on the given user.
611      */
getActiveAdmins(UserReference user)612     public Set<ComponentReference> getActiveAdmins(UserReference user) {
613         try (PermissionContext p =
614                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS_FULL)) {
615             List<ComponentName> activeAdmins = devicePolicyManager(user).getActiveAdmins();
616             if (activeAdmins == null) {
617                 return Set.of();
618             }
619             return activeAdmins.stream().map(ComponentReference::new).collect(
620                     Collectors.toSet());
621         }
622     }
623 
624     /**
625      * See {@link DevicePolicyManager#resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState}.
626      */
627     @TargetApi(UPSIDE_DOWN_CAKE)
resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState()628     public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState() {
629         Versions.requireMinimumVersion(UPSIDE_DOWN_CAKE);
630 
631         try (PermissionContext p = TestApis.permissions().withPermission(MANAGE_ROLE_HOLDERS)) {
632             devicePolicyManager(TestApis.users().instrumented())
633                     .resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState();
634         }
635     }
636 
637     /**
638      * Set or check user restrictions.
639      */
userRestrictions(UserHandle user)640     public UserRestrictions userRestrictions(UserHandle user) {
641         return userRestrictions(UserReference.of(user));
642     }
643 
644     /**
645      * Set or check user restrictions on the instrumented user
646      */
userRestrictions()647     public UserRestrictions userRestrictions() {
648         return new UserRestrictions(TestApis.users().instrumented());
649     }
650 
651     /**
652      * Set or check user restrictions.
653      */
userRestrictions(UserReference user)654     public UserRestrictions userRestrictions(UserReference user) {
655         return new UserRestrictions(user);
656     }
657 
658     /**
659      * OEM-Set default cross profile packages.
660      */
661     @Experimental
defaultCrossProfilePackages()662     public Set<Package> defaultCrossProfilePackages() {
663         return sDevicePolicyManager.getDefaultCrossProfilePackages()
664                 .stream().map(i -> TestApis.packages().find(i))
665                 .collect(Collectors.toSet());
666     }
667 
668     /**
669      * True if there is a Device Owner who can grant sensor permissions.
670      */
671     @Experimental
672     @SuppressWarnings("NewApi")
canAdminGrantSensorsPermissions()673     public boolean canAdminGrantSensorsPermissions() {
674         if (!Versions.meetsMinimumSdkVersionRequirement(31)) {
675             return true;
676         }
677         return sDevicePolicyManager.canAdminGrantSensorsPermissions();
678     }
679 
680     /**
681      * See DevicePolicyManager#getUserProvisioningState().
682      */
683     @Experimental
getUserProvisioningState()684     public int getUserProvisioningState() {
685         return getUserProvisioningState(TestApis.users().instrumented());
686     }
687 
688     /**
689      * @see DevicePolicyManager#getUserProvisioningState().
690      */
691     @Experimental
getUserProvisioningState(UserReference user)692     public int getUserProvisioningState(UserReference user) {
693         try (PermissionContext p =
694                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS)) {
695             return devicePolicyManager(user).getUserProvisioningState();
696         }
697     }
698 
699     /**
700      * Get password expiration timeout for the instrumented user.
701      */
702     @Experimental
getPasswordExpirationTimeout()703     public long getPasswordExpirationTimeout() {
704         return getPasswordExpirationTimeout(TestApis.users().instrumented());
705     }
706 
707     /**
708      * See {@link DevicePolicyManager#getPasswordExpirationTimeout}.
709      */
710     @Experimental
getPasswordExpirationTimeout(UserReference user)711     public long getPasswordExpirationTimeout(UserReference user) {
712         try (PermissionContext p =
713                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS)) {
714             return devicePolicyManager(user)
715                     .getPasswordExpirationTimeout(/* componentName= */ null);
716         }
717     }
718 
719     /**
720      * Get maximum time to lock for the instrumented user.
721      */
722     @Experimental
getMaximumTimeToLock()723     public long getMaximumTimeToLock() {
724         return getMaximumTimeToLock(TestApis.users().instrumented());
725     }
726 
727     /**
728      * See {@link DevicePolicyManager#getMaximumTimeToLock}.
729      */
730     @Experimental
getMaximumTimeToLock(UserReference user)731     public long getMaximumTimeToLock(UserReference user) {
732         try (PermissionContext p =
733                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS)) {
734             return devicePolicyManager(user)
735                     .getMaximumTimeToLock(/* componentName= */ null);
736         }
737     }
738 
739     /**
740      * Get strong auth timeout for the instrumented user.
741      */
742     @Experimental
getRequiredStrongAuthTimeout()743     public long getRequiredStrongAuthTimeout() {
744         return getRequiredStrongAuthTimeout(TestApis.users().instrumented());
745     }
746 
747     /**
748      * See {@link DevicePolicyManager#getRequiredStrongAuthTimeout}.
749      */
750     @Experimental
getRequiredStrongAuthTimeout(UserReference user)751     public long getRequiredStrongAuthTimeout(UserReference user) {
752         try (PermissionContext p =
753                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS)) {
754             return devicePolicyManager(user)
755                     .getRequiredStrongAuthTimeout(/* componentName= */ null);
756         }
757     }
758 
759     // TODO: Consider wrapping keyguard disabled features with a bedstead concept instead of flags
760 
761     /**
762      * Get keyguard disabled features for the instrumented user.
763      */
764     @Experimental
getKeyguardDisabledFeatures()765     public int getKeyguardDisabledFeatures() {
766         return getKeyguardDisabledFeatures(TestApis.users().instrumented());
767     }
768 
769     /**
770      * See {@link DevicePolicyManager#getKeyguardDisabledFeatures}.
771      */
772     @Experimental
getKeyguardDisabledFeatures(UserReference user)773     public int getKeyguardDisabledFeatures(UserReference user) {
774         try (PermissionContext p =
775                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS)) {
776             return devicePolicyManager(user)
777                     .getKeyguardDisabledFeatures(/* componentName= */ null);
778         }
779     }
780 
781     /**
782      * Get keyguard disabled features for the instrumented user.
783      */
784     @Experimental
getTrustAgentConfiguration(ComponentName trustAgent)785     public Set<PersistableBundle> getTrustAgentConfiguration(ComponentName trustAgent) {
786         return getTrustAgentConfiguration(trustAgent, TestApis.users().instrumented());
787     }
788 
789     /**
790      * See {@link DevicePolicyManager#getTrustAgentConfiguration}.
791      */
792     @Experimental
getTrustAgentConfiguration( ComponentName trustAgent, UserReference user)793     public Set<PersistableBundle> getTrustAgentConfiguration(
794             ComponentName trustAgent, UserReference user) {
795         try (PermissionContext p =
796                      TestApis.permissions().withPermission(INTERACT_ACROSS_USERS)) {
797             List<PersistableBundle> configurations = devicePolicyManager(user)
798                     .getTrustAgentConfiguration(/* componentName= */ null, trustAgent);
799             return configurations == null ? Set.of() : Set.copyOf(configurations);
800         }
801     }
802 
803     /**
804      * True if either this is the system user or the user is affiliated with a device owner on
805      * the device.
806      */
807     @Experimental
isAffiliated()808     public boolean isAffiliated() {
809         return isAffiliated(TestApis.users().instrumented());
810     }
811 
812     // TODO(276248451): Make user handle aware so it'll work cross-user
813     @Experimental
isAffiliated(UserReference user)814     private boolean isAffiliated(UserReference user) {
815         return devicePolicyManager(user).isAffiliatedUser();
816     }
817 
818     @Experimental
getPermittedInputMethods()819     public List<String> getPermittedInputMethods() {
820         // TODO: Enable cross-user
821         try (PermissionContext p = TestApis.permissions().withPermission(QUERY_ADMIN_POLICY)) {
822             return sDevicePolicyManager.getPermittedInputMethodsForCurrentUser();
823         }
824     }
825 
826     /**
827      * Recalculate the "hasIncompatibleAccounts" cache inside DevicePolicyManager.
828      */
829     @Experimental
calculateHasIncompatibleAccounts()830     public void calculateHasIncompatibleAccounts() {
831         if (!Versions.meetsMinimumSdkVersionRequirement(Versions.U)) {
832             // Nothing to calculate pre-U
833             return;
834         }
835         try (BlockingLogcatListener b =
836                      TestApis.logcat().listen(
837                              l -> l.contains("Finished calculating hasIncompatibleAccountsTask"))) {
838             sDevicePolicyManager.calculateHasIncompatibleAccounts();
839         }
840     }
841 
842     /** See {@link DevicePolicyManager#getPermittedAccessibilityServices} */
843     @Experimental
getPermittedAccessibilityServices()844     public Set<Package> getPermittedAccessibilityServices() {
845         return getPermittedAccessibilityServices(TestApis.users().instrumented());
846     }
847 
848     /** See {@link DevicePolicyManager#getPermittedAccessibilityServices} */
849     @Experimental
getPermittedAccessibilityServices(UserReference user)850     public Set<Package> getPermittedAccessibilityServices(UserReference user) {
851         try (PermissionContext p = TestApis.permissions().withPermission(INTERACT_ACROSS_USERS, QUERY_ADMIN_POLICY)) {
852             List<String> services = sDevicePolicyManager.getPermittedAccessibilityServices(user.id());
853             if (services == null) {
854                 return null;
855             }
856             return services.stream()
857                     .map(packageName -> TestApis.packages().find(packageName))
858                     .collect(Collectors.toSet());
859         }
860     }
861 }
862