1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.trust.test.lib 18 19 import android.app.trust.TrustManager 20 import android.content.ComponentName 21 import android.content.Context 22 import android.trust.BaseTrustAgentService 23 import android.trust.test.lib.TrustAgentRule.Companion.invoke 24 import android.util.Log 25 import androidx.test.core.app.ApplicationProvider.getApplicationContext 26 import com.android.internal.widget.LockPatternUtils 27 import com.google.common.truth.Truth.assertWithMessage 28 import kotlin.reflect.KClass 29 import org.junit.rules.TestRule 30 import org.junit.runner.Description 31 import org.junit.runners.model.Statement 32 33 /** 34 * Enables a trust agent and causes the system service to bind to it. 35 * 36 * The enabled agent can be accessed during the test via the [agent] property. 37 * 38 * @constructor Creates the rule. Do not use; instead, use [invoke]. 39 */ 40 class TrustAgentRule<T : BaseTrustAgentService>( 41 private val serviceClass: KClass<T>, 42 private val startUnlocked: Boolean, 43 private val startEnabled: Boolean, 44 ) : TestRule { 45 private val context: Context = getApplicationContext() 46 private val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager 47 private val lockPatternUtils = LockPatternUtils(context) 48 49 val agent get() = BaseTrustAgentService.instance(serviceClass) as T 50 applynull51 override fun apply(base: Statement, description: Description) = object : Statement() { 52 override fun evaluate() { 53 verifyTrustServiceRunning() 54 if (startUnlocked) { 55 reportSuccessfulUnlock() 56 } else { 57 Log.i(TAG, "Trust manager not starting in unlocked state") 58 } 59 60 try { 61 if (startEnabled) { 62 enableAndVerifyTrustAgentIsRunning() 63 } else { 64 Log.i(TAG, "Trust agent ${serviceClass.simpleName} not enabled") 65 } 66 base.evaluate() 67 } finally { 68 disableTrustAgent() 69 } 70 } 71 } 72 verifyTrustServiceRunningnull73 private fun verifyTrustServiceRunning() { 74 assertWithMessage("Trust service is not running").that(trustManager).isNotNull() 75 } 76 reportSuccessfulUnlocknull77 fun reportSuccessfulUnlock() { 78 Log.i(TAG, "Reporting successful unlock") 79 trustManager.reportUnlockAttempt(true, context.userId) 80 } 81 reportFailedUnlocknull82 fun reportFailedUnlock() { 83 Log.i(TAG, "Reporting failed unlock") 84 trustManager.reportUnlockAttempt(false, context.userId) 85 } 86 enableAndVerifyTrustAgentIsRunningnull87 fun enableAndVerifyTrustAgentIsRunning(maxWait: Long = 30000L) { 88 enableTrustAgent() 89 verifyAgentIsRunning(maxWait) 90 } 91 enableTrustAgentnull92 fun enableTrustAgent() { 93 val componentName = ComponentName(context, serviceClass.java) 94 val userId = context.userId 95 Log.i(TAG, "Enabling trust agent ${componentName.flattenToString()} for user $userId") 96 val agents = mutableListOf(componentName) 97 .plus(lockPatternUtils.getEnabledTrustAgents(userId)) 98 .distinct() 99 lockPatternUtils.setEnabledTrustAgents(agents, userId) 100 } 101 verifyAgentIsRunningnull102 fun verifyAgentIsRunning(maxWait: Long = 30000L) { 103 wait("${serviceClass.simpleName} to be running", maxWait) { 104 BaseTrustAgentService.instance(serviceClass) != null 105 } 106 } 107 ensureAgentIsNotRunningnull108 fun ensureAgentIsNotRunning(window: Long = 30000L) { 109 ensure("${serviceClass.simpleName} is not running", window) { 110 BaseTrustAgentService.instance(serviceClass) == null 111 } 112 } 113 disableTrustAgentnull114 private fun disableTrustAgent() { 115 val componentName = ComponentName(context, serviceClass.java) 116 val userId = context.userId 117 Log.i(TAG, "Disabling trust agent ${componentName.flattenToString()} for user $userId") 118 val agents = lockPatternUtils.getEnabledTrustAgents(userId).toMutableList() 119 .distinct() 120 .minus(componentName) 121 lockPatternUtils.setEnabledTrustAgents(agents, userId) 122 } 123 124 companion object { 125 /** 126 * Creates a new rule for the specified agent class. Starts with the device unlocked and 127 * the trust agent enabled. Example usage: 128 * ``` 129 * @get:Rule val rule = TrustAgentRule<MyTestAgent>() 130 * ``` 131 * 132 * Also supports setting different device lock and trust agent enablement states: 133 * ``` 134 * @get:Rule val rule = TrustAgentRule<MyTestAgent>(startUnlocked = false, startEnabled = false) 135 * ``` 136 */ invokenull137 inline operator fun <reified T : BaseTrustAgentService> invoke( 138 startUnlocked: Boolean = true, 139 startEnabled: Boolean = true, 140 ) = 141 TrustAgentRule(T::class, startUnlocked, startEnabled) 142 143 144 private const val TAG = "TrustAgentRule" 145 } 146 } 147