/* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/android_sdk/jni/dev_perfetto_sdk_PerfettoTrackEventExtra.h" #include #include "src/android_sdk/nativehelper/JNIHelp.h" #include "src/android_sdk/nativehelper/scoped_utf_chars.h" #include "src/android_sdk/nativehelper/utils.h" #include "src/android_sdk/perfetto_sdk_for_jni/tracing_sdk.h" #include namespace perfetto { namespace jni { template inline static T* toPointer(jlong ptr) { return reinterpret_cast(static_cast(ptr)); } template inline static jlong toJLong(T* ptr) { return static_cast(reinterpret_cast(ptr)); } /** * @brief A thread-safe utility class for converting Java UTF-16 strings to * ASCII in JNI environment. * * StringBuffer provides efficient conversion of Java strings to ASCII with * optimized memory handling. It uses a two-tiered buffering strategy: * 1. A fast path using pre-allocated thread-local buffers for strings up to 128 * characters * 2. A fallback path using dynamic allocation for longer strings * * Non-ASCII characters (>255) are replaced with '?' during conversion. The * class maintains thread safety through thread-local storage and provides * zero-copy string views for optimal performance. * * Memory Management: * - Uses fixed-size thread-local buffers for both UTF-16 and ASCII characters * - Overflow strings are stored in a thread-local list to maintain valid string * views * - Avoids unnecessary allocations in the common case of small strings * * Usage example: * @code * JNIEnv* env = ...; * jstring java_string = ...; * std::string_view ascii = StringBuffer::utf16_to_ascii(env, java_string); * // Use the ASCII string... * StringBuffer::reset(); // Clean up when done * @endcode * * Thread Safety: All methods are thread-safe due to thread-local storage. */ class StringBuffer { private: static constexpr size_t BASE_SIZE = 128; // Temporarily stores the UTF-16 characters retrieved from the Java // string before they are converted to ASCII. static thread_local inline char char_buffer[BASE_SIZE]; // For fast-path conversions when the resulting ASCII string fits within // the pre-allocated space. All ascii strings in a trace event will be stored // here until emitted. static thread_local inline jchar jchar_buffer[BASE_SIZE]; // When the fast-path conversion is not possible (because char_buffer // doesn't have enough space), the converted ASCII string is stored // in this list. We use list here to avoid moving the strings on resize // with vector. This way, we can give out string_views from the stored // strings. The additional overhead from list node allocations is fine cos we // are already in an extremely unlikely path here and there are other bigger // problems if here. static thread_local inline std::list overflow_strings; // current offset into the char_buffer. static thread_local inline size_t current_offset{0}; // This allows us avoid touching the overflow_strings directly in the fast // path. Touching it causes some thread local init routine to run which shows // up in profiles. static thread_local inline bool is_overflow_strings_empty = true; static void copy_utf16_to_ascii(const jchar* src, size_t len, char* dst, JNIEnv* env, jstring str) { std::transform(src, src + len, dst, [](jchar c) { return (c <= 0xFF) ? static_cast(c) : '?'; }); if (src != jchar_buffer) { // We hit the slow path to populate src, so we have to release. env->ReleaseStringCritical(str, src); } } public: static void reset() { if (!is_overflow_strings_empty) { overflow_strings.clear(); is_overflow_strings_empty = true; } current_offset = 0; } // Converts a Java string (jstring) to an ASCII string_view. Characters // outside the ASCII range (0-255) are replaced with '?'. // // @param env The JNI environment. // @param val The Java string to convert. // @return A string_view representing the ASCII version of the string. // Returns an empty string_view if the input is null or empty. static std::string_view utf16_to_ascii(JNIEnv* env, jstring val) { if (!val) return ""; const jsize len = env->GetStringLength(val); if (len == 0) return ""; const jchar* temp_buffer; // Fast path: Enough space in jchar_buffer if (static_cast(len) <= BASE_SIZE) { env->GetStringRegion(val, 0, len, jchar_buffer); temp_buffer = jchar_buffer; } else { // Slow path: Fallback to asking ART for the string which will likely // allocate and return a copy. temp_buffer = env->GetStringCritical(val, nullptr); } const size_t next_offset = current_offset + len + 1; // Fast path: Enough space in char_buffer if (BASE_SIZE > next_offset) { copy_utf16_to_ascii(temp_buffer, len, char_buffer + current_offset, env, val); char_buffer[current_offset + len] = '\0'; auto res = std::string_view(char_buffer + current_offset, len); current_offset = next_offset; return res; } else { // Slow path: Not enough space in char_buffer. Use overflow_strings. // This will cause a string alloc but should be very unlikely to hit. std::string& str = overflow_strings.emplace_back(len + 1, '\0'); copy_utf16_to_ascii(temp_buffer, len, str.data(), env, val); is_overflow_strings_empty = false; return std::string_view(str); } } }; static jlong android_os_PerfettoTrackEventExtraArgInt64_init(JNIEnv* env, jclass, jstring name) { return toJLong(new sdk_for_jni::DebugArg( StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgBool_init(JNIEnv* env, jclass, jstring name) { return toJLong(new sdk_for_jni::DebugArg( StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgDouble_init(JNIEnv* env, jclass, jstring name) { return toJLong(new sdk_for_jni::DebugArg( StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgString_init(JNIEnv* env, jclass, jstring name) { return toJLong(new sdk_for_jni::DebugArg( StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgInt64_delete() { return toJLong(&sdk_for_jni::DebugArg::delete_arg); } static jlong android_os_PerfettoTrackEventExtraArgBool_delete() { return toJLong(&sdk_for_jni::DebugArg::delete_arg); } static jlong android_os_PerfettoTrackEventExtraArgDouble_delete() { return toJLong(&sdk_for_jni::DebugArg::delete_arg); } static jlong android_os_PerfettoTrackEventExtraArgString_delete() { return toJLong(&sdk_for_jni::DebugArg::delete_arg); } static jlong android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr( jlong ptr) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); return toJLong(arg->get()); } static jlong android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr( jlong ptr) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); return toJLong(arg->get()); } static jlong android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr( jlong ptr) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); return toJLong(arg->get()); } static jlong android_os_PerfettoTrackEventExtraArgString_get_extra_ptr( jlong ptr) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); return toJLong(arg->get()); } static void android_os_PerfettoTrackEventExtraArgInt64_set_value(jlong ptr, jlong val) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); arg->set_value(val); } static void android_os_PerfettoTrackEventExtraArgBool_set_value(jlong ptr, jboolean val) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); arg->set_value(val); } static void android_os_PerfettoTrackEventExtraArgDouble_set_value(jlong ptr, jdouble val) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); arg->set_value(val); } static void android_os_PerfettoTrackEventExtraArgString_set_value(JNIEnv* env, jclass, jlong ptr, jstring val) { sdk_for_jni::DebugArg* arg = toPointer>(ptr); arg->set_value(StringBuffer::utf16_to_ascii(env, val).data()); } static jlong android_os_PerfettoTrackEventExtraFieldInt64_init() { return toJLong(new sdk_for_jni::ProtoField()); } static jlong android_os_PerfettoTrackEventExtraFieldDouble_init() { return toJLong(new sdk_for_jni::ProtoField()); } static jlong android_os_PerfettoTrackEventExtraFieldString_init() { return toJLong(new sdk_for_jni::ProtoField()); } static jlong android_os_PerfettoTrackEventExtraFieldNested_init() { return toJLong(new sdk_for_jni::ProtoFieldNested()); } static jlong android_os_PerfettoTrackEventExtraFieldInt64_delete() { return toJLong(&sdk_for_jni::ProtoField::delete_field); } static jlong android_os_PerfettoTrackEventExtraFieldDouble_delete() { return toJLong(&sdk_for_jni::ProtoField::delete_field); } static jlong android_os_PerfettoTrackEventExtraFieldString_delete() { return toJLong(&sdk_for_jni::ProtoField::delete_field); } static jlong android_os_PerfettoTrackEventExtraFieldNested_delete() { return toJLong(&sdk_for_jni::ProtoFieldNested::delete_field); } static jlong android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr( jlong ptr) { sdk_for_jni::ProtoField* field = toPointer>(ptr); return toJLong(field->get()); } static jlong android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr( jlong ptr) { sdk_for_jni::ProtoField* field = toPointer>(ptr); return toJLong(field->get()); } static jlong android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr( jlong ptr) { sdk_for_jni::ProtoField* field = toPointer>(ptr); return toJLong(field->get()); } static jlong android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr( jlong ptr) { sdk_for_jni::ProtoFieldNested* field = toPointer(ptr); return toJLong(field->get()); } static void android_os_PerfettoTrackEventExtraFieldInt64_set_value(jlong ptr, jlong id, jlong val) { sdk_for_jni::ProtoField* field = toPointer>(ptr); field->set_value(id, val); } static void android_os_PerfettoTrackEventExtraFieldDouble_set_value( jlong ptr, jlong id, jdouble val) { sdk_for_jni::ProtoField* field = toPointer>(ptr); field->set_value(id, val); } static void android_os_PerfettoTrackEventExtraFieldString_set_value( JNIEnv* env, jclass, jlong ptr, jlong id, jstring val) { sdk_for_jni::ProtoField* field = toPointer>(ptr); field->set_value(id, StringBuffer::utf16_to_ascii(env, val).data()); } static void android_os_PerfettoTrackEventExtraFieldNested_add_field( jlong field_ptr, jlong arg_ptr) { sdk_for_jni::ProtoFieldNested* field = toPointer(field_ptr); field->add_field(toPointer(arg_ptr)); } static void android_os_PerfettoTrackEventExtraFieldNested_set_id(jlong ptr, jlong id) { sdk_for_jni::ProtoFieldNested* field = toPointer(ptr); field->set_id(id); } static jlong android_os_PerfettoTrackEventExtraFlow_init() { return toJLong(new sdk_for_jni::Flow()); } static void android_os_PerfettoTrackEventExtraFlow_set_process_flow(jlong ptr, jlong id) { sdk_for_jni::Flow* flow = toPointer(ptr); flow->set_process_flow(id); } static void android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow( jlong ptr, jlong id) { sdk_for_jni::Flow* flow = toPointer(ptr); flow->set_process_terminating_flow(id); } static jlong android_os_PerfettoTrackEventExtraFlow_delete() { return toJLong(&sdk_for_jni::Flow::delete_flow); } static jlong android_os_PerfettoTrackEventExtraFlow_get_extra_ptr(jlong ptr) { sdk_for_jni::Flow* flow = toPointer(ptr); return toJLong(flow->get()); } static jlong android_os_PerfettoTrackEventExtraNamedTrack_init( JNIEnv* env, jclass, jlong id, jstring name, jlong parent_uuid) { return toJLong(new sdk_for_jni::NamedTrack( id, parent_uuid, StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraNamedTrack_delete() { return toJLong(&sdk_for_jni::NamedTrack::delete_track); } static jlong android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr( jlong ptr) { sdk_for_jni::NamedTrack* track = toPointer(ptr); return toJLong(track->get()); } static jlong android_os_PerfettoTrackEventExtraCounterTrack_init( JNIEnv* env, jclass, jstring name, jlong parent_uuid) { return toJLong(new sdk_for_jni::RegisteredTrack( 1, parent_uuid, StringBuffer::utf16_to_ascii(env, name).data(), true)); } static jlong android_os_PerfettoTrackEventExtraCounterTrack_delete() { return toJLong(&sdk_for_jni::RegisteredTrack::delete_track); } static jlong android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr( jlong ptr) { sdk_for_jni::RegisteredTrack* track = toPointer(ptr); return toJLong(track->get()); } static jlong android_os_PerfettoTrackEventExtraCounterInt64_init() { return toJLong(new sdk_for_jni::Counter()); } static jlong android_os_PerfettoTrackEventExtraCounterInt64_delete() { return toJLong(&sdk_for_jni::Counter::delete_counter); } static void android_os_PerfettoTrackEventExtraCounterInt64_set_value( jlong ptr, jlong val) { sdk_for_jni::Counter* counter = toPointer>(ptr); counter->set_value(val); } static jlong android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr( jlong ptr) { sdk_for_jni::Counter* counter = toPointer>(ptr); return toJLong(counter->get()); } static jlong android_os_PerfettoTrackEventExtraCounterDouble_init() { return toJLong(new sdk_for_jni::Counter()); } static jlong android_os_PerfettoTrackEventExtraCounterDouble_delete() { return toJLong(&sdk_for_jni::Counter::delete_counter); } static void android_os_PerfettoTrackEventExtraCounterDouble_set_value( jlong ptr, jdouble val) { sdk_for_jni::Counter* counter = toPointer>(ptr); counter->set_value(val); } static jlong android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr( jlong ptr) { sdk_for_jni::Counter* counter = toPointer>(ptr); return toJLong(counter->get()); } static jlong android_os_PerfettoTrackEventExtra_init() { return toJLong(new sdk_for_jni::Extra()); } static jlong android_os_PerfettoTrackEventExtra_delete() { return toJLong(&sdk_for_jni::Extra::delete_extra); } static void android_os_PerfettoTrackEventExtra_add_arg(jlong extra_ptr, jlong arg_ptr) { sdk_for_jni::Extra* extra = toPointer(extra_ptr); extra->push_extra(toPointer(arg_ptr)); } static void android_os_PerfettoTrackEventExtra_clear_args(jlong ptr) { sdk_for_jni::Extra* extra = toPointer(ptr); extra->clear_extras(); } static void android_os_PerfettoTrackEventExtra_emit(JNIEnv* env, jclass, jint type, jlong cat_ptr, jstring name, jlong extra_ptr) { sdk_for_jni::Category* category = toPointer(cat_ptr); trace_event(type, category->get(), StringBuffer::utf16_to_ascii(env, name).data(), toPointer(extra_ptr)); StringBuffer::reset(); } static jlong android_os_PerfettoTrackEventExtraProto_init() { return toJLong(new sdk_for_jni::Proto()); } static jlong android_os_PerfettoTrackEventExtraProto_delete() { return toJLong(&sdk_for_jni::Proto::delete_proto); } static jlong android_os_PerfettoTrackEventExtraProto_get_extra_ptr(jlong ptr) { sdk_for_jni::Proto* proto = toPointer(ptr); return toJLong(proto->get()); } static void android_os_PerfettoTrackEventExtraProto_add_field(long proto_ptr, jlong arg_ptr) { sdk_for_jni::Proto* proto = toPointer(proto_ptr); proto->add_field(toPointer(arg_ptr)); } static void android_os_PerfettoTrackEventExtraProto_clear_fields(jlong ptr) { sdk_for_jni::Proto* proto = toPointer(ptr); proto->clear_fields(); } static const JNINativeMethod gExtraMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtra_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtra_delete}, {"native_add_arg", "(JJ)V", (void*)android_os_PerfettoTrackEventExtra_add_arg}, {"native_clear_args", "(J)V", (void*)android_os_PerfettoTrackEventExtra_clear_args}, {"native_emit", "(IJLjava/lang/String;J)V", (void*)android_os_PerfettoTrackEventExtra_emit}}; static const JNINativeMethod gProtoMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraProto_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraProto_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraProto_get_extra_ptr}, {"native_add_field", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraProto_add_field}, {"native_clear_fields", "(J)V", (void*)android_os_PerfettoTrackEventExtraProto_clear_fields}}; static const JNINativeMethod gArgInt64Methods[] = { {"native_init", "(Ljava/lang/String;)J", (void*)android_os_PerfettoTrackEventExtraArgInt64_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgInt64_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraArgInt64_get_extra_ptr}, {"native_set_value", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraArgInt64_set_value}, }; static const JNINativeMethod gArgBoolMethods[] = { {"native_init", "(Ljava/lang/String;)J", (void*)android_os_PerfettoTrackEventExtraArgBool_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgBool_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraArgBool_get_extra_ptr}, {"native_set_value", "(JZ)V", (void*)android_os_PerfettoTrackEventExtraArgBool_set_value}, }; static const JNINativeMethod gArgDoubleMethods[] = { {"native_init", "(Ljava/lang/String;)J", (void*)android_os_PerfettoTrackEventExtraArgDouble_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgDouble_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraArgDouble_get_extra_ptr}, {"native_set_value", "(JD)V", (void*)android_os_PerfettoTrackEventExtraArgDouble_set_value}, }; static const JNINativeMethod gArgStringMethods[] = { {"native_init", "(Ljava/lang/String;)J", (void*)android_os_PerfettoTrackEventExtraArgString_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraArgString_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraArgString_get_extra_ptr}, {"native_set_value", "(JLjava/lang/String;)V", (void*)android_os_PerfettoTrackEventExtraArgString_set_value}, }; static const JNINativeMethod gFieldInt64Methods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldInt64_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldInt64_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraFieldInt64_get_extra_ptr}, {"native_set_value", "(JJJ)V", (void*)android_os_PerfettoTrackEventExtraFieldInt64_set_value}, }; static const JNINativeMethod gFieldDoubleMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldDouble_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldDouble_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraFieldDouble_get_extra_ptr}, {"native_set_value", "(JJD)V", (void*)android_os_PerfettoTrackEventExtraFieldDouble_set_value}, }; static const JNINativeMethod gFieldStringMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldString_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldString_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraFieldString_get_extra_ptr}, {"native_set_value", "(JJLjava/lang/String;)V", (void*)android_os_PerfettoTrackEventExtraFieldString_set_value}, }; static const JNINativeMethod gFieldNestedMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFieldNested_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFieldNested_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraFieldNested_get_extra_ptr}, {"native_add_field", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraFieldNested_add_field}, {"native_set_id", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraFieldNested_set_id}}; static const JNINativeMethod gFlowMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraFlow_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraFlow_delete}, {"native_set_process_flow", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraFlow_set_process_flow}, {"native_set_process_terminating_flow", "(JJ)V", (void*) android_os_PerfettoTrackEventExtraFlow_set_process_terminating_flow}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraFlow_get_extra_ptr}, }; static const JNINativeMethod gNamedTrackMethods[] = { {"native_init", "(JLjava/lang/String;J)J", (void*)android_os_PerfettoTrackEventExtraNamedTrack_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraNamedTrack_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr}, }; static const JNINativeMethod gCounterTrackMethods[] = { {"native_init", "(Ljava/lang/String;J)J", (void*)android_os_PerfettoTrackEventExtraCounterTrack_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraCounterTrack_delete}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraCounterTrack_get_extra_ptr}}; static const JNINativeMethod gCounterInt64Methods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraCounterInt64_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraCounterInt64_delete}, {"native_set_value", "(JJ)V", (void*)android_os_PerfettoTrackEventExtraCounterInt64_set_value}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraCounterInt64_get_extra_ptr}}; static const JNINativeMethod gCounterDoubleMethods[] = { {"native_init", "()J", (void*)android_os_PerfettoTrackEventExtraCounterDouble_init}, {"native_delete", "()J", (void*)android_os_PerfettoTrackEventExtraCounterDouble_delete}, {"native_set_value", "(JD)V", (void*)android_os_PerfettoTrackEventExtraCounterDouble_set_value}, {"native_get_extra_ptr", "(J)J", (void*)android_os_PerfettoTrackEventExtraCounterDouble_get_extra_ptr}}; #define LOG_ALWAYS_FATAL_IF(cond, fmt) \ if (cond) \ __android_log_assert(nullptr, "PerfettoJNI", fmt); int register_android_os_PerfettoTrackEventExtra(JNIEnv* env) { int res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgInt64", gArgInt64Methods, NELEM(gArgInt64Methods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg int64 native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgBool", gArgBoolMethods, NELEM(gArgBoolMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg bool native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgDouble", gArgDoubleMethods, NELEM(gArgDoubleMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg double native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$ArgString", gArgStringMethods, NELEM(gArgStringMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register arg string native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldInt64", gFieldInt64Methods, NELEM(gFieldInt64Methods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field int64 native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldDouble", gFieldDoubleMethods, NELEM(gFieldDoubleMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field double native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldString", gFieldStringMethods, NELEM(gFieldStringMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field string native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$FieldNested", gFieldNestedMethods, NELEM(gFieldNestedMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register field nested native methods."); res = jniRegisterNativeMethods(env, "dev/perfetto/sdk/PerfettoTrackEventExtra", gExtraMethods, NELEM(gExtraMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register extra native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$Proto", gProtoMethods, NELEM(gProtoMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register proto native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$Flow", gFlowMethods, NELEM(gFlowMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register flow native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$NamedTrack", gNamedTrackMethods, NELEM(gNamedTrackMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register named track native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$CounterTrack", gCounterTrackMethods, NELEM(gCounterTrackMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register counter track native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$CounterInt64", gCounterInt64Methods, NELEM(gCounterInt64Methods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register counter int64 native methods."); res = jniRegisterNativeMethods( env, "dev/perfetto/sdk/PerfettoTrackEventExtra$CounterDouble", gCounterDoubleMethods, NELEM(gCounterDoubleMethods)); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register counter double native methods."); return 0; } #undef LOG_ALWAYS_FATAL_IF } // namespace jni } // namespace perfetto