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