1 /*
2  * Copyright (C) 2022 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 #include <android/log.h>
19 #include "../tracing_perfetto.h"
20 
21 // Limit of 4096 should be safe as that's what android.os.Trace is using. See:
22 // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/jni/
23 // android_os_Trace.cpp;l=42;drc=8dae06607c3ca449516ca2564d40a7174481c2ae
24 #define BUFFER_SIZE 4096 // Note: keep in sync with PerfettoSdkTraceTest
25 
26 extern "C" {
27 
28 static void JNICALL
Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeRegisterWithPerfetto(JNIEnv * env,__unused jclass clazz)29 Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeRegisterWithPerfetto(
30         JNIEnv *env, __unused jclass clazz) {
31     tracing_perfetto::RegisterWithPerfetto();
32 }
33 
34 static void JNICALL
Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeTraceEventBegin(JNIEnv * env,__unused jclass clazz,jint key,jstring traceInfo)35 Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeTraceEventBegin(
36         JNIEnv *env, __unused jclass clazz, jint key, jstring traceInfo) {
37     jsize lengthUtf = env->GetStringUTFLength(traceInfo);
38 
39     jsize lengthUtfWithNull = lengthUtf + 1;
40     if (lengthUtfWithNull <= BUFFER_SIZE) {
41         // fast path
42         std::array<char, BUFFER_SIZE> traceInfoUtf;
43         jsize length = env->GetStringLength(traceInfo);
44         env->GetStringUTFRegion(traceInfo, 0, length, traceInfoUtf.data());
45         traceInfoUtf[lengthUtf] = '\0'; // terminate the string
46         tracing_perfetto::TraceEventBegin(key, traceInfoUtf.data());
47     } else {
48         // slow path
49         const char *traceInfoUtf = env->GetStringUTFChars(traceInfo, NULL);
50         tracing_perfetto::TraceEventBegin(key, traceInfoUtf);
51         env->ReleaseStringUTFChars(traceInfo, traceInfoUtf);
52     }
53 }
54 
55 static void JNICALL
Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeTraceEventEnd()56 Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeTraceEventEnd() {
57     tracing_perfetto::TraceEventEnd();
58 }
59 
60 static jstring JNICALL
Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeVersion(JNIEnv * env,__unused jclass clazz)61 Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeVersion(
62         JNIEnv *env, __unused jclass clazz) {
63     return env->NewStringUTF(tracing_perfetto::Version());
64 }
65 } // extern "C"
66 
67 // Explicitly registering native methods using CriticalNative / FastNative as per:
68 // https://source.android.com/devices/tech/dalvik/improvements#faster-native-methods.
69 // Note: this applies to Android 8 - 11. In Android 12+, this is recommended (to avoid slow lookups
70 // on first use), but not necessary.
71 
72 static JNINativeMethod sMethods[] = {
73         {"nativeRegisterWithPerfetto",
74                 "()V",
75                 reinterpret_cast<void *>(
76                     Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeRegisterWithPerfetto)
77         },
78         {"nativeTraceEventBegin",
79                 "(ILjava/lang/String;)V",
80                 reinterpret_cast<void *>(
81                     Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeTraceEventBegin)
82         },
83         {"nativeTraceEventEnd",
84                 "()V",
85                 reinterpret_cast<void *>(
86                     Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeTraceEventEnd)
87         },
88         {"nativeVersion",
89                 "()Ljava/lang/String;",
90                 reinterpret_cast<void *>(
91                     Java_androidx_tracing_perfetto_jni_PerfettoNative_nativeVersion)
92         },
93 };
94 
JNI_OnLoad(JavaVM * vm,void *)95 jint JNI_OnLoad(JavaVM *vm, void * /* reserved */) {
96     JNIEnv *env = NULL;
97     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
98         PERFETTO_LOG("JNI_OnLoad failure when trying to register native methods for tracing.");
99         return JNI_ERR;
100     }
101     jclass clazz = env->FindClass("androidx/tracing/perfetto/jni/PerfettoNative");
102     if (clazz == NULL) {
103         PERFETTO_LOG("Cannot find PerfettoNative class when trying to register native methods for "
104                      "tracing.");
105         return JNI_ERR;
106     }
107 
108     int result = env->RegisterNatives(clazz, sMethods, 4);
109     env->DeleteLocalRef(clazz);
110 
111     if (result != 0) {
112         PERFETTO_LOG("Failure when trying to call RegisterNatives to register native methods for "
113                      "tracing.");
114         return JNI_ERR;
115     }
116 
117     PERFETTO_LOG("Successfully registered native methods for tracing.");
118     return JNI_VERSION_1_6;
119 }
120