Skip to content

Commit d11ca4d

Browse files
committed
Improve systrace tag propagation
The native side of the tracing code latches a copy of the tags from a system property on first use. The Java-side tracing code latches a copy of the native's copy during class init. The tracing code is preloaded by the zygote, which means we get the flags during zygote init and don't update them when we launch a new app. This changes the Java sources to also defer initialization until first use, so that newly-launched apps will use the current value of the system property. Bug 7323431 Change-Id: I7db048ec54345ae9565088a35c2e2b4c82f993fd
1 parent 8074e98 commit d11ca4d

File tree

1 file changed

+50
-6
lines changed

1 file changed

+50
-6
lines changed

core/java/android/os/Trace.java

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package android.os;
1818

19+
import android.util.Log;
20+
1921
/**
2022
* Writes trace events to the kernel trace buffer. These trace events can be
2123
* collected using the "atrace" program for offline analysis.
@@ -27,6 +29,8 @@
2729
* @hide
2830
*/
2931
public final class Trace {
32+
private static final String TAG = "Trace";
33+
3034
// These tags must be kept in sync with frameworks/native/include/utils/Trace.h.
3135
public static final long TRACE_TAG_NEVER = 0;
3236
public static final long TRACE_TAG_ALWAYS = 1L << 0;
@@ -49,32 +53,72 @@ public final class Trace {
4953

5054
public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags";
5155

52-
private static long sEnabledTags = nativeGetEnabledTags();
56+
// This works as a "not ready" flag because TRACE_TAG_ALWAYS is always set.
57+
private static final long TRACE_FLAGS_NOT_READY = 0;
58+
59+
// Must be volatile to avoid word tearing.
60+
private static volatile long sEnabledTags = TRACE_FLAGS_NOT_READY;
5361

5462
private static native long nativeGetEnabledTags();
5563
private static native void nativeTraceCounter(long tag, String name, int value);
5664
private static native void nativeTraceBegin(long tag, String name);
5765
private static native void nativeTraceEnd(long tag);
5866

5967
static {
68+
// We configure two separate change callbacks, one in Trace.cpp and one here. The
69+
// native callback reads the tags from the system property, and this callback
70+
// reads the value that the native code retrieved. It's essential that the native
71+
// callback executes first.
72+
//
73+
// The system provides ordering through a priority level. Callbacks made through
74+
// SystemProperties.addChangeCallback currently have a negative priority, while
75+
// our native code is using a priority of zero.
6076
SystemProperties.addChangeCallback(new Runnable() {
6177
@Override public void run() {
62-
sEnabledTags = nativeGetEnabledTags();
78+
cacheEnabledTags();
6379
}
6480
});
6581
}
6682

6783
private Trace() {
6884
}
6985

86+
/**
87+
* Caches a copy of the enabled-tag bits. The "master" copy is held by the native code,
88+
* and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property.
89+
* <p>
90+
* If the native code hasn't yet read the property, we will cause it to do one-time
91+
* initialization. We don't want to do this during class init, because this class is
92+
* preloaded, so all apps would be stuck with whatever the zygote saw. (The zygote
93+
* doesn't see the system-property update broadcasts.)
94+
* <p>
95+
* We want to defer initialization until the first use by an app, post-zygote.
96+
* <p>
97+
* We're okay if multiple threads call here simultaneously -- the native state is
98+
* synchronized, and sEnabledTags is volatile (prevents word tearing).
99+
*/
100+
private static long cacheEnabledTags() {
101+
long tags = nativeGetEnabledTags();
102+
if (tags == TRACE_FLAGS_NOT_READY) {
103+
Log.w(TAG, "Unexpected value from nativeGetEnabledTags: " + tags);
104+
// keep going
105+
}
106+
sEnabledTags = tags;
107+
return tags;
108+
}
109+
70110
/**
71111
* Returns true if a trace tag is enabled.
72112
*
73113
* @param traceTag The trace tag to check.
74114
* @return True if the trace tag is valid.
75115
*/
76116
public static boolean isTagEnabled(long traceTag) {
77-
return (sEnabledTags & traceTag) != 0;
117+
long tags = sEnabledTags;
118+
if (tags == TRACE_FLAGS_NOT_READY) {
119+
tags = cacheEnabledTags();
120+
}
121+
return (tags & traceTag) != 0;
78122
}
79123

80124
/**
@@ -85,7 +129,7 @@ public static boolean isTagEnabled(long traceTag) {
85129
* @param counterValue The counter value.
86130
*/
87131
public static void traceCounter(long traceTag, String counterName, int counterValue) {
88-
if ((sEnabledTags & traceTag) != 0) {
132+
if (isTagEnabled(traceTag)) {
89133
nativeTraceCounter(traceTag, counterName, counterValue);
90134
}
91135
}
@@ -98,7 +142,7 @@ public static void traceCounter(long traceTag, String counterName, int counterVa
98142
* @param methodName The method name to appear in the trace.
99143
*/
100144
public static void traceBegin(long traceTag, String methodName) {
101-
if ((sEnabledTags & traceTag) != 0) {
145+
if (isTagEnabled(traceTag)) {
102146
nativeTraceBegin(traceTag, methodName);
103147
}
104148
}
@@ -110,7 +154,7 @@ public static void traceBegin(long traceTag, String methodName) {
110154
* @param traceTag The trace tag.
111155
*/
112156
public static void traceEnd(long traceTag) {
113-
if ((sEnabledTags & traceTag) != 0) {
157+
if (isTagEnabled(traceTag)) {
114158
nativeTraceEnd(traceTag);
115159
}
116160
}

0 commit comments

Comments
 (0)