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 
105     private static final long TRACE_TAG_NOT_READY = 1L << 63;
106     private static final int MAX_SECTION_NAME_LEN = 127;
107 
108     // Must be volatile to avoid word tearing.
109     // This is only kept in case any apps get this by reflection but do not
110     // check the return value for null.
111     @UnsupportedAppUsage
112     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
113 
114     private static int sZygoteDebugFlags = 0;
115 
116     @UnsupportedAppUsage
117     @CriticalNative
nativeGetEnabledTags()118     private static native long nativeGetEnabledTags();
nativeSetAppTracingAllowed(boolean allowed)119     private static native void nativeSetAppTracingAllowed(boolean allowed);
nativeSetTracingEnabled(boolean allowed)120     private static native void nativeSetTracingEnabled(boolean allowed);
121 
122     @FastNative
nativeTraceCounter(long tag, String name, long value)123     private static native void nativeTraceCounter(long tag, String name, long value);
124     @FastNative
nativeTraceBegin(long tag, String name)125     private static native void nativeTraceBegin(long tag, String name);
126     @FastNative
nativeTraceEnd(long tag)127     private static native void nativeTraceEnd(long tag);
128     @FastNative
nativeAsyncTraceBegin(long tag, String name, int cookie)129     private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
130     @FastNative
nativeAsyncTraceEnd(long tag, String name, int cookie)131     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
132 
Trace()133     private Trace() {
134     }
135 
136     /**
137      * Returns true if a trace tag is enabled.
138      *
139      * @param traceTag The trace tag to check.
140      * @return True if the trace tag is valid.
141      *
142      * @hide
143      */
144     @UnsupportedAppUsage
isTagEnabled(long traceTag)145     public static boolean isTagEnabled(long traceTag) {
146         long tags = nativeGetEnabledTags();
147         return (tags & traceTag) != 0;
148     }
149 
150     /**
151      * Writes trace message to indicate the value of a given counter.
152      *
153      * @param traceTag The trace tag.
154      * @param counterName The counter name to appear in the trace.
155      * @param counterValue The counter value.
156      *
157      * @hide
158      */
159     @UnsupportedAppUsage
traceCounter(long traceTag, String counterName, int counterValue)160     public static void traceCounter(long traceTag, String counterName, int counterValue) {
161         if (isTagEnabled(traceTag)) {
162             nativeTraceCounter(traceTag, counterName, counterValue);
163         }
164     }
165 
166     /**
167      * Set whether application tracing is allowed for this process.  This is intended to be set
168      * once at application start-up time based on whether the application is debuggable.
169      *
170      * @hide
171      */
172     @UnsupportedAppUsage
setAppTracingAllowed(boolean allowed)173     public static void setAppTracingAllowed(boolean allowed) {
174         nativeSetAppTracingAllowed(allowed);
175     }
176 
177     /**
178      * Set whether tracing is enabled in this process.
179      * @hide
180      */
setTracingEnabled(boolean enabled, int debugFlags)181     public static void setTracingEnabled(boolean enabled, int debugFlags) {
182         nativeSetTracingEnabled(enabled);
183         sZygoteDebugFlags = debugFlags;
184     }
185 
186     /**
187      * Writes a trace message to indicate that a given section of code has
188      * begun. Must be followed by a call to {@link #traceEnd} using the same
189      * tag.
190      *
191      * @param traceTag The trace tag.
192      * @param methodName The method name to appear in the trace.
193      *
194      * @hide
195      */
196     @UnsupportedAppUsage
traceBegin(long traceTag, String methodName)197     public static void traceBegin(long traceTag, String methodName) {
198         if (isTagEnabled(traceTag)) {
199             nativeTraceBegin(traceTag, methodName);
200         }
201     }
202 
203     /**
204      * Writes a trace message to indicate that the current method has ended.
205      * Must be called exactly once for each call to {@link #traceBegin} using the same tag.
206      *
207      * @param traceTag The trace tag.
208      *
209      * @hide
210      */
211     @UnsupportedAppUsage
traceEnd(long traceTag)212     public static void traceEnd(long traceTag) {
213         if (isTagEnabled(traceTag)) {
214             nativeTraceEnd(traceTag);
215         }
216     }
217 
218     /**
219      * Writes a trace message to indicate that a given section of code has
220      * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
221      * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
222      * asynchronous events do not need to be nested. The name and cookie used to
223      * begin an event must be used to end it.
224      *
225      * @param traceTag The trace tag.
226      * @param methodName The method name to appear in the trace.
227      * @param cookie Unique identifier for distinguishing simultaneous events
228      *
229      * @hide
230      */
231     @UnsupportedAppUsage
asyncTraceBegin(long traceTag, String methodName, int cookie)232     public static void asyncTraceBegin(long traceTag, String methodName, int cookie) {
233         if (isTagEnabled(traceTag)) {
234             nativeAsyncTraceBegin(traceTag, methodName, cookie);
235         }
236     }
237 
238     /**
239      * Writes a trace message to indicate that the current method has ended.
240      * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
241      * using the same tag, name and cookie.
242      *
243      * @param traceTag The trace tag.
244      * @param methodName The method name to appear in the trace.
245      * @param cookie Unique identifier for distinguishing simultaneous events
246      *
247      * @hide
248      */
249     @UnsupportedAppUsage
asyncTraceEnd(long traceTag, String methodName, int cookie)250     public static void asyncTraceEnd(long traceTag, String methodName, int cookie) {
251         if (isTagEnabled(traceTag)) {
252             nativeAsyncTraceEnd(traceTag, methodName, cookie);
253         }
254     }
255 
256     /**
257      * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate
258      * string creation for trace sections that require formatting. It is not necessary
259      * to guard all Trace method calls as they internally already check this. However it is
260      * recommended to use this to prevent creating any temporary objects that would then be
261      * passed to those methods to reduce runtime cost when tracing isn't enabled.
262      *
263      * @return true if tracing is currently enabled, false otherwise
264      */
isEnabled()265     public static boolean isEnabled() {
266         return isTagEnabled(TRACE_TAG_APP);
267     }
268 
269     /**
270      * Writes a trace message to indicate that a given section of code has begun. This call must
271      * be followed by a corresponding call to {@link #endSection()} on the same thread.
272      *
273      * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
274      * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
275      * these characters they will be replaced with a space character in the trace.
276      *
277      * @param sectionName The name of the code section to appear in the trace.  This may be at
278      * most 127 Unicode code units long.
279      */
beginSection(@onNull String sectionName)280     public static void beginSection(@NonNull String sectionName) {
281         if (isTagEnabled(TRACE_TAG_APP)) {
282             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
283                 throw new IllegalArgumentException("sectionName is too long");
284             }
285             nativeTraceBegin(TRACE_TAG_APP, sectionName);
286         }
287     }
288 
289     /**
290      * Writes a trace message to indicate that a given section of code has ended. This call must
291      * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method
292      * will mark the end of the most recently begun section of code, so care must be taken to
293      * ensure that beginSection / endSection pairs are properly nested and called from the same
294      * thread.
295      */
endSection()296     public static void endSection() {
297         if (isTagEnabled(TRACE_TAG_APP)) {
298             nativeTraceEnd(TRACE_TAG_APP);
299         }
300     }
301 
302     /**
303      * Writes a trace message to indicate that a given section of code has
304      * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
305      * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()},
306      * asynchronous events do not need to be nested. The name and cookie used to
307      * begin an event must be used to end it.
308      *
309      * @param methodName The method name to appear in the trace.
310      * @param cookie Unique identifier for distinguishing simultaneous events
311      */
beginAsyncSection(@onNull String methodName, int cookie)312     public static void beginAsyncSection(@NonNull String methodName, int cookie) {
313         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
314     }
315 
316     /**
317      * Writes a trace message to indicate that the current method has ended.
318      * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)}
319      * using the same name and cookie.
320      *
321      * @param methodName The method name to appear in the trace.
322      * @param cookie Unique identifier for distinguishing simultaneous events
323      */
endAsyncSection(@onNull String methodName, int cookie)324     public static void endAsyncSection(@NonNull String methodName, int cookie) {
325         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
326     }
327 
328     /**
329      * Writes trace message to indicate the value of a given counter.
330      *
331      * @param counterName The counter name to appear in the trace.
332      * @param counterValue The counter value.
333      */
setCounter(@onNull String counterName, long counterValue)334     public static void setCounter(@NonNull String counterName, long counterValue) {
335         if (isTagEnabled(TRACE_TAG_APP)) {
336             nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue);
337         }
338     }
339 }
340