1 /*
2  * Copyright 2023 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 #define LOG_TAG "Perfetto"
18 
19 #include "android_tracing_PerfettoDataSourceInstance.h"
20 
21 #include <android_runtime/AndroidRuntime.h>
22 #include <android_runtime/Log.h>
23 #include <nativehelper/JNIHelp.h>
24 #include <perfetto/public/data_source.h>
25 #include <perfetto/public/producer.h>
26 #include <perfetto/public/protos/trace/test_event.pzc.h>
27 #include <perfetto/public/protos/trace/trace_packet.pzc.h>
28 #include <utils/Log.h>
29 #include <utils/RefBase.h>
30 
31 #include <sstream>
32 #include <thread>
33 
34 #include "core_jni_helpers.h"
35 
36 namespace android {
37 
38 static struct {
39     jclass clazz;
40     jmethodID init;
41 } gStartCallbackArgumentsClassInfo;
42 
43 static struct {
44     jclass clazz;
45     jmethodID init;
46 } gFlushCallbackArgumentsClassInfo;
47 
48 static struct {
49     jclass clazz;
50     jmethodID init;
51 } gStopCallbackArgumentsClassInfo;
52 
53 static JavaVM* gVm;
54 
callJavaMethodWithArgsObject(JNIEnv * env,jobject classRef,jmethodID method,jobject args)55 void callJavaMethodWithArgsObject(JNIEnv* env, jobject classRef, jmethodID method, jobject args) {
56     ScopedLocalRef<jobject> localClassRef(env, env->NewLocalRef(classRef));
57 
58     if (localClassRef == nullptr) {
59         ALOGE("Weak reference went out of scope");
60         return;
61     }
62 
63     env->CallVoidMethod(localClassRef.get(), method, args);
64 
65     if (env->ExceptionCheck()) {
66         env->ExceptionDescribe();
67         LOGE_EX(env);
68         env->ExceptionClear();
69     }
70 }
71 
PerfettoDataSourceInstance(JNIEnv * env,jobject javaDataSourceInstance,PerfettoDsInstanceIndex inst_idx)72 PerfettoDataSourceInstance::PerfettoDataSourceInstance(JNIEnv* env, jobject javaDataSourceInstance,
73                                                        PerfettoDsInstanceIndex inst_idx)
74       : inst_idx(inst_idx), mJavaDataSourceInstance(env->NewGlobalRef(javaDataSourceInstance)) {}
75 
~PerfettoDataSourceInstance()76 PerfettoDataSourceInstance::~PerfettoDataSourceInstance() {
77     JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
78     env->DeleteGlobalRef(mJavaDataSourceInstance);
79 }
80 
onStart(JNIEnv * env)81 void PerfettoDataSourceInstance::onStart(JNIEnv* env) {
82     ScopedLocalRef<jobject> args(env,
83                                  env->NewObject(gStartCallbackArgumentsClassInfo.clazz,
84                                                 gStartCallbackArgumentsClassInfo.init));
85     jclass cls = env->GetObjectClass(mJavaDataSourceInstance);
86     jmethodID mid = env->GetMethodID(cls, "onStart",
87                                      "(Landroid/tracing/perfetto/StartCallbackArguments;)V");
88 
89     callJavaMethodWithArgsObject(env, mJavaDataSourceInstance, mid, args.get());
90 }
91 
onFlush(JNIEnv * env)92 void PerfettoDataSourceInstance::onFlush(JNIEnv* env) {
93     ScopedLocalRef<jobject> args(env,
94                                  env->NewObject(gFlushCallbackArgumentsClassInfo.clazz,
95                                                 gFlushCallbackArgumentsClassInfo.init));
96     jclass cls = env->GetObjectClass(mJavaDataSourceInstance);
97     jmethodID mid = env->GetMethodID(cls, "onFlush",
98                                      "(Landroid/tracing/perfetto/FlushCallbackArguments;)V");
99 
100     callJavaMethodWithArgsObject(env, mJavaDataSourceInstance, mid, args.get());
101 }
102 
onStop(JNIEnv * env)103 void PerfettoDataSourceInstance::onStop(JNIEnv* env) {
104     ScopedLocalRef<jobject> args(env,
105                                  env->NewObject(gStopCallbackArgumentsClassInfo.clazz,
106                                                 gStopCallbackArgumentsClassInfo.init));
107     jclass cls = env->GetObjectClass(mJavaDataSourceInstance);
108     jmethodID mid =
109             env->GetMethodID(cls, "onStop", "(Landroid/tracing/perfetto/StopCallbackArguments;)V");
110 
111     callJavaMethodWithArgsObject(env, mJavaDataSourceInstance, mid, args.get());
112 }
113 
register_android_tracing_PerfettoDataSourceInstance(JNIEnv * env)114 int register_android_tracing_PerfettoDataSourceInstance(JNIEnv* env) {
115     if (env->GetJavaVM(&gVm) != JNI_OK) {
116         LOG_ALWAYS_FATAL("Failed to get JavaVM from JNIEnv: %p", env);
117     }
118 
119     jclass clazz = env->FindClass("android/tracing/perfetto/StartCallbackArguments");
120     gStartCallbackArgumentsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
121     gStartCallbackArgumentsClassInfo.init =
122             env->GetMethodID(gStartCallbackArgumentsClassInfo.clazz, "<init>", "()V");
123 
124     clazz = env->FindClass("android/tracing/perfetto/FlushCallbackArguments");
125     gFlushCallbackArgumentsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
126     gFlushCallbackArgumentsClassInfo.init =
127             env->GetMethodID(gFlushCallbackArgumentsClassInfo.clazz, "<init>", "()V");
128 
129     clazz = env->FindClass("android/tracing/perfetto/StopCallbackArguments");
130     gStopCallbackArgumentsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
131     gStopCallbackArgumentsClassInfo.init =
132             env->GetMethodID(gStopCallbackArgumentsClassInfo.clazz, "<init>", "()V");
133 
134     return 0;
135 }
136 
137 } // namespace android