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