• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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.os;
18 
19 import com.android.internal.ravenwood.RavenwoodEnvironment;
20 
21 import dalvik.annotation.optimization.CriticalNative;
22 import dalvik.annotation.optimization.FastNative;
23 
24 import libcore.util.NativeAllocationRegistry;
25 
26 import java.util.concurrent.atomic.AtomicInteger;
27 
28 /**
29  * Writes trace events to the perfetto trace buffer. These trace events can be
30  * collected and visualized using the Perfetto UI.
31  *
32  * <p>This tracing mechanism is independent of the method tracing mechanism
33  * offered by {@link Debug#startMethodTracing} or {@link Trace}.
34  *
35  * @hide
36  */
37 @android.ravenwood.annotation.RavenwoodKeepWholeClass
38 public final class PerfettoTrace {
39     private static final String TAG = "PerfettoTrace";
40 
41     // Keep in sync with C++
42     private static final int PERFETTO_TE_TYPE_SLICE_BEGIN = 1;
43     private static final int PERFETTO_TE_TYPE_SLICE_END = 2;
44     private static final int PERFETTO_TE_TYPE_INSTANT = 3;
45     private static final int PERFETTO_TE_TYPE_COUNTER = 4;
46 
47     private static final boolean IS_FLAG_ENABLED = android.os.Flags.perfettoSdkTracingV2();
48 
49     /**
50      * For fetching the next flow event id in a process.
51      */
52     private static final AtomicInteger sFlowEventId = new AtomicInteger();
53 
54     public static final PerfettoTrace.Category MQ_CATEGORY = new PerfettoTrace.Category("mq");
55 
56     /**
57      * Perfetto category a trace event belongs to.
58      * Registering a category is not sufficient to capture events within the category, it must
59      * also be enabled in the trace config.
60      */
61     @android.ravenwood.annotation.RavenwoodKeepWholeClass
62     public static final class Category implements PerfettoTrackEventExtra.PerfettoPointer {
63         private static final NativeAllocationRegistry sRegistry =
64                 NativeAllocationRegistry.createMalloced(
65                         Category.class.getClassLoader(), native_delete());
66 
67         private final long mPtr;
68         private final long mExtraPtr;
69         private final String mName;
70         private final String mTag;
71         private final String mSeverity;
72         private boolean mIsRegistered;
73 
74         /**
75          * Category ctor.
76          *
77          * @param name The category name.
78          */
Category(String name)79         public Category(String name) {
80             this(name, "", "");
81         }
82 
83         /**
84          * Category ctor.
85          *
86          * @param name The category name.
87          * @param tag An atrace tag name that this category maps to.
88          */
Category(String name, String tag)89         public Category(String name, String tag) {
90             this(name, tag, "");
91         }
92 
93         /**
94          * Category ctor.
95          *
96          * @param name The category name.
97          * @param tag An atrace tag name that this category maps to.
98          * @param severity A Log style severity string for the category.
99          */
Category(String name, String tag, String severity)100         public Category(String name, String tag, String severity) {
101             mName = name;
102             mTag = tag;
103             mSeverity = severity;
104             mPtr = native_init(name, tag, severity);
105             mExtraPtr = native_get_extra_ptr(mPtr);
106             if (!RavenwoodEnvironment.getInstance().isRunningOnRavenwood()) {
107                 sRegistry.registerNativeAllocation(this, mPtr);
108             }
109         }
110 
111         @FastNative
112         @android.ravenwood.annotation.RavenwoodReplace
native_init(String name, String tag, String severity)113         private static native long native_init(String name, String tag, String severity);
114         @CriticalNative
115         @android.ravenwood.annotation.RavenwoodReplace
native_delete()116         private static native long native_delete();
117         @CriticalNative
native_register(long ptr)118         private static native void native_register(long ptr);
119         @CriticalNative
native_unregister(long ptr)120         private static native void native_unregister(long ptr);
121         @CriticalNative
native_is_enabled(long ptr)122         private static native boolean native_is_enabled(long ptr);
123         @CriticalNative
124         @android.ravenwood.annotation.RavenwoodReplace
native_get_extra_ptr(long ptr)125         private static native long native_get_extra_ptr(long ptr);
126 
native_init$ravenwood(String name, String tag, String severity)127         private static long native_init$ravenwood(String name, String tag, String severity) {
128             // Tracing currently completely disabled under Ravenwood
129             return 0;
130         }
131 
native_delete$ravenwood()132         private static long native_delete$ravenwood() {
133             // Tracing currently completely disabled under Ravenwood
134             return 0;
135         }
136 
native_get_extra_ptr$ravenwood(long ptr)137         private static long native_get_extra_ptr$ravenwood(long ptr) {
138             // Tracing currently completely disabled under Ravenwood
139             return 0;
140         }
141 
142         /**
143          * Register the category.
144          */
register()145         public Category register() {
146             native_register(mPtr);
147             mIsRegistered = true;
148             return this;
149         }
150 
151         /**
152          * Unregister the category.
153          */
unregister()154         public Category unregister() {
155             native_unregister(mPtr);
156             mIsRegistered = false;
157             return this;
158         }
159 
160         /**
161          * Whether the category is enabled or not.
162          */
163         @android.ravenwood.annotation.RavenwoodReplace
isEnabled()164         public boolean isEnabled() {
165             return IS_FLAG_ENABLED && native_is_enabled(mPtr);
166         }
167 
isEnabled$ravenwood()168         public boolean isEnabled$ravenwood() {
169             // Tracing currently completely disabled under Ravenwood
170             return false;
171         }
172 
173         /**
174          * Whether the category is registered or not.
175          */
isRegistered()176         public boolean isRegistered() {
177             return mIsRegistered;
178         }
179 
180         /**
181          * Returns the native pointer for the category.
182          */
183         @Override
getPtr()184         public long getPtr() {
185             return mExtraPtr;
186         }
187     }
188 
189     /**
190      * Manages a perfetto tracing session.
191      * Constructing this object with a config automatically starts a tracing session. Each session
192      * must be closed after use and then the resulting trace bytes can be read.
193      *
194      * The session could be in process or system wide, depending on {@code isBackendInProcess}.
195      * This functionality is intended for testing.
196      */
197     public static final class Session {
198         private final long mPtr;
199 
200         /**
201          * Session ctor.
202          */
Session(boolean isBackendInProcess, byte[] config)203         public Session(boolean isBackendInProcess, byte[] config) {
204             mPtr = native_start_session(isBackendInProcess, config);
205         }
206 
207         /**
208          * Closes the session and returns the trace.
209          */
close()210         public byte[] close() {
211             return native_stop_session(mPtr);
212         }
213     }
214 
215     @CriticalNative
native_get_process_track_uuid()216     private static native long native_get_process_track_uuid();
217     @CriticalNative
native_get_thread_track_uuid(long tid)218     private static native long native_get_thread_track_uuid(long tid);
219 
220     @FastNative
native_activate_trigger(String name, int ttlMs)221     private static native void native_activate_trigger(String name, int ttlMs);
222     @FastNative
native_register(boolean isBackendInProcess)223     private static native void native_register(boolean isBackendInProcess);
224 
native_start_session(boolean isBackendInProcess, byte[] config)225     private static native long native_start_session(boolean isBackendInProcess, byte[] config);
native_stop_session(long ptr)226     private static native byte[] native_stop_session(long ptr);
227 
228     /**
229      * Writes a trace message to indicate a given section of code was invoked.
230      *
231      * @param category The perfetto category.
232      * @param eventName The event name to appear in the trace.
233      */
instant(Category category, String eventName)234     public static PerfettoTrackEventExtra.Builder instant(Category category, String eventName) {
235         return PerfettoTrackEventExtra.builder(category.isEnabled())
236             .init(PERFETTO_TE_TYPE_INSTANT, category)
237             .setEventName(eventName);
238     }
239 
240     /**
241      * Writes a trace message to indicate the start of a given section of code.
242      *
243      * @param category The perfetto category.
244      * @param eventName The event name to appear in the trace.
245      */
begin(Category category, String eventName)246     public static PerfettoTrackEventExtra.Builder begin(Category category, String eventName) {
247         return PerfettoTrackEventExtra.builder(category.isEnabled())
248             .init(PERFETTO_TE_TYPE_SLICE_BEGIN, category)
249             .setEventName(eventName);
250     }
251 
252     /**
253      * Writes a trace message to indicate the end of a given section of code.
254      *
255      * @param category The perfetto category.
256      */
end(Category category)257     public static PerfettoTrackEventExtra.Builder end(Category category) {
258         return PerfettoTrackEventExtra.builder(category.isEnabled())
259             .init(PERFETTO_TE_TYPE_SLICE_END, category);
260     }
261 
262     /**
263      * Writes a trace message to indicate the value of a given section of code.
264      *
265      * @param category The perfetto category.
266      * @param value The value of the counter.
267      */
counter(Category category, long value)268     public static PerfettoTrackEventExtra.Builder counter(Category category, long value) {
269         return PerfettoTrackEventExtra.builder(category.isEnabled())
270             .init(PERFETTO_TE_TYPE_COUNTER, category)
271             .setCounter(value);
272     }
273 
274     /**
275      * Writes a trace message to indicate the value of a given section of code.
276      *
277      * @param category The perfetto category.
278      * @param value The value of the counter.
279      * @param trackName The trackName for the event.
280      */
counter( Category category, long value, String trackName)281     public static PerfettoTrackEventExtra.Builder counter(
282             Category category, long value, String trackName) {
283         return counter(category, value).usingProcessCounterTrack(trackName);
284     }
285 
286     /**
287      * Writes a trace message to indicate the value of a given section of code.
288      *
289      * @param category The perfetto category.
290      * @param value The value of the counter.
291      */
counter(Category category, double value)292     public static PerfettoTrackEventExtra.Builder counter(Category category, double value) {
293         return PerfettoTrackEventExtra.builder(category.isEnabled())
294             .init(PERFETTO_TE_TYPE_COUNTER, category)
295             .setCounter(value);
296     }
297 
298     /**
299      * Writes a trace message to indicate the value of a given section of code.
300      *
301      * @param category The perfetto category.
302      * @param value The value of the counter.
303      * @param trackName The trackName for the event.
304      */
counter( Category category, double value, String trackName)305     public static PerfettoTrackEventExtra.Builder counter(
306             Category category, double value, String trackName) {
307         return counter(category, value).usingProcessCounterTrack(trackName);
308     }
309 
310     /**
311      * Returns the next flow id to be used.
312      */
getFlowId()313     public static int getFlowId() {
314         return sFlowEventId.incrementAndGet();
315     }
316 
317     /**
318      * Returns the global track uuid that can be used as a parent track uuid.
319      */
getGlobalTrackUuid()320     public static long getGlobalTrackUuid() {
321         return 0;
322     }
323 
324     /**
325      * Returns the process track uuid that can be used as a parent track uuid.
326      */
getProcessTrackUuid()327     public static long getProcessTrackUuid() {
328         if (!IS_FLAG_ENABLED) {
329             return 0;
330         }
331         return native_get_process_track_uuid();
332     }
333 
334     /**
335      * Given a thread tid, returns the thread track uuid that can be used as a parent track uuid.
336      */
getThreadTrackUuid(long tid)337     public static long getThreadTrackUuid(long tid) {
338         if (!IS_FLAG_ENABLED) {
339             return 0;
340         }
341         return native_get_thread_track_uuid(tid);
342     }
343 
344     /**
345      * Activates a trigger by name {@code triggerName} with expiry in {@code ttlMs}.
346      */
activateTrigger(String triggerName, int ttlMs)347     public static void activateTrigger(String triggerName, int ttlMs) {
348         if (!IS_FLAG_ENABLED) {
349             return;
350         }
351         native_activate_trigger(triggerName, ttlMs);
352     }
353 
354     /**
355      * Registers the process with Perfetto.
356      */
register(boolean isBackendInProcess)357     public static void register(boolean isBackendInProcess) {
358         native_register(isBackendInProcess);
359     }
360 
361     /**
362      * Registers categories with Perfetto.
363      */
registerCategories()364     public static void registerCategories() {
365         MQ_CATEGORY.register();
366     }
367 }
368