xref: /aosp_15_r20/platform_testing/libraries/flicker/src/android/tools/flicker/Utils.kt (revision dd0948b35e70be4c0246aabd6c72554a5eb8b22a)
1 /*
<lambda>null2  * 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
18 
19 import android.tools.Scenario
20 import android.tools.io.Reader
21 import android.tools.traces.TRACE_CONFIG_REQUIRE_CHANGES
22 import android.tools.traces.io.ResultReaderWithLru
23 import android.tools.traces.io.ResultWriter
24 import android.tools.traces.monitors.PerfettoTraceMonitor
25 import android.tools.traces.monitors.ScreenRecorder
26 import android.tools.traces.monitors.TraceMonitor
27 import android.tools.traces.monitors.events.EventLogMonitor
28 import android.tools.traces.monitors.view.ViewTraceMonitor
29 import android.tools.traces.monitors.wm.LegacyShellTransitionTraceMonitor
30 import android.tools.traces.monitors.wm.LegacyWmTransitionTraceMonitor
31 import android.tools.traces.monitors.wm.WindowManagerTraceMonitor
32 import android.tools.traces.surfaceflinger.LayersTrace
33 import android.tools.traces.wm.TransitionChange
34 import android.tools.traces.wm.WindowManagerTrace
35 import androidx.test.platform.app.InstrumentationRegistry
36 import java.io.File
37 import java.util.function.Consumer
38 import kotlin.io.path.createTempDirectory
39 
40 object Utils {
41     // Order matters since this is used to start traces in the order the monitors are defined here
42     // and stop them in reverse order.
43     @JvmField
44     val ALL_MONITORS: List<TraceMonitor> =
45         mutableListOf<TraceMonitor>(
46                 ScreenRecorder(InstrumentationRegistry.getInstrumentation().targetContext)
47             )
48             .apply {
49                 val perfettoMonitorBuilder = PerfettoTraceMonitor.newBuilder()
50                 perfettoMonitorBuilder.enableLayersTrace().enableTransactionsTrace()
51 
52                 if (android.tracing.Flags.perfettoViewCaptureTracing()) {
53                     perfettoMonitorBuilder.enableViewCaptureTrace()
54                 } else {
55                     this.add(ViewTraceMonitor())
56                 }
57 
58                 if (android.tracing.Flags.perfettoTransitionTracing()) {
59                     perfettoMonitorBuilder.enableTransitionsTrace()
60                 } else {
61                     this.add(LegacyWmTransitionTraceMonitor())
62                     this.add(LegacyShellTransitionTraceMonitor())
63                 }
64 
65                 if (android.tracing.Flags.perfettoWmTracing()) {
66                     perfettoMonitorBuilder.enableWindowManagerTrace()
67                 } else {
68                     this.add(WindowManagerTraceMonitor())
69                 }
70 
71                 if (android.tracing.Flags.perfettoProtologTracing()) {
72                     perfettoMonitorBuilder.enableProtoLog()
73                 }
74 
75                 if (android.tracing.Flags.perfettoIme()) {
76                     perfettoMonitorBuilder.enableImeTrace()
77                 }
78 
79                 this.add(perfettoMonitorBuilder.build())
80             }
81             .apply {
82                 // Start this trace last, since we get our CUJ tags from it and don't want to
83                 // extract CUJ slices of the trace that are missing data from the other traces.
84                 this.add(EventLogMonitor())
85             }
86 
87     @JvmStatic
88     @JvmOverloads
89     fun captureTrace(
90         scenario: Scenario,
91         outputDir: File = createTempDirectory().toFile(),
92         monitors: List<TraceMonitor> = ALL_MONITORS,
93         actions: Consumer<ResultWriter>,
94     ): Reader {
95         val writer = ResultWriter().forScenario(scenario).withOutputDir(outputDir).setRunComplete()
96         monitors.fold({ actions.accept(writer) }) { action, monitor ->
97             { monitor.withTracing(writer) { action() } }
98         }()
99         val result = writer.write()
100 
101         return ResultReaderWithLru(result, TRACE_CONFIG_REQUIRE_CHANGES)
102     }
103 }
104 
Stringnull105 fun String.camelToSnakeCase(): String {
106     return this.fold(StringBuilder()) { acc, c ->
107             acc.let {
108                 val lowerC = c.lowercase()
109                 acc.append(if (acc.isNotEmpty() && c.isUpperCase()) "_$lowerC" else lowerC)
110             }
111         }
112         .toString()
113 }
114 
isAppTransitionChangenull115 fun isAppTransitionChange(
116     transitionChange: TransitionChange,
117     layersTrace: LayersTrace?,
118     wmTrace: WindowManagerTrace?,
119 ): Boolean {
120     require(layersTrace != null || wmTrace != null) {
121         "Requires at least one of wm of layers trace to not be null"
122     }
123 
124     val layerDescriptors =
125         layersTrace?.let {
126             it.getLayerDescriptorById(transitionChange.layerId)
127                 ?: error("Failed to find layer with id ${transitionChange.layerId}")
128         }
129     val windowDescriptor =
130         wmTrace?.let {
131             it.getWindowDescriptorById(transitionChange.windowId)
132                 ?: error("Failed to find layer with id ${transitionChange.windowId}")
133         }
134     return (layerDescriptors?.isAppLayer ?: true) && (windowDescriptor?.isAppWindow ?: true)
135 }
136