From 55c16799323dba4de2c59caed806ee12d5afcaa4 Mon Sep 17 00:00:00 2001 From: Matthew Robertson Date: Wed, 23 Sep 2026 14:04:51 -0400 Subject: [PATCH 1/6] Improve the readability of android_span_data.cpp --- .clang-format | 3 + src/android_span_data.cpp | 162 +++++++++++++++----------------------- 2 files changed, 68 insertions(+), 97 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..12693f7 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +# Generated by CLion for Google +BasedOnStyle: Google +AccessModifierOffset: -2 diff --git a/src/android_span_data.cpp b/src/android_span_data.cpp index 803e266..df18d2a 100644 --- a/src/android_span_data.cpp +++ b/src/android_span_data.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include @@ -28,8 +27,6 @@ namespace firebase::telemetry::persistence { namespace { -const char LOG_TAG[] = "AndroidSpanData"; - jclass g_span_class = nullptr; jclass g_string_class = nullptr; jmethodID g_create_span_mid = nullptr; @@ -77,8 +74,6 @@ jint cache_jni_globals(JNIEnv* env) { jclass span_class = env->FindClass("com/google/firebase/crashlytics/telemetry/Span"); if (span_class == nullptr) { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to find span class"); return JNI_ERR; } g_span_class = reinterpret_cast(env->NewGlobalRef(span_class)); @@ -95,11 +90,7 @@ jint cache_jni_globals(JNIEnv* env) { env->GetStaticMethodID(g_span_class, "createRecoveredSpan", "(JJJJJLjava/lang/String;[Ljava/lang/String;)Lcom/" "google/firebase/crashlytics/telemetry/Span;"); - if (g_create_span_mid == nullptr) { - return JNI_ERR; - } - - return JNI_OK; + return g_create_span_mid != nullptr ? JNI_OK : JNI_ERR; } void release_jni_globals(JNIEnv* env) { @@ -151,7 +142,7 @@ jobject create_jni_span_object(JNIEnv* env, const Span& span) { } } - jobject recoveredSpanObj = env->CallStaticObjectMethod( + jobject recovered_span_obj = env->CallStaticObjectMethod( g_span_class, g_create_span_mid, span.trace_id().high, span.trace_id().low, span.span_id(), span.parent_span_id(), span.start_time(), name, attributes); @@ -159,7 +150,7 @@ jobject create_jni_span_object(JNIEnv* env, const Span& span) { env->DeleteLocalRef(name); env->DeleteLocalRef(attributes); - return recoveredSpanObj; + return recovered_span_obj; } std::vector> parse_jni_attributes( @@ -241,7 +232,7 @@ jlong JNICALL initialize_native(JNIEnv* env, jclass /* clazz */, jobjectArray JNICALL recover_spans_native(JNIEnv* env, jclass /* clazz */, jlong context_ptr) { unspecified_context_t* context = - reinterpret_cast(context_ptr); + reinterpret_cast(context_ptr); std::vector recovered_spans = get_recovered_spans(context); return create_jni_span_objects_array(env, recovered_spans); @@ -250,7 +241,7 @@ jobjectArray JNICALL recover_spans_native(JNIEnv* env, jclass /* clazz */, void JNICALL shutdown_native(JNIEnv* /* env */, jclass /* clazz */, jlong context_ptr) { unspecified_context_t* context = - reinterpret_cast(context_ptr); + reinterpret_cast(context_ptr); release_span_data(context); } @@ -261,153 +252,130 @@ void JNICALL add_span(JNIEnv* env, jobject /* thiz */, jlong context_ptr, jlong parent_span_id, jlong start_time, jstring name, jobjectArray attributes) { unspecified_context_t* context = - reinterpret_cast(context_ptr); + reinterpret_cast(context_ptr); MutableSpanData* mutable_span_data = get_mutable_span_data(context).get(); - if (mutable_span_data != nullptr) { - mutable_span_data->add( - Span(TraceId{static_cast(trace_id_high), - static_cast(trace_id_low)}, - static_cast(span_id), - static_cast(parent_span_id), - static_cast(start_time), 0, - jstring_to_string(env, name, MAX_SPAN_NAME_LEN), - parse_jni_attributes(env, attributes))); - } else { - __android_log_print( - ANDROID_LOG_ERROR, LOG_TAG, - "Failed to add span: mutable span data is not initialized"); + if (mutable_span_data == nullptr) { + return; } + + mutable_span_data->add( + Span(TraceId{static_cast(trace_id_high), + static_cast(trace_id_low)}, + static_cast(span_id), + static_cast(parent_span_id), + static_cast(start_time), 0, + jstring_to_string(env, name, MAX_SPAN_NAME_LEN), + parse_jni_attributes(env, attributes))); } void JNICALL end_span(JNIEnv* /* env */, jobject /* thiz */, jlong context_ptr, jlong span_id) { unspecified_context_t* context = - reinterpret_cast(context_ptr); + reinterpret_cast(context_ptr); MutableSpanData* mutable_span_data = get_mutable_span_data(context).get(); - if (mutable_span_data != nullptr) { - mutable_span_data->end(static_cast(span_id)); - } else { - __android_log_print( - ANDROID_LOG_ERROR, LOG_TAG, - "Failed to end span: mutable span data is not initialized"); + if (mutable_span_data == nullptr) { + return; } + + mutable_span_data->end(static_cast(span_id)); } void JNICALL set_attribute_on_span(JNIEnv* env, jobject /* thiz */, jlong context_ptr, jlong span_id, jstring key, jstring value) { unspecified_context_t* context = - reinterpret_cast(context_ptr); + reinterpret_cast(context_ptr); MutableSpanData* mutable_span_data = get_mutable_span_data(context).get(); - if (mutable_span_data != nullptr) { - std::uint64_t native_span_id = static_cast(span_id); - mutable_span_data->set_attribute_on_span( - native_span_id, jstring_to_string(env, key, MAX_ATTRIBUTE_KEY_LEN), - jstring_to_string(env, value, MAX_ATTRIBUTE_VAL_LEN)); - } else { - __android_log_print( - ANDROID_LOG_ERROR, LOG_TAG, - "Failed to set attribute on span: mutable span data is not " - "initialized"); + if (mutable_span_data == nullptr) { + return; } + + std::uint64_t native_span_id = static_cast(span_id); + mutable_span_data->set_attribute_on_span( + native_span_id, jstring_to_string(env, key, MAX_ATTRIBUTE_KEY_LEN), + jstring_to_string(env, value, MAX_ATTRIBUTE_VAL_LEN)); } jlong JNICALL count_mutable_spans(JNIEnv* /* env */, jobject /* thiz */, jlong context_ptr) { unspecified_context_t* context = - reinterpret_cast(context_ptr); + reinterpret_cast(context_ptr); MutableSpanData* mutable_span_data = get_mutable_span_data(context).get(); if (mutable_span_data == nullptr) { return 0; } + return static_cast(mutable_span_data->count()); } -} // namespace +const JNINativeMethod base_methods[] = { + {"initializeNative", "(Ljava/lang/String;I)J", + reinterpret_cast(initialize_native)}, + {"recoverSpansNative", + "(J)[Lcom/google/firebase/crashlytics/telemetry/Span;", + reinterpret_cast(recover_spans_native)}, + {"shutdownNative", "(J)V", reinterpret_cast(shutdown_native)}, +}; + +const JNINativeMethod mutable_methods[] = { + {"addSpanNative", "(JJJJJJLjava/lang/String;[Ljava/lang/String;)V", + reinterpret_cast(add_span)}, + {"endSpanNative", "(JJ)V", reinterpret_cast(end_span)}, + {"setAttributeOnSpanNative", "(JJLjava/lang/String;Ljava/lang/String;)V", + reinterpret_cast(set_attribute_on_span)}, + {"countSpansNative", "(J)J", reinterpret_cast(count_mutable_spans)}, +}; jint register_natives(JNIEnv* env) { if (cache_jni_globals(env) != JNI_OK) { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to initialize JNI global cache"); return JNI_ERR; } // Native Method Table Registrations for CrashlyticsOtelContext jclass base_clazz = env->FindClass( "com/google/firebase/crashlytics/telemetry/CrashlyticsOtelContext"); - if (base_clazz != nullptr) { - static const JNINativeMethod base_methods[] = { - {"initializeNative", "(Ljava/lang/String;I)J", - reinterpret_cast(initialize_native)}, - {"recoverSpansNative", - "(J)[Lcom/google/firebase/crashlytics/telemetry/Span;", - reinterpret_cast(recover_spans_native)}, - {"shutdownNative", "(J)V", reinterpret_cast(shutdown_native)}, - }; - if (env->RegisterNatives(base_clazz, base_methods, - std::size(base_methods)) < 0) { - __android_log_print( - ANDROID_LOG_ERROR, LOG_TAG, - "Failed to register native methods for CrashlyticsOtelContext"); - return JNI_ERR; - } - } else { - __android_log_print( - ANDROID_LOG_ERROR, LOG_TAG, - "Failed to find CrashlyticsOtelContext class reference"); + if (base_clazz == nullptr) { + return JNI_ERR; + } + if (env->RegisterNatives(base_clazz, base_methods, + std::size(base_methods)) != JNI_OK) { return JNI_ERR; } // Native Method Table Registrations for MutationContext jclass mutable_clazz = env->FindClass( "com/google/firebase/crashlytics/telemetry/MutationContext"); - if (mutable_clazz != nullptr) { - static const JNINativeMethod mutable_methods[] = { - {"addSpanNative", "(JJJJJJLjava/lang/String;[Ljava/lang/String;)V", - reinterpret_cast(add_span)}, - {"endSpanNative", "(JJ)V", reinterpret_cast(end_span)}, - {"setAttributeOnSpanNative", - "(JJLjava/lang/String;Ljava/lang/String;)V", - reinterpret_cast(set_attribute_on_span)}, - {"countSpansNative", "(J)J", - reinterpret_cast(count_mutable_spans)}}; - if (env->RegisterNatives(mutable_clazz, mutable_methods, - std::size(mutable_methods)) < 0) { - __android_log_print( - ANDROID_LOG_ERROR, LOG_TAG, - "Failed to register native methods for MutationContext"); - return JNI_ERR; - } - } else { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, - "Failed to find MutationContext class reference"); + if (mutable_clazz == nullptr) { + return JNI_ERR; + } + if (env->RegisterNatives(mutable_clazz, mutable_methods, + std::size(mutable_methods)) != JNI_OK) { return JNI_ERR; } return JNI_OK; } +} // namespace } // namespace firebase::telemetry::persistence // Explicit JNI Lifecycle & Cache Initializations ----------------------------- extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = nullptr; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - return JNI_ERR; - } - - if (firebase::telemetry::persistence::register_natives(env) != JNI_OK) { + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } - return JNI_VERSION_1_6; + return firebase::telemetry::persistence::register_natives(env) == JNI_OK + ? JNI_VERSION_1_6 + : JNI_ERR; } extern "C" JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* /* reserved */) { JNIEnv* env = nullptr; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) == JNI_OK) { + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) == JNI_OK) { firebase::telemetry::persistence::release_jni_globals(env); } } From 5a9e858a0b040214aa792d2a239d6aa87c80ce91 Mon Sep 17 00:00:00 2001 From: Matthew Robertson Date: Wed, 23 Sep 2026 14:10:26 -0400 Subject: [PATCH 2/6] Rename CrashlyticsOtelContext to TelemetryContext --- src/android_span_data.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/android_span_data.cpp b/src/android_span_data.cpp index df18d2a..d6ebf40 100644 --- a/src/android_span_data.cpp +++ b/src/android_span_data.cpp @@ -308,13 +308,13 @@ jlong JNICALL count_mutable_spans(JNIEnv* /* env */, jobject /* thiz */, return static_cast(mutable_span_data->count()); } -const JNINativeMethod base_methods[] = { +const JNINativeMethod telemetry_methods[] = { {"initializeNative", "(Ljava/lang/String;I)J", reinterpret_cast(initialize_native)}, {"recoverSpansNative", "(J)[Lcom/google/firebase/crashlytics/telemetry/Span;", reinterpret_cast(recover_spans_native)}, - {"shutdownNative", "(J)V", reinterpret_cast(shutdown_native)}, + {"shutdownNative", "(J)V", reinterpret_cast(shutdown_native)}, }; const JNINativeMethod mutable_methods[] = { @@ -331,14 +331,14 @@ jint register_natives(JNIEnv* env) { return JNI_ERR; } - // Native Method Table Registrations for CrashlyticsOtelContext - jclass base_clazz = env->FindClass( - "com/google/firebase/crashlytics/telemetry/CrashlyticsOtelContext"); - if (base_clazz == nullptr) { + // Native Method Table Registrations for TelemetryContext + jclass telemetry_clazz = env->FindClass( + "com/google/firebase/crashlytics/telemetry/TelemetryContext"); + if (telemetry_clazz == nullptr) { return JNI_ERR; } - if (env->RegisterNatives(base_clazz, base_methods, - std::size(base_methods)) != JNI_OK) { + if (env->RegisterNatives(telemetry_clazz, telemetry_methods, + std::size(telemetry_methods)) != JNI_OK) { return JNI_ERR; } From 79488ee634335ca01afc705774b50ac424e0fa51 Mon Sep 17 00:00:00 2001 From: Matthew Robertson Date: Wed, 23 Sep 2026 14:11:19 -0400 Subject: [PATCH 3/6] Fix naming convention on constexpr's --- src/android_span_data.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/android_span_data.cpp b/src/android_span_data.cpp index d6ebf40..9d9e5c9 100644 --- a/src/android_span_data.cpp +++ b/src/android_span_data.cpp @@ -31,10 +31,10 @@ jclass g_span_class = nullptr; jclass g_string_class = nullptr; jmethodID g_create_span_mid = nullptr; -constexpr std::size_t MAX_SPAN_NAME_LEN = 64; -constexpr std::size_t MAX_ATTRIBUTE_KEY_LEN = 64; -constexpr std::size_t MAX_ATTRIBUTE_VAL_LEN = 128; -constexpr std::size_t MAX_FILE_PATH_LEN = 4096; +constexpr std::size_t max_span_name_len = 64; +constexpr std::size_t max_attribute_key_len = 64; +constexpr std::size_t max_attribute_val_len = 128; +constexpr std::size_t max_file_path_len = 4096; template jstring create_bounded_jstring(JNIEnv* env, std::string_view str) { @@ -110,7 +110,7 @@ jobject create_jni_span_object(JNIEnv* env, const Span& span) { return nullptr; } - jstring name = create_bounded_jstring(env, span.name()); + jstring name = create_bounded_jstring(env, span.name()); if (name == nullptr) { return nullptr; } @@ -125,8 +125,8 @@ jobject create_jni_span_object(JNIEnv* env, const Span& span) { jsize index = 0; for (const auto& [key, val] : span.attributes()) { - jstring jkey = create_bounded_jstring(env, key); - jstring jval = create_bounded_jstring(env, val); + jstring jkey = create_bounded_jstring(env, key); + jstring jval = create_bounded_jstring(env, val); if (jkey != nullptr && jval != nullptr) { env->SetObjectArrayElement(attributes, index, jkey); @@ -169,8 +169,8 @@ std::vector> parse_jni_attributes( jstring jval = static_cast(env->GetObjectArrayElement(attributes, i)); if (jkey != nullptr && jval != nullptr) { - attrs.emplace_back(jstring_to_string(env, jkey, MAX_ATTRIBUTE_KEY_LEN), - jstring_to_string(env, jval, MAX_ATTRIBUTE_VAL_LEN)); + attrs.emplace_back(jstring_to_string(env, jkey, max_attribute_key_len), + jstring_to_string(env, jval, max_attribute_val_len)); } if (jkey != nullptr) { env->DeleteLocalRef(jkey); @@ -222,7 +222,7 @@ jlong JNICALL initialize_native(JNIEnv* env, jclass /* clazz */, } MmapSize mmap_size = static_cast(size_ordinal); - std::string path = jstring_to_string(env, file_path, MAX_FILE_PATH_LEN); + std::string path = jstring_to_string(env, file_path, max_file_path_len); unspecified_context_t* context = initialize_span_data(path, mmap_size); @@ -264,7 +264,7 @@ void JNICALL add_span(JNIEnv* env, jobject /* thiz */, jlong context_ptr, static_cast(span_id), static_cast(parent_span_id), static_cast(start_time), 0, - jstring_to_string(env, name, MAX_SPAN_NAME_LEN), + jstring_to_string(env, name, max_span_name_len), parse_jni_attributes(env, attributes))); } @@ -292,8 +292,8 @@ void JNICALL set_attribute_on_span(JNIEnv* env, jobject /* thiz */, std::uint64_t native_span_id = static_cast(span_id); mutable_span_data->set_attribute_on_span( - native_span_id, jstring_to_string(env, key, MAX_ATTRIBUTE_KEY_LEN), - jstring_to_string(env, value, MAX_ATTRIBUTE_VAL_LEN)); + native_span_id, jstring_to_string(env, key, max_attribute_key_len), + jstring_to_string(env, value, max_attribute_val_len)); } jlong JNICALL count_mutable_spans(JNIEnv* /* env */, jobject /* thiz */, From 0ccbe214deb12050faf14e3a9a1d76061f40f6a9 Mon Sep 17 00:00:00 2001 From: Matthew Robertson Date: Wed, 23 Sep 2026 15:40:15 -0400 Subject: [PATCH 4/6] Clean up jni references on registration failure --- src/android_span_data.cpp | 45 ++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/android_span_data.cpp b/src/android_span_data.cpp index 9d9e5c9..a0e2445 100644 --- a/src/android_span_data.cpp +++ b/src/android_span_data.cpp @@ -70,6 +70,18 @@ std::string jstring_to_string(JNIEnv* env, jstring src, std::size_t max_len) { return result; } +void release_jni_globals(JNIEnv* env) { + if (g_span_class != nullptr) { + env->DeleteGlobalRef(g_span_class); + g_span_class = nullptr; + } + if (g_string_class != nullptr) { + env->DeleteGlobalRef(g_string_class); + g_string_class = nullptr; + } + g_create_span_mid = nullptr; +} + jint cache_jni_globals(JNIEnv* env) { jclass span_class = env->FindClass("com/google/firebase/crashlytics/telemetry/Span"); @@ -81,6 +93,7 @@ jint cache_jni_globals(JNIEnv* env) { jclass string_class = env->FindClass("java/lang/String"); if (string_class == nullptr) { + release_jni_globals(env); return JNI_ERR; } g_string_class = reinterpret_cast(env->NewGlobalRef(string_class)); @@ -90,18 +103,12 @@ jint cache_jni_globals(JNIEnv* env) { env->GetStaticMethodID(g_span_class, "createRecoveredSpan", "(JJJJJLjava/lang/String;[Ljava/lang/String;)Lcom/" "google/firebase/crashlytics/telemetry/Span;"); - return g_create_span_mid != nullptr ? JNI_OK : JNI_ERR; -} - -void release_jni_globals(JNIEnv* env) { - if (g_span_class != nullptr) { - env->DeleteGlobalRef(g_span_class); - g_span_class = nullptr; - } - if (g_string_class != nullptr) { - env->DeleteGlobalRef(g_string_class); - g_string_class = nullptr; +if (g_create_span_mid == nullptr) { + release_jni_globals(env); + return JNI_ERR; } + + return JNI_OK; } jobject create_jni_span_object(JNIEnv* env, const Span& span) { @@ -335,10 +342,14 @@ jint register_natives(JNIEnv* env) { jclass telemetry_clazz = env->FindClass( "com/google/firebase/crashlytics/telemetry/TelemetryContext"); if (telemetry_clazz == nullptr) { + release_jni_globals(env); return JNI_ERR; } - if (env->RegisterNatives(telemetry_clazz, telemetry_methods, - std::size(telemetry_methods)) != JNI_OK) { + jint telemetry_reg = env->RegisterNatives(telemetry_clazz, telemetry_methods, + std::size(telemetry_methods)); + env->DeleteLocalRef(telemetry_clazz); + if (telemetry_reg != JNI_OK) { + release_jni_globals(env); return JNI_ERR; } @@ -346,10 +357,14 @@ jint register_natives(JNIEnv* env) { jclass mutable_clazz = env->FindClass( "com/google/firebase/crashlytics/telemetry/MutationContext"); if (mutable_clazz == nullptr) { + release_jni_globals(env); return JNI_ERR; } - if (env->RegisterNatives(mutable_clazz, mutable_methods, - std::size(mutable_methods)) != JNI_OK) { + jint mutable_reg = env->RegisterNatives(mutable_clazz, mutable_methods, + std::size(mutable_methods)); + env->DeleteLocalRef(mutable_clazz); + if (mutable_reg != JNI_OK) { + release_jni_globals(env); return JNI_ERR; } From 93b5b9133b89d302fcdb35cdf03ba49a0a70b5a4 Mon Sep 17 00:00:00 2001 From: Matthew Robertson Date: Wed, 23 Sep 2026 15:46:11 -0400 Subject: [PATCH 5/6] Remove liblog dep from Android build --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e37240b..9929e2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,8 +81,6 @@ if (ANDROID) "LINKER:--exclude-libs,ALL" "LINKER:--gc-sections" ) - - target_link_libraries(firebase-telemetry-persistence PRIVATE log) endif () if (NOT ANDROID) From 53922343558cbb4b7d7d6b621109250285cf1b9f Mon Sep 17 00:00:00 2001 From: Matthew Robertson Date: Thu, 24 Sep 2026 15:46:48 -0400 Subject: [PATCH 6/6] Rename to PersistenceContext --- src/android_span_data.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/android_span_data.cpp b/src/android_span_data.cpp index a0e2445..b3a3b51 100644 --- a/src/android_span_data.cpp +++ b/src/android_span_data.cpp @@ -315,7 +315,7 @@ jlong JNICALL count_mutable_spans(JNIEnv* /* env */, jobject /* thiz */, return static_cast(mutable_span_data->count()); } -const JNINativeMethod telemetry_methods[] = { +const JNINativeMethod persistence_methods[] = { {"initializeNative", "(Ljava/lang/String;I)J", reinterpret_cast(initialize_native)}, {"recoverSpansNative", @@ -338,17 +338,17 @@ jint register_natives(JNIEnv* env) { return JNI_ERR; } - // Native Method Table Registrations for TelemetryContext - jclass telemetry_clazz = env->FindClass( - "com/google/firebase/crashlytics/telemetry/TelemetryContext"); - if (telemetry_clazz == nullptr) { + // Native Method Table Registrations for PersistenceContext + jclass persistence_clazz = env->FindClass( + "com/google/firebase/crashlytics/telemetry/PersistenceContext"); + if (persistence_clazz == nullptr) { release_jni_globals(env); return JNI_ERR; } - jint telemetry_reg = env->RegisterNatives(telemetry_clazz, telemetry_methods, - std::size(telemetry_methods)); - env->DeleteLocalRef(telemetry_clazz); - if (telemetry_reg != JNI_OK) { + jint persistence_reg = env->RegisterNatives( + persistence_clazz, persistence_methods, std::size(persistence_methods)); + env->DeleteLocalRef(persistence_clazz); + if (persistence_reg != JNI_OK) { release_jni_globals(env); return JNI_ERR; }