1 /*
2  * 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.systemui.util
18 
19 import android.os.Trace
20 import android.os.TraceNameSupplier
21 import java.util.concurrent.atomic.AtomicInteger
22 
23 /**
24  * Run a block within a [Trace] section. Calls [Trace.beginSection] before and [Trace.endSection]
25  * after the passed block.
26  */
27 inline fun <T> traceSection(tag: String, block: () -> T): T =
28     if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
29         Trace.traceBegin(Trace.TRACE_TAG_APP, tag)
30         try {
31             block()
32         } finally {
33             Trace.traceEnd(Trace.TRACE_TAG_APP)
34         }
35     } else {
36         block()
37     }
38 
39 class TraceUtils {
40     companion object {
41         inline fun traceRunnable(tag: String, crossinline block: () -> Unit): Runnable {
42             return Runnable { traceSection(tag) { block() } }
43         }
44 
45         /**
46          * Helper function for creating a Runnable object that implements TraceNameSupplier.
47          *
48          * This is useful for posting Runnables to Handlers with meaningful names.
49          */
50         inline fun namedRunnable(tag: String, crossinline block: () -> Unit): Runnable {
51             return object : Runnable, TraceNameSupplier {
52                 override fun getTraceName(): String = tag
53                 override fun run() = block()
54             }
55         }
56 
57         /**
58          * Cookie used for async traces. Shouldn't be public, but to use it inside inline methods
59          * there is no other way around.
60          */
61         val lastCookie = AtomicInteger(0)
62 
63         /**
64          * Creates an async slice in a track called "AsyncTraces".
65          *
66          * This can be used to trace coroutine code. Note that all usages of this method will appear
67          * under a single track.
68          */
69         inline fun <T> traceAsync(method: String, block: () -> T): T =
70             traceAsync("AsyncTraces", method, block)
71 
72         /**
73          * Creates an async slice in a track with [trackName] while [block] runs.
74          *
75          * This can be used to trace coroutine code. [method] will be the name of the slice,
76          * [trackName] of the track. The track is one of the rows visible in a perfetto trace inside
77          * SystemUI process.
78          */
79         inline fun <T> traceAsync(trackName: String, method: String, block: () -> T): T {
80             val cookie = lastCookie.incrementAndGet()
81             Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, trackName, method, cookie)
82             try {
83                 return block()
84             } finally {
85                 Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, trackName, cookie)
86             }
87         }
88     }
89 }
90