1 /*
2  * Copyright (C) 2024 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.xts.root
18 
19 import android.util.Log
20 import com.android.bedstead.adb.adb
21 import com.android.bedstead.harrier.AnnotationExecutor
22 import com.android.bedstead.harrier.AnnotationExecutorUtil
23 import com.android.bedstead.harrier.DeviceState
24 import com.android.bedstead.harrier.annotations.FailureMode
25 import com.android.bedstead.nene.TestApis
26 import com.android.bedstead.nene.utils.ShellCommandUtils
27 import com.android.bedstead.nene.utils.Tags
28 import com.android.xts.root.Tags.ADB_ROOT
29 import com.android.xts.root.Tags.ROOT_INSTRUMENTATION
30 import com.android.xts.root.annotations.RequireAdbRoot
31 import com.android.xts.root.annotations.RequireRootInstrumentation
32 
33 /**
34  * [AnnotationExecutor] used for parsing [RequireAdbRoot].
35  */
36 class RootAnnotationExecutor : AnnotationExecutor {
37 
38     companion object {
<lambda>null39         private val isInstrumentedAsRoot: Boolean by lazy {
40             // We need to replace this with a better way of discovering root instrumentation
41             try {
42                 // TODO: This is only available from V+ so will always return
43                 // false before that even if we are instrumented as root. We
44                 // should replace this with an alternative way of discovering
45                 // root instrumentation.
46                 ShellCommandUtils.uiAutomation().clearOverridePermissionStates(-1)
47                 true
48             } catch (e: Throwable) {
49                 Log.i("RootAnnotationExecutor", "Got exception while trying to act as root", e)
50                 false
51             }
52         }
53     }
54 
applyAnnotationnull55     override fun applyAnnotation(annotation: Annotation) {
56         when (annotation) {
57             is RequireAdbRoot -> requireAdbRoot(annotation.failureMode)
58             is RequireRootInstrumentation -> requireRootInstrumentation(annotation.failureMode)
59         }
60     }
61 
requireAdbRootnull62     private fun requireAdbRoot(failureMode: FailureMode) {
63         if (TestApis.adb().isRootAvailable()) {
64             Tags.addTag(ADB_ROOT)
65         } else {
66             AnnotationExecutorUtil.failOrSkip("Device does not have root available.", failureMode)
67         }
68     }
69 
requireRootInstrumentationnull70     private fun requireRootInstrumentation(failureMode: FailureMode) {
71         if (isInstrumentedAsRoot) {
72             Tags.addTag(ROOT_INSTRUMENTATION)
73         } else {
74             AnnotationExecutorUtil.failOrSkip("Test is not instrumented as root.", failureMode)
75         }
76     }
77 }
78 
79 /** True if the currently executing test is supposed to be run with ADB root capabilities. */
DeviceStatenull80 fun DeviceState.testUsesAdbRoot() = Tags.hasTag(ADB_ROOT)
81 
82 /** True if the currently executing test is supposed to be run with root instrumentation. */
83 fun DeviceState.testUsesRootInstrumentation() = Tags.hasTag(ROOT_INSTRUMENTATION)
84