• 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     @FastNative
nativeRegisterWithPerfetto()168     private static native void nativeRegisterWithPerfetto();
169 
Trace()170     private Trace() {
171     }
172 
173     /**
174      * Returns true if a trace tag is enabled.
175      *
176      * @param traceTag The trace tag to check.
177      * @return True if the trace tag is valid.
178      *
179      * @hide
180      */
181     @UnsupportedAppUsage
182     @SystemApi(client = MODULE_LIBRARIES)
isTagEnabled(long traceTag)183     public static boolean isTagEnabled(long traceTag) {
184         return nativeIsTagEnabled(traceTag);
185     }
186 
187     /**
188      * Writes trace message to indicate the value of a given counter.
189      *
190      * @param traceTag The trace tag.
191      * @param counterName The counter name to appear in the trace.
192      * @param counterValue The counter value.
193      *
194      * @hide
195      */
196     @UnsupportedAppUsage
197     @SystemApi(client = MODULE_LIBRARIES)
traceCounter(long traceTag, @NonNull String counterName, int counterValue)198     public static void traceCounter(long traceTag, @NonNull String counterName, int counterValue) {
199         if (isTagEnabled(traceTag)) {
200             nativeTraceCounter(traceTag, counterName, counterValue);
201         }
202     }
203 
204     /**
205      * From Android S, this is no-op.
206      *
207      * Before, set whether application tracing is allowed for this process.  This is intended to be
208      * set once at application start-up time based on whether the application is debuggable.
209      *
210      * @hide
211      */
212     @UnsupportedAppUsage
setAppTracingAllowed(boolean allowed)213     public static void setAppTracingAllowed(boolean allowed) {
214         nativeSetAppTracingAllowed(allowed);
215     }
216 
217     /**
218      * Set whether tracing is enabled in this process.
219      * @hide
220      */
setTracingEnabled(boolean enabled, int debugFlags)221     public static void setTracingEnabled(boolean enabled, int debugFlags) {
222         nativeSetTracingEnabled(enabled);
223         sZygoteDebugFlags = debugFlags;
224     }
225 
226     /**
227      * Writes a trace message to indicate that a given section of code has
228      * begun. Must be followed by a call to {@link #traceEnd} using the same
229      * tag.
230      *
231      * @param traceTag The trace tag.
232      * @param methodName The method name to appear in the trace.
233      *
234      * @hide
235      */
236     @UnsupportedAppUsage
237     @SystemApi(client = MODULE_LIBRARIES)
traceBegin(long traceTag, @NonNull String methodName)238     public static void traceBegin(long traceTag, @NonNull String methodName) {
239         if (isTagEnabled(traceTag)) {
240             nativeTraceBegin(traceTag, methodName);
241         }
242     }
243 
244     /**
245      * Writes a trace message to indicate that the current method has ended.
246      * Must be called exactly once for each call to {@link #traceBegin} using the same tag.
247      *
248      * @param traceTag The trace tag.
249      *
250      * @hide
251      */
252     @UnsupportedAppUsage
253     @SystemApi(client = MODULE_LIBRARIES)
traceEnd(long traceTag)254     public static void traceEnd(long traceTag) {
255         if (isTagEnabled(traceTag)) {
256             nativeTraceEnd(traceTag);
257         }
258     }
259 
260     /**
261      * Writes a trace message to indicate that a given section of code has
262      * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
263      * tag, name and cookie.
264      *
265      * If two events with the same methodName overlap in time then they *must* have
266      * different cookie values. If they do not, the trace can become corrupted
267      * in unpredictable ways.
268      *
269      * Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
270      * asynchronous events cannot be not nested. Consider using
271      * {@link #asyncTraceForTrackBegin(long, String, String, int)}
272      * if nested asynchronous events are needed.
273      *
274      * @param traceTag The trace tag.
275      * @param methodName The method name to appear in the trace.
276      * @param cookie Unique identifier for distinguishing simultaneous events
277      *
278      * @hide
279      */
280     @UnsupportedAppUsage
281     @SystemApi(client = MODULE_LIBRARIES)
asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie)282     public static void asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie) {
283         if (isTagEnabled(traceTag)) {
284             nativeAsyncTraceBegin(traceTag, methodName, cookie);
285         }
286     }
287 
288     /**
289      * Writes a trace message to indicate that the current method has ended.
290      * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
291      * using the same tag, name and cookie.
292      *
293      * See the documentation for {@link #asyncTraceBegin(long, String, int)}.
294      * for inteded usage of this method.
295      *
296      * @param traceTag The trace tag.
297      * @param methodName The method name to appear in the trace.
298      * @param cookie Unique identifier for distinguishing simultaneous events
299      *
300      * @hide
301      */
302     @UnsupportedAppUsage
303     @SystemApi(client = MODULE_LIBRARIES)
asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie)304     public static void asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie) {
305         if (isTagEnabled(traceTag)) {
306             nativeAsyncTraceEnd(traceTag, methodName, cookie);
307         }
308     }
309 
310 
311     /**
312      * Writes a trace message to indicate that a given section of code has
313      * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same
314      * track name and cookie.
315      *
316      * Events with the same trackName and cookie nest inside each other in the
317      * same way as calls to {@link #traceBegin(long, String)} and
318      * {@link #traceEnd(long)}.
319      *
320      * If two events with the same trackName overlap in time but do not nest
321      * correctly, then they *must* have different cookie values. If they do not,
322      * the trace can become corrupted in unpredictable ways.
323      *
324      * Good Example:
325      *
326      * public void parent() {
327      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "parent", mId);
328      *   child()
329      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId);
330      * }
331      *
332      * public void child() {
333      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "child", mId);
334      *   // Some code here.
335      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId);
336      * }
337      *
338      * This would be visualized as so:
339      *   [   Parent   ]
340      *     [ Child ]
341      *
342      * Bad Example:
343      *
344      * public static void processData(String dataToProcess) {
345      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", 0);
346      *   // Some code here.
347      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", 0);
348      * }
349      *
350      * public static void processDataInParallel({@code List<String>} data) {
351      *   ExecutorService executor = Executors.newCachedThreadPool();
352      *   for (String s : data) {
353      *     pool.execute(() -> processData(s));
354      *   }
355      * }
356      *
357      * This is invalid because it's possible for processData to be run many times
358      * in parallel (i.e. processData events overlap) but the same cookie is
359      * provided each time.
360      *
361      * To fix this, specify a different id in each invocation of processData:
362      *
363      * public static void processData(String dataToProcess, int id) {
364      *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", id);
365      *   // Some code here.
366      *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", id);
367      * }
368      *
369      * public static void processDataInParallel({@code List<String>} data) {
370      *   ExecutorService executor = Executors.newCachedThreadPool();
371      *   for (int i = 0; i < data.size(); ++i) {
372      *     pool.execute(() -> processData(data.get(i), i));
373      *   }
374      * }
375      *
376      * @param traceTag The trace tag.
377      * @param trackName The track where the event should appear in the trace.
378      * @param methodName The method name to appear in the trace.
379      * @param cookie Unique identifier used for nesting events on a single
380      *               track. Events which overlap without nesting on the same
381      *               track must have different values for cookie.
382      *
383      * @hide
384      */
asyncTraceForTrackBegin(long traceTag, @NonNull String trackName, @NonNull String methodName, int cookie)385     public static void asyncTraceForTrackBegin(long traceTag,
386             @NonNull String trackName, @NonNull String methodName, int cookie) {
387         if (isTagEnabled(traceTag)) {
388             nativeAsyncTraceForTrackBegin(traceTag, trackName, methodName, cookie);
389         }
390     }
391 
392     /**
393      * Writes a trace message to indicate that the current method has ended.
394      * Must be called exactly once for each call to
395      * {@link #asyncTraceForTrackBegin(long, String, String, int)}
396      * using the same tag, track name, and cookie.
397      *
398      * See the documentation for {@link #asyncTraceForTrackBegin(long, String, String, int)}.
399      * for inteded usage of this method.
400      *
401      * @param traceTag The trace tag.
402      * @param trackName The track where the event should appear in the trace.
403      * @param cookie Unique identifier used for nesting events on a single
404      *               track. Events which overlap without nesting on the same
405      *               track must have different values for cookie.
406      *
407      * @hide
408      */
asyncTraceForTrackEnd(long traceTag, @NonNull String trackName, int cookie)409     public static void asyncTraceForTrackEnd(long traceTag,
410             @NonNull String trackName, int cookie) {
411         if (isTagEnabled(traceTag)) {
412             nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie);
413         }
414     }
415 
416     /**
417      * Writes a trace message to indicate that a given section of code was invoked.
418      *
419      * @param traceTag The trace tag.
420      * @param methodName The method name to appear in the trace.
421      * @hide
422      */
instant(long traceTag, String methodName)423     public static void instant(long traceTag, String methodName) {
424         if (isTagEnabled(traceTag)) {
425             nativeInstant(traceTag, methodName);
426         }
427     }
428 
429     /**
430      * Writes a trace message to indicate that a given section of code was invoked.
431      *
432      * @param traceTag The trace tag.
433      * @param trackName The track where the event should appear in the trace.
434      * @param methodName The method name to appear in the trace.
435      * @hide
436      */
instantForTrack(long traceTag, String trackName, String methodName)437     public static void instantForTrack(long traceTag, String trackName, String methodName) {
438         if (isTagEnabled(traceTag)) {
439             nativeInstantForTrack(traceTag, trackName, methodName);
440         }
441     }
442 
443     /**
444      * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate
445      * string creation for trace sections that require formatting. It is not necessary
446      * to guard all Trace method calls as they internally already check this. However it is
447      * recommended to use this to prevent creating any temporary objects that would then be
448      * passed to those methods to reduce runtime cost when tracing isn't enabled.
449      *
450      * @return true if tracing is currently enabled, false otherwise
451      */
isEnabled()452     public static boolean isEnabled() {
453         return isTagEnabled(TRACE_TAG_APP);
454     }
455 
456     /**
457      * Writes a trace message to indicate that a given section of code has begun. This call must
458      * be followed by a corresponding call to {@link #endSection()} on the same thread.
459      *
460      * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
461      * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
462      * these characters they will be replaced with a space character in the trace.
463      *
464      * @param sectionName The name of the code section to appear in the trace.  This may be at
465      *                    most 127 Unicode code units long.
466      * @throws IllegalArgumentException if {@code sectionName} is too long.
467      */
beginSection(@onNull String sectionName)468     public static void beginSection(@NonNull String sectionName) {
469         if (isTagEnabled(TRACE_TAG_APP)) {
470             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
471                 throw new IllegalArgumentException("sectionName is too long");
472             }
473             nativeTraceBegin(TRACE_TAG_APP, sectionName);
474         }
475     }
476 
477     /**
478      * Writes a trace message to indicate that a given section of code has ended. This call must
479      * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method
480      * will mark the end of the most recently begun section of code, so care must be taken to
481      * ensure that beginSection / endSection pairs are properly nested and called from the same
482      * thread.
483      */
endSection()484     public static void endSection() {
485         if (isTagEnabled(TRACE_TAG_APP)) {
486             nativeTraceEnd(TRACE_TAG_APP);
487         }
488     }
489 
490     /**
491      * Writes a trace message to indicate that a given section of code has
492      * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
493      * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()},
494      * asynchronous events do not need to be nested. The name and cookie used to
495      * begin an event must be used to end it.
496      *
497      * @param methodName The method name to appear in the trace.
498      * @param cookie Unique identifier for distinguishing simultaneous events
499      */
beginAsyncSection(@onNull String methodName, int cookie)500     public static void beginAsyncSection(@NonNull String methodName, int cookie) {
501         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
502     }
503 
504     /**
505      * Writes a trace message to indicate that the current method has ended.
506      * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)}
507      * using the same name and cookie.
508      *
509      * @param methodName The method name to appear in the trace.
510      * @param cookie Unique identifier for distinguishing simultaneous events
511      */
endAsyncSection(@onNull String methodName, int cookie)512     public static void endAsyncSection(@NonNull String methodName, int cookie) {
513         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
514     }
515 
516     /**
517      * Writes trace message to indicate the value of a given counter.
518      *
519      * @param counterName The counter name to appear in the trace.
520      * @param counterValue The counter value.
521      */
setCounter(@onNull String counterName, long counterValue)522     public static void setCounter(@NonNull String counterName, long counterValue) {
523         if (isTagEnabled(TRACE_TAG_APP)) {
524             nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue);
525         }
526     }
527 
528     /**
529      * Initialize the perfetto SDK. This must be called before any tracing
530      * calls so that perfetto SDK can be used, otherwise libcutils would be
531      * used.
532      *
533      * @hide
534      */
registerWithPerfetto()535     public static void registerWithPerfetto() {
536         nativeRegisterWithPerfetto();
537     }
538 }
539