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
17 #include "src/android_sdk/jni/dev_perfetto_sdk_PerfettoTrackEventExtra.h"
18
19 #include <jni.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 #include <list>
26
27 namespace perfetto {
28 namespace jni {
29
30 template <typename T>
toPointer(jlong ptr)31 inline static T* toPointer(jlong ptr) {
32 return reinterpret_cast<T*>(static_cast<uintptr_t>(ptr));
33 }
34
35 template <typename T>
toJLong(T * ptr)36 inline static jlong toJLong(T* ptr) {
37 return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
38 }
39
40 /**
41 * @brief A thread-safe utility class for converting Java UTF-16 strings to
42 * ASCII in JNI environment.
43 *
44 * StringBuffer provides efficient conversion of Java strings to ASCII with
45 * optimized memory handling. It uses a two-tiered buffering strategy:
46 * 1. A fast path using pre-allocated thread-local buffers for strings up to 128
47 * characters
48 * 2. A fallback path using dynamic allocation for longer strings
49 *
50 * Non-ASCII characters (>255) are replaced with '?' during conversion. The
51 * class maintains thread safety through thread-local storage and provides
52 * zero-copy string views for optimal performance.
53 *
54 * Memory Management:
55 * - Uses fixed-size thread-local buffers for both UTF-16 and ASCII characters
56 * - Overflow strings are stored in a thread-local list to maintain valid string
57 * views
58 * - Avoids unnecessary allocations in the common case of small strings
59 *
60 * Usage example:
61 * @code
62 * JNIEnv* env = ...;
63 * jstring java_string = ...;
64 * std::string_view ascii = StringBuffer::utf16_to_ascii(env, java_string);
65 * // Use the ASCII string...
66 * StringBuffer::reset(); // Clean up when done
67 * @endcode
68 *
69 * Thread Safety: All methods are thread-safe due to thread-local storage.
70 */
71 class StringBuffer {
72 private:
73 static constexpr size_t BASE_SIZE = 128;
74 // Temporarily stores the UTF-16 characters retrieved from the Java
75 // string before they are converted to ASCII.
76 static thread_local inline char char_buffer[BASE_SIZE];
77 // For fast-path conversions when the resulting ASCII string fits within
78 // the pre-allocated space. All ascii strings in a trace event will be stored
79 // here until emitted.
80 static thread_local inline jchar jchar_buffer[BASE_SIZE];
81 // When the fast-path conversion is not possible (because char_buffer
82 // doesn't have enough space), the converted ASCII string is stored
83 // in this list. We use list here to avoid moving the strings on resize
84 // with vector. This way, we can give out string_views from the stored
85 // strings. The additional overhead from list node allocations is fine cos we
86 // are already in an extremely unlikely path here and there are other bigger
87 // problems if here.
88 static thread_local inline std::list<std::string> overflow_strings;
89 // current offset into the char_buffer.
90 static thread_local inline size_t current_offset{0};
91 // This allows us avoid touching the overflow_strings directly in the fast
92 // path. Touching it causes some thread local init routine to run which shows
93 // up in profiles.
94 static thread_local inline bool is_overflow_strings_empty = true;
95
copy_utf16_to_ascii(const jchar * src,size_t len,char * dst,JNIEnv * env,jstring str)96 static void copy_utf16_to_ascii(const jchar* src,
97 size_t len,
98 char* dst,
99 JNIEnv* env,
100 jstring str) {
101 std::transform(src, src + len, dst, [](jchar c) {
102 return (c <= 0xFF) ? static_cast<char>(c) : '?';
103 });
104
105 if (src != jchar_buffer) {
106 // We hit the slow path to populate src, so we have to release.
107 env->ReleaseStringCritical(str, src);
108 }
109 }
110
111 public:
reset()112 static void reset() {
113 if (!is_overflow_strings_empty) {
114 overflow_strings.clear();
115 is_overflow_strings_empty = true;
116 }
117 current_offset = 0;
118 }
119
120 // Converts a Java string (jstring) to an ASCII string_view. Characters
121 // outside the ASCII range (0-255) are replaced with '?'.
122 //
123 // @param env The JNI environment.
124 // @param val The Java string to convert.
125 // @return A string_view representing the ASCII version of the string.
126 // Returns an empty string_view if the input is null or empty.
utf16_to_ascii(JNIEnv * env,jstring val)127 static std::string_view utf16_to_ascii(JNIEnv* env, jstring val) {
128 if (!val)
129 return "";
130
131 const jsize len = env->GetStringLength(val);
132 if (len == 0)
133 return "";
134
135 const jchar* temp_buffer;
136
137 // Fast path: Enough space in jchar_buffer
138 if (static_cast<size_t>(len) <= BASE_SIZE) {
139 env->GetStringRegion(val, 0, len, jchar_buffer);
140 temp_buffer = jchar_buffer;
141 } else {
142 // Slow path: Fallback to asking ART for the string which will likely
143 // allocate and return a copy.
144 temp_buffer = env->GetStringCritical(val, nullptr);
145 }
146
147 const size_t next_offset = current_offset + len + 1;
148 // Fast path: Enough space in char_buffer
149 if (BASE_SIZE > next_offset) {
150 copy_utf16_to_ascii(temp_buffer, len, char_buffer + current_offset, env,
151 val);
152 char_buffer[current_offset + len] = '\0';
153
154 auto res = std::string_view(char_buffer + current_offset, len);
155 current_offset = next_offset;
156 return res;
157 } else {
158 // Slow path: Not enough space in char_buffer. Use overflow_strings.
159 // This will cause a string alloc but should be very unlikely to hit.
160 std::string& str = overflow_strings.emplace_back(len + 1, '\0');
161
162 copy_utf16_to_ascii(temp_buffer, len, str.data(), env, val);
163 is_overflow_strings_empty = false;
164 return std::string_view(str);
165 }
166 }
167 };
168
android_os_PerfettoTrackEventExtraArgInt64_init(JNIEnv * env,jclass,jstring name)169 static jlong android_os_PerfettoTrackEventExtraArgInt64_init(JNIEnv* env,
170 jclass,
171 jstring name) {
172 return toJLong(new sdk_for_jni::DebugArg<int64_t>(
173 StringBuffer::utf16_to_ascii(env, name).data()));
174 }
175
android_os_PerfettoTrackEventExtraArgBool_init(JNIEnv * env,jclass,jstring name)176 static jlong android_os_PerfettoTrackEventExtraArgBool_init(JNIEnv* env,
177 jclass,
178 jstring name) {
179 return toJLong(new sdk_for_jni::DebugArg<bool>(
180 StringBuffer::utf16_to_ascii(env, name).data()));
181 }
182
android_os_PerfettoTrackEventExtraArgDouble_init(JNIEnv * env,jclass,jstring name)183 static jlong android_os_PerfettoTrackEventExtraArgDouble_init(JNIEnv* env,
184 jclass,
185 jstring name) {
186 return toJLong(new sdk_for_jni::DebugArg<double>(
187 StringBuffer::utf16_to_ascii(env, name).data()));
188 }
189
android_os_PerfettoTrackEventExtraArgString_init(JNIEnv * env,jclass,jstring name)190 static jlong android_os_PerfettoTrackEventExtraArgString_init(JNIEnv* env,
191 jclass,
192 jstring name) {
193 return toJLong(new sdk_for_jni::DebugArg<const char*>(
194 StringBuffer::utf16_to_ascii(env, name).data()));
195 }
196
android_os_PerfettoTrackEventExtraArgInt64_delete()197 static jlong android_os_PerfettoTrackEventExtraArgInt64_delete() {
198 return toJLong(&sdk_for_jni::DebugArg<int64_t>::delete_arg);
199 }
200
android_os_PerfettoTrackEventExtraArgBool_delete()201 static jlong android_os_PerfettoTrackEventExtraArgBool_delete() {
202 return toJLong(&sdk_for_jni::DebugArg<bool>::delete_arg);
203 }
204
android_os_PerfettoTrackEventExtraArgDouble_delete()205 static jlong android_os_PerfettoTrackEventExtraArgDouble_delete() {
206 return toJLong(&sdk_for_jni::DebugArg<double>::delete_arg);
207 }
208
android_os_PerfettoTrackEventExtraArgString_delete()209 static jlong android_os_PerfettoTrackEventExtraArgString_delete() {
210 return toJLong(&sdk_for_jni::DebugArg<const char*>::delete_arg);
211 }
212
android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr(jlong ptr)213 static jlong android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr(
214 jlong ptr) {
215 sdk_for_jni::DebugArg<int64_t>* arg =
216 toPointer<sdk_for_jni::DebugArg<int64_t>>(ptr);
217 return toJLong(arg->get());
218 }
219
android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr(jlong ptr)220 static jlong android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr(
221 jlong ptr) {
222 sdk_for_jni::DebugArg<bool>* arg =
223 toPointer<sdk_for_jni::DebugArg<bool>>(ptr);
224 return toJLong(arg->get());
225 }
226
android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr(jlong ptr)227 static jlong android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr(
228 jlong ptr) {
229 sdk_for_jni::DebugArg<double>* arg =
230 toPointer<sdk_for_jni::DebugArg<double>>(ptr);
231 return toJLong(arg->get());
232 }
233
android_os_PerfettoTrackEventExtraArgString_get_extra_ptr(jlong ptr)234 static jlong android_os_PerfettoTrackEventExtraArgString_get_extra_ptr(
235 jlong ptr) {
236 sdk_for_jni::DebugArg<const char*>* arg =
237 toPointer<sdk_for_jni::DebugArg<const char*>>(ptr);
238 return toJLong(arg->get());
239 }
240
android_os_PerfettoTrackEventExtraArgInt64_set_value(jlong ptr,jlong val)241 static void android_os_PerfettoTrackEventExtraArgInt64_set_value(jlong ptr,
242 jlong val) {
243 sdk_for_jni::DebugArg<int64_t>* arg =
244 toPointer<sdk_for_jni::DebugArg<int64_t>>(ptr);
245 arg->set_value(val);
246 }
247
android_os_PerfettoTrackEventExtraArgBool_set_value(jlong ptr,jboolean val)248 static void android_os_PerfettoTrackEventExtraArgBool_set_value(jlong ptr,
249 jboolean val) {
250 sdk_for_jni::DebugArg<bool>* arg =
251 toPointer<sdk_for_jni::DebugArg<bool>>(ptr);
252 arg->set_value(val);
253 }
254
android_os_PerfettoTrackEventExtraArgDouble_set_value(jlong ptr,jdouble val)255 static void android_os_PerfettoTrackEventExtraArgDouble_set_value(jlong ptr,
256 jdouble val) {
257 sdk_for_jni::DebugArg<double>* arg =
258 toPointer<sdk_for_jni::DebugArg<double>>(ptr);
259 arg->set_value(val);
260 }
261
android_os_PerfettoTrackEventExtraArgString_set_value(JNIEnv * env,jclass,jlong ptr,jstring val)262 static void android_os_PerfettoTrackEventExtraArgString_set_value(JNIEnv* env,
263 jclass,
264 jlong ptr,
265 jstring val) {
266 sdk_for_jni::DebugArg<const char*>* arg =
267 toPointer<sdk_for_jni::DebugArg<const char*>>(ptr);
268 arg->set_value(StringBuffer::utf16_to_ascii(env, val).data());
269 }
270
android_os_PerfettoTrackEventExtraFieldInt64_init()271 static jlong android_os_PerfettoTrackEventExtraFieldInt64_init() {
272 return toJLong(new sdk_for_jni::ProtoField<int64_t>());
273 }
274
android_os_PerfettoTrackEventExtraFieldDouble_init()275 static jlong android_os_PerfettoTrackEventExtraFieldDouble_init() {
276 return toJLong(new sdk_for_jni::ProtoField<double>());
277 }
278
android_os_PerfettoTrackEventExtraFieldString_init()279 static jlong android_os_PerfettoTrackEventExtraFieldString_init() {
280 return toJLong(new sdk_for_jni::ProtoField<const char*>());
281 }
282
android_os_PerfettoTrackEventExtraFieldNested_init()283 static jlong android_os_PerfettoTrackEventExtraFieldNested_init() {
284 return toJLong(new sdk_for_jni::ProtoFieldNested());
285 }
286
android_os_PerfettoTrackEventExtraFieldInt64_delete()287 static jlong android_os_PerfettoTrackEventExtraFieldInt64_delete() {
288 return toJLong(&sdk_for_jni::ProtoField<int64_t>::delete_field);
289 }
290
android_os_PerfettoTrackEventExtraFieldDouble_delete()291 static jlong android_os_PerfettoTrackEventExtraFieldDouble_delete() {
292 return toJLong(&sdk_for_jni::ProtoField<double>::delete_field);
293 }
294
android_os_PerfettoTrackEventExtraFieldString_delete()295 static jlong android_os_PerfettoTrackEventExtraFieldString_delete() {
296 return toJLong(&sdk_for_jni::ProtoField<const char*>::delete_field);
297 }
298
android_os_PerfettoTrackEventExtraFieldNested_delete()299 static jlong android_os_PerfettoTrackEventExtraFieldNested_delete() {
300 return toJLong(&sdk_for_jni::ProtoFieldNested::delete_field);
301 }
302
android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr(jlong ptr)303 static jlong android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr(
304 jlong ptr) {
305 sdk_for_jni::ProtoField<int64_t>* field =
306 toPointer<sdk_for_jni::ProtoField<int64_t>>(ptr);
307 return toJLong(field->get());
308 }
309
android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr(jlong ptr)310 static jlong android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr(
311 jlong ptr) {
312 sdk_for_jni::ProtoField<double>* field =
313 toPointer<sdk_for_jni::ProtoField<double>>(ptr);
314 return toJLong(field->get());
315 }
316
android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr(jlong ptr)317 static jlong android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr(
318 jlong ptr) {
319 sdk_for_jni::ProtoField<const char*>* field =
320 toPointer<sdk_for_jni::ProtoField<const char*>>(ptr);
321 return toJLong(field->get());
322 }
323
android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr(jlong ptr)324 static jlong android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr(
325 jlong ptr) {
326 sdk_for_jni::ProtoFieldNested* field =
327 toPointer<sdk_for_jni::ProtoFieldNested>(ptr);
328 return toJLong(field->get());
329 }
330
android_os_PerfettoTrackEventExtraFieldInt64_set_value(jlong ptr,jlong id,jlong val)331 static void android_os_PerfettoTrackEventExtraFieldInt64_set_value(jlong ptr,
332 jlong id,
333 jlong val) {
334 sdk_for_jni::ProtoField<int64_t>* field =
335 toPointer<sdk_for_jni::ProtoField<int64_t>>(ptr);
336 field->set_value(id, val);
337 }
338
android_os_PerfettoTrackEventExtraFieldDouble_set_value(jlong ptr,jlong id,jdouble val)339 static void android_os_PerfettoTrackEventExtraFieldDouble_set_value(
340 jlong ptr,
341 jlong id,
342 jdouble val) {
343 sdk_for_jni::ProtoField<double>* field =
344 toPointer<sdk_for_jni::ProtoField<double>>(ptr);
345 field->set_value(id, val);
346 }
347
android_os_PerfettoTrackEventExtraFieldString_set_value(JNIEnv * env,jclass,jlong ptr,jlong id,jstring val)348 static void android_os_PerfettoTrackEventExtraFieldString_set_value(
349 JNIEnv* env,
350 jclass,
351 jlong ptr,
352 jlong id,
353 jstring val) {
354 sdk_for_jni::ProtoField<const char*>* field =
355 toPointer<sdk_for_jni::ProtoField<const char*>>(ptr);
356 field->set_value(id, StringBuffer::utf16_to_ascii(env, val).data());
357 }
358
android_os_PerfettoTrackEventExtraFieldNested_add_field(jlong field_ptr,jlong arg_ptr)359 static void android_os_PerfettoTrackEventExtraFieldNested_add_field(
360 jlong field_ptr,
361 jlong arg_ptr) {
362 sdk_for_jni::ProtoFieldNested* field =
363 toPointer<sdk_for_jni::ProtoFieldNested>(field_ptr);
364 field->add_field(toPointer<PerfettoTeHlProtoField>(arg_ptr));
365 }
366
android_os_PerfettoTrackEventExtraFieldNested_set_id(jlong ptr,jlong id)367 static void android_os_PerfettoTrackEventExtraFieldNested_set_id(jlong ptr,
368 jlong id) {
369 sdk_for_jni::ProtoFieldNested* field =
370 toPointer<sdk_for_jni::ProtoFieldNested>(ptr);
371 field->set_id(id);
372 }
373
android_os_PerfettoTrackEventExtraFlow_init()374 static jlong android_os_PerfettoTrackEventExtraFlow_init() {
375 return toJLong(new sdk_for_jni::Flow());
376 }
377
android_os_PerfettoTrackEventExtraFlow_set_process_flow(jlong ptr,jlong id)378 static void android_os_PerfettoTrackEventExtraFlow_set_process_flow(jlong ptr,
379 jlong id) {
380 sdk_for_jni::Flow* flow = toPointer<sdk_for_jni::Flow>(ptr);
381 flow->set_process_flow(id);
382 }
383
android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow(jlong ptr,jlong id)384 static void android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow(
385 jlong ptr,
386 jlong id) {
387 sdk_for_jni::Flow* flow = toPointer<sdk_for_jni::Flow>(ptr);
388 flow->set_process_terminating_flow(id);
389 }
390
android_os_PerfettoTrackEventExtraFlow_delete()391 static jlong android_os_PerfettoTrackEventExtraFlow_delete() {
392 return toJLong(&sdk_for_jni::Flow::delete_flow);
393 }
394
android_os_PerfettoTrackEventExtraFlow_get_extra_ptr(jlong ptr)395 static jlong android_os_PerfettoTrackEventExtraFlow_get_extra_ptr(jlong ptr) {
396 sdk_for_jni::Flow* flow = toPointer<sdk_for_jni::Flow>(ptr);
397 return toJLong(flow->get());
398 }
399
android_os_PerfettoTrackEventExtraNamedTrack_init(JNIEnv * env,jclass,jlong id,jstring name,jlong parent_uuid)400 static jlong android_os_PerfettoTrackEventExtraNamedTrack_init(
401 JNIEnv* env,
402 jclass,
403 jlong id,
404 jstring name,
405 jlong parent_uuid) {
406 return toJLong(new sdk_for_jni::NamedTrack(
407 id, parent_uuid, StringBuffer::utf16_to_ascii(env, name).data()));
408 }
409
android_os_PerfettoTrackEventExtraNamedTrack_delete()410 static jlong android_os_PerfettoTrackEventExtraNamedTrack_delete() {
411 return toJLong(&sdk_for_jni::NamedTrack::delete_track);
412 }
413
android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr(jlong ptr)414 static jlong android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr(
415 jlong ptr) {
416 sdk_for_jni::NamedTrack* track = toPointer<sdk_for_jni::NamedTrack>(ptr);
417 return toJLong(track->get());
418 }
419
android_os_PerfettoTrackEventExtraCounterTrack_init(JNIEnv * env,jclass,jstring name,jlong parent_uuid)420 static jlong android_os_PerfettoTrackEventExtraCounterTrack_init(
421 JNIEnv* env,
422 jclass,
423 jstring name,
424 jlong parent_uuid) {
425 return toJLong(new sdk_for_jni::RegisteredTrack(
426 1, parent_uuid, StringBuffer::utf16_to_ascii(env, name).data(), true));
427 }
428
android_os_PerfettoTrackEventExtraCounterTrack_delete()429 static jlong android_os_PerfettoTrackEventExtraCounterTrack_delete() {
430 return toJLong(&sdk_for_jni::RegisteredTrack::delete_track);
431 }
432
android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr(jlong ptr)433 static jlong android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr(
434 jlong ptr) {
435 sdk_for_jni::RegisteredTrack* track =
436 toPointer<sdk_for_jni::RegisteredTrack>(ptr);
437 return toJLong(track->get());
438 }
439
android_os_PerfettoTrackEventExtraCounterInt64_init()440 static jlong android_os_PerfettoTrackEventExtraCounterInt64_init() {
441 return toJLong(new sdk_for_jni::Counter<int64_t>());
442 }
443
android_os_PerfettoTrackEventExtraCounterInt64_delete()444 static jlong android_os_PerfettoTrackEventExtraCounterInt64_delete() {
445 return toJLong(&sdk_for_jni::Counter<int64_t>::delete_counter);
446 }
447
android_os_PerfettoTrackEventExtraCounterInt64_set_value(jlong ptr,jlong val)448 static void android_os_PerfettoTrackEventExtraCounterInt64_set_value(
449 jlong ptr,
450 jlong val) {
451 sdk_for_jni::Counter<int64_t>* counter =
452 toPointer<sdk_for_jni::Counter<int64_t>>(ptr);
453 counter->set_value(val);
454 }
455
android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr(jlong ptr)456 static jlong android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr(
457 jlong ptr) {
458 sdk_for_jni::Counter<int64_t>* counter =
459 toPointer<sdk_for_jni::Counter<int64_t>>(ptr);
460 return toJLong(counter->get());
461 }
462
android_os_PerfettoTrackEventExtraCounterDouble_init()463 static jlong android_os_PerfettoTrackEventExtraCounterDouble_init() {
464 return toJLong(new sdk_for_jni::Counter<double>());
465 }
466
android_os_PerfettoTrackEventExtraCounterDouble_delete()467 static jlong android_os_PerfettoTrackEventExtraCounterDouble_delete() {
468 return toJLong(&sdk_for_jni::Counter<double>::delete_counter);
469 }
470
android_os_PerfettoTrackEventExtraCounterDouble_set_value(jlong ptr,jdouble val)471 static void android_os_PerfettoTrackEventExtraCounterDouble_set_value(
472 jlong ptr,
473 jdouble val) {
474 sdk_for_jni::Counter<double>* counter =
475 toPointer<sdk_for_jni::Counter<double>>(ptr);
476 counter->set_value(val);
477 }
478
android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr(jlong ptr)479 static jlong android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr(
480 jlong ptr) {
481 sdk_for_jni::Counter<double>* counter =
482 toPointer<sdk_for_jni::Counter<double>>(ptr);
483 return toJLong(counter->get());
484 }
485
android_os_PerfettoTrackEventExtra_init()486 static jlong android_os_PerfettoTrackEventExtra_init() {
487 return toJLong(new sdk_for_jni::Extra());
488 }
489
android_os_PerfettoTrackEventExtra_delete()490 static jlong android_os_PerfettoTrackEventExtra_delete() {
491 return toJLong(&sdk_for_jni::Extra::delete_extra);
492 }
493
android_os_PerfettoTrackEventExtra_add_arg(jlong extra_ptr,jlong arg_ptr)494 static void android_os_PerfettoTrackEventExtra_add_arg(jlong extra_ptr,
495 jlong arg_ptr) {
496 sdk_for_jni::Extra* extra = toPointer<sdk_for_jni::Extra>(extra_ptr);
497 extra->push_extra(toPointer<PerfettoTeHlExtra>(arg_ptr));
498 }
499
android_os_PerfettoTrackEventExtra_clear_args(jlong ptr)500 static void android_os_PerfettoTrackEventExtra_clear_args(jlong ptr) {
501 sdk_for_jni::Extra* extra = toPointer<sdk_for_jni::Extra>(ptr);
502 extra->clear_extras();
503 }
504
android_os_PerfettoTrackEventExtra_emit(JNIEnv * env,jclass,jint type,jlong cat_ptr,jstring name,jlong extra_ptr)505 static void android_os_PerfettoTrackEventExtra_emit(JNIEnv* env,
506 jclass,
507 jint type,
508 jlong cat_ptr,
509 jstring name,
510 jlong extra_ptr) {
511 sdk_for_jni::Category* category = toPointer<sdk_for_jni::Category>(cat_ptr);
512 trace_event(type, category->get(),
513 StringBuffer::utf16_to_ascii(env, name).data(),
514 toPointer<sdk_for_jni::Extra>(extra_ptr));
515 StringBuffer::reset();
516 }
517
android_os_PerfettoTrackEventExtraProto_init()518 static jlong android_os_PerfettoTrackEventExtraProto_init() {
519 return toJLong(new sdk_for_jni::Proto());
520 }
521
android_os_PerfettoTrackEventExtraProto_delete()522 static jlong android_os_PerfettoTrackEventExtraProto_delete() {
523 return toJLong(&sdk_for_jni::Proto::delete_proto);
524 }
525
android_os_PerfettoTrackEventExtraProto_get_extra_ptr(jlong ptr)526 static jlong android_os_PerfettoTrackEventExtraProto_get_extra_ptr(jlong ptr) {
527 sdk_for_jni::Proto* proto = toPointer<sdk_for_jni::Proto>(ptr);
528 return toJLong(proto->get());
529 }
530
android_os_PerfettoTrackEventExtraProto_add_field(long proto_ptr,jlong arg_ptr)531 static void android_os_PerfettoTrackEventExtraProto_add_field(long proto_ptr,
532 jlong arg_ptr) {
533 sdk_for_jni::Proto* proto = toPointer<sdk_for_jni::Proto>(proto_ptr);
534 proto->add_field(toPointer<PerfettoTeHlProtoField>(arg_ptr));
535 }
536
android_os_PerfettoTrackEventExtraProto_clear_fields(jlong ptr)537 static void android_os_PerfettoTrackEventExtraProto_clear_fields(jlong ptr) {
538 sdk_for_jni::Proto* proto = toPointer<sdk_for_jni::Proto>(ptr);
539 proto->clear_fields();
540 }
541
542 static const JNINativeMethod gExtraMethods[] = {
native_init()543 {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtra_init},
native_delete()544 {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtra_delete},
native_add_arg(JJ)545 {"native_add_arg", "(JJ)V",
546 (void*)android_os_PerfettoTrackEventExtra_add_arg},
native_clear_args(J)547 {"native_clear_args", "(J)V",
548 (void*)android_os_PerfettoTrackEventExtra_clear_args},
native_emit(IJLjava/lang/String;J)549 {"native_emit", "(IJLjava/lang/String;J)V",
550 (void*)android_os_PerfettoTrackEventExtra_emit}};
551
552 static const JNINativeMethod gProtoMethods[] = {
native_init()553 {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraProto_init},
native_delete()554 {"native_delete", "()J",
555 (void*)android_os_PerfettoTrackEventExtraProto_delete},
native_get_extra_ptr(J)556 {"native_get_extra_ptr", "(J)J",
557 (void*)android_os_PerfettoTrackEventExtraProto_get_extra_ptr},
native_add_field(JJ)558 {"native_add_field", "(JJ)V",
559 (void*)android_os_PerfettoTrackEventExtraProto_add_field},
native_clear_fields(J)560 {"native_clear_fields", "(J)V",
561 (void*)android_os_PerfettoTrackEventExtraProto_clear_fields}};
562
563 static const JNINativeMethod gArgInt64Methods[] = {
native_init(Ljava/lang/String;)564 {"native_init", "(Ljava/lang/String;)J",
565 (void*)android_os_PerfettoTrackEventExtraArgInt64_init},
native_delete()566 {"native_delete", "()J",
567 (void*)android_os_PerfettoTrackEventExtraArgInt64_delete},
native_get_extra_ptr(J)568 {"native_get_extra_ptr", "(J)J",
569 (void*)android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr},
native_set_value(JJ)570 {"native_set_value", "(JJ)V",
571 (void*)android_os_PerfettoTrackEventExtraArgInt64_set_value},
572 };
573
574 static const JNINativeMethod gArgBoolMethods[] = {
native_init(Ljava/lang/String;)575 {"native_init", "(Ljava/lang/String;)J",
576 (void*)android_os_PerfettoTrackEventExtraArgBool_init},
native_delete()577 {"native_delete", "()J",
578 (void*)android_os_PerfettoTrackEventExtraArgBool_delete},
native_get_extra_ptr(J)579 {"native_get_extra_ptr", "(J)J",
580 (void*)android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr},
native_set_value(JZ)581 {"native_set_value", "(JZ)V",
582 (void*)android_os_PerfettoTrackEventExtraArgBool_set_value},
583 };
584
585 static const JNINativeMethod gArgDoubleMethods[] = {
native_init(Ljava/lang/String;)586 {"native_init", "(Ljava/lang/String;)J",
587 (void*)android_os_PerfettoTrackEventExtraArgDouble_init},
native_delete()588 {"native_delete", "()J",
589 (void*)android_os_PerfettoTrackEventExtraArgDouble_delete},
native_get_extra_ptr(J)590 {"native_get_extra_ptr", "(J)J",
591 (void*)android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr},
native_set_value(JD)592 {"native_set_value", "(JD)V",
593 (void*)android_os_PerfettoTrackEventExtraArgDouble_set_value},
594 };
595
596 static const JNINativeMethod gArgStringMethods[] = {
native_init(Ljava/lang/String;)597 {"native_init", "(Ljava/lang/String;)J",
598 (void*)android_os_PerfettoTrackEventExtraArgString_init},
native_delete()599 {"native_delete", "()J",
600 (void*)android_os_PerfettoTrackEventExtraArgString_delete},
native_get_extra_ptr(J)601 {"native_get_extra_ptr", "(J)J",
602 (void*)android_os_PerfettoTrackEventExtraArgString_get_extra_ptr},
native_set_value(JLjava/lang/String;)603 {"native_set_value", "(JLjava/lang/String;)V",
604 (void*)android_os_PerfettoTrackEventExtraArgString_set_value},
605 };
606
607 static const JNINativeMethod gFieldInt64Methods[] = {
native_init()608 {"native_init", "()J",
609 (void*)android_os_PerfettoTrackEventExtraFieldInt64_init},
native_delete()610 {"native_delete", "()J",
611 (void*)android_os_PerfettoTrackEventExtraFieldInt64_delete},
native_get_extra_ptr(J)612 {"native_get_extra_ptr", "(J)J",
613 (void*)android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr},
native_set_value(JJJ)614 {"native_set_value", "(JJJ)V",
615 (void*)android_os_PerfettoTrackEventExtraFieldInt64_set_value},
616 };
617
618 static const JNINativeMethod gFieldDoubleMethods[] = {
native_init()619 {"native_init", "()J",
620 (void*)android_os_PerfettoTrackEventExtraFieldDouble_init},
native_delete()621 {"native_delete", "()J",
622 (void*)android_os_PerfettoTrackEventExtraFieldDouble_delete},
native_get_extra_ptr(J)623 {"native_get_extra_ptr", "(J)J",
624 (void*)android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr},
native_set_value(JJD)625 {"native_set_value", "(JJD)V",
626 (void*)android_os_PerfettoTrackEventExtraFieldDouble_set_value},
627 };
628
629 static const JNINativeMethod gFieldStringMethods[] = {
native_init()630 {"native_init", "()J",
631 (void*)android_os_PerfettoTrackEventExtraFieldString_init},
native_delete()632 {"native_delete", "()J",
633 (void*)android_os_PerfettoTrackEventExtraFieldString_delete},
native_get_extra_ptr(J)634 {"native_get_extra_ptr", "(J)J",
635 (void*)android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr},
native_set_value(JJLjava/lang/String;)636 {"native_set_value", "(JJLjava/lang/String;)V",
637 (void*)android_os_PerfettoTrackEventExtraFieldString_set_value},
638 };
639
640 static const JNINativeMethod gFieldNestedMethods[] = {
native_init()641 {"native_init", "()J",
642 (void*)android_os_PerfettoTrackEventExtraFieldNested_init},
native_delete()643 {"native_delete", "()J",
644 (void*)android_os_PerfettoTrackEventExtraFieldNested_delete},
native_get_extra_ptr(J)645 {"native_get_extra_ptr", "(J)J",
646 (void*)android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr},
native_add_field(JJ)647 {"native_add_field", "(JJ)V",
648 (void*)android_os_PerfettoTrackEventExtraFieldNested_add_field},
native_set_id(JJ)649 {"native_set_id", "(JJ)V",
650 (void*)android_os_PerfettoTrackEventExtraFieldNested_set_id}};
651
652 static const JNINativeMethod gFlowMethods[] = {
native_init()653 {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFlow_init},
native_delete()654 {"native_delete", "()J",
655 (void*)android_os_PerfettoTrackEventExtraFlow_delete},
native_set_process_flow(JJ)656 {"native_set_process_flow", "(JJ)V",
657 (void*)android_os_PerfettoTrackEventExtraFlow_set_process_flow},
native_set_process_terminating_flow(JJ)658 {"native_set_process_terminating_flow", "(JJ)V",
659 (void*)
660 android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow},
native_get_extra_ptr(J)661 {"native_get_extra_ptr", "(J)J",
662 (void*)android_os_PerfettoTrackEventExtraFlow_get_extra_ptr},
663 };
664
665 static const JNINativeMethod gNamedTrackMethods[] = {
native_init(JLjava/lang/String;J)666 {"native_init", "(JLjava/lang/String;J)J",
667 (void*)android_os_PerfettoTrackEventExtraNamedTrack_init},
native_delete()668 {"native_delete", "()J",
669 (void*)android_os_PerfettoTrackEventExtraNamedTrack_delete},
native_get_extra_ptr(J)670 {"native_get_extra_ptr", "(J)J",
671 (void*)android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr},
672 };
673
674 static const JNINativeMethod gCounterTrackMethods[] = {
native_init(Ljava/lang/String;J)675 {"native_init", "(Ljava/lang/String;J)J",
676 (void*)android_os_PerfettoTrackEventExtraCounterTrack_init},
native_delete()677 {"native_delete", "()J",
678 (void*)android_os_PerfettoTrackEventExtraCounterTrack_delete},
native_get_extra_ptr(J)679 {"native_get_extra_ptr", "(J)J",
680 (void*)android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr}};
681
682 static const JNINativeMethod gCounterInt64Methods[] = {
native_init()683 {"native_init", "()J",
684 (void*)android_os_PerfettoTrackEventExtraCounterInt64_init},
native_delete()685 {"native_delete", "()J",
686 (void*)android_os_PerfettoTrackEventExtraCounterInt64_delete},
native_set_value(JJ)687 {"native_set_value", "(JJ)V",
688 (void*)android_os_PerfettoTrackEventExtraCounterInt64_set_value},
native_get_extra_ptr(J)689 {"native_get_extra_ptr", "(J)J",
690 (void*)android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr}};
691
692 static const JNINativeMethod gCounterDoubleMethods[] = {
native_init()693 {"native_init", "()J",
694 (void*)android_os_PerfettoTrackEventExtraCounterDouble_init},
native_delete()695 {"native_delete", "()J",
696 (void*)android_os_PerfettoTrackEventExtraCounterDouble_delete},
native_set_value(JD)697 {"native_set_value", "(JD)V",
698 (void*)android_os_PerfettoTrackEventExtraCounterDouble_set_value},
native_get_extra_ptr(J)699 {"native_get_extra_ptr", "(J)J",
700 (void*)android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr}};
701
702 #define LOG_ALWAYS_FATAL_IF(cond, fmt) \
703 if (cond) \
704 __android_log_assert(nullptr, "PerfettoJNI", fmt);
705
register_android_os_PerfettoTrackEventExtra(JNIEnv * env)706 int register_android_os_PerfettoTrackEventExtra(JNIEnv* env) {
707 int res = jniRegisterNativeMethods(
708 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgInt64",
709 gArgInt64Methods, NELEM(gArgInt64Methods));
710 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg int64 native methods.");
711
712 res = jniRegisterNativeMethods(
713 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgBool", gArgBoolMethods,
714 NELEM(gArgBoolMethods));
715 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg bool native methods.");
716
717 res = jniRegisterNativeMethods(
718 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgDouble",
719 gArgDoubleMethods, NELEM(gArgDoubleMethods));
720 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg double native methods.");
721
722 res = jniRegisterNativeMethods(
723 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgString",
724 gArgStringMethods, NELEM(gArgStringMethods));
725 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg string native methods.");
726
727 res = jniRegisterNativeMethods(
728 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldInt64",
729 gFieldInt64Methods, NELEM(gFieldInt64Methods));
730 LOG_ALWAYS_FATAL_IF(res < 0,
731 "Unable to register field int64 native methods.");
732
733 res = jniRegisterNativeMethods(
734 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldDouble",
735 gFieldDoubleMethods, NELEM(gFieldDoubleMethods));
736 LOG_ALWAYS_FATAL_IF(res < 0,
737 "Unable to register field double native methods.");
738
739 res = jniRegisterNativeMethods(
740 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldString",
741 gFieldStringMethods, NELEM(gFieldStringMethods));
742 LOG_ALWAYS_FATAL_IF(res < 0,
743 "Unable to register field string native methods.");
744
745 res = jniRegisterNativeMethods(
746 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldNested",
747 gFieldNestedMethods, NELEM(gFieldNestedMethods));
748 LOG_ALWAYS_FATAL_IF(res < 0,
749 "Unable to register field nested native methods.");
750
751 res =
752 jniRegisterNativeMethods(env, "dev/perfetto/sdk/PerfettoTrackEventExtra",
753 gExtraMethods, NELEM(gExtraMethods));
754 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register extra native methods.");
755
756 res = jniRegisterNativeMethods(
757 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$Proto", gProtoMethods,
758 NELEM(gProtoMethods));
759 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register proto native methods.");
760
761 res = jniRegisterNativeMethods(
762 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$Flow", gFlowMethods,
763 NELEM(gFlowMethods));
764 LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register flow native methods.");
765
766 res = jniRegisterNativeMethods(
767 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$NamedTrack",
768 gNamedTrackMethods, NELEM(gNamedTrackMethods));
769 LOG_ALWAYS_FATAL_IF(res < 0,
770 "Unable to register named track native methods.");
771
772 res = jniRegisterNativeMethods(
773 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$CounterTrack",
774 gCounterTrackMethods, NELEM(gCounterTrackMethods));
775 LOG_ALWAYS_FATAL_IF(res < 0,
776 "Unable to register counter track native methods.");
777
778 res = jniRegisterNativeMethods(
779 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$CounterInt64",
780 gCounterInt64Methods, NELEM(gCounterInt64Methods));
781 LOG_ALWAYS_FATAL_IF(res < 0,
782 "Unable to register counter int64 native methods.");
783
784 res = jniRegisterNativeMethods(
785 env, "dev/perfetto/sdk/PerfettoTrackEventExtra$CounterDouble",
786 gCounterDoubleMethods, NELEM(gCounterDoubleMethods));
787 LOG_ALWAYS_FATAL_IF(res < 0,
788 "Unable to register counter double native methods.");
789 return 0;
790 }
791
792 #undef LOG_ALWAYS_FATAL_IF
793
794 } // namespace jni
795 } // namespace perfetto
796