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.annotation.UnsupportedAppUsage;
21 
22 import com.android.internal.os.Zygote;
23 
24 import dalvik.annotation.optimization.FastNative;
25 
26 /**
27  * Writes trace events to the system trace buffer.  These trace events can be
28  * collected and visualized using the Systrace tool.
29  *
30  * <p>This tracing mechanism is independent of the method tracing mechanism
31  * offered by {@link Debug#startMethodTracing}.  In particular, it enables
32  * tracing of events that occur across multiple processes.
33  * <p>For information about using the Systrace tool, read <a
34  * href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance
35  * with Systrace</a>.
36  */
37 public final class Trace {
38     /*
39      * Writes trace events to the kernel trace buffer.  These trace events can be
40      * collected using the "atrace" program for offline analysis.
41      */
42 
43     private static final String TAG = "Trace";
44 
45     // These tags must be kept in sync with system/core/include/cutils/trace.h.
46     // They should also be added to frameworks/native/cmds/atrace/atrace.cpp.
47     /** @hide */
48     public static final long TRACE_TAG_NEVER = 0;
49     /** @hide */
50     public static final long TRACE_TAG_ALWAYS = 1L << 0;
51     /** @hide */
52     public static final long TRACE_TAG_GRAPHICS = 1L << 1;
53     /** @hide */
54     public static final long TRACE_TAG_INPUT = 1L << 2;
55     /** @hide */
56     @UnsupportedAppUsage
57     public static final long TRACE_TAG_VIEW = 1L << 3;
58     /** @hide */
59     public static final long TRACE_TAG_WEBVIEW = 1L << 4;
60     /** @hide */
61     public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5;
62     /** @hide */
63     public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6;
64     /** @hide */
65     public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7;
66     /** @hide */
67     public static final long TRACE_TAG_AUDIO = 1L << 8;
68     /** @hide */
69     public static final long TRACE_TAG_VIDEO = 1L << 9;
70     /** @hide */
71     public static final long TRACE_TAG_CAMERA = 1L << 10;
72     /** @hide */
73     public static final long TRACE_TAG_HAL = 1L << 11;
74     /** @hide */
75     @UnsupportedAppUsage
76     public static final long TRACE_TAG_APP = 1L << 12;
77     /** @hide */
78     public static final long TRACE_TAG_RESOURCES = 1L << 13;
79     /** @hide */
80     public static final long TRACE_TAG_DALVIK = 1L << 14;
81     /** @hide */
82     public static final long TRACE_TAG_RS = 1L << 15;
83     /** @hide */
84     public static final long TRACE_TAG_BIONIC = 1L << 16;
85     /** @hide */
86     public static final long TRACE_TAG_POWER = 1L << 17;
87     /** @hide */
88     public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
89     /** @hide */
90     public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
91     /** @hide */
92     public static final long TRACE_TAG_DATABASE = 1L << 20;
93     /** @hide */
94     public static final long TRACE_TAG_NETWORK = 1L << 21;
95     /** @hide */
96     public static final long TRACE_TAG_ADB = 1L << 22;
97     /** @hide */
98     public static final long TRACE_TAG_VIBRATOR = 1L << 23;
99     /** @hide */
100     public static final long TRACE_TAG_AIDL = 1L << 24;
101     /** @hide */
102     public static final long TRACE_TAG_NNAPI = 1L << 25;
103     /** @hide */
104     public static final long TRACE_TAG_RRO = 1L << 26;
105 
106     private static final long TRACE_TAG_NOT_READY = 1L << 63;
107     private static final int MAX_SECTION_NAME_LEN = 127;
108 
109     // Must be volatile to avoid word tearing.
110     @UnsupportedAppUsage
111     private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
112 
113     private static int sZygoteDebugFlags = 0;
114 
115     @UnsupportedAppUsage
nativeGetEnabledTags()116     private static native long nativeGetEnabledTags();
nativeSetAppTracingAllowed(boolean allowed)117     private static native void nativeSetAppTracingAllowed(boolean allowed);
nativeSetTracingEnabled(boolean allowed)118     private static native void nativeSetTracingEnabled(boolean allowed);
119 
120     @FastNative
nativeTraceCounter(long tag, String name, long value)121     private static native void nativeTraceCounter(long tag, String name, long value);
122     @FastNative
nativeTraceBegin(long tag, String name)123     private static native void nativeTraceBegin(long tag, String name);
124     @FastNative
nativeTraceEnd(long tag)125     private static native void nativeTraceEnd(long tag);
126     @FastNative
nativeAsyncTraceBegin(long tag, String name, int cookie)127     private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
128     @FastNative
nativeAsyncTraceEnd(long tag, String name, int cookie)129     private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
130 
131     static {
132         // We configure two separate change callbacks, one in Trace.cpp and one here.  The
133         // native callback reads the tags from the system property, and this callback
134         // reads the value that the native code retrieved.  It's essential that the native
135         // callback executes first.
136         //
137         // The system provides ordering through a priority level.  Callbacks made through
138         // SystemProperties.addChangeCallback currently have a negative priority, while
139         // our native code is using a priority of zero.
SystemProperties.addChangeCallback()140         SystemProperties.addChangeCallback(() -> {
141             cacheEnabledTags();
142             if ((sZygoteDebugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
143                 traceCounter(TRACE_TAG_ALWAYS, "java_debuggable", 1);
144             }
145         });
146     }
147 
Trace()148     private Trace() {
149     }
150 
151     /**
152      * Caches a copy of the enabled-tag bits.  The "master" copy is held by the native code,
153      * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property.
154      * <p>
155      * If the native code hasn't yet read the property, we will cause it to do one-time
156      * initialization.  We don't want to do this during class init, because this class is
157      * preloaded, so all apps would be stuck with whatever the zygote saw.  (The zygote
158      * doesn't see the system-property update broadcasts.)
159      * <p>
160      * We want to defer initialization until the first use by an app, post-zygote.
161      * <p>
162      * We're okay if multiple threads call here simultaneously -- the native state is
163      * synchronized, and sEnabledTags is volatile (prevents word tearing).
164      */
cacheEnabledTags()165     private static long cacheEnabledTags() {
166         long tags = nativeGetEnabledTags();
167         sEnabledTags = tags;
168         return tags;
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
isTagEnabled(long traceTag)180     public static boolean isTagEnabled(long traceTag) {
181         long tags = sEnabledTags;
182         if (tags == TRACE_TAG_NOT_READY) {
183             tags = cacheEnabledTags();
184         }
185         return (tags & traceTag) != 0;
186     }
187 
188     /**
189      * Writes trace message to indicate the value of a given counter.
190      *
191      * @param traceTag The trace tag.
192      * @param counterName The counter name to appear in the trace.
193      * @param counterValue The counter value.
194      *
195      * @hide
196      */
197     @UnsupportedAppUsage
traceCounter(long traceTag, String counterName, int counterValue)198     public static void traceCounter(long traceTag, String counterName, int counterValue) {
199         if (isTagEnabled(traceTag)) {
200             nativeTraceCounter(traceTag, counterName, counterValue);
201         }
202     }
203 
204     /**
205      * Set whether application tracing is allowed for this process.  This is intended to be set
206      * 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         // Setting whether app tracing is allowed may change the tags, so we update the cached
215         // tags here.
216         cacheEnabledTags();
217     }
218 
219     /**
220      * Set whether tracing is enabled in this process.  Tracing is disabled shortly after Zygote
221      * initializes and re-enabled after processes fork from Zygote.  This is done because Zygote
222      * has no way to be notified about changes to the tracing tags, and if Zygote ever reads and
223      * caches the tracing tags, forked processes will inherit those stale tags.
224      *
225      * @hide
226      */
setTracingEnabled(boolean enabled, int debugFlags)227     public static void setTracingEnabled(boolean enabled, int debugFlags) {
228         nativeSetTracingEnabled(enabled);
229         sZygoteDebugFlags = debugFlags;
230 
231         // Setting whether tracing is enabled may change the tags, so we update the cached tags
232         // here.
233         cacheEnabledTags();
234     }
235 
236     /**
237      * Writes a trace message to indicate that a given section of code has
238      * begun. Must be followed by a call to {@link #traceEnd} using the same
239      * tag.
240      *
241      * @param traceTag The trace tag.
242      * @param methodName The method name to appear in the trace.
243      *
244      * @hide
245      */
246     @UnsupportedAppUsage
traceBegin(long traceTag, String methodName)247     public static void traceBegin(long traceTag, String methodName) {
248         if (isTagEnabled(traceTag)) {
249             nativeTraceBegin(traceTag, methodName);
250         }
251     }
252 
253     /**
254      * Writes a trace message to indicate that the current method has ended.
255      * Must be called exactly once for each call to {@link #traceBegin} using the same tag.
256      *
257      * @param traceTag The trace tag.
258      *
259      * @hide
260      */
261     @UnsupportedAppUsage
traceEnd(long traceTag)262     public static void traceEnd(long traceTag) {
263         if (isTagEnabled(traceTag)) {
264             nativeTraceEnd(traceTag);
265         }
266     }
267 
268     /**
269      * Writes a trace message to indicate that a given section of code has
270      * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
271      * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
272      * asynchronous events do not need to be nested. The name and cookie used to
273      * begin an event must be used to end it.
274      *
275      * @param traceTag The trace tag.
276      * @param methodName The method name to appear in the trace.
277      * @param cookie Unique identifier for distinguishing simultaneous events
278      *
279      * @hide
280      */
281     @UnsupportedAppUsage
asyncTraceBegin(long traceTag, String methodName, int cookie)282     public static void asyncTraceBegin(long traceTag, 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      * @param traceTag The trace tag.
294      * @param methodName The method name to appear in the trace.
295      * @param cookie Unique identifier for distinguishing simultaneous events
296      *
297      * @hide
298      */
299     @UnsupportedAppUsage
asyncTraceEnd(long traceTag, String methodName, int cookie)300     public static void asyncTraceEnd(long traceTag, String methodName, int cookie) {
301         if (isTagEnabled(traceTag)) {
302             nativeAsyncTraceEnd(traceTag, methodName, cookie);
303         }
304     }
305 
306     /**
307      * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate
308      * string creation for trace sections that require formatting. It is not necessary
309      * to guard all Trace method calls as they internally already check this. However it is
310      * recommended to use this to prevent creating any temporary objects that would then be
311      * passed to those methods to reduce runtime cost when tracing isn't enabled.
312      *
313      * @return true if tracing is currently enabled, false otherwise
314      */
isEnabled()315     public static boolean isEnabled() {
316         return isTagEnabled(TRACE_TAG_APP);
317     }
318 
319     /**
320      * Writes a trace message to indicate that a given section of code has begun. This call must
321      * be followed by a corresponding call to {@link #endSection()} on the same thread.
322      *
323      * <p class="note"> At this time the vertical bar character '|', newline character '\n', and
324      * null character '\0' are used internally by the tracing mechanism.  If sectionName contains
325      * these characters they will be replaced with a space character in the trace.
326      *
327      * @param sectionName The name of the code section to appear in the trace.  This may be at
328      * most 127 Unicode code units long.
329      */
beginSection(@onNull String sectionName)330     public static void beginSection(@NonNull String sectionName) {
331         if (isTagEnabled(TRACE_TAG_APP)) {
332             if (sectionName.length() > MAX_SECTION_NAME_LEN) {
333                 throw new IllegalArgumentException("sectionName is too long");
334             }
335             nativeTraceBegin(TRACE_TAG_APP, sectionName);
336         }
337     }
338 
339     /**
340      * Writes a trace message to indicate that a given section of code has ended. This call must
341      * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method
342      * will mark the end of the most recently begun section of code, so care must be taken to
343      * ensure that beginSection / endSection pairs are properly nested and called from the same
344      * thread.
345      */
endSection()346     public static void endSection() {
347         if (isTagEnabled(TRACE_TAG_APP)) {
348             nativeTraceEnd(TRACE_TAG_APP);
349         }
350     }
351 
352     /**
353      * Writes a trace message to indicate that a given section of code has
354      * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same
355      * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()},
356      * asynchronous events do not need to be nested. The name and cookie used to
357      * begin an event must be used to end it.
358      *
359      * @param methodName The method name to appear in the trace.
360      * @param cookie Unique identifier for distinguishing simultaneous events
361      */
beginAsyncSection(@onNull String methodName, int cookie)362     public static void beginAsyncSection(@NonNull String methodName, int cookie) {
363         asyncTraceBegin(TRACE_TAG_APP, methodName, cookie);
364     }
365 
366     /**
367      * Writes a trace message to indicate that the current method has ended.
368      * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)}
369      * using the same name and cookie.
370      *
371      * @param methodName The method name to appear in the trace.
372      * @param cookie Unique identifier for distinguishing simultaneous events
373      */
endAsyncSection(@onNull String methodName, int cookie)374     public static void endAsyncSection(@NonNull String methodName, int cookie) {
375         asyncTraceEnd(TRACE_TAG_APP, methodName, cookie);
376     }
377 
378     /**
379      * Writes trace message to indicate the value of a given counter.
380      *
381      * @param counterName The counter name to appear in the trace.
382      * @param counterValue The counter value.
383      */
setCounter(@onNull String counterName, long counterValue)384     public static void setCounter(@NonNull String counterName, long counterValue) {
385         if (isTagEnabled(TRACE_TAG_APP)) {
386             nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue);
387         }
388     }
389 }
390