• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
20 
21 import android.annotation.NonNull;
22 import android.annotation.SystemApi;
23 import android.compat.annotation.UnsupportedAppUsage;
24 
25 import dalvik.annotation.optimization.CriticalNative;
26 import dalvik.annotation.optimization.FastNative;
27 
28 /**
29  * Writes trace events to the system trace buffer.  These trace events can be
30  * collected and visualized using the Systrace tool.
31  *
32  * <p>This tracing mechanism is independent of the method tracing mechanism
33  * offered by {@link Debug#startMethodTracing}.  In particular, it enables
34  * tracing of events that occur across multiple processes.
35  * <p>For information about using the Systrace tool, read <a
36  * href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance
37  * with Systrace</a>.
38  */
39 @android.ravenwood.annotation.RavenwoodKeepWholeClass
40 public final class Trace {
41     /*
42      * Writes trace events to the kernel trace buffer.  These trace events can be
43      * collected using the "atrace" program for offline analysis.
44      */
45 
46     private static final String TAG = "Trace";
47 
48     // These tags must be kept in sync with system/core/include/cutils/trace.h.
49     // They should also be added to frameworks/native/cmds/atrace/atrace.cpp.
50     /** @hide */
51     public static final long TRACE_TAG_NEVER = 0;
52     /** @hide */
53     public static final long TRACE_TAG_ALWAYS = 1L << 0;
54     /** @hide */
55     public static final long TRACE_TAG_GRAPHICS = 1L << 1;
56     /** @hide */
57     public static final long TRACE_TAG_INPUT = 1L << 2;
58     /** @hide */
59     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
60     public static final long TRACE_TAG_VIEW = 1L << 3;
61     /** @hide */
62     public static final long TRACE_TAG_WEBVIEW = 1L << 4;
63     /** @hide */
64     public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5;
65     /** @hide */
66     public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6;
67     /** @hide */
68     public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7;
69     /** @hide */
70     public static final long TRACE_TAG_AUDIO = 1L << 8;
71     /** @hide */
72     public static final long TRACE_TAG_VIDEO = 1L << 9;
73     /** @hide */
74     public static final long TRACE_TAG_CAMERA = 1L << 10;
75     /** @hide */
76     public static final long TRACE_TAG_HAL = 1L << 11;
77     /** @hide */
78     @UnsupportedAppUsage
79     public static final long TRACE_TAG_APP = 1L << 12;
80     /** @hide */
81     public static final long TRACE_TAG_RESOURCES = 1L << 13;
82     /** @hide */
83     public static final long TRACE_TAG_DALVIK = 1L << 14;
84     /** @hide */
85     public static final long TRACE_TAG_RS = 1L << 15;
86     /** @hide */
87     public static final long TRACE_TAG_BIONIC = 1L << 16;
88     /** @hide */
89     public static final long TRACE_TAG_POWER = 1L << 17;
90     /** @hide */
91     public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
92     /** @hide */
93     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
94     /** @hide */
95     public static final long TRACE_TAG_DATABASE = 1L << 20;
96     /** @hide */
97     @SystemApi(client = MODULE_LIBRARIES)
98     public static final long TRACE_TAG_NETWORK = 1L << 21;
99     /** @hide */
100     public static final long TRACE_TAG_ADB = 1L << 22;
101     /** @hide */
102     public static final long TRACE_TAG_VIBRATOR = 1L << 23;
103     /** @hide */
104     @SystemApi
105     public static final long TRACE_TAG_AIDL = 1L << 24;
106     /** @hide */
107     public static final long TRACE_TAG_NNAPI = 1L << 25;
108     /** @hide */
109     public static final long TRACE_TAG_RRO = 1L << 26;
110     /** @hide */
111     public static final long TRACE_TAG_THERMAL = 1L << 27;
112 
113     private static final long TRACE_TAG_NOT_READY = 1L << 63;
114     /** @hide **/
115     public static final int MAX_SECTION_NAME_LEN = 127;
116 
117     // Must be volatile to avoid word tearing.
118     // This is only kept in case any apps get this by reflection but do not
119     // check the return value for null.
120     @UnsupportedAppUsage
121     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
122 
123     private static int sZygoteDebugFlags = 0;
124 
125     @UnsupportedAppUsage
126     @CriticalNative
127     @android.ravenwood.annotation.RavenwoodReplace
nativeIsTagEnabled(long tag)128     private static native boolean nativeIsTagEnabled(long tag);
129     @android.ravenwood.annotation.RavenwoodReplace
nativeSetAppTracingAllowed(boolean allowed)130     private static native void nativeSetAppTracingAllowed(boolean allowed);
131     @android.ravenwood.annotation.RavenwoodReplace
nativeSetTracingEnabled(boolean allowed)132     private static native void nativeSetTracingEnabled(boolean allowed);
133 
nativeIsTagEnabled$ravenwood(long traceTag)134     private static boolean nativeIsTagEnabled$ravenwood(long traceTag) {
135         // Tracing currently completely disabled under Ravenwood
136         return false;
137     }
138 
nativeSetAppTracingAllowed$ravenwood(boolean allowed)139     private static void nativeSetAppTracingAllowed$ravenwood(boolean allowed) {
140         // Tracing currently completely disabled under Ravenwood
141     }
142 
nativeSetTracingEnabled$ravenwood(boolean allowed)143     private static void nativeSetTracingEnabled$ravenwood(boolean allowed) {
144         // Tracing currently completely disabled under Ravenwood
145     }
146 
147     @FastNative
nativeTraceCounter(long tag, String name, long value)148     private static native void nativeTraceCounter(long tag, String name, long value);
149     @FastNative
nativeTraceBegin(long tag, String name)150     private static native void nativeTraceBegin(long tag, String name);
151     @FastNative
nativeTraceEnd(long tag)152     private static native void nativeTraceEnd(long tag);
153     @FastNative
nativeAsyncTraceBegin(long tag, String name, int cookie)154     private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
155     @FastNative
nativeAsyncTraceEnd(long tag, String name, int cookie)156     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
157     @FastNative
nativeAsyncTraceForTrackBegin(long tag, String trackName, String name, int cookie)158     private static native void nativeAsyncTraceForTrackBegin(long tag,
159             String trackName, String name, int cookie);
160     @FastNative
nativeAsyncTraceForTrackEnd(long tag, String trackName, int cookie)161     private static native void nativeAsyncTraceForTrackEnd(long tag,
162             String trackName, int cookie);
163     @FastNative
nativeInstant(long tag, String name)164     private static native void nativeInstant(long tag, String name);
165     @FastNative
nativeInstantForTrack(long tag, String trackName, String name)166     private static native void nativeInstantForTrack(long tag, String trackName, String name);
167 
Trace()168     private Trace() {
169     }
170 
171     /**
172      * Returns true if a trace tag is enabled.
173      *
174      * @param traceTag The trace tag to check.
175      * @return True if the trace tag is valid.
176      *
177      * @hide
178      */
179     @UnsupportedAppUsage
180     @SystemApi(client = MODULE_LIBRARIES)
isTagEnabled(long traceTag)181     public static boolean isTagEnabled(long traceTag) {
182         return nativeIsTagEnabled(traceTag);
183     }
184 
185     /**
186      * Writes trace message to indicate the value of a given counter.
187      *
188      * @param traceTag The trace tag.
189      * @param counterName The counter name to appear in the trace.
190      * @param counterValue The counter value.
191      *
192      * @hide
193      */
194     @UnsupportedAppUsage
195     @SystemApi(client = MODULE_LIBRARIES)
traceCounter(long traceTag, @NonNull String counterName, int counterValue)196     public static void traceCounter(long traceTag, @NonNull String counterName, int counterValue) {
197         if (isTagEnabled(traceTag)) {
198             nativeTraceCounter(traceTag, counterName, counterValue);
199         }
200     }
201 
202     /**
203      * From Android S, this is no-op.
204      *
205      * Before, set whether application tracing is allowed for this process.  This is intended to be
206      * set once at application start-up time based on whether the application is debuggable.
207      *
208      * @hide
209      */
210     @UnsupportedAppUsage
setAppTracingAllowed(boolean allowed)211     public static void setAppTracingAllowed(boolean allowed) {
212         nativeSetAppTracingAllowed(allowed);
213     }
214 
215     /**
216      * Set whether tracing is enabled in this process.
217      * @hide
218      */
setTracingEnabled(boolean enabled, int debugFlags)219     public static void setTracingEnabled(boolean enabled, int debugFlags) {
220         nativeSetTracingEnabled(enabled);
221         sZygoteDebugFlags = debugFlags;
222     }
223 
224     /**
225      * Writes a trace message to indicate that a given section of code has
226      * begun. Must be followed by a call to {@link #traceEnd} using the same
227      * tag.
228      *
229      * @param traceTag The trace tag.
230      * @param methodName The method name to appear in the trace.
231      *
232      * @hide
233      */
234     @UnsupportedAppUsage
235     @SystemApi(client = MODULE_LIBRARIES)
traceBegin(long traceTag, @NonNull String methodName)236     public static void traceBegin(long traceTag, @NonNull String methodName) {
237         if (isTagEnabled(traceTag)) {
238             nativeTraceBegin(traceTag, methodName);
239         }
240     }
241 
242     /**
243      * Writes a trace message to indicate that the current method has ended.
244      * Must be called exactly once for each call to {@link #traceBegin} using the same tag.
245      *
246      * @param traceTag The trace tag.
247      *
248      * @hide
249      */
250     @UnsupportedAppUsage
251     @SystemApi(client = MODULE_LIBRARIES)
traceEnd(long traceTag)252     public static void traceEnd(long traceTag) {
253         if (isTagEnabled(traceTag)) {
254             nativeTraceEnd(traceTag);
255         }
256     }
257 
258     /**
259      * Writes a trace message to indicate that a given section of code has
260      * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
261      * tag, name and cookie.
262      *
263      * If two events with the same methodName overlap in time then they *must* have
264      * different cookie values. If they do not, the trace can become corrupted
265      * in unpredictable ways.
266      *
267      * Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
268      * asynchronous events cannot be not nested. Consider using
269      * {@link #asyncTraceForTrackBegin(long, String, String, int)}
270      * if nested asynchronous events are needed.
271      *
272      * @param traceTag The trace tag.
273      * @param methodName The method name to appear in the trace.
274      * @param cookie Unique identifier for distinguishing simultaneous events
275      *
276      * @hide
277      */
278     @UnsupportedAppUsage
279     @SystemApi(client = MODULE_LIBRARIES)
asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie)280     public static void asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie) {
281         if (isTagEnabled(traceTag)) {
282             nativeAsyncTraceBegin(traceTag, methodName, cookie);
283         }
284     }
285 
286     /**
287      * Writes a trace message to indicate that the current method has ended.
288      * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
289      * using the same tag, name and cookie.
290      *
291      * See the documentation for {@link #asyncTraceBegin(long, String, int)}.
292      * for inteded usage of this method.
293      *
294      * @param traceTag The trace tag.
295      * @param methodName The method name to appear in the trace.
296      * @param cookie Unique identifier for distinguishing simultaneous events
297      *
298      * @hide
299      */
300     @UnsupportedAppUsage
301     @SystemApi(client = MODULE_LIBRARIES)
asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie)302     public static void asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie) {
303         if (isTagEnabled(traceTag)) {
304             nativeAsyncTraceEnd(traceTag, methodName, cookie);
305         }
306     }
307 
308 
309     /**
310      * Writes a trace message to indicate that a given section of code has
311      * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same
312      * track name and cookie.
313      *
314      * Events with the same trackName and cookie nest inside each other in the
315      * same way as calls to {@link #traceBegin(long, String)} and
316      * {@link #traceEnd(long)}.
317      *
318      * If two events with the same trackName overlap in time but do not nest
319      * correctly, then they *must* have different cookie values. If they do not,
320      * the trace can become corrupted in unpredictable ways.
321      *
322      * Good Example:
323      *
324      * public void parent() {
325      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "parent", mId);
326      *   child()
327      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId);
328      * }
329      *
330      * public void child() {
331      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "child", mId);
332      *   // Some code here.
333      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId);
334      * }
335      *
336      * This would be visualized as so:
337      *   [   Parent   ]
338      *     [ Child ]
339      *
340      * Bad Example:
341      *
342      * public static void processData(String dataToProcess) {
343      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", 0);
344      *   // Some code here.
345      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", 0);
346      * }
347      *
348      * public static void processDataInParallel({@code List<String>} data) {
349      *   ExecutorService executor = Executors.newCachedThreadPool();
350      *   for (String s : data) {
351      *     pool.execute(() -> processData(s));
352      *   }
353      * }
354      *
355      * This is invalid because it's possible for processData to be run many times
356      * in parallel (i.e. processData events overlap) but the same cookie is
357      * provided each time.
358      *
359      * To fix this, specify a different id in each invocation of processData:
360      *
361      * public static void processData(String dataToProcess, int id) {
362      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", id);
363      *   // Some code here.
364      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", id);
365      * }
366      *
367      * public static void processDataInParallel({@code List<String>} data) {
368      *   ExecutorService executor = Executors.newCachedThreadPool();
369      *   for (int i = 0; i < data.size(); ++i) {
370      *     pool.execute(() -> processData(data.get(i), i));
371      *   }
372      * }
373      *
374      * @param traceTag The trace tag.
375      * @param trackName The track where the event should appear in the trace.
376      * @param methodName The method name to appear in the trace.
377      * @param cookie Unique identifier used for nesting events on a single
378      *               track. Events which overlap without nesting on the same
379      *               track must have different values for cookie.
380      *
381      * @hide
382      */
asyncTraceForTrackBegin(long traceTag, @NonNull String trackName, @NonNull String methodName, int cookie)383     public static void asyncTraceForTrackBegin(long traceTag,
384             @NonNull String trackName, @NonNull String methodName, int cookie) {
385         if (isTagEnabled(traceTag)) {
386             nativeAsyncTraceForTrackBegin(traceTag, trackName, methodName, cookie);
387         }
388     }
389 
390     /**
391      * Writes a trace message to indicate that the current method has ended.
392      * Must be called exactly once for each call to
393      * {@link #asyncTraceForTrackBegin(long, String, String, int)}
394      * using the same tag, track name, and cookie.
395      *
396      * See the documentation for {@link #asyncTraceForTrackBegin(long, String, String, int)}.
397      * for inteded usage of this method.
398      *
399      * @param traceTag The trace tag.
400      * @param trackName The track where the event should appear in the trace.
401      * @param cookie Unique identifier used for nesting events on a single
402      *               track. Events which overlap without nesting on the same
403      *               track must have different values for cookie.
404      *
405      * @hide
406      */
asyncTraceForTrackEnd(long traceTag, @NonNull String trackName, int cookie)407     public static void asyncTraceForTrackEnd(long traceTag,
408             @NonNull String trackName, int cookie) {
409         if (isTagEnabled(traceTag)) {
410             nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie);
411         }
412     }
413 
414     /**
415      * Writes a trace message to indicate that a given section of code was invoked.
416      *
417      * @param traceTag The trace tag.
418      * @param methodName The method name to appear in the trace.
419      * @hide
420      */
instant(long traceTag, String methodName)421     public static void instant(long traceTag, String methodName) {
422         if (isTagEnabled(traceTag)) {
423             nativeInstant(traceTag, methodName);
424         }
425     }
426 
427     /**
428      * Writes a trace message to indicate that a given section of code was invoked.
429      *
430      * @param traceTag The trace tag.
431      * @param trackName The track where the event should appear in the trace.
432      * @param methodName The method name to appear in the trace.
433      * @hide
434      */
instantForTrack(long traceTag, String trackName, String methodName)435     public static void instantForTrack(long traceTag, String trackName, String methodName) {
436         if (isTagEnabled(traceTag)) {
437             nativeInstantForTrack(traceTag, trackName, methodName);
438         }
439     }
440 
441     /**
442      * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate
443      * string creation for trace sections that require formatting. It is not necessary
444      * to guard all Trace method calls as they internally already check this. However it is
445      * recommended to use this to prevent creating any temporary objects that would then be
446      * passed to those methods to reduce runtime cost when tracing isn't enabled.
447      *
448      * @return true if tracing is currently enabled, false otherwise
449      */
isEnabled()450     public static boolean isEnabled() {
451         return isTagEnabled(TRACE_TAG_APP);
452     }
453 
454     /**
455      * Writes a trace message to indicate that a given section of code has begun. This call must
456      * be followed by a corresponding call to {@link #endSection()} on the same thread.
457      *
458      * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
459      * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
460      * these characters they will be replaced with a space character in the trace.
461      *
462      * @param sectionName The name of the code section to appear in the trace.  This may be at
463      *                    most 127 Unicode code units long.
464      * @throws IllegalArgumentException if {@code sectionName} is too long.
465      */
beginSection(@onNull String sectionName)466     public static void beginSection(@NonNull String sectionName) {
467         if (isTagEnabled(TRACE_TAG_APP)) {
468             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
469                 throw new IllegalArgumentException("sectionName is too long");
470             }
471             nativeTraceBegin(TRACE_TAG_APP, sectionName);
472         }
473     }
474 
475     /**
476      * Writes a trace message to indicate that a given section of code has ended. This call must
477      * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method
478      * will mark the end of the most recently begun section of code, so care must be taken to
479      * ensure that beginSection / endSection pairs are properly nested and called from the same
480      * thread.
481      */
endSection()482     public static void endSection() {
483         if (isTagEnabled(TRACE_TAG_APP)) {
484             nativeTraceEnd(TRACE_TAG_APP);
485         }
486     }
487 
488     /**
489      * Writes a trace message to indicate that a given section of code has
490      * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
491      * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()},
492      * asynchronous events do not need to be nested. The name and cookie used to
493      * begin an event must be used to end it.
494      *
495      * @param methodName The method name to appear in the trace.
496      * @param cookie Unique identifier for distinguishing simultaneous events
497      */
beginAsyncSection(@onNull String methodName, int cookie)498     public static void beginAsyncSection(@NonNull String methodName, int cookie) {
499         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
500     }
501 
502     /**
503      * Writes a trace message to indicate that the current method has ended.
504      * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)}
505      * using the same name and cookie.
506      *
507      * @param methodName The method name to appear in the trace.
508      * @param cookie Unique identifier for distinguishing simultaneous events
509      */
endAsyncSection(@onNull String methodName, int cookie)510     public static void endAsyncSection(@NonNull String methodName, int cookie) {
511         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
512     }
513 
514     /**
515      * Writes trace message to indicate the value of a given counter.
516      *
517      * @param counterName The counter name to appear in the trace.
518      * @param counterValue The counter value.
519      */
setCounter(@onNull String counterName, long counterValue)520     public static void setCounter(@NonNull String counterName, long counterValue) {
521         setCounter(TRACE_TAG_APP, counterName, counterValue);
522     }
523 
524     /**
525      * Writes trace message to indicate the value of a given counter under a given trace tag.
526      *
527      * @param traceTag The trace tag.
528      * @param counterName The counter name to appear in the trace.
529      * @param counterValue The counter value.
530      * @hide
531      */
setCounter(long traceTag, @NonNull String counterName, long counterValue)532     public static void setCounter(long traceTag, @NonNull String counterName, long counterValue) {
533         if (isTagEnabled(traceTag)) {
534             nativeTraceCounter(traceTag, counterName, counterValue);
535         }
536     }
537 
538     /**
539      * Initialize the perfetto SDK. This must be called before any tracing
540      * calls so that perfetto SDK can be used, otherwise libcutils would be
541      * used.
542      *
543      * @hide
544      */
registerWithPerfetto()545     public static void registerWithPerfetto() {
546         PerfettoTrace.register(false /* isBackendInProcess */);
547         PerfettoTrace.registerCategories();
548     }
549 }
550