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 android.tools.flicker.legacy.runner 18 19 import android.app.Instrumentation 20 import android.tools.Scenario 21 import android.tools.flicker.FlickerTag 22 import android.tools.flicker.junit.Utils 23 import android.tools.flicker.legacy.FlickerTestData 24 import android.tools.io.TraceType 25 import android.tools.traces.getCurrentState 26 import android.tools.traces.io.ResultWriter 27 import android.tools.traces.monitors.NoTraceMonitor 28 import android.tools.traces.now 29 import android.tools.traces.parsers.WindowManagerStateHelper 30 import android.tools.withTracing 31 import android.util.EventLog 32 import android.util.Log 33 import java.io.File 34 import org.junit.rules.TestRule 35 import org.junit.runner.Description 36 import org.junit.runners.model.Statement 37 38 /** 39 * Test rule to execute the transition and update [resultWriter] 40 * 41 * @param flicker test definition 42 * @param resultWriter to write 43 * @param scenario to run the transition 44 * @param instrumentation to interact with the device 45 * @param commands to run during the transition 46 * @param wmHelper to stabilize the UI before/after transitions 47 */ 48 class TransitionExecutionRule( 49 private val flicker: FlickerTestData, 50 private val resultWriter: ResultWriter, 51 private val scenario: Scenario, 52 private val instrumentation: Instrumentation = flicker.instrumentation, 53 private val commands: List<FlickerTestData.() -> Any> = flicker.transitions, 54 private val wmHelper: WindowManagerStateHelper = flicker.wmHelper 55 ) : TestRule { 56 private var tags = mutableSetOf<String>() 57 applynull58 override fun apply(base: Statement?, description: Description?): Statement { 59 return object : Statement() { 60 override fun evaluate() { 61 withTracing("transition") { 62 try { 63 Utils.notifyRunnerProgress(scenario, "Running transition $description") 64 doRunBeforeTransition() 65 commands.forEach { it.invoke(flicker) } 66 base?.evaluate() 67 } finally { 68 doRunAfterTransition() 69 } 70 } 71 } 72 } 73 } 74 doRunBeforeTransitionnull75 private fun doRunBeforeTransition() { 76 Utils.doWaitForUiStabilize(wmHelper) 77 withTracing("doRunBeforeTransition") { 78 Utils.notifyRunnerProgress(scenario, "Running doRunBeforeTransition") 79 Log.d(FLICKER_RUNNER_TAG, "doRunBeforeTransition") 80 val now = now() 81 resultWriter.setTransitionStartTime(now) 82 EventLog.writeEvent( 83 FlickerTag.TRANSITION_START, 84 now.unixNanos, 85 now.elapsedNanos, 86 now.systemUptimeNanos 87 ) 88 flicker.setCreateTagListener { doCreateTag(it) } 89 doValidate() 90 } 91 } 92 doRunAfterTransitionnull93 private fun doRunAfterTransition() { 94 Utils.doWaitForUiStabilize(wmHelper) 95 withTracing("doRunAfterTransition") { 96 Utils.notifyRunnerProgress(scenario, "Running doRunAfterTransition") 97 Log.d(FLICKER_RUNNER_TAG, "doRunAfterTransition") 98 val now = now() 99 resultWriter.setTransitionEndTime(now) 100 EventLog.writeEvent( 101 FlickerTag.TRANSITION_END, 102 now.unixNanos, 103 now.elapsedNanos, 104 now.systemUptimeNanos 105 ) 106 flicker.clearTagListener() 107 } 108 } 109 doValidatenull110 private fun doValidate() { 111 require(flicker.traceMonitors.isNotEmpty()) { NO_MONITORS_ERROR } 112 require(commands.isNotEmpty() || flicker.traceMonitors.all { it is NoTraceMonitor }) { 113 EMPTY_TRANSITIONS_ERROR 114 } 115 } 116 doValidateTagnull117 private fun doValidateTag(tag: String) { 118 require(!tags.contains(tag)) { "Tag `$tag` already used" } 119 require(!tag.contains(" ")) { "Tag can't contain spaces, instead it was `$tag`" } 120 require(!tag.contains("__")) { "Tag can't `__``, instead it was `$tag`" } 121 } 122 doCreateTagnull123 private fun doCreateTag(tag: String) { 124 withTracing("doRunAfterTransition") { 125 Utils.notifyRunnerProgress(scenario, "Creating tag $tag") 126 doValidateTag(tag) 127 tags.add(tag) 128 129 val deviceStateBytes = getCurrentState() 130 val wmDumpFile = File.createTempFile(TraceType.WM_DUMP.fileName, tag) 131 val layersDumpFile = File.createTempFile(TraceType.SF_DUMP.fileName, tag) 132 133 wmDumpFile.writeBytes(deviceStateBytes.first) 134 layersDumpFile.writeBytes(deviceStateBytes.second) 135 136 resultWriter.addTraceResult(TraceType.WM_DUMP, wmDumpFile, tag) 137 resultWriter.addTraceResult(TraceType.SF_DUMP, layersDumpFile, tag) 138 } 139 } 140 } 141