diff --git a/mobile/library/common/jni/android_network_utility.cc b/mobile/library/common/jni/android_network_utility.cc index 1dd944b87547..dd5b9c7faecd 100644 --- a/mobile/library/common/jni/android_network_utility.cc +++ b/mobile/library/common/jni/android_network_utility.cc @@ -77,16 +77,15 @@ call_jvm_verify_x509_cert_chain(Envoy::JNI::JniHelper& jni_helper, jmethodID jmid_verifyServerCertificates = jni_helper.getStaticMethodId( jcls_AndroidNetworkLibrary, "verifyServerCertificates", "([[B[B[B)Lio/envoyproxy/envoymobile/utilities/AndroidCertVerifyResult;"); - jobjectArray chain_byte_array = Envoy::JNI::ToJavaArrayOfByteArray(jni_helper, cert_chain); - jbyteArray auth_string = Envoy::JNI::ToJavaByteArray(jni_helper, auth_type); - jbyteArray host_string = Envoy::JNI::ToJavaByteArray( + Envoy::JNI::LocalRefUniquePtr chain_byte_array = + Envoy::JNI::ToJavaArrayOfByteArray(jni_helper, cert_chain); + Envoy::JNI::LocalRefUniquePtr auth_string = + Envoy::JNI::ToJavaByteArray(jni_helper, auth_type); + Envoy::JNI::LocalRefUniquePtr host_string = Envoy::JNI::ToJavaByteArray( jni_helper, reinterpret_cast(hostname.data()), hostname.length()); - Envoy::JNI::LocalRefUniquePtr result = - jni_helper.callStaticObjectMethod(jcls_AndroidNetworkLibrary, jmid_verifyServerCertificates, - chain_byte_array, auth_string, host_string); - jni_helper.getEnv()->DeleteLocalRef(chain_byte_array); - jni_helper.getEnv()->DeleteLocalRef(auth_string); - jni_helper.getEnv()->DeleteLocalRef(host_string); + Envoy::JNI::LocalRefUniquePtr result = jni_helper.callStaticObjectMethod( + jcls_AndroidNetworkLibrary, jmid_verifyServerCertificates, chain_byte_array.get(), + auth_string.get(), host_string.get()); jni_helper.getEnv()->DeleteLocalRef(jcls_AndroidNetworkLibrary); return result; } diff --git a/mobile/library/common/jni/jni_helper.h b/mobile/library/common/jni/jni_helper.h index 49923611349c..6587e9d803b8 100644 --- a/mobile/library/common/jni/jni_helper.h +++ b/mobile/library/common/jni/jni_helper.h @@ -31,6 +31,9 @@ class LocalRefDeleter { public: explicit LocalRefDeleter(JNIEnv* env) : env_(env) {} + // This is to allow move semantics in `LocalRefUniquePtr`. + LocalRefDeleter& operator=(const LocalRefDeleter&) { return *this; } + void operator()(jobject object) const { if (object != nullptr) { env_->DeleteLocalRef(object); diff --git a/mobile/library/common/jni/jni_interface.cc b/mobile/library/common/jni/jni_interface.cc index 88cb7449fe60..5fd3a6dbf19f 100644 --- a/mobile/library/common/jni/jni_interface.cc +++ b/mobile/library/common/jni/jni_interface.cc @@ -88,17 +88,17 @@ static void jvm_on_track(envoy_map events, const void* context) { } Envoy::JNI::JniHelper jni_helper(Envoy::JNI::get_env()); - jobject events_hashmap = Envoy::JNI::native_map_to_map(jni_helper, events); + Envoy::JNI::LocalRefUniquePtr events_hashmap = + Envoy::JNI::native_map_to_map(jni_helper, events); jobject j_context = static_cast(const_cast(context)); Envoy::JNI::LocalRefUniquePtr jcls_EnvoyEventTracker = jni_helper.getObjectClass(j_context); jmethodID jmid_onTrack = jni_helper.getMethodId(jcls_EnvoyEventTracker.get(), "track", "(Ljava/util/Map;)V"); - jni_helper.callVoidMethod(j_context, jmid_onTrack, events_hashmap); + jni_helper.callVoidMethod(j_context, jmid_onTrack, events_hashmap.get()); release_envoy_map(events); - jni_helper.getEnv()->DeleteLocalRef(events_hashmap); } extern "C" JNIEXPORT jint JNICALL @@ -221,15 +221,15 @@ static void passHeaders(const char* method, const Envoy::Types::ManagedEnvoyHead // requires a null-terminated *modified* UTF-8 string. // Create platform byte array for header key - jbyteArray j_key = Envoy::JNI::native_data_to_array(jni_helper, headers.get().entries[i].key); + Envoy::JNI::LocalRefUniquePtr j_key = + Envoy::JNI::native_data_to_array(jni_helper, headers.get().entries[i].key); // Create platform byte array for header value - jbyteArray j_value = + Envoy::JNI::LocalRefUniquePtr j_value = Envoy::JNI::native_data_to_array(jni_helper, headers.get().entries[i].value); // Pass this header pair to the platform - jni_helper.callVoidMethod(j_context, jmid_passHeader, j_key, j_value, start_headers); - jni_helper.getEnv()->DeleteLocalRef(j_key); - jni_helper.getEnv()->DeleteLocalRef(j_value); + jni_helper.callVoidMethod(j_context, jmid_passHeader, j_key.get(), j_value.get(), + start_headers); // We don't release local refs currently because we've pushed a large enough frame, but we could // consider this and/or periodically popping the frame. @@ -253,18 +253,17 @@ static void* jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoy jmethodID jmid_onHeaders = jni_helper.getMethodId(jcls_JvmCallbackContext.get(), method, "(JZ[J)Ljava/lang/Object;"); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); // Note: be careful of JVM types. Before we casted to jlong we were getting integer problems. // TODO: make this cast safer. - jobject result = - jni_helper.getEnv()->CallObjectMethod(j_context, jmid_onHeaders, (jlong)headers.get().length, - end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel); + jobject result = jni_helper.getEnv()->CallObjectMethod( + j_context, jmid_onHeaders, (jlong)headers.get().length, end_stream ? JNI_TRUE : JNI_FALSE, + j_stream_intel.get()); // TODO(Augustyniak): Pass the name of the filter in here so that we can instrument the origin of // the JNI exception better. bool exception_cleared = Envoy::JNI::Exception::checkAndClear(method); - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); - if (!exception_cleared) { return result; } @@ -274,20 +273,23 @@ static void* jvm_on_headers(const char* method, const Envoy::Types::ManagedEnvoy // 2. Return headers received on as method's input as part of the method's output. Envoy::JNI::LocalRefUniquePtr jcls_object_array = jni_helper.findClass("java/lang/Object"); - jobjectArray noopResult = jni_helper.getEnv()->NewObjectArray(2, jcls_object_array.get(), NULL); + Envoy::JNI::LocalRefUniquePtr noopResult = + jni_helper.newObjectArray(2, jcls_object_array.get(), NULL); Envoy::JNI::LocalRefUniquePtr jcls_int = jni_helper.findClass("java/lang/Integer"); jmethodID jmid_intInit = jni_helper.getMethodId(jcls_int.get(), "", "(I)V"); - jobject j_status = jni_helper.getEnv()->NewObject(jcls_int.get(), jmid_intInit, 0); + Envoy::JNI::LocalRefUniquePtr j_status = + jni_helper.newObject(jcls_int.get(), jmid_intInit, 0); // Set status to "0" (FilterHeadersStatus::Continue). Signal that the intent // is to continue the iteration of the filter chain. - jni_helper.setObjectArrayElement(noopResult, 0, j_status); + jni_helper.setObjectArrayElement(noopResult.get(), 0, j_status.get()); // Since the "on headers" call threw an exception set input headers as output headers. - jni_helper.setObjectArrayElement(noopResult, 1, - Envoy::JNI::ToJavaArrayOfObjectArray(jni_helper, headers)); + Envoy::JNI::LocalRefUniquePtr j_headers = + Envoy::JNI::ToJavaArrayOfObjectArray(jni_helper, headers); + jni_helper.setObjectArrayElement(noopResult.get(), 1, j_headers.get()); - return noopResult; + return noopResult.release(); } static void* jvm_on_response_headers(envoy_headers headers, bool end_stream, @@ -361,15 +363,15 @@ static void* jvm_on_data(const char* method, envoy_data data, bool end_stream, jmethodID jmid_onData = jni_helper.getMethodId(jcls_JvmCallbackContext.get(), method, "([BZ[J)Ljava/lang/Object;"); - jbyteArray j_data = Envoy::JNI::native_data_to_array(jni_helper, data); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_data = + Envoy::JNI::native_data_to_array(jni_helper, data); + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); jobject result = jni_helper - .callObjectMethod(j_context, jmid_onData, j_data, - end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel) + .callObjectMethod(j_context, jmid_onData, j_data.get(), + end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel.get()) .release(); - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); - jni_helper.getEnv()->DeleteLocalRef(j_data); release_envoy_data(data); return result; @@ -472,15 +474,14 @@ static void* jvm_on_trailers(const char* method, envoy_headers trailers, jmethodID jmid_onTrailers = jni_helper.getMethodId(jcls_JvmCallbackContext.get(), method, "(J[J)Ljava/lang/Object;"); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); // Note: be careful of JVM types. Before we casted to jlong we were getting integer problems. // TODO: make this cast safer. - jobject result = - jni_helper - .callObjectMethod(j_context, jmid_onTrailers, (jlong)trailers.length, j_stream_intel) - .release(); - - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); + jobject result = jni_helper + .callObjectMethod(j_context, jmid_onTrailers, (jlong)trailers.length, + j_stream_intel.get()) + .release(); return result; } @@ -627,7 +628,8 @@ jvm_http_filter_on_resume(const char* method, envoy_headers* headers, envoy_data headers_length = (jlong)headers->length; passHeaders("passHeader", *headers, j_context); } - jbyteArray j_in_data = nullptr; + Envoy::JNI::LocalRefUniquePtr j_in_data = Envoy::JNI::LocalRefUniquePtr( + nullptr, Envoy::JNI::LocalRefDeleter(jni_helper.getEnv())); if (data) { j_in_data = Envoy::JNI::native_data_to_array(jni_helper, *data); } @@ -636,7 +638,8 @@ jvm_http_filter_on_resume(const char* method, envoy_headers* headers, envoy_data trailers_length = (jlong)trailers->length; passHeaders("passTrailer", *trailers, j_context); } - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); Envoy::JNI::LocalRefUniquePtr jcls_JvmCallbackContext = jni_helper.getObjectClass(j_context); @@ -645,13 +648,8 @@ jvm_http_filter_on_resume(const char* method, envoy_headers* headers, envoy_data // Note: be careful of JVM types. Before we casted to jlong we were getting integer problems. // TODO: make this cast safer. Envoy::JNI::LocalRefUniquePtr result = jni_helper.callObjectMethod( - j_context, jmid_onResume, headers_length, j_in_data, trailers_length, - end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel); - - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); - if (j_in_data != nullptr) { - jni_helper.getEnv()->DeleteLocalRef(j_in_data); - } + j_context, jmid_onResume, headers_length, j_in_data.get(), trailers_length, + end_stream ? JNI_TRUE : JNI_FALSE, j_stream_intel.get()); Envoy::JNI::LocalRefUniquePtr status = jni_helper.getObjectArrayElement(result.get(), 0); Envoy::JNI::LocalRefUniquePtr j_headers = @@ -699,15 +697,15 @@ static void* call_jvm_on_complete(envoy_stream_intel stream_intel, jmethodID jmid_onComplete = jni_helper.getMethodId(jcls_JvmObserverContext.get(), "onComplete", "([J[J)Ljava/lang/Object;"); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); - jlongArray j_final_stream_intel = + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_final_stream_intel = Envoy::JNI::native_final_stream_intel_to_array(jni_helper, final_stream_intel); - jobject result = - jni_helper.callObjectMethod(j_context, jmid_onComplete, j_stream_intel, j_final_stream_intel) - .release(); + jobject result = jni_helper + .callObjectMethod(j_context, jmid_onComplete, j_stream_intel.get(), + j_final_stream_intel.get()) + .release(); - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); - jni_helper.getEnv()->DeleteLocalRef(j_final_stream_intel); return result; } @@ -722,19 +720,19 @@ static void* call_jvm_on_error(envoy_error error, envoy_stream_intel stream_inte jmethodID jmid_onError = jni_helper.getMethodId(jcls_JvmObserverContext.get(), "onError", "(I[BI[J[J)Ljava/lang/Object;"); - jbyteArray j_error_message = Envoy::JNI::native_data_to_array(jni_helper, error.message); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); - jlongArray j_final_stream_intel = + Envoy::JNI::LocalRefUniquePtr j_error_message = + Envoy::JNI::native_data_to_array(jni_helper, error.message); + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_final_stream_intel = Envoy::JNI::native_final_stream_intel_to_array(jni_helper, final_stream_intel); - jobject result = jni_helper - .callObjectMethod(j_context, jmid_onError, error.error_code, j_error_message, - error.attempt_count, j_stream_intel, j_final_stream_intel) - .release(); + jobject result = + jni_helper + .callObjectMethod(j_context, jmid_onError, error.error_code, j_error_message.get(), + error.attempt_count, j_stream_intel.get(), j_final_stream_intel.get()) + .release(); - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); - jni_helper.getEnv()->DeleteLocalRef(j_final_stream_intel); - jni_helper.getEnv()->DeleteLocalRef(j_error_message); release_envoy_error(error); return result; } @@ -758,16 +756,16 @@ static void* call_jvm_on_cancel(envoy_stream_intel stream_intel, jmethodID jmid_onCancel = jni_helper.getMethodId(jcls_JvmObserverContext.get(), "onCancel", "([J[J)Ljava/lang/Object;"); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); - jlongArray j_final_stream_intel = + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_final_stream_intel = Envoy::JNI::native_final_stream_intel_to_array(jni_helper, final_stream_intel); - jobject result = - jni_helper.callObjectMethod(j_context, jmid_onCancel, j_stream_intel, j_final_stream_intel) - .release(); + jobject result = jni_helper + .callObjectMethod(j_context, jmid_onCancel, j_stream_intel.get(), + j_final_stream_intel.get()) + .release(); - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); - jni_helper.getEnv()->DeleteLocalRef(j_final_stream_intel); return result; } @@ -808,12 +806,13 @@ static void* jvm_on_send_window_available(envoy_stream_intel stream_intel, void* jmethodID jmid_onSendWindowAvailable = jni_helper.getMethodId( jcls_JvmObserverContext.get(), "onSendWindowAvailable", "([J)Ljava/lang/Object;"); - jlongArray j_stream_intel = Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); + Envoy::JNI::LocalRefUniquePtr j_stream_intel = + Envoy::JNI::native_stream_intel_to_array(jni_helper, stream_intel); jobject result = - jni_helper.callObjectMethod(j_context, jmid_onSendWindowAvailable, j_stream_intel).release(); + jni_helper.callObjectMethod(j_context, jmid_onSendWindowAvailable, j_stream_intel.get()) + .release(); - jni_helper.getEnv()->DeleteLocalRef(j_stream_intel); return result; } @@ -828,13 +827,12 @@ static envoy_data jvm_kv_store_read(envoy_data key, const void* context) { jni_helper.getObjectClass(j_context); jmethodID jmid_read = jni_helper.getMethodId(jcls_JvmKeyValueStoreContext.get(), "read", "([B)[B"); - jbyteArray j_key = Envoy::JNI::native_data_to_array(jni_helper, key); + Envoy::JNI::LocalRefUniquePtr j_key = + Envoy::JNI::native_data_to_array(jni_helper, key); Envoy::JNI::LocalRefUniquePtr j_value = - jni_helper.callObjectMethod(j_context, jmid_read, j_key); + jni_helper.callObjectMethod(j_context, jmid_read, j_key.get()); envoy_data native_data = Envoy::JNI::array_to_native_data(jni_helper, j_value.get()); - jni_helper.getEnv()->DeleteLocalRef(j_key); - return native_data; } @@ -848,10 +846,9 @@ static void jvm_kv_store_remove(envoy_data key, const void* context) { jni_helper.getObjectClass(j_context); jmethodID jmid_remove = jni_helper.getMethodId(jcls_JvmKeyValueStoreContext.get(), "remove", "([B)V"); - jbyteArray j_key = Envoy::JNI::native_data_to_array(jni_helper, key); - jni_helper.callVoidMethod(j_context, jmid_remove, j_key); - - jni_helper.getEnv()->DeleteLocalRef(j_key); + Envoy::JNI::LocalRefUniquePtr j_key = + Envoy::JNI::native_data_to_array(jni_helper, key); + jni_helper.callVoidMethod(j_context, jmid_remove, j_key.get()); } static void jvm_kv_store_save(envoy_data key, envoy_data value, const void* context) { @@ -864,12 +861,11 @@ static void jvm_kv_store_save(envoy_data key, envoy_data value, const void* cont jni_helper.getObjectClass(j_context); jmethodID jmid_save = jni_helper.getMethodId(jcls_JvmKeyValueStoreContext.get(), "save", "([B[B)V"); - jbyteArray j_key = Envoy::JNI::native_data_to_array(jni_helper, key); - jbyteArray j_value = Envoy::JNI::native_data_to_array(jni_helper, value); - jni_helper.callVoidMethod(j_context, jmid_save, j_key, j_value); - - jni_helper.getEnv()->DeleteLocalRef(j_value); - jni_helper.getEnv()->DeleteLocalRef(j_key); + Envoy::JNI::LocalRefUniquePtr j_key = + Envoy::JNI::native_data_to_array(jni_helper, key); + Envoy::JNI::LocalRefUniquePtr j_value = + Envoy::JNI::native_data_to_array(jni_helper, value); + jni_helper.callVoidMethod(j_context, jmid_save, j_key.get(), j_value.get()); } // JvmFilterFactoryContext @@ -1423,10 +1419,10 @@ static void jvm_add_test_root_certificate(const uint8_t* cert, size_t len) { jmethodID jmid_addTestRootCertificate = jni_helper.getStaticMethodId(jcls_AndroidNetworkLibrary, "addTestRootCertificate", "([B)V"); - jbyteArray cert_array = Envoy::JNI::ToJavaByteArray(jni_helper, cert, len); + Envoy::JNI::LocalRefUniquePtr cert_array = + Envoy::JNI::ToJavaByteArray(jni_helper, cert, len); jni_helper.callStaticVoidMethod(jcls_AndroidNetworkLibrary, jmid_addTestRootCertificate, - cert_array); - jni_helper.getEnv()->DeleteLocalRef(cert_array); + cert_array.get()); jni_helper.getEnv()->DeleteLocalRef(jcls_AndroidNetworkLibrary); } diff --git a/mobile/library/common/jni/jni_utility.cc b/mobile/library/common/jni/jni_utility.cc index ff0970405be2..66c648ca5951 100644 --- a/mobile/library/common/jni/jni_utility.cc +++ b/mobile/library/common/jni/jni_utility.cc @@ -72,22 +72,23 @@ LocalRefUniquePtr native_data_to_string(JniHelper& jni_helper, envoy_da return jni_helper.newStringUtf(str.c_str()); } -jbyteArray native_data_to_array(JniHelper& jni_helper, envoy_data data) { - jbyteArray j_data = jni_helper.getEnv()->NewByteArray(data.length); - void* critical_data = jni_helper.getEnv()->GetPrimitiveArrayCritical(j_data, nullptr); +LocalRefUniquePtr native_data_to_array(JniHelper& jni_helper, envoy_data data) { + LocalRefUniquePtr j_data = jni_helper.newByteArray(data.length); + void* critical_data = jni_helper.getEnv()->GetPrimitiveArrayCritical(j_data.get(), nullptr); RELEASE_ASSERT(critical_data != nullptr, "unable to allocate memory in jni_utility"); memcpy(critical_data, data.bytes, data.length); // NOLINT(safe-memcpy) // Here '0' (for which there is no named constant) indicates we want to commit the changes back // to the JVM and free the c array, where applicable. // TODO: potential perf improvement. Check if copied via isCopy, and optimize memory handling. - jni_helper.getEnv()->ReleasePrimitiveArrayCritical(j_data, critical_data, 0); + jni_helper.getEnv()->ReleasePrimitiveArrayCritical(j_data.get(), critical_data, 0); return j_data; } -jlongArray native_stream_intel_to_array(JniHelper& jni_helper, envoy_stream_intel stream_intel) { - jlongArray j_array = jni_helper.getEnv()->NewLongArray(4); +LocalRefUniquePtr native_stream_intel_to_array(JniHelper& jni_helper, + envoy_stream_intel stream_intel) { + LocalRefUniquePtr j_array = jni_helper.newLongArray(4); jlong* critical_array = - static_cast(jni_helper.getEnv()->GetPrimitiveArrayCritical(j_array, nullptr)); + static_cast(jni_helper.getEnv()->GetPrimitiveArrayCritical(j_array.get(), nullptr)); RELEASE_ASSERT(critical_array != nullptr, "unable to allocate memory in jni_utility"); critical_array[0] = static_cast(stream_intel.stream_id); critical_array[1] = static_cast(stream_intel.connection_id); @@ -95,15 +96,16 @@ jlongArray native_stream_intel_to_array(JniHelper& jni_helper, envoy_stream_inte critical_array[3] = static_cast(stream_intel.consumed_bytes_from_response); // Here '0' (for which there is no named constant) indicates we want to commit the changes back // to the JVM and free the c array, where applicable. - jni_helper.getEnv()->ReleasePrimitiveArrayCritical(j_array, critical_array, 0); + jni_helper.getEnv()->ReleasePrimitiveArrayCritical(j_array.get(), critical_array, 0); return j_array; } -jlongArray native_final_stream_intel_to_array(JniHelper& jni_helper, - envoy_final_stream_intel final_stream_intel) { - jlongArray j_array = jni_helper.getEnv()->NewLongArray(16); +LocalRefUniquePtr +native_final_stream_intel_to_array(JniHelper& jni_helper, + envoy_final_stream_intel final_stream_intel) { + LocalRefUniquePtr j_array = jni_helper.newLongArray(16); jlong* critical_array = - static_cast(jni_helper.getEnv()->GetPrimitiveArrayCritical(j_array, nullptr)); + static_cast(jni_helper.getEnv()->GetPrimitiveArrayCritical(j_array.get(), nullptr)); RELEASE_ASSERT(critical_array != nullptr, "unable to allocate memory in jni_utility"); critical_array[0] = static_cast(final_stream_intel.stream_start_ms); @@ -125,22 +127,22 @@ jlongArray native_final_stream_intel_to_array(JniHelper& jni_helper, // Here '0' (for which there is no named constant) indicates we want to commit the changes back // to the JVM and free the c array, where applicable. - jni_helper.getEnv()->ReleasePrimitiveArrayCritical(j_array, critical_array, 0); + jni_helper.getEnv()->ReleasePrimitiveArrayCritical(j_array.get(), critical_array, 0); return j_array; } -jobject native_map_to_map(JniHelper& jni_helper, envoy_map map) { +LocalRefUniquePtr native_map_to_map(JniHelper& jni_helper, envoy_map map) { LocalRefUniquePtr jcls_hashMap = jni_helper.findClass("java/util/HashMap"); jmethodID jmid_hashMapInit = jni_helper.getMethodId(jcls_hashMap.get(), "", "(I)V"); - jobject j_hashMap = - jni_helper.getEnv()->NewObject(jcls_hashMap.get(), jmid_hashMapInit, map.length); + LocalRefUniquePtr j_hashMap = + jni_helper.newObject(jcls_hashMap.get(), jmid_hashMapInit, map.length); jmethodID jmid_hashMapPut = jni_helper.getMethodId( jcls_hashMap.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); for (envoy_map_size_t i = 0; i < map.length; i++) { LocalRefUniquePtr key = native_data_to_string(jni_helper, map.entries[i].key); LocalRefUniquePtr value = native_data_to_string(jni_helper, map.entries[i].value); LocalRefUniquePtr ignored = - jni_helper.callObjectMethod(j_hashMap, jmid_hashMapPut, key.get(), value.get()); + jni_helper.callObjectMethod(j_hashMap.get(), jmid_hashMapPut, key.get(), value.get()); } return j_hashMap; } @@ -256,43 +258,47 @@ envoy_map to_native_map(JniHelper& jni_helper, jobjectArray entries) { return native_map; } -jobjectArray ToJavaArrayOfObjectArray(JniHelper& jni_helper, - const Envoy::Types::ManagedEnvoyHeaders& map) { +LocalRefUniquePtr +ToJavaArrayOfObjectArray(JniHelper& jni_helper, const Envoy::Types::ManagedEnvoyHeaders& map) { LocalRefUniquePtr jcls_byte_array = jni_helper.findClass("java/lang/Object"); - jobjectArray javaArray = - jni_helper.getEnv()->NewObjectArray(2 * map.get().length, jcls_byte_array.get(), nullptr); + LocalRefUniquePtr javaArray = + jni_helper.newObjectArray(2 * map.get().length, jcls_byte_array.get(), nullptr); for (envoy_map_size_t i = 0; i < map.get().length; i++) { - jbyteArray key = native_data_to_array(jni_helper, map.get().entries[i].key); - jbyteArray value = native_data_to_array(jni_helper, map.get().entries[i].value); + LocalRefUniquePtr key = native_data_to_array(jni_helper, map.get().entries[i].key); + LocalRefUniquePtr value = + native_data_to_array(jni_helper, map.get().entries[i].value); - jni_helper.setObjectArrayElement(javaArray, 2 * i, key); - jni_helper.setObjectArrayElement(javaArray, 2 * i + 1, value); + jni_helper.setObjectArrayElement(javaArray.get(), 2 * i, key.get()); + jni_helper.setObjectArrayElement(javaArray.get(), 2 * i + 1, value.get()); } return javaArray; } -jobjectArray ToJavaArrayOfByteArray(JniHelper& jni_helper, const std::vector& v) { +LocalRefUniquePtr ToJavaArrayOfByteArray(JniHelper& jni_helper, + const std::vector& v) { LocalRefUniquePtr jcls_byte_array = jni_helper.findClass("[B"); - jobjectArray joa = jni_helper.getEnv()->NewObjectArray(v.size(), jcls_byte_array.get(), nullptr); + LocalRefUniquePtr joa = + jni_helper.newObjectArray(v.size(), jcls_byte_array.get(), nullptr); for (size_t i = 0; i < v.size(); ++i) { - jbyteArray byte_array = + LocalRefUniquePtr byte_array = ToJavaByteArray(jni_helper, reinterpret_cast(v[i].data()), v[i].length()); - jni_helper.setObjectArrayElement(joa, i, byte_array); + jni_helper.setObjectArrayElement(joa.get(), i, byte_array.get()); } return joa; } -jbyteArray ToJavaByteArray(JniHelper& jni_helper, const uint8_t* bytes, size_t len) { - jbyteArray byte_array = jni_helper.getEnv()->NewByteArray(len); +LocalRefUniquePtr ToJavaByteArray(JniHelper& jni_helper, const uint8_t* bytes, + size_t len) { + LocalRefUniquePtr byte_array = jni_helper.newByteArray(len); const jbyte* jbytes = reinterpret_cast(bytes); - jni_helper.setByteArrayRegion(byte_array, /*start=*/0, len, jbytes); + jni_helper.setByteArrayRegion(byte_array.get(), /*start=*/0, len, jbytes); return byte_array; } -jbyteArray ToJavaByteArray(JniHelper& jni_helper, const std::string& str) { +LocalRefUniquePtr ToJavaByteArray(JniHelper& jni_helper, const std::string& str) { const uint8_t* str_bytes = reinterpret_cast(str.data()); return ToJavaByteArray(jni_helper, str_bytes, str.size()); } diff --git a/mobile/library/common/jni/jni_utility.h b/mobile/library/common/jni/jni_utility.h index cc4ed9b2c9ee..a65a94301b6b 100644 --- a/mobile/library/common/jni/jni_utility.h +++ b/mobile/library/common/jni/jni_utility.h @@ -57,14 +57,16 @@ envoy_data array_to_native_data(JniHelper& jni_helper, jbyteArray j_data, size_t * @param env, the JNI env pointer. * @param envoy_data, the source to copy from. * - * @return jbyteArray, copied data. It is up to the function caller to clean up memory. + * @return jbyteArray, copied data. */ -jbyteArray native_data_to_array(JniHelper& jni_helper, envoy_data data); +LocalRefUniquePtr native_data_to_array(JniHelper& jni_helper, envoy_data data); -jlongArray native_stream_intel_to_array(JniHelper& jni_helper, envoy_stream_intel stream_intel); +LocalRefUniquePtr native_stream_intel_to_array(JniHelper& jni_helper, + envoy_stream_intel stream_intel); -jlongArray native_final_stream_intel_to_array(JniHelper& jni_helper, - envoy_final_stream_intel final_stream_intel); +LocalRefUniquePtr +native_final_stream_intel_to_array(JniHelper& jni_helper, + envoy_final_stream_intel final_stream_intel); /** * Utility function that copies envoy_map to a java HashMap jobject. @@ -72,9 +74,9 @@ jlongArray native_final_stream_intel_to_array(JniHelper& jni_helper, * @param env, the JNI env pointer. * @param envoy_map, the source to copy from. * - * @return jobject, copied data. It is up to the function caller to clean up memory. + * @return jobject, copied data. */ -jobject native_map_to_map(JniHelper& jni_helper, envoy_map map); +LocalRefUniquePtr native_map_to_map(JniHelper& jni_helper, envoy_map map); LocalRefUniquePtr native_data_to_string(JniHelper& jni_helper, envoy_data data); @@ -96,14 +98,16 @@ envoy_map to_native_map(JniHelper& jni_helper, jobjectArray entries); * Utilities to translate C++ std library constructs to their Java counterpart. * The underlying data is always copied to disentangle C++ and Java objects lifetime. */ -jobjectArray ToJavaArrayOfByteArray(JniHelper& jni_helper, const std::vector& v); +LocalRefUniquePtr ToJavaArrayOfByteArray(JniHelper& jni_helper, + const std::vector& v); -jbyteArray ToJavaByteArray(JniHelper& jni_helper, const uint8_t* bytes, size_t len); +LocalRefUniquePtr ToJavaByteArray(JniHelper& jni_helper, const uint8_t* bytes, + size_t len); -jbyteArray ToJavaByteArray(JniHelper& jni_helper, const std::string& str); +LocalRefUniquePtr ToJavaByteArray(JniHelper& jni_helper, const std::string& str); -jobjectArray ToJavaArrayOfObjectArray(JniHelper& jni_helper, - const Envoy::Types::ManagedEnvoyHeaders& map); +LocalRefUniquePtr +ToJavaArrayOfObjectArray(JniHelper& jni_helper, const Envoy::Types::ManagedEnvoyHeaders& map); void JavaArrayOfByteArrayToStringVector(JniHelper& jni_helper, jobjectArray array, std::vector* out);