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