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 @Suppress("unused")
37 class RootAnnotationExecutor : AnnotationExecutor {
38 
39     companion object {
<lambda>null40         private val isInstrumentedAsRoot: Boolean by lazy {
41             // We need to replace this with a better way of discovering root instrumentation
42             try {
43                 // TODO: This is only available from V+ so will always return
44                 // false before that even if we are instrumented as root. We
45                 // should replace this with an alternative way of discovering
46                 // root instrumentation.
47                 ShellCommandUtils.uiAutomation().clearOverridePermissionStates(-1)
48                 true
49             } catch (e: Throwable) {
50                 Log.i("RootAnnotationExecutor", "Got exception while trying to act as root", e)
51                 false
52             }
53         }
54     }
55 
applyAnnotationnull56     override fun applyAnnotation(annotation: Annotation) {
57         when (annotation) {
58             is RequireAdbRoot -> requireAdbRoot(annotation.failureMode)
59             is RequireRootInstrumentation -> requireRootInstrumentation(annotation.failureMode)
60         }
61     }
62 
requireAdbRootnull63     private fun requireAdbRoot(failureMode: FailureMode) {
64         if (TestApis.adb().isRootAvailable()) {
65             Tags.addTag(ADB_ROOT)
66         } else {
67             AnnotationExecutorUtil.failOrSkip("Device does not have root available.", failureMode)
68         }
69     }
70 
requireRootInstrumentationnull71     private fun requireRootInstrumentation(failureMode: FailureMode) {
72         if (isInstrumentedAsRoot) {
73             Tags.addTag(ROOT_INSTRUMENTATION)
74         } else {
75             AnnotationExecutorUtil.failOrSkip("Test is not instrumented as root.", failureMode)
76         }
77     }
78 }
79 
80 /** True if the currently executing test is supposed to be run with ADB root capabilities. */
DeviceStatenull81 fun DeviceState.testUsesAdbRoot() = Tags.hasTag(ADB_ROOT)
82 
83 /** True if the currently executing test is supposed to be run with root instrumentation. */
84 fun DeviceState.testUsesRootInstrumentation() = Tags.hasTag(ROOT_INSTRUMENTATION)
85