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 android.annotation.NonNull;
20 import android.compat.annotation.UnsupportedAppUsage;
21 
22 import dalvik.annotation.optimization.CriticalNative;
23 import dalvik.annotation.optimization.FastNative;
24 
25 /**
26  * Writes trace events to the system trace buffer.  These trace events can be
27  * collected and visualized using the Systrace tool.
28  *
29  * <p>This tracing mechanism is independent of the method tracing mechanism
30  * offered by {@link Debug#startMethodTracing}.  In particular, it enables
31  * tracing of events that occur across multiple processes.
32  * <p>For information about using the Systrace tool, read <a
33  * href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance
34  * with Systrace</a>.
35  */
36 public final class Trace {
37     /*
38      * Writes trace events to the kernel trace buffer.  These trace events can be
39      * collected using the "atrace" program for offline analysis.
40      */
41 
42     private static final String TAG = "Trace";
43 
44     // These tags must be kept in sync with system/core/include/cutils/trace.h.
45     // They should also be added to frameworks/native/cmds/atrace/atrace.cpp.
46     /** @hide */
47     public static final long TRACE_TAG_NEVER = 0;
48     /** @hide */
49     public static final long TRACE_TAG_ALWAYS = 1L << 0;
50     /** @hide */
51     public static final long TRACE_TAG_GRAPHICS = 1L << 1;
52     /** @hide */
53     public static final long TRACE_TAG_INPUT = 1L << 2;
54     /** @hide */
55     @UnsupportedAppUsage
56     public static final long TRACE_TAG_VIEW = 1L << 3;
57     /** @hide */
58     public static final long TRACE_TAG_WEBVIEW = 1L << 4;
59     /** @hide */
60     public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5;
61     /** @hide */
62     public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6;
63     /** @hide */
64     public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7;
65     /** @hide */
66     public static final long TRACE_TAG_AUDIO = 1L << 8;
67     /** @hide */
68     public static final long TRACE_TAG_VIDEO = 1L << 9;
69     /** @hide */
70     public static final long TRACE_TAG_CAMERA = 1L << 10;
71     /** @hide */
72     public static final long TRACE_TAG_HAL = 1L << 11;
73     /** @hide */
74     @UnsupportedAppUsage
75     public static final long TRACE_TAG_APP = 1L << 12;
76     /** @hide */
77     public static final long TRACE_TAG_RESOURCES = 1L << 13;
78     /** @hide */
79     public static final long TRACE_TAG_DALVIK = 1L << 14;
80     /** @hide */
81     public static final long TRACE_TAG_RS = 1L << 15;
82     /** @hide */
83     public static final long TRACE_TAG_BIONIC = 1L << 16;
84     /** @hide */
85     public static final long TRACE_TAG_POWER = 1L << 17;
86     /** @hide */
87     public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
88     /** @hide */
89     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
90     /** @hide */
91     public static final long TRACE_TAG_DATABASE = 1L << 20;
92     /** @hide */
93     public static final long TRACE_TAG_NETWORK = 1L << 21;
94     /** @hide */
95     public static final long TRACE_TAG_ADB = 1L << 22;
96     /** @hide */
97     public static final long TRACE_TAG_VIBRATOR = 1L << 23;
98     /** @hide */
99     public static final long TRACE_TAG_AIDL = 1L << 24;
100     /** @hide */
101     public static final long TRACE_TAG_NNAPI = 1L << 25;
102     /** @hide */
103     public static final long TRACE_TAG_RRO = 1L << 26;
104     /** @hide */
105     public static final long TRACE_TAG_APEX_MANAGER = 1L << 18;
106 
107     private static final long TRACE_TAG_NOT_READY = 1L << 63;
108     private static final int MAX_SECTION_NAME_LEN = 127;
109 
110     // Must be volatile to avoid word tearing.
111     // This is only kept in case any apps get this by reflection but do not
112     // check the return value for null.
113     @UnsupportedAppUsage
114     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
115 
116     private static int sZygoteDebugFlags = 0;
117 
118     @UnsupportedAppUsage
119     @CriticalNative
nativeGetEnabledTags()120     private static native long nativeGetEnabledTags();
nativeSetAppTracingAllowed(boolean allowed)121     private static native void nativeSetAppTracingAllowed(boolean allowed);
nativeSetTracingEnabled(boolean allowed)122     private static native void nativeSetTracingEnabled(boolean allowed);
123 
124     @FastNative
nativeTraceCounter(long tag, String name, long value)125     private static native void nativeTraceCounter(long tag, String name, long value);
126     @FastNative
nativeTraceBegin(long tag, String name)127     private static native void nativeTraceBegin(long tag, String name);
128     @FastNative
nativeTraceEnd(long tag)129     private static native void nativeTraceEnd(long tag);
130     @FastNative
nativeAsyncTraceBegin(long tag, String name, int cookie)131     private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
132     @FastNative
nativeAsyncTraceEnd(long tag, String name, int cookie)133     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
134 
Trace()135     private Trace() {
136     }
137 
138     /**
139      * Returns true if a trace tag is enabled.
140      *
141      * @param traceTag The trace tag to check.
142      * @return True if the trace tag is valid.
143      *
144      * @hide
145      */
146     @UnsupportedAppUsage
isTagEnabled(long traceTag)147     public static boolean isTagEnabled(long traceTag) {
148         long tags = nativeGetEnabledTags();
149         return (tags & traceTag) != 0;
150     }
151 
152     /**
153      * Writes trace message to indicate the value of a given counter.
154      *
155      * @param traceTag The trace tag.
156      * @param counterName The counter name to appear in the trace.
157      * @param counterValue The counter value.
158      *
159      * @hide
160      */
161     @UnsupportedAppUsage
traceCounter(long traceTag, String counterName, int counterValue)162     public static void traceCounter(long traceTag, String counterName, int counterValue) {
163         if (isTagEnabled(traceTag)) {
164             nativeTraceCounter(traceTag, counterName, counterValue);
165         }
166     }
167 
168     /**
169      * Set whether application tracing is allowed for this process.  This is intended to be set
170      * once at application start-up time based on whether the application is debuggable.
171      *
172      * @hide
173      */
174     @UnsupportedAppUsage
setAppTracingAllowed(boolean allowed)175     public static void setAppTracingAllowed(boolean allowed) {
176         nativeSetAppTracingAllowed(allowed);
177     }
178 
179     /**
180      * Set whether tracing is enabled in this process.
181      * @hide
182      */
setTracingEnabled(boolean enabled, int debugFlags)183     public static void setTracingEnabled(boolean enabled, int debugFlags) {
184         nativeSetTracingEnabled(enabled);
185         sZygoteDebugFlags = debugFlags;
186     }
187 
188     /**
189      * Writes a trace message to indicate that a given section of code has
190      * begun. Must be followed by a call to {@link #traceEnd} using the same
191      * tag.
192      *
193      * @param traceTag The trace tag.
194      * @param methodName The method name to appear in the trace.
195      *
196      * @hide
197      */
198     @UnsupportedAppUsage
traceBegin(long traceTag, String methodName)199     public static void traceBegin(long traceTag, String methodName) {
200         if (isTagEnabled(traceTag)) {
201             nativeTraceBegin(traceTag, methodName);
202         }
203     }
204 
205     /**
206      * Writes a trace message to indicate that the current method has ended.
207      * Must be called exactly once for each call to {@link #traceBegin} using the same tag.
208      *
209      * @param traceTag The trace tag.
210      *
211      * @hide
212      */
213     @UnsupportedAppUsage
traceEnd(long traceTag)214     public static void traceEnd(long traceTag) {
215         if (isTagEnabled(traceTag)) {
216             nativeTraceEnd(traceTag);
217         }
218     }
219 
220     /**
221      * Writes a trace message to indicate that a given section of code has
222      * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
223      * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
224      * asynchronous events do not need to be nested. The name and cookie used to
225      * begin an event must be used to end it.
226      *
227      * @param traceTag The trace tag.
228      * @param methodName The method name to appear in the trace.
229      * @param cookie Unique identifier for distinguishing simultaneous events
230      *
231      * @hide
232      */
233     @UnsupportedAppUsage
asyncTraceBegin(long traceTag, String methodName, int cookie)234     public static void asyncTraceBegin(long traceTag, String methodName, int cookie) {
235         if (isTagEnabled(traceTag)) {
236             nativeAsyncTraceBegin(traceTag, methodName, cookie);
237         }
238     }
239 
240     /**
241      * Writes a trace message to indicate that the current method has ended.
242      * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
243      * using the same tag, name and cookie.
244      *
245      * @param traceTag The trace tag.
246      * @param methodName The method name to appear in the trace.
247      * @param cookie Unique identifier for distinguishing simultaneous events
248      *
249      * @hide
250      */
251     @UnsupportedAppUsage
asyncTraceEnd(long traceTag, String methodName, int cookie)252     public static void asyncTraceEnd(long traceTag, String methodName, int cookie) {
253         if (isTagEnabled(traceTag)) {
254             nativeAsyncTraceEnd(traceTag, methodName, cookie);
255         }
256     }
257 
258     /**
259      * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate
260      * string creation for trace sections that require formatting. It is not necessary
261      * to guard all Trace method calls as they internally already check this. However it is
262      * recommended to use this to prevent creating any temporary objects that would then be
263      * passed to those methods to reduce runtime cost when tracing isn't enabled.
264      *
265      * @return true if tracing is currently enabled, false otherwise
266      */
isEnabled()267     public static boolean isEnabled() {
268         return isTagEnabled(TRACE_TAG_APP);
269     }
270 
271     /**
272      * Writes a trace message to indicate that a given section of code has begun. This call must
273      * be followed by a corresponding call to {@link #endSection()} on the same thread.
274      *
275      * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
276      * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
277      * these characters they will be replaced with a space character in the trace.
278      *
279      * @param sectionName The name of the code section to appear in the trace.  This may be at
280      * most 127 Unicode code units long.
281      */
beginSection(@onNull String sectionName)282     public static void beginSection(@NonNull String sectionName) {
283         if (isTagEnabled(TRACE_TAG_APP)) {
284             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
285                 throw new IllegalArgumentException("sectionName is too long");
286             }
287             nativeTraceBegin(TRACE_TAG_APP, sectionName);
288         }
289     }
290 
291     /**
292      * Writes a trace message to indicate that a given section of code has ended. This call must
293      * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method
294      * will mark the end of the most recently begun section of code, so care must be taken to
295      * ensure that beginSection / endSection pairs are properly nested and called from the same
296      * thread.
297      */
endSection()298     public static void endSection() {
299         if (isTagEnabled(TRACE_TAG_APP)) {
300             nativeTraceEnd(TRACE_TAG_APP);
301         }
302     }
303 
304     /**
305      * Writes a trace message to indicate that a given section of code has
306      * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
307      * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()},
308      * asynchronous events do not need to be nested. The name and cookie used to
309      * begin an event must be used to end it.
310      *
311      * @param methodName The method name to appear in the trace.
312      * @param cookie Unique identifier for distinguishing simultaneous events
313      */
beginAsyncSection(@onNull String methodName, int cookie)314     public static void beginAsyncSection(@NonNull String methodName, int cookie) {
315         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
316     }
317 
318     /**
319      * Writes a trace message to indicate that the current method has ended.
320      * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)}
321      * using the same name and cookie.
322      *
323      * @param methodName The method name to appear in the trace.
324      * @param cookie Unique identifier for distinguishing simultaneous events
325      */
endAsyncSection(@onNull String methodName, int cookie)326     public static void endAsyncSection(@NonNull String methodName, int cookie) {
327         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
328     }
329 
330     /**
331      * Writes trace message to indicate the value of a given counter.
332      *
333      * @param counterName The counter name to appear in the trace.
334      * @param counterValue The counter value.
335      */
setCounter(@onNull String counterName, long counterValue)336     public static void setCounter(@NonNull String counterName, long counterValue) {
337         if (isTagEnabled(TRACE_TAG_APP)) {
338             nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue);
339         }
340     }
341 }
342