fix: Fix HostObject destructors to make sure a JNI Environment is set up (#2462)

* fix: Fix HostObject destructors to make sure a JNI Environment is set up

* Use `reset` instead of `= nullptr`

* Format

* Format
This commit is contained in:
Marc Rousavy 2024-01-30 16:51:09 +01:00 committed by GitHub
parent 9e1297531e
commit 5f75b9e8dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 21 additions and 9 deletions

View File

@ -15,6 +15,9 @@ MutableJByteBuffer::MutableJByteBuffer(jni::alias_ref<jni::JByteBuffer> byteBuff
} }
MutableJByteBuffer::~MutableJByteBuffer() noexcept { MutableJByteBuffer::~MutableJByteBuffer() noexcept {
// Hermes GC might destroy HostObjects on an arbitrary Thread which might not be
// connected to the JNI environment. To make sure fbjni can properly destroy
// the Java method, we connect to a JNI environment first.
jni::ThreadScope::WithClassLoader([&] { _byteBuffer.reset(); }); jni::ThreadScope::WithClassLoader([&] { _byteBuffer.reset(); });
} }
@ -30,4 +33,4 @@ jni::global_ref<jni::JByteBuffer> MutableJByteBuffer::getByteBuffer() {
return _byteBuffer; return _byteBuffer;
} }
} // namespace vision } // namespace vision

View File

@ -22,10 +22,9 @@ using namespace facebook;
FrameHostObject::FrameHostObject(const jni::alias_ref<JFrame::javaobject>& frame) : frame(make_global(frame)) {} FrameHostObject::FrameHostObject(const jni::alias_ref<JFrame::javaobject>& frame) : frame(make_global(frame)) {}
FrameHostObject::~FrameHostObject() { FrameHostObject::~FrameHostObject() {
// Hermes' Garbage Collector (Hades GC) calls destructors on a separate Thread // Hermes GC might destroy HostObjects on an arbitrary Thread which might not be
// which might not be attached to JNI. Ensure that we use the JNI class loader when // connected to the JNI environment. To make sure fbjni can properly destroy
// deallocating the `frame` HybridClass, because otherwise JNI cannot call the Java // the Java method, we connect to a JNI environment first.
// destroy() function.
jni::ThreadScope::WithClassLoader([&] { frame.reset(); }); jni::ThreadScope::WithClassLoader([&] { frame.reset(); });
} }

View File

@ -16,6 +16,9 @@ FrameProcessorPluginHostObject::FrameProcessorPluginHostObject(jni::alias_ref<JF
: _plugin(make_global(plugin)) {} : _plugin(make_global(plugin)) {}
FrameProcessorPluginHostObject::~FrameProcessorPluginHostObject() { FrameProcessorPluginHostObject::~FrameProcessorPluginHostObject() {
// Hermes GC might destroy HostObjects on an arbitrary Thread which might not be
// connected to the JNI environment. To make sure fbjni can properly destroy
// the Java method, we connect to a JNI environment first.
jni::ThreadScope::WithClassLoader([&] { _plugin.reset(); }); jni::ThreadScope::WithClassLoader([&] { _plugin.reset(); });
} }

View File

@ -30,7 +30,12 @@ VisionCameraProxy::VisionCameraProxy(const jni::alias_ref<JVisionCameraProxy::ja
_javaProxy = make_global(javaProxy); _javaProxy = make_global(javaProxy);
} }
VisionCameraProxy::~VisionCameraProxy() {} VisionCameraProxy::~VisionCameraProxy() {
// Hermes GC might destroy HostObjects on an arbitrary Thread which might not be
// connected to the JNI environment. To make sure fbjni can properly destroy
// the Java method, we connect to a JNI environment first.
jni::ThreadScope::WithClassLoader([&] { _javaProxy.reset(); });
}
std::vector<jsi::PropNameID> VisionCameraProxy::getPropertyNames(jsi::Runtime& runtime) { std::vector<jsi::PropNameID> VisionCameraProxy::getPropertyNames(jsi::Runtime& runtime) {
std::vector<jsi::PropNameID> result; std::vector<jsi::PropNameID> result;
@ -96,6 +101,10 @@ jsi::Value VisionCameraProxy::get(jsi::Runtime& runtime, const jsi::PropNameID&
return jsi::Value::undefined(); return jsi::Value::undefined();
} }
void VisionCameraInstaller::registerNatives() {
javaClassStatic()->registerNatives({makeNativeMethod("install", VisionCameraInstaller::install)});
}
void VisionCameraInstaller::install(jni::alias_ref<jni::JClass>, jni::alias_ref<JVisionCameraProxy::javaobject> proxy) { void VisionCameraInstaller::install(jni::alias_ref<jni::JClass>, jni::alias_ref<JVisionCameraProxy::javaobject> proxy) {
// global.VisionCameraProxy // global.VisionCameraProxy
auto visionCameraProxy = std::make_shared<VisionCameraProxy>(proxy); auto visionCameraProxy = std::make_shared<VisionCameraProxy>(proxy);

View File

@ -38,9 +38,7 @@ private:
class VisionCameraInstaller : public jni::JavaClass<VisionCameraInstaller> { class VisionCameraInstaller : public jni::JavaClass<VisionCameraInstaller> {
public: public:
static auto constexpr kJavaDescriptor = "Lcom/mrousavy/camera/frameprocessor/VisionCameraInstaller;"; static auto constexpr kJavaDescriptor = "Lcom/mrousavy/camera/frameprocessor/VisionCameraInstaller;";
static void registerNatives() { static void registerNatives();
javaClassStatic()->registerNatives({makeNativeMethod("install", VisionCameraInstaller::install)});
}
static void install(jni::alias_ref<jni::JClass> clazz, jni::alias_ref<JVisionCameraProxy::javaobject> proxy); static void install(jni::alias_ref<jni::JClass> clazz, jni::alias_ref<JVisionCameraProxy::javaobject> proxy);
}; };