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 #include <cutils/compiler.h>
18 #include <cutils/trace.h>
19 #include <jni.h>
20 #include <log/log.h>
21 #include <nativehelper/JNIHelp.h>
22 #include <tracing_perfetto.h>
23 
24 #include <array>
25 
26 static constexpr const char* kNullReplacement = "(null)";
27 
28 namespace android {
29 
sanitizeString(char * str)30 inline static void sanitizeString(char* str) {
31     while (*str) {
32         char c = *str;
33         if (c == '\n' || c == '|') {
34             *str = ' ';
35         }
36         str++;
37     }
38 }
39 
40 template<typename F>
withString(JNIEnv * env,jstring jstr,F callback)41 inline static void withString(JNIEnv* env, jstring jstr, F callback) {
42     if (CC_UNLIKELY(jstr == nullptr)) {
43         callback(kNullReplacement);
44         return;
45     }
46 
47     // We need to handle the worst case of 1 character -> 4 bytes
48     // So make a buffer of size 4097 and let it hold a string with a maximum length
49     // of 1024. The extra last byte for the null terminator.
50     std::array<char, 4097> buffer;
51     // We have no idea of knowing how much data GetStringUTFRegion wrote, so null it out in
52     // advance so we can have a reliable null terminator
53     memset(buffer.data(), 0, buffer.size());
54     jsize size = std::min(env->GetStringLength(jstr), 1024);
55     env->GetStringUTFRegion(jstr, 0, size, buffer.data());
56     sanitizeString(buffer.data());
57 
58     callback(buffer.data());
59 }
60 
android_os_Trace_nativeTraceCounter(JNIEnv * env,jclass,jlong tag,jstring nameStr,jlong value)61 static void android_os_Trace_nativeTraceCounter(JNIEnv* env, jclass,
62         jlong tag, jstring nameStr, jlong value) {
63     withString(env, nameStr,
64                [tag, value](const char* str) { tracing_perfetto::traceCounter(tag, str, value); });
65 }
66 
android_os_Trace_nativeTraceBegin(JNIEnv * env,jclass,jlong tag,jstring nameStr)67 static void android_os_Trace_nativeTraceBegin(JNIEnv* env, jclass,
68         jlong tag, jstring nameStr) {
69     withString(env, nameStr, [tag](const char* str) { tracing_perfetto::traceBegin(tag, str); });
70 }
71 
android_os_Trace_nativeTraceEnd(JNIEnv *,jclass,jlong tag)72 static void android_os_Trace_nativeTraceEnd(JNIEnv*, jclass, jlong tag) {
73     tracing_perfetto::traceEnd(tag);
74 }
75 
android_os_Trace_nativeAsyncTraceBegin(JNIEnv * env,jclass,jlong tag,jstring nameStr,jint cookie)76 static void android_os_Trace_nativeAsyncTraceBegin(JNIEnv* env, jclass,
77         jlong tag, jstring nameStr, jint cookie) {
78     withString(env, nameStr, [tag, cookie](const char* str) {
79         tracing_perfetto::traceAsyncBegin(tag, str, cookie);
80     });
81 }
82 
android_os_Trace_nativeAsyncTraceEnd(JNIEnv * env,jclass,jlong tag,jstring nameStr,jint cookie)83 static void android_os_Trace_nativeAsyncTraceEnd(JNIEnv* env, jclass,
84         jlong tag, jstring nameStr, jint cookie) {
85     withString(env, nameStr, [tag, cookie](const char* str) {
86         tracing_perfetto::traceAsyncEnd(tag, str, cookie);
87     });
88 }
89 
android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv * env,jclass,jlong tag,jstring trackStr,jstring nameStr,jint cookie)90 static void android_os_Trace_nativeAsyncTraceForTrackBegin(JNIEnv* env, jclass,
91         jlong tag, jstring trackStr, jstring nameStr, jint cookie) {
92     withString(env, trackStr, [env, tag, nameStr, cookie](const char* track) {
93         withString(env, nameStr, [tag, track, cookie](const char* name) {
94             tracing_perfetto::traceAsyncBeginForTrack(tag, name, track, cookie);
95         });
96     });
97 }
98 
android_os_Trace_nativeAsyncTraceForTrackEnd(JNIEnv * env,jclass,jlong tag,jstring trackStr,jint cookie)99 static void android_os_Trace_nativeAsyncTraceForTrackEnd(JNIEnv* env, jclass,
100         jlong tag, jstring trackStr, jint cookie) {
101     withString(env, trackStr, [tag, cookie](const char* track) {
102         tracing_perfetto::traceAsyncEndForTrack(tag, track, cookie);
103     });
104 }
105 
android_os_Trace_nativeSetAppTracingAllowed(JNIEnv *,jclass,jboolean allowed)106 static void android_os_Trace_nativeSetAppTracingAllowed(JNIEnv*, jclass, jboolean allowed) {
107     // TODO(b/331916606): this is load-bearing for an app to notice that it is
108     // traced after post-zygote-fork specialisation.
109     atrace_update_tags();
110 }
111 
android_os_Trace_nativeSetTracingEnabled(JNIEnv *,jclass,jboolean enabled)112 static void android_os_Trace_nativeSetTracingEnabled(JNIEnv*, jclass, jboolean enabled) {
113     // no-op
114 }
115 
android_os_Trace_nativeInstant(JNIEnv * env,jclass,jlong tag,jstring nameStr)116 static void android_os_Trace_nativeInstant(JNIEnv* env, jclass,
117         jlong tag, jstring nameStr) {
118     withString(env, nameStr, [tag](const char* str) { tracing_perfetto::traceInstant(tag, str); });
119 }
120 
android_os_Trace_nativeInstantForTrack(JNIEnv * env,jclass,jlong tag,jstring trackStr,jstring nameStr)121 static void android_os_Trace_nativeInstantForTrack(JNIEnv* env, jclass,
122         jlong tag, jstring trackStr, jstring nameStr) {
123     withString(env, trackStr, [env, tag, nameStr](const char* track) {
124         withString(env, nameStr, [tag, track](const char* name) {
125             tracing_perfetto::traceInstantForTrack(tag, track, name);
126         });
127     });
128 }
129 
android_os_Trace_nativeIsTagEnabled(jlong tag)130 static jboolean android_os_Trace_nativeIsTagEnabled(jlong tag) {
131     return tracing_perfetto::isTagEnabled(tag);
132 }
133 
android_os_Trace_nativeRegisterWithPerfetto(JNIEnv * env)134 static void android_os_Trace_nativeRegisterWithPerfetto(JNIEnv* env) {
135     tracing_perfetto::registerWithPerfetto();
136 }
137 
138 static const JNINativeMethod gTraceMethods[] = {
139         /* name, signature, funcPtr */
140         {"nativeSetAppTracingAllowed", "(Z)V", (void*)android_os_Trace_nativeSetAppTracingAllowed},
141         {"nativeSetTracingEnabled", "(Z)V", (void*)android_os_Trace_nativeSetTracingEnabled},
142 
143         // ----------- @FastNative  ----------------
144 
145         {"nativeTraceCounter", "(JLjava/lang/String;J)V",
146          (void*)android_os_Trace_nativeTraceCounter},
147         {"nativeTraceBegin", "(JLjava/lang/String;)V", (void*)android_os_Trace_nativeTraceBegin},
148         {"nativeTraceEnd", "(J)V", (void*)android_os_Trace_nativeTraceEnd},
149         {"nativeAsyncTraceBegin", "(JLjava/lang/String;I)V",
150          (void*)android_os_Trace_nativeAsyncTraceBegin},
151         {"nativeAsyncTraceEnd", "(JLjava/lang/String;I)V",
152          (void*)android_os_Trace_nativeAsyncTraceEnd},
153         {"nativeAsyncTraceForTrackBegin", "(JLjava/lang/String;Ljava/lang/String;I)V",
154          (void*)android_os_Trace_nativeAsyncTraceForTrackBegin},
155         {"nativeAsyncTraceForTrackEnd", "(JLjava/lang/String;I)V",
156          (void*)android_os_Trace_nativeAsyncTraceForTrackEnd},
157         {"nativeInstant", "(JLjava/lang/String;)V", (void*)android_os_Trace_nativeInstant},
158         {"nativeInstantForTrack", "(JLjava/lang/String;Ljava/lang/String;)V",
159          (void*)android_os_Trace_nativeInstantForTrack},
160         {"nativeRegisterWithPerfetto", "()V", (void*)android_os_Trace_nativeRegisterWithPerfetto},
161 
162         // ----------- @CriticalNative  ----------------
163         {"nativeIsTagEnabled", "(J)Z", (void*)android_os_Trace_nativeIsTagEnabled},
164 };
165 
register_android_os_Trace(JNIEnv * env)166 int register_android_os_Trace(JNIEnv* env) {
167     int res = jniRegisterNativeMethods(env, "android/os/Trace",
168             gTraceMethods, NELEM(gTraceMethods));
169     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
170 
171     return 0;
172 }
173 
174 } // namespace android
175