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