• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 #include <android/log.h>
17 #include <jni.h>
18 
19 #include "src/android_sdk/jni/dev_perfetto_sdk_PerfettoTrackEventExtra.h"
20 #include "src/android_sdk/nativehelper/JNIHelp.h"
21 #include "src/android_sdk/nativehelper/scoped_utf_chars.h"
22 #include "src/android_sdk/nativehelper/utils.h"
23 #include "src/android_sdk/perfetto_sdk_for_jni/tracing_sdk.h"
24 
25 namespace perfetto {
26 namespace jni {
27 constexpr int kFlushTimeoutMs = 5000;
28 
29 template <typename T>
toPointer(jlong ptr)30 inline static T* toPointer(jlong ptr) {
31   return reinterpret_cast<T*>(static_cast<uintptr_t>(ptr));
32 }
33 
34 template <typename T>
toJLong(T * ptr)35 inline static jlong toJLong(T* ptr) {
36   return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
37 }
38 
android_os_PerfettoTrace_get_process_track_uuid()39 static jlong android_os_PerfettoTrace_get_process_track_uuid() {
40   return sdk_for_jni::get_process_track_uuid();
41 }
42 
android_os_PerfettoTrace_get_thread_track_uuid(jlong tid)43 static jlong android_os_PerfettoTrace_get_thread_track_uuid(jlong tid) {
44   return sdk_for_jni::get_thread_track_uuid(tid);
45 }
46 
android_os_PerfettoTrace_activate_trigger(JNIEnv * env,jclass,jstring name,jint ttl_ms)47 static void android_os_PerfettoTrace_activate_trigger(JNIEnv* env,
48                                                       jclass,
49                                                       jstring name,
50                                                       jint ttl_ms) {
51   ScopedUtfChars name_chars = GET_UTF_OR_RETURN_VOID(env, name);
52   sdk_for_jni::activate_trigger(name_chars.c_str(),
53                                 static_cast<uint32_t>(ttl_ms));
54 }
55 
android_os_PerfettoTrace_register(JNIEnv *,jclass,bool is_backend_in_process)56 void android_os_PerfettoTrace_register(JNIEnv*,
57                                        jclass,
58                                        bool is_backend_in_process) {
59   sdk_for_jni::register_perfetto(is_backend_in_process);
60 }
61 
android_os_PerfettoTraceCategory_init(JNIEnv * env,jclass,jstring name,jstring tag,jstring severity)62 static jlong android_os_PerfettoTraceCategory_init(JNIEnv* env,
63                                                    jclass,
64                                                    jstring name,
65                                                    jstring tag,
66                                                    jstring severity) {
67   ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name);
68   ScopedUtfChars tag_chars = GET_UTF_OR_RETURN(env, tag);
69   ScopedUtfChars severity_chars = GET_UTF_OR_RETURN(env, severity);
70 
71   return toJLong(new sdk_for_jni::Category(
72       name_chars.c_str(), tag_chars.c_str(), severity_chars.c_str()));
73 }
74 
android_os_PerfettoTraceCategory_delete()75 static jlong android_os_PerfettoTraceCategory_delete() {
76   return toJLong(&sdk_for_jni::Category::delete_category);
77 }
78 
android_os_PerfettoTraceCategory_register(jlong ptr)79 static void android_os_PerfettoTraceCategory_register(jlong ptr) {
80   auto* category = toPointer<sdk_for_jni::Category>(ptr);
81   category->register_category();
82 }
83 
android_os_PerfettoTraceCategory_unregister(jlong ptr)84 static void android_os_PerfettoTraceCategory_unregister(jlong ptr) {
85   auto* category = toPointer<sdk_for_jni::Category>(ptr);
86   category->unregister_category();
87 }
88 
android_os_PerfettoTraceCategory_is_enabled(jlong ptr)89 static jboolean android_os_PerfettoTraceCategory_is_enabled(jlong ptr) {
90   auto* category = toPointer<sdk_for_jni::Category>(ptr);
91   return category->is_category_enabled();
92 }
93 
android_os_PerfettoTraceCategory_get_extra_ptr(jlong ptr)94 static jlong android_os_PerfettoTraceCategory_get_extra_ptr(jlong ptr) {
95   auto* category = toPointer<sdk_for_jni::Category>(ptr);
96   return toJLong(category->get());
97 }
98 
android_os_PerfettoTrace_start_session(JNIEnv * env,jclass,jboolean is_backend_in_process,jbyteArray config_bytes)99 static jlong android_os_PerfettoTrace_start_session(
100     JNIEnv* env,
101     jclass /* obj */,
102     jboolean is_backend_in_process,
103     jbyteArray config_bytes) {
104   jsize length = env->GetArrayLength(config_bytes);
105   std::vector<uint8_t> data;
106   data.reserve(length);
107   env->GetByteArrayRegion(config_bytes, 0, length,
108                           reinterpret_cast<jbyte*>(data.data()));
109 
110   auto session =
111       new sdk_for_jni::Session(is_backend_in_process, data.data(), length);
112 
113   return reinterpret_cast<long>(session);
114 }
115 
android_os_PerfettoTrace_stop_session(JNIEnv * env,jclass,jlong ptr)116 static jbyteArray android_os_PerfettoTrace_stop_session(
117     [[maybe_unused]] JNIEnv* env,
118     jclass /* obj */,
119     jlong ptr) {
120   auto* session = reinterpret_cast<sdk_for_jni::Session*>(ptr);
121 
122   session->FlushBlocking(kFlushTimeoutMs);
123   session->StopBlocking();
124 
125   std::vector<uint8_t> data = session->ReadBlocking();
126 
127   delete session;
128 
129   jbyteArray bytes = env->NewByteArray(data.size());
130   env->SetByteArrayRegion(bytes, 0, data.size(),
131                           reinterpret_cast<jbyte*>(data.data()));
132   return bytes;
133 }
134 
135 static const JNINativeMethod gCategoryMethods[] = {
native_init(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)136     {"native_init", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J",
137      (void*)android_os_PerfettoTraceCategory_init},
native_delete()138     {"native_delete", "()J", (void*)android_os_PerfettoTraceCategory_delete},
native_register(J)139     {"native_register", "(J)V",
140      (void*)android_os_PerfettoTraceCategory_register},
native_unregister(J)141     {"native_unregister", "(J)V",
142      (void*)android_os_PerfettoTraceCategory_unregister},
native_is_enabled(J)143     {"native_is_enabled", "(J)Z",
144      (void*)android_os_PerfettoTraceCategory_is_enabled},
native_get_extra_ptr(J)145     {"native_get_extra_ptr", "(J)J",
146      (void*)android_os_PerfettoTraceCategory_get_extra_ptr},
147 };
148 
149 static const JNINativeMethod gTraceMethods[] = {
native_get_process_track_uuid()150     {"native_get_process_track_uuid", "()J",
151      (void*)android_os_PerfettoTrace_get_process_track_uuid},
native_get_thread_track_uuid(J)152     {"native_get_thread_track_uuid", "(J)J",
153      (void*)android_os_PerfettoTrace_get_thread_track_uuid},
native_activate_trigger(Ljava/lang/String;I)154     {"native_activate_trigger", "(Ljava/lang/String;I)V",
155      (void*)android_os_PerfettoTrace_activate_trigger},
native_register(Z)156     {"native_register", "(Z)V", (void*)android_os_PerfettoTrace_register},
native_start_session(Z[B)157     {"native_start_session", "(Z[B)J",
158      (void*)android_os_PerfettoTrace_start_session},
native_stop_session(J)159     {"native_stop_session", "(J)[B",
160      (void*)android_os_PerfettoTrace_stop_session}};
161 
162 #define LOG_ALWAYS_FATAL_IF(cond, fmt) \
163   if (cond)                            \
164     __android_log_assert(nullptr, "PerfettoJNI", fmt);
165 
register_android_os_PerfettoTrace(JNIEnv * env)166 int register_android_os_PerfettoTrace(JNIEnv* env) {
167   int res = jniRegisterNativeMethods(env, "dev/perfetto/sdk/PerfettoTrace",
168                                      gTraceMethods, NELEM(gTraceMethods));
169   LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register perfetto native methods.");
170 
171   res = jniRegisterNativeMethods(env, "dev/perfetto/sdk/PerfettoTrace$Category",
172                                  gCategoryMethods, NELEM(gCategoryMethods));
173   LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register category native methods.");
174 
175   return 0;
176 }
177 
178 #undef LOG_ALWAYS_FATAL_IF
179 
180 }  // namespace jni
181 }  // namespace perfetto
182 
JNI_OnLoad(JavaVM * vm,void *)183 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
184   JNIEnv* env;
185   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
186     return JNI_ERR;
187   }
188 
189   perfetto::jni::register_android_os_PerfettoTrace(env);
190   perfetto::jni::register_android_os_PerfettoTrackEventExtra(env);
191 
192   return JNI_VERSION_1_6;
193 }
194