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