• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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 @file:JvmName("MonitorUtils")
18 @file:OptIn(
19     androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi::class,
20     androidx.benchmark.traceprocessor.ExperimentalTraceProcessorApi::class,
21 )
22 
23 package android.tools.traces.monitors
24 
25 import android.tools.ScenarioBuilder
26 import android.tools.Tag
27 import android.tools.io.Reader
28 import android.tools.io.TraceType
29 import android.tools.traces.SERVICE_TRACE_CONFIG
30 import android.tools.traces.TRACE_CONFIG_REQUIRE_CHANGES
31 import android.tools.traces.io.IResultData
32 import android.tools.traces.io.ResultReader
33 import android.tools.traces.io.ResultReaderWithLru
34 import android.tools.traces.io.ResultWriter
35 import android.tools.traces.monitors.wm.WindowManagerTraceMonitor
36 import android.tools.traces.parsers.perfetto.LayersTraceParser
37 import android.tools.traces.parsers.perfetto.TraceProcessorSession
38 import android.tools.traces.parsers.perfetto.TransactionsTraceParser
39 import android.tools.traces.parsers.perfetto.WindowManagerTraceParser
40 import android.tools.traces.surfaceflinger.LayersTrace
41 import android.tools.traces.surfaceflinger.TransactionsTrace
42 import android.tools.traces.wm.WindowManagerTrace
43 import java.io.File
44 import perfetto.protos.PerfettoConfig.SurfaceFlingerLayersConfig
45 import perfetto.protos.PerfettoConfig.WindowManagerConfig
46 
47 private fun buildResultReader(resultData: IResultData): ResultReader =
48     ResultReader(resultData, TRACE_CONFIG_REQUIRE_CHANGES)
49 
50 /**
51  * Reads the Perfetto file form the result reader and keep (or not) a copy
52  *
53  * @param debugFile File to keep a copy of the parsed trace, leave null to not keep any copies
54  * @throws UnsupportedOperationException If tracing is already activated
55  */
56 private fun readBytes(
57     reader: ResultReader,
58     debugFile: File?,
59     traceType: TraceType = TraceType.PERFETTO,
60     tag: String = Tag.ALL,
61 ): ByteArray {
62     val bytes = reader.readBytes(traceType, tag) ?: error("Missing trace $traceType")
63     reader.artifact.deleteIfExists()
64     debugFile?.writeBytes(bytes)
65     return bytes
66 }
67 
68 /**
69  * Acquire the [WindowManagerTrace] with the device state changes that happen when executing the
70  * commands defined in the [predicate].
71  *
72  * @param predicate Commands to execute
73  * @throws UnsupportedOperationException If tracing is already activated
74  */
withWMTracingnull75 fun withWMTracing(
76     logFrequency: WindowManagerConfig.LogFrequency =
77         WindowManagerConfig.LogFrequency.LOG_FREQUENCY_FRAME,
78     debugFile: File? = null,
79     predicate: Runnable,
80 ): WindowManagerTrace {
81     val reader =
82         PerfettoTraceMonitor.newBuilder()
83             .enableWindowManagerTrace(logFrequency)
84             .build()
85             .withTracing(resultReaderProvider = { buildResultReader(it) }, predicate)
86 
87     val bytes = readBytes(reader, debugFile)
88     return TraceProcessorSession.loadPerfettoTrace(bytes) { session ->
89         WindowManagerTraceParser().parse(session)
90     }
91 }
92 
93 /**
94  * Acquire the [LayersTrace] with the device state changes that happen when executing the commands
95  * defined in the [predicate].
96  *
97  * @param flags Flags to indicate tracing level
98  * @param predicate Commands to execute
99  * @param debugFile File to keep a copy of the parsed trace, leave null to not keep any copies
100  * @throws UnsupportedOperationException If tracing is already activated
101  */
102 @JvmOverloads
withSFTracingnull103 fun withSFTracing(
104     flags: List<SurfaceFlingerLayersConfig.TraceFlag>? = null,
105     debugFile: File? = null,
106     predicate: Runnable,
107 ): LayersTrace {
108     val reader =
109         PerfettoTraceMonitor.newBuilder()
110             .enableLayersTrace(flags)
111             .build()
112             .withTracing(resultReaderProvider = { buildResultReader(it) }, predicate)
113 
114     val bytes = readBytes(reader, debugFile)
115     return TraceProcessorSession.loadPerfettoTrace(bytes) { session ->
116         LayersTraceParser().parse(session)
117     }
118 }
119 
120 /**
121  * Acquire the [TransactionsTrace] with the device state changes that happen when executing the
122  * commands defined in the [predicate].
123  *
124  * @param debugFile File to keep a copy of the parsed trace, leave null to not keep any copies
125  * @param predicate Commands to execute
126  * @throws UnsupportedOperationException If tracing is already activated
127  */
withTransactionsTracingnull128 fun withTransactionsTracing(debugFile: File? = null, predicate: Runnable): TransactionsTrace {
129     val reader =
130         PerfettoTraceMonitor.newBuilder()
131             .enableTransactionsTrace()
132             .build()
133             .withTracing(resultReaderProvider = { buildResultReader(it) }, predicate)
134     val bytes = readBytes(reader, debugFile)
135     return TraceProcessorSession.loadPerfettoTrace(bytes) { session ->
136         TransactionsTraceParser().parse(session)
137     }
138 }
139 
140 /**
141  * Acquire the [WindowManagerTrace] and [LayersTrace] with the device state changes that happen when
142  * executing the commands defined in the [predicate].
143  *
144  * @param traceMonitors List of monitors to start
145  * @param debugFile File to keep a copy of the parsed trace, leave null to not keep any copies
146  * @param predicate Commands to execute
147  * @throws UnsupportedOperationException If tracing is already activated
148  */
withTracingnull149 fun withTracing(
150     traceMonitors: List<TraceMonitor> =
151         mutableListOf<TraceMonitor>()
152             .apply {
153                 if (!android.tracing.Flags.perfettoWmTracing()) {
154                     this.add(WindowManagerTraceMonitor())
155                 }
156             }
<lambda>null157             .apply {
158                 val monitorBuilder =
159                     PerfettoTraceMonitor.newBuilder().enableLayersTrace().enableTransactionsTrace()
160 
161                 if (android.tracing.Flags.perfettoWmTracing()) {
162                     monitorBuilder.enableWindowManagerTrace()
163                 }
164 
165                 this.add(monitorBuilder.build())
166             }
167             .toList(),
168     debugFile: File? = null,
169     predicate: Runnable,
170 ): Reader {
171     val tmpFile = File.createTempFile("recordTraces", "")
172     val writer =
173         ResultWriter()
174             .forScenario(ScenarioBuilder().forClass(tmpFile.name).build())
175             .withOutputDir(tmpFile.parentFile)
176 
177     try {
<lambda>null178         traceMonitors.forEach { it.start() }
179         predicate.run()
180     } finally {
<lambda>null181         traceMonitors.forEach { it.stop(writer) }
182     }
183     val reader = ResultReaderWithLru(writer.write(), SERVICE_TRACE_CONFIG)
184     debugFile?.writeBytes(reader.artifact.readBytes())
185     return reader
186 }
187 
188 /**
189  * Acquire the [WindowManagerTrace] and [LayersTrace] with the device state changes that happen when
190  * executing the commands defined in the [predicate].
191  *
192  * @param predicate Commands to execute
193  * @return a pair containing the WM and SF traces
194  * @throws UnsupportedOperationException If tracing is already activated
195  */
recordTracesnull196 fun recordTraces(predicate: Runnable): ResultReader {
197     return PerfettoTraceMonitor.newBuilder()
198         .enableLayersTrace()
199         .enableWindowManagerTrace()
200         .build()
201         .withTracing(resultReaderProvider = { buildResultReader(it) }, predicate)
202 }
203