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.perfetto.ExperimentalPerfettoTraceProcessorApi::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.traces.SERVICE_TRACE_CONFIG
29 import android.tools.traces.io.ResultReaderWithLru
30 import android.tools.traces.io.ResultWriter
31 import android.tools.traces.monitors.wm.WindowManagerTraceMonitor
32 import android.tools.traces.parsers.perfetto.LayersTraceParser
33 import android.tools.traces.parsers.perfetto.TraceProcessorSession
34 import android.tools.traces.parsers.perfetto.TransactionsTraceParser
35 import android.tools.traces.parsers.wm.WindowManagerTraceParser
36 import android.tools.traces.surfaceflinger.LayersTrace
37 import android.tools.traces.surfaceflinger.TransactionsTrace
38 import android.tools.traces.wm.WindowManagerTrace
39 import java.io.File
40 import perfetto.protos.PerfettoConfig.SurfaceFlingerLayersConfig
41 
42 /**
43  * Acquire the [WindowManagerTrace] with the device state changes that happen when executing the
44  * commands defined in the [predicate].
45  *
46  * @param predicate Commands to execute
47  * @throws UnsupportedOperationException If tracing is already activated
48  */
49 fun withWMTracing(predicate: () -> Unit): WindowManagerTrace {
50     return WindowManagerTraceParser()
51         .parse(WindowManagerTraceMonitor().withTracing(Tag.ALL, predicate))
52 }
53 
54 /**
55  * Acquire the [LayersTrace] with the device state changes that happen when executing the commands
56  * defined in the [predicate].
57  *
58  * @param flags Flags to indicate tracing level
59  * @param predicate Commands to execute
60  * @throws UnsupportedOperationException If tracing is already activated
61  */
62 @JvmOverloads
withSFTracingnull63 fun withSFTracing(
64     flags: List<SurfaceFlingerLayersConfig.TraceFlag>? = null,
65     predicate: () -> Unit
66 ): LayersTrace {
67     val trace =
68         PerfettoTraceMonitor.newBuilder()
69             .enableLayersTrace(flags)
70             .build()
71             .withTracing(Tag.ALL, predicate)
72     return TraceProcessorSession.loadPerfettoTrace(trace) { session ->
73         LayersTraceParser().parse(session)
74     }
75 }
76 
77 /**
78  * Acquire the [TransactionsTrace] with the device state changes that happen when executing the
79  * commands defined in the [predicate].
80  *
81  * @param predicate Commands to execute
82  * @throws UnsupportedOperationException If tracing is already activated
83  */
84 @JvmOverloads
withTransactionsTracingnull85 fun withTransactionsTracing(predicate: () -> Unit): TransactionsTrace {
86     val trace =
87         PerfettoTraceMonitor.newBuilder()
88             .enableTransactionsTrace()
89             .build()
90             .withTracing(Tag.ALL, predicate)
91     return TraceProcessorSession.loadPerfettoTrace(trace) { session ->
92         TransactionsTraceParser().parse(session)
93     }
94 }
95 
96 /**
97  * Acquire the [WindowManagerTrace] and [LayersTrace] with the device state changes that happen when
98  * executing the commands defined in the [predicate].
99  *
100  * @param predicate Commands to execute
101  * @throws UnsupportedOperationException If tracing is already activated
102  */
withTracingnull103 fun withTracing(
104     traceMonitors: List<TraceMonitor> =
105         listOf(
106             WindowManagerTraceMonitor(),
107             PerfettoTraceMonitor.newBuilder().enableLayersTrace().enableTransactionsTrace().build(),
108         ),
109     predicate: () -> Unit
110 ): Reader {
111     val tmpFile = File.createTempFile("recordTraces", "")
112     val writer =
113         ResultWriter()
114             .forScenario(ScenarioBuilder().forClass(tmpFile.name).build())
115             .withOutputDir(tmpFile.parentFile)
116 
117     try {
118         traceMonitors.forEach { it.start() }
119         predicate()
120     } finally {
121         traceMonitors.forEach { it.stop(writer) }
122     }
123     return ResultReaderWithLru(writer.write(), SERVICE_TRACE_CONFIG)
124 }
125 
126 /**
127  * Acquire the [WindowManagerTrace] and [LayersTrace] with the device state changes that happen when
128  * executing the commands defined in the [predicate].
129  *
130  * @param predicate Commands to execute
131  * @return a pair containing the WM and SF traces
132  * @throws UnsupportedOperationException If tracing is already activated
133  */
recordTracesnull134 fun recordTraces(predicate: () -> Unit): Pair<ByteArray, ByteArray> {
135     var wmTraceData = ByteArray(0)
136     val layersTraceData =
137         PerfettoTraceMonitor.newBuilder().enableLayersTrace().build().withTracing {
138             wmTraceData = WindowManagerTraceMonitor().withTracing(Tag.ALL, predicate)
139         }
140 
141     return Pair(wmTraceData, layersTraceData)
142 }
143