• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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