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