I'm trying to use JSI and JNI in a React-Native app for sending ArrayBuffer
without encoding data.
For this, I have a C++ function receiveDataFromCpp()
:
extern "C"
JNIEXPORT void JNICALL
Java_com_mymodule_rtnstreamstream_RTNStreamModule_nativeInstall(JNIEnv *env, jobject thiz, jlong jsi) {
jsi::Runtime * runtime = reinterpret_cast<jsi::Runtime *>(jsi);
jobject rtnstream_kt_module = env->NewGlobalRef(thiz);
rtnstream::install(*runtime, env, rtnstream_kt_module);
}
jsi::Function getDeviceName = jsi::Function::createFromHostFunction(
jsiRuntime,
jsi::PropNameID::forAscii(jsiRuntime, "receiveDataFromCpp"),
0,
[&env, &rtnstream_kt_module](
jsi::Runtime& runtime,
const jsi::Value& thisValue,
const jsi::Value* arguments,
std::size_t count
) -> jsi::Value {
if (count != 1 || !arguments[0].isObject()) {
throw jsi::JSError(runtime, "Argument has to be an ArrayBuffer");
}
jsi::Object object = arguments[0].asObject(runtime);
jsi::ArrayBuffer arrayBuffer = object.getArrayBuffer(runtime);
size_t bufferSize = arrayBuffer.size(runtime);
uint8_t* bufferData = arrayBuffer.data(runtime);
jbyteArray jbyteArrayData = env->NewByteArray(bufferSize);
env->SetByteArrayRegion(jbyteArrayData, 0, bufferSize, reinterpret_cast<const jbyte*>(bufferData));
jclass java_class = env->FindClass("com/myModule/RTNStreamModule");
jmethodID receiveDataFromCpp = env->GetMethodID(java_class, "receiveDataFromCpp", "([B)V"); // My kotlin method
env->CallVoidMethod(rtnstream_kt_module, receiveDataFromCpp, jbyteArrayData);
if (jbyteArrayData != nullptr) {
env->DeleteLocalRef(jbyteArrayData); // Clean up
}
return jsi::Value(static_cast<double>(bufferSize));
});
And from JS, just use receiveDataFromCpp(data);
It works the first time, but if I re-run receiveDataFromCpp
, I get this crash error:
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 26510 (mqt_v_js), pid 26432
I do not understand because I think the clean up is correct. Can anyone help me?
bufferSize
is valid and correct. Check thatbufferData
is not null. Check thatrtnstream_kt_module
is not null.JNIEnv *env
value can not be safely used outside of the context of getting it from the JVM, whether or not it was passed as an argument from a JNI call or from attaching the current thread to the JVM. AndJNIEnv *env
values aren't the only values that can't safely be cached. This doesn't appear to be a complete example, so if you are caching values like that, you can't.