1 /* <lambda>null2 * Copyright (C) 2021 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.server.wm.flicker 18 19 import android.util.Log 20 import androidx.annotation.VisibleForTesting 21 import com.android.server.wm.flicker.assertions.FlickerAssertionError 22 import com.android.server.wm.flicker.assertions.FlickerSubject 23 import com.android.server.wm.flicker.dsl.AssertionTag 24 import com.android.server.wm.flicker.traces.eventlog.EventLogSubject 25 import com.android.server.wm.traces.common.windowmanager.WindowManagerTrace 26 import com.android.server.wm.flicker.traces.eventlog.FocusEvent 27 import com.android.server.wm.flicker.traces.layers.LayersTraceSubject 28 import com.android.server.wm.flicker.traces.windowmanager.WindowManagerTraceSubject 29 import com.android.server.wm.traces.common.layers.LayerTraceEntry 30 import com.android.server.wm.traces.common.layers.LayersTrace 31 import com.android.server.wm.traces.common.windowmanager.WindowManagerState 32 import com.android.server.wm.traces.parser.layers.LayersTraceParser 33 import com.android.server.wm.traces.parser.windowmanager.WindowManagerTraceParser 34 import java.io.IOException 35 import java.nio.file.Files 36 import java.nio.file.Path 37 38 /** 39 * Defines the result of a flicker run 40 */ 41 class FlickerRunResult private constructor( 42 /** 43 * Run identifier 44 */ 45 @JvmField val iteration: Int, 46 /** 47 * Path to the trace files associated with the result (incl. screen recording) 48 */ 49 @JvmField val traceFiles: List<Path>, 50 /** 51 * Determines which assertions to run (e.g., start, end, all, or a custom tag) 52 */ 53 @JvmField var assertionTag: String, 54 /** 55 * Truth subject that corresponds to a [WindowManagerTrace] or [WindowManagerState] 56 */ 57 internal val wmSubject: FlickerSubject?, 58 /** 59 * Truth subject that corresponds to a [LayersTrace] or [LayerTraceEntry] 60 */ 61 internal val layersSubject: FlickerSubject?, 62 /** 63 * Truth subject that corresponds to a list of [FocusEvent] 64 */ 65 @VisibleForTesting 66 val eventLogSubject: EventLogSubject? 67 ) { 68 fun getSubjects(): List<FlickerSubject> { 69 val result = mutableListOf<FlickerSubject>() 70 71 wmSubject?.run { result.add(this.clone()) } 72 layersSubject?.run { result.add(this.clone()) } 73 eventLogSubject?.run { result.add(this.clone()) } 74 75 return result 76 } 77 78 private fun Path?.tryDelete() { 79 try { 80 this?.let { Files.deleteIfExists(it) } 81 } catch (e: IOException) { 82 Log.e(FLICKER_TAG, "Unable do delete $this", e) 83 } 84 } 85 86 fun canDelete(failures: List<FlickerAssertionError>): Boolean { 87 return failures.flatMap { it.traceFiles }.none { failureTrace -> 88 this.traceFiles.any { it == failureTrace } 89 } 90 } 91 92 /** 93 * Delete the trace files collected 94 */ 95 fun cleanUp() { 96 this.traceFiles.forEach { it.tryDelete() } 97 } 98 99 class Builder @JvmOverloads constructor(private val iteration: Int = 0) { 100 /** 101 * Path to the WindowManager trace file, if collected 102 */ 103 var wmTraceFile: Path? = null 104 105 /** 106 * Path to the SurfaceFlinger trace file, if collected 107 */ 108 var layersTraceFile: Path? = null 109 110 /** 111 * Path to screen recording of the run, if collected 112 */ 113 var screenRecording: Path? = null 114 115 /** 116 * List of focus events, if collected 117 */ 118 var eventLog: List<FocusEvent>? = null 119 120 private fun getTraceFiles() = listOfNotNull(wmTraceFile, layersTraceFile, screenRecording) 121 122 private fun buildResult( 123 assertionTag: String, 124 wmSubject: FlickerSubject?, 125 layersSubject: FlickerSubject?, 126 eventLogSubject: EventLogSubject? = null 127 ): FlickerRunResult { 128 return FlickerRunResult(iteration, 129 getTraceFiles(), 130 assertionTag, 131 wmSubject, 132 layersSubject, 133 eventLogSubject 134 ) 135 } 136 137 /** 138 * Builds a new [FlickerRunResult] for a trace 139 * 140 * @param assertionTag Tag to associate with the result 141 * @param wmTrace WindowManager trace 142 * @param layersTrace Layers trace 143 */ 144 fun buildStateResult( 145 assertionTag: String, 146 wmTrace: WindowManagerTrace?, 147 layersTrace: LayersTrace? 148 ): FlickerRunResult { 149 val wmSubject = wmTrace?.let { WindowManagerTraceSubject.assertThat(it).first() } 150 val layersSubject = layersTrace?.let { LayersTraceSubject.assertThat(it).first() } 151 return buildResult(assertionTag, wmSubject, layersSubject) 152 } 153 154 @VisibleForTesting 155 fun buildEventLogResult(): FlickerRunResult { 156 val events = eventLog ?: emptyList() 157 return buildResult( 158 AssertionTag.ALL, 159 wmSubject = null, 160 layersSubject = null, 161 eventLogSubject = EventLogSubject.assertThat(events) 162 ) 163 } 164 165 @VisibleForTesting 166 fun buildTraceResults(): List<FlickerRunResult> { 167 var wmTrace: WindowManagerTrace? = null 168 var layersTrace: LayersTrace? = null 169 170 if (wmTrace == null && wmTraceFile != null) { 171 Log.v(FLICKER_TAG, "Parsing WM trace") 172 wmTrace = wmTraceFile?.let { 173 val traceData = Files.readAllBytes(it) 174 WindowManagerTraceParser.parseFromTrace(traceData) 175 } 176 } 177 178 if (layersTrace == null && layersTraceFile != null) { 179 Log.v(FLICKER_TAG, "Parsing Layers trace") 180 layersTrace = layersTraceFile?.let { 181 val traceData = Files.readAllBytes(it) 182 LayersTraceParser.parseFromTrace(traceData) 183 } 184 } 185 186 val wmSubject = wmTrace?.let { WindowManagerTraceSubject.assertThat(it) } 187 val layersSubject = layersTrace?.let { LayersTraceSubject.assertThat(it) } 188 189 val traceResult = buildResult( 190 AssertionTag.ALL, wmSubject, layersSubject) 191 val initialStateResult = buildResult( 192 AssertionTag.START, wmSubject?.first(), layersSubject?.first()) 193 val finalStateResult = buildResult( 194 AssertionTag.END, wmSubject?.last(), layersSubject?.last()) 195 196 return listOf(initialStateResult, finalStateResult, traceResult) 197 } 198 199 fun buildAll(): List<FlickerRunResult> { 200 val result = buildTraceResults().toMutableList() 201 if (eventLog != null) { 202 result.add(buildEventLogResult()) 203 } 204 205 return result 206 } 207 } 208 } 209