• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package 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