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