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