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