• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.service
18 
19 import android.util.Log
20 import com.android.helpers.ICollectorHelper
21 import com.android.server.wm.flicker.getDefaultFlickerOutputDir
22 import com.android.server.wm.flicker.monitor.LayersTraceMonitor
23 import com.android.server.wm.flicker.monitor.TraceMonitor
24 import com.android.server.wm.flicker.monitor.WindowManagerTraceMonitor
25 import com.android.server.wm.flicker.service.FlickerService.Companion.getFassFilePath
26 import com.android.server.wm.traces.common.errors.ErrorTrace
27 import com.android.server.wm.traces.common.layers.LayersTrace
28 import com.android.server.wm.traces.common.windowmanager.WindowManagerTrace
29 import com.android.server.wm.traces.parser.layers.LayersTraceParser
30 import com.android.server.wm.traces.parser.windowmanager.WindowManagerTraceParser
31 import java.nio.file.Files
32 import java.nio.file.Path
33 
34 /**
35  * An {@link ICollectorHelper} for collecting FASS assertions information.
36  *
37  * <p>This parses the output of {@link FlickerService} and returns a collection of
38  * assertions metrics.
39  */
40 class FlickerCollectionHelper : ICollectorHelper<Int> {
41     private val LOG_TAG = FlickerCollectionHelper::class.java.simpleName
42     private val outputDir = getDefaultFlickerOutputDir()
43 
44     private val UNDEFINED_TRANSITION_CLASS = "UndefinedTransitionClass"
45     private var transitionClassName: String = UNDEFINED_TRANSITION_CLASS
46 
47     private val traceMonitors: List<TraceMonitor> = listOf(
48             WindowManagerTraceMonitor(outputDir),
49             LayersTraceMonitor(outputDir)
50     )
51 
52     internal var errorTrace: ErrorTrace = ErrorTrace(emptyArray())
53         private set
54 
55     private var wmTrace: WindowManagerTrace = WindowManagerTrace(emptyArray())
56     private var layersTrace: LayersTrace = LayersTrace(emptyArray())
57 
58     /** Clear existing fass files and start the monitors.  */
59     override fun startCollecting(): Boolean {
60         Log.i(LOG_TAG, "startCollecting")
61         cleanupTraceFiles()
62         traceMonitors.forEach {
63             it.start()
64         }
65         return true
66     }
67 
68     /** Collect the assertions metrics for Flicker as a Service.  */
69     override fun getMetrics(): Map<String, Int> {
70         Log.i(LOG_TAG, "getMetrics")
71         traceMonitors.forEach {
72             it.stop()
73         }
74 
75         Files.createDirectories(outputDir)
76         wmTrace = getWindowManagerTrace(getFassFilePath(outputDir, "wm_trace"))
77         layersTrace = getLayersTrace(getFassFilePath(outputDir, "layers_trace"))
78 
79         val flickerService = FlickerService()
80         val (errors, assertions) = flickerService.process(wmTrace, layersTrace, outputDir)
81         errorTrace = errors
82 
83         return assertionsToMetrics(assertions)
84     }
85 
86     /** Do nothing, because nothing is needed to disable fass.  */
87     override fun stopCollecting(): Boolean {
88         Log.i(LOG_TAG, "stopCollecting")
89         return true
90     }
91 
92     fun setTransitionClassName(className: String?) {
93         this.transitionClassName = className ?: UNDEFINED_TRANSITION_CLASS
94     }
95 
96     /**
97      * Convert the assertions generated by the Flicker Service to specific metric key pairs that
98      * contain enough information to later further and analyze in dashboards.
99      */
100     private fun assertionsToMetrics(assertions: Map<String, Int>): Map<String, Int> {
101         val processedAssertions: MutableMap<String, Int> = mutableMapOf()
102 
103         for ((assertionName, result) in assertions) {
104             // Add information about the CUJ we are running the assertions on
105             processedAssertions["$transitionClassName::$assertionName"] = result
106         }
107 
108         return processedAssertions
109     }
110 
111     /**
112      * Remove the WM trace and layers trace files collected from previous test runs if the
113      * directory exists.
114      */
115     private fun cleanupTraceFiles() {
116         if (!Files.exists(outputDir)) {
117             return
118         }
119 
120         Files.list(outputDir).filter {
121             file -> !Files.isDirectory(file.toAbsolutePath())
122         }.forEach { file ->
123             Files.delete(file)
124         }
125     }
126 
127     /**
128      * Parse the window manager trace file.
129      *
130      * @param traceFilePath
131      * @return parsed window manager trace.
132      */
133     private fun getWindowManagerTrace(traceFilePath: Path): WindowManagerTrace {
134         val wmTraceByteArray: ByteArray = Files.readAllBytes(traceFilePath)
135         return WindowManagerTraceParser.parseFromTrace(wmTraceByteArray)
136     }
137 
138     /**
139      * Parse the layers trace file.
140      *
141      * @param traceFilePath
142      * @return parsed layers trace.
143      */
144     private fun getLayersTrace(traceFilePath: Path): LayersTrace {
145         val layersTraceByteArray: ByteArray = Files.readAllBytes(traceFilePath)
146         return LayersTraceParser.parseFromTrace(layersTraceByteArray)
147     }
148 }
149