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 "NativeJavaPerfettoDs"
18 
19 #include "android_tracing_PerfettoDataSource.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 createInstance;
41     jmethodID createTlsState;
42     jmethodID createIncrementalState;
43 } gPerfettoDataSourceClassInfo;
44 
45 static struct {
46     jclass clazz;
47     jmethodID init;
48 } gCreateTlsStateArgsClassInfo;
49 
50 static struct {
51     jclass clazz;
52     jmethodID init;
53 } gCreateIncrementalStateArgsClassInfo;
54 
55 static JavaVM* gVm;
56 
57 struct TlsState {
58     jobject jobj;
59 };
60 
61 struct IncrementalState {
62     jobject jobj;
63 };
64 
65 // In a single thread there can be only one trace point active across all data source, so we can use
66 // a single global thread_local variable to keep track of the active tracer iterator.
67 thread_local static bool gInIteration;
68 thread_local static struct PerfettoDsTracerIterator gIterator;
69 
PerfettoDataSource(JNIEnv * env,jobject javaDataSource,std::string dataSourceName)70 PerfettoDataSource::PerfettoDataSource(JNIEnv* env, jobject javaDataSource,
71                                        std::string dataSourceName)
72       : dataSourceName(std::move(dataSourceName)),
73         mJavaDataSource(env->NewGlobalRef(javaDataSource)) {}
74 
newInstance(JNIEnv * env,void * ds_config,size_t ds_config_size,PerfettoDsInstanceIndex inst_id)75 jobject PerfettoDataSource::newInstance(JNIEnv* env, void* ds_config, size_t ds_config_size,
76                                         PerfettoDsInstanceIndex inst_id) {
77     jbyteArray configArray = env->NewByteArray(ds_config_size);
78 
79     void* temp = env->GetPrimitiveArrayCritical((jarray)configArray, 0);
80     memcpy(temp, ds_config, ds_config_size);
81     env->ReleasePrimitiveArrayCritical(configArray, temp, 0);
82 
83     jobject instance =
84             env->CallObjectMethod(mJavaDataSource, gPerfettoDataSourceClassInfo.createInstance,
85                                   configArray, inst_id);
86 
87     if (env->ExceptionCheck()) {
88         LOGE_EX(env);
89         env->ExceptionClear();
90         LOG_ALWAYS_FATAL("Failed to create new Java Perfetto datasource instance");
91     }
92 
93     return instance;
94 }
95 
TraceIterateBegin()96 bool PerfettoDataSource::TraceIterateBegin() {
97     if (gInIteration) {
98         return false;
99     }
100 
101     gIterator = PerfettoDsTraceIterateBegin(&dataSource);
102 
103     if (gIterator.impl.tracer == nullptr) {
104         return false;
105     }
106 
107     gInIteration = true;
108     return true;
109 }
110 
TraceIterateNext()111 bool PerfettoDataSource::TraceIterateNext() {
112     if (!gInIteration) {
113         LOG_ALWAYS_FATAL("Tried calling TraceIterateNext outside of a tracer iteration.");
114         return false;
115     }
116 
117     PerfettoDsTraceIterateNext(&dataSource, &gIterator);
118 
119     if (gIterator.impl.tracer == nullptr) {
120         // Reached end of iterator. No more datasource instances.
121         gInIteration = false;
122         return false;
123     }
124 
125     return true;
126 }
127 
TraceIterateBreak()128 void PerfettoDataSource::TraceIterateBreak() {
129     if (!gInIteration) {
130         return;
131     }
132 
133     PerfettoDsTraceIterateBreak(&dataSource, &gIterator);
134     gInIteration = false;
135 }
136 
GetInstanceIndex()137 PerfettoDsInstanceIndex PerfettoDataSource::GetInstanceIndex() {
138     if (!gInIteration) {
139         LOG_ALWAYS_FATAL("Tried calling GetInstanceIndex outside of a tracer iteration.");
140         return -1;
141     }
142 
143     return gIterator.impl.inst_id;
144 }
145 
GetCustomTls()146 jobject PerfettoDataSource::GetCustomTls() {
147     if (!gInIteration) {
148         LOG_ALWAYS_FATAL("Tried getting CustomTls outside of a tracer iteration.");
149         return nullptr;
150     }
151 
152     TlsState* tls_state =
153             reinterpret_cast<TlsState*>(PerfettoDsGetCustomTls(&dataSource, &gIterator));
154 
155     return tls_state->jobj;
156 }
157 
SetCustomTls(jobject tlsState)158 void PerfettoDataSource::SetCustomTls(jobject tlsState) {
159     if (!gInIteration) {
160         LOG_ALWAYS_FATAL("Tried getting CustomTls outside of a tracer iteration.");
161         return;
162     }
163 
164     TlsState* tls_state =
165             reinterpret_cast<TlsState*>(PerfettoDsGetCustomTls(&dataSource, &gIterator));
166 
167     tls_state->jobj = tlsState;
168 }
169 
GetIncrementalState()170 jobject PerfettoDataSource::GetIncrementalState() {
171     if (!gInIteration) {
172         LOG_ALWAYS_FATAL("Tried getting IncrementalState outside of a tracer iteration.");
173         return nullptr;
174     }
175 
176     IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(
177             PerfettoDsGetIncrementalState(&dataSource, &gIterator));
178 
179     return incr_state->jobj;
180 }
181 
SetIncrementalState(jobject incrementalState)182 void PerfettoDataSource::SetIncrementalState(jobject incrementalState) {
183     if (!gInIteration) {
184         LOG_ALWAYS_FATAL("Tried getting IncrementalState outside of a tracer iteration.");
185         return;
186     }
187 
188     IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(
189             PerfettoDsGetIncrementalState(&dataSource, &gIterator));
190 
191     incr_state->jobj = incrementalState;
192 }
193 
WritePackets(JNIEnv * env,jobjectArray packets)194 void PerfettoDataSource::WritePackets(JNIEnv* env, jobjectArray packets) {
195     if (!gInIteration) {
196         LOG_ALWAYS_FATAL("Tried writing packets outside of a tracer iteration.");
197         return;
198     }
199 
200     int packets_count = env->GetArrayLength(packets);
201     for (int i = 0; i < packets_count; i++) {
202         jbyteArray packet_proto_buffer = (jbyteArray)env->GetObjectArrayElement(packets, i);
203 
204         jbyte* raw_proto_buffer = env->GetByteArrayElements(packet_proto_buffer, nullptr);
205         int buffer_size = env->GetArrayLength(packet_proto_buffer);
206 
207         struct PerfettoDsRootTracePacket trace_packet;
208         PerfettoDsTracerPacketBegin(&gIterator, &trace_packet);
209         PerfettoPbMsgAppendBytes(&trace_packet.msg.msg, (const uint8_t*)raw_proto_buffer,
210                                  buffer_size);
211         PerfettoDsTracerPacketEnd(&gIterator, &trace_packet);
212 
213         env->ReleaseByteArrayElements(packet_proto_buffer, raw_proto_buffer, 0 /* default mode */);
214     }
215 }
216 
flushAll()217 void PerfettoDataSource::flushAll() {
218     PERFETTO_DS_TRACE(dataSource, ctx) {
219         PerfettoDsTracerFlush(&ctx, nullptr, nullptr);
220     }
221 }
222 
~PerfettoDataSource()223 PerfettoDataSource::~PerfettoDataSource() {
224     JNIEnv* env = AndroidRuntime::getJNIEnv();
225     env->DeleteGlobalRef(mJavaDataSource);
226 }
227 
nativeCreate(JNIEnv * env,jclass clazz,jobject javaDataSource,jstring name)228 jlong nativeCreate(JNIEnv* env, jclass clazz, jobject javaDataSource, jstring name) {
229     const char* nativeString = env->GetStringUTFChars(name, 0);
230     PerfettoDataSource* dataSource = new PerfettoDataSource(env, javaDataSource, nativeString);
231     env->ReleaseStringUTFChars(name, nativeString);
232 
233     dataSource->incStrong((void*)nativeCreate);
234 
235     return reinterpret_cast<jlong>(dataSource);
236 }
237 
nativeDestroy(void * ptr)238 void nativeDestroy(void* ptr) {
239     PerfettoDataSource* dataSource = reinterpret_cast<PerfettoDataSource*>(ptr);
240     dataSource->decStrong((void*)nativeCreate);
241 }
242 
nativeGetFinalizer(JNIEnv *,jclass)243 static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
244     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&nativeDestroy));
245 }
246 
nativeWritePackets(JNIEnv * env,jclass clazz,jlong ds_ptr,jobjectArray packets)247 void nativeWritePackets(JNIEnv* env, jclass clazz, jlong ds_ptr, jobjectArray packets) {
248     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(ds_ptr);
249     datasource->WritePackets(env, packets);
250 }
251 
nativeFlushAll(JNIEnv * env,jclass clazz,jlong ptr)252 void nativeFlushAll(JNIEnv* env, jclass clazz, jlong ptr) {
253     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(ptr);
254     datasource->flushAll();
255 }
256 
nativeRegisterDataSource(JNIEnv * env,jclass clazz,jlong datasource_ptr,jint buffer_exhausted_policy,jboolean will_notify_on_stop,jboolean no_flush)257 void nativeRegisterDataSource(JNIEnv* env, jclass clazz, jlong datasource_ptr,
258                               jint buffer_exhausted_policy, jboolean will_notify_on_stop,
259                               jboolean no_flush) {
260     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(datasource_ptr);
261 
262     struct PerfettoDsParams params = PerfettoDsParamsDefault();
263     params.will_notify_on_stop = will_notify_on_stop;
264     params.buffer_exhausted_policy = (PerfettoDsBufferExhaustedPolicy)buffer_exhausted_policy;
265 
266     params.user_arg = reinterpret_cast<void*>(datasource.get());
267 
268     params.on_setup_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id,
269                             void* ds_config, size_t ds_config_size, void* user_arg,
270                             struct PerfettoDsOnSetupArgs*) -> void* {
271         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
272 
273         auto* datasource = reinterpret_cast<PerfettoDataSource*>(user_arg);
274 
275         ScopedLocalRef<jobject> java_data_source_instance(env,
276                                                           datasource->newInstance(env, ds_config,
277                                                                                   ds_config_size,
278                                                                                   inst_id));
279 
280         auto* datasource_instance =
281                 new PerfettoDataSourceInstance(env, java_data_source_instance.get(), inst_id);
282         return static_cast<void*>(datasource_instance);
283     };
284 
285     params.on_create_tls_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id,
286                                  struct PerfettoDsTracerImpl* tracer, void* user_arg) -> void* {
287         // Populated later and only if required by the java side
288         auto* tls_state = new TlsState(NULL);
289         return static_cast<void*>(tls_state);
290     };
291 
292     params.on_delete_tls_cb = [](void* ptr) {
293         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
294 
295         TlsState* tls_state = reinterpret_cast<TlsState*>(ptr);
296 
297         if (tls_state->jobj != NULL) {
298             env->DeleteGlobalRef(tls_state->jobj);
299         }
300         delete tls_state;
301     };
302 
303     params.on_create_incr_cb = [](struct PerfettoDsImpl* ds_impl, PerfettoDsInstanceIndex inst_id,
304                                   struct PerfettoDsTracerImpl* tracer, void* user_arg) -> void* {
305         // Populated later and only if required by the java side
306         auto* incr_state = new IncrementalState(NULL);
307         return static_cast<void*>(incr_state);
308     };
309 
310     params.on_delete_incr_cb = [](void* ptr) {
311         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
312 
313         IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(ptr);
314 
315         if (incr_state->jobj != NULL) {
316             env->DeleteGlobalRef(incr_state->jobj);
317         }
318         delete incr_state;
319     };
320 
321     params.on_start_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*, void* inst_ctx,
322                             struct PerfettoDsOnStartArgs*) {
323         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
324 
325         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
326         datasource_instance->onStart(env);
327     };
328 
329     if (!no_flush) {
330         params.on_flush_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex, void*,
331                                 void* inst_ctx, struct PerfettoDsOnFlushArgs*) {
332             JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
333 
334             auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
335             datasource_instance->onFlush(env);
336         };
337     }
338 
339     params.on_stop_cb = [](struct PerfettoDsImpl*, PerfettoDsInstanceIndex inst_id, void* user_arg,
340                            void* inst_ctx, struct PerfettoDsOnStopArgs*) {
341         JNIEnv* env = GetOrAttachJNIEnvironment(gVm, JNI_VERSION_1_6);
342 
343         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
344         datasource_instance->onStop(env);
345     };
346 
347     params.on_destroy_cb = [](struct PerfettoDsImpl* ds_impl, void* user_arg,
348                               void* inst_ctx) -> void {
349         auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(inst_ctx);
350 
351         delete datasource_instance;
352     };
353 
354     PerfettoDsRegister(&datasource->dataSource, datasource->dataSourceName.c_str(), params);
355 }
356 
nativeGetPerfettoInstanceLocked(JNIEnv *,jclass,jlong dataSourcePtr,PerfettoDsInstanceIndex instance_idx)357 jobject nativeGetPerfettoInstanceLocked(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr,
358                                         PerfettoDsInstanceIndex instance_idx) {
359     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
360     auto* datasource_instance = static_cast<PerfettoDataSourceInstance*>(
361             PerfettoDsImplGetInstanceLocked(datasource->dataSource.impl, instance_idx));
362 
363     if (datasource_instance == nullptr) {
364         // datasource instance doesn't exist
365         ALOG(LOG_WARN, LOG_TAG,
366              "DS instance invalid!! nativeGetPerfettoInstanceLocked returning NULL");
367         return nullptr;
368     }
369 
370     return datasource_instance->GetJavaDataSourceInstance();
371 }
372 
nativeReleasePerfettoInstanceLocked(JNIEnv *,jclass,jlong dataSourcePtr,PerfettoDsInstanceIndex instance_idx)373 void nativeReleasePerfettoInstanceLocked(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr,
374                                          PerfettoDsInstanceIndex instance_idx) {
375     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
376     PerfettoDsImplReleaseInstanceLocked(datasource->dataSource.impl, instance_idx);
377 }
378 
nativePerfettoDsTraceIterateBegin(JNIEnv *,jclass,jlong dataSourcePtr)379 bool nativePerfettoDsTraceIterateBegin(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
380     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
381     return datasource->TraceIterateBegin();
382 }
383 
nativePerfettoDsTraceIterateNext(JNIEnv *,jclass,jlong dataSourcePtr)384 bool nativePerfettoDsTraceIterateNext(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
385     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
386     return datasource->TraceIterateNext();
387 }
388 
nativePerfettoDsTraceIterateBreak(JNIEnv *,jclass,jlong dataSourcePtr)389 void nativePerfettoDsTraceIterateBreak(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
390     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
391     return datasource->TraceIterateBreak();
392 }
393 
nativeGetPerfettoDsInstanceIndex(JNIEnv *,jclass,jlong dataSourcePtr)394 jint nativeGetPerfettoDsInstanceIndex(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
395     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
396     return (jint)datasource->GetInstanceIndex();
397 }
398 
nativeGetCustomTls(JNIEnv *,jclass,jlong dataSourcePtr)399 jobject nativeGetCustomTls(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
400     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
401     return datasource->GetCustomTls();
402 }
403 
nativeSetCustomTls(JNIEnv * env,jclass,jlong dataSourcePtr,jobject tlsState)404 void nativeSetCustomTls(JNIEnv* env, jclass /* clazz */, jlong dataSourcePtr, jobject tlsState) {
405     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
406     tlsState = env->NewGlobalRef(tlsState);
407     return datasource->SetCustomTls(tlsState);
408 }
409 
nativeGetIncrementalState(JNIEnv *,jclass,jlong dataSourcePtr)410 jobject nativeGetIncrementalState(JNIEnv* /* env */, jclass /* clazz */, jlong dataSourcePtr) {
411     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
412     return datasource->GetIncrementalState();
413 }
414 
nativeSetIncrementalState(JNIEnv * env,jclass,jlong dataSourcePtr,jobject incrementalState)415 void nativeSetIncrementalState(JNIEnv* env, jclass /* clazz */, jlong dataSourcePtr,
416                                jobject incrementalState) {
417     sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
418     incrementalState = env->NewGlobalRef(incrementalState);
419     return datasource->SetIncrementalState(incrementalState);
420 }
421 
422 const JNINativeMethod gMethods[] = {
423         /* name, signature, funcPtr */
424         {"nativeCreate", "(Landroid/tracing/perfetto/DataSource;Ljava/lang/String;)J",
425          (void*)nativeCreate},
426         {"nativeFlushAll", "(J)V", (void*)nativeFlushAll},
427         {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
428         {"nativeRegisterDataSource", "(JIZZ)V", (void*)nativeRegisterDataSource},
429         {"nativeGetPerfettoInstanceLocked", "(JI)Landroid/tracing/perfetto/DataSourceInstance;",
430          (void*)nativeGetPerfettoInstanceLocked},
431         {"nativeReleasePerfettoInstanceLocked", "(JI)V",
432          (void*)nativeReleasePerfettoInstanceLocked},
433 
434         {"nativePerfettoDsTraceIterateBegin", "(J)Z", (void*)nativePerfettoDsTraceIterateBegin},
435         {"nativePerfettoDsTraceIterateNext", "(J)Z", (void*)nativePerfettoDsTraceIterateNext},
436         {"nativePerfettoDsTraceIterateBreak", "(J)V", (void*)nativePerfettoDsTraceIterateBreak},
437         {"nativeGetPerfettoDsInstanceIndex", "(J)I", (void*)nativeGetPerfettoDsInstanceIndex},
438 
439         {"nativeWritePackets", "(J[[B)V", (void*)nativeWritePackets}};
440 
441 const JNINativeMethod gMethodsTracingContext[] = {
442         /* name, signature, funcPtr */
443         {"nativeGetCustomTls", "(J)Ljava/lang/Object;", (void*)nativeGetCustomTls},
444         {"nativeGetIncrementalState", "(J)Ljava/lang/Object;", (void*)nativeGetIncrementalState},
445         {"nativeSetCustomTls", "(JLjava/lang/Object;)V", (void*)nativeSetCustomTls},
446         {"nativeSetIncrementalState", "(JLjava/lang/Object;)V", (void*)nativeSetIncrementalState},
447 };
448 
register_android_tracing_PerfettoDataSource(JNIEnv * env)449 int register_android_tracing_PerfettoDataSource(JNIEnv* env) {
450     int res = jniRegisterNativeMethods(env, "android/tracing/perfetto/DataSource", gMethods,
451                                        NELEM(gMethods));
452 
453     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
454 
455     res = jniRegisterNativeMethods(env, "android/tracing/perfetto/TracingContext",
456                                    gMethodsTracingContext, NELEM(gMethodsTracingContext));
457 
458     LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
459 
460     if (env->GetJavaVM(&gVm) != JNI_OK) {
461         LOG_ALWAYS_FATAL("Failed to get JavaVM from JNIEnv: %p", env);
462     }
463 
464     jclass clazz = env->FindClass("android/tracing/perfetto/DataSource");
465     gPerfettoDataSourceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
466     gPerfettoDataSourceClassInfo.createInstance =
467             env->GetMethodID(gPerfettoDataSourceClassInfo.clazz, "createInstance",
468                              "([BI)Landroid/tracing/perfetto/DataSourceInstance;");
469     gPerfettoDataSourceClassInfo.createTlsState =
470             env->GetMethodID(gPerfettoDataSourceClassInfo.clazz, "createTlsState",
471                              "(Landroid/tracing/perfetto/CreateTlsStateArgs;)Ljava/lang/Object;");
472     gPerfettoDataSourceClassInfo.createIncrementalState =
473             env->GetMethodID(gPerfettoDataSourceClassInfo.clazz, "createIncrementalState",
474                              "(Landroid/tracing/perfetto/CreateIncrementalStateArgs;)Ljava/lang/"
475                              "Object;");
476 
477     clazz = env->FindClass("android/tracing/perfetto/CreateTlsStateArgs");
478     gCreateTlsStateArgsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
479     gCreateTlsStateArgsClassInfo.init =
480             env->GetMethodID(gCreateTlsStateArgsClassInfo.clazz, "<init>",
481                              "(Landroid/tracing/perfetto/DataSource;I)V");
482 
483     clazz = env->FindClass("android/tracing/perfetto/CreateIncrementalStateArgs");
484     gCreateIncrementalStateArgsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
485     gCreateIncrementalStateArgsClassInfo.init =
486             env->GetMethodID(gCreateIncrementalStateArgsClassInfo.clazz, "<init>",
487                              "(Landroid/tracing/perfetto/DataSource;I)V");
488 
489     return 0;
490 }
491 
492 } // namespace android