Merge "Add async events tracing to android.os.Trace" into jb-mr2-dev
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 607def7..dde25d56 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -74,6 +74,8 @@
     private static native void nativeTraceCounter(long tag, String name, int value);
     private static native void nativeTraceBegin(long tag, String name);
     private static native void nativeTraceEnd(long tag);
+    private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
+    private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
     private static native void nativeSetAppTracingAllowed(boolean allowed);
 
     static {
@@ -195,6 +197,42 @@
     }
 
     /**
+     * Writes a trace message to indicate that a given section of code has
+     * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
+     * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
+     * asynchronous events do not need to be nested. The name and cookie used to
+     * begin an event must be used to end it.
+     *
+     * @param traceTag The trace tag.
+     * @param methodName The method name to appear in the trace.
+     * @param cookie Unique identifier for distinguishing simultaneous events
+     *
+     * @hide
+     */
+    public static void asyncTraceBegin(long traceTag, String methodName, int cookie) {
+        if (isTagEnabled(traceTag)) {
+            nativeAsyncTraceBegin(traceTag, methodName, cookie);
+        }
+    }
+
+    /**
+     * Writes a trace message to indicate that the current method has ended.
+     * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
+     * using the same tag, name and cookie.
+     *
+     * @param traceTag The trace tag.
+     * @param methodName The method name to appear in the trace.
+     * @param cookie Unique identifier for distinguishing simultaneous events
+     *
+     * @hide
+     */
+    public static void asyncTraceEnd(long traceTag, String methodName, int cookie) {
+        if (isTagEnabled(traceTag)) {
+            nativeAsyncTraceEnd(traceTag, methodName, cookie);
+        }
+    }
+
+    /**
      * Writes a trace message to indicate that a given section of code has begun. This call must
      * be followed by a corresponding call to {@link #endSection()} on the same thread.
      *
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 00ecd0a..1315291 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -27,6 +27,18 @@
 
 namespace android {
 
+static void sanitizeString(String8& utf8Chars) {
+    size_t size = utf8Chars.size();
+    char* str = utf8Chars.lockBuffer(size);
+    for (size_t i = 0; i < size; i++) {
+        char c = str[i];
+        if (c == '\0' || c == '\n' || c == '|') {
+            str[i] = ' ';
+        }
+    }
+    utf8Chars.unlockBuffer();
+}
+
 static jlong android_os_Trace_nativeGetEnabledTags(JNIEnv* env, jclass clazz) {
     return atrace_get_enabled_tags();
 }
@@ -41,17 +53,8 @@
         jlong tag, jstring nameStr) {
     const size_t MAX_SECTION_NAME_LEN = 127;
     ScopedStringChars jchars(env, nameStr);
-    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()),
-            jchars.size());
-    size_t size = utf8Chars.size();
-    char* str = utf8Chars.lockBuffer(size);
-    for (size_t i = 0; i < size; i++) {
-        char c = str[i];
-        if (c == '\0' || c == '\n' || c == '|') {
-            str[i] = ' ';
-        }
-    }
-    utf8Chars.unlockBuffer();
+    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
+    sanitizeString(utf8Chars);
     atrace_begin(tag, utf8Chars.string());
 }
 
@@ -60,6 +63,24 @@
     atrace_end(tag);
 }
 
+static void android_os_Trace_nativeAsyncTraceBegin(JNIEnv* env, jclass clazz,
+        jlong tag, jstring nameStr, jint cookie) {
+    const size_t MAX_SECTION_NAME_LEN = 127;
+    ScopedStringChars jchars(env, nameStr);
+    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
+    sanitizeString(utf8Chars);
+    atrace_async_begin(tag, utf8Chars.string(), cookie);
+}
+
+static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass clazz,
+        jlong tag, jstring nameStr, jint cookie) {
+    const size_t MAX_SECTION_NAME_LEN = 127;
+    ScopedStringChars jchars(env, nameStr);
+    String8 utf8Chars(reinterpret_cast<const char16_t*>(jchars.get()), jchars.size());
+    sanitizeString(utf8Chars);
+    atrace_async_end(tag, utf8Chars.string(), cookie);
+}
+
 static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv* env,
         jclass clazz, jboolean allowed) {
     atrace_set_debuggable(allowed);
@@ -79,6 +100,12 @@
     { "nativeTraceEnd",
             "(J)V",
             (void*)android_os_Trace_nativeTraceEnd },
+    { "nativeAsyncTraceBegin",
+            "(JLjava/lang/String;I)V",
+            (void*)android_os_Trace_nativeAsyncTraceBegin },
+    { "nativeAsyncTraceEnd",
+            "(JLjava/lang/String;I)V",
+            (void*)android_os_Trace_nativeAsyncTraceEnd },
     { "nativeSetAppTracingAllowed",
             "(Z)V",
             (void*)android_os_Trace_nativeSetAppTracingAllowed },