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 kotlin.io.path.createTempDirectory
38
39 object Utils {
40 // Order matters since this is used to start traces in the order the monitors are defined here
41 // and stop them in reverse order.
42 val ALL_MONITORS: List<TraceMonitor> =
43 mutableListOf(
44 ScreenRecorder(InstrumentationRegistry.getInstrumentation().targetContext),
45 WindowManagerTraceMonitor(),
46 )
47 .apply {
48 val perfettoMonitorBuilder = PerfettoTraceMonitor.newBuilder()
49 perfettoMonitorBuilder.enableLayersTrace().enableTransactionsTrace()
50
51 if (android.tracing.Flags.perfettoViewCaptureTracing()) {
52 perfettoMonitorBuilder.enableViewCaptureTrace()
53 } else {
54 this.add(ViewTraceMonitor())
55 }
56
57 if (android.tracing.Flags.perfettoTransitionTracing()) {
58 perfettoMonitorBuilder.enableTransitionsTrace()
59 } else {
60 this.add(LegacyWmTransitionTraceMonitor())
61 this.add(LegacyShellTransitionTraceMonitor())
62 }
63
64 if (android.tracing.Flags.perfettoProtologTracing()) {
65 perfettoMonitorBuilder.enableProtoLog()
66 }
67
68 if (android.tracing.Flags.perfettoIme()) {
69 perfettoMonitorBuilder.enableImeTrace()
70 }
71
72 this.add(perfettoMonitorBuilder.build())
73 }
74 .apply {
75 // Start this trace last, since we get our CUJ tags from it and don't want to
76 // extract CUJ slices of the trace that are missing data from the other traces.
77 this.add(EventLogMonitor())
78 }
79
80 fun captureTrace(
81 scenario: Scenario,
82 outputDir: File = createTempDirectory().toFile(),
83 monitors: List<TraceMonitor> = ALL_MONITORS,
84 actions: (writer: ResultWriter) -> Unit
85 ): Reader {
86 val writer = ResultWriter().forScenario(scenario).withOutputDir(outputDir).setRunComplete()
87 monitors.fold({ actions.invoke(writer) }) { action, monitor ->
88 { monitor.withTracing(writer) { action() } }
89 }()
90 val result = writer.write()
91
92 return ResultReaderWithLru(result, TRACE_CONFIG_REQUIRE_CHANGES)
93 }
94 }
95
Stringnull96 fun String.camelToSnakeCase(): String {
97 return this.fold(StringBuilder()) { acc, c ->
98 acc.let {
99 val lowerC = c.lowercase()
100 acc.append(if (acc.isNotEmpty() && c.isUpperCase()) "_$lowerC" else lowerC)
101 }
102 }
103 .toString()
104 }
105
isAppTransitionChangenull106 fun isAppTransitionChange(
107 transitionChange: TransitionChange,
108 layersTrace: LayersTrace?,
109 wmTrace: WindowManagerTrace?
110 ): Boolean {
111 require(layersTrace != null || wmTrace != null) {
112 "Requires at least one of wm of layers trace to not be null"
113 }
114
115 val layerDescriptors =
116 layersTrace?.let {
117 it.getLayerDescriptorById(transitionChange.layerId)
118 ?: error("Failed to find layer with id ${transitionChange.layerId}")
119 }
120 val windowDescriptor =
121 wmTrace?.let {
122 it.getWindowDescriptorById(transitionChange.windowId)
123 ?: error("Failed to find layer with id ${transitionChange.windowId}")
124 }
125 return (layerDescriptors?.isAppLayer ?: true) && (windowDescriptor?.isAppWindow ?: true)
126 }
127