From 708f527ec79f2b4a108e3f2d7b662bae069b353e Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Tue, 21 Oct 2025 06:33:11 -0700 Subject: [PATCH] Ensure JVM thread is attached when destroying FabricMountingManager (#54218) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/54218 Observed some crashes coming from `schedulerDidRequestPreliminaryViewAllocation` which seemed to point at the FabricMountingManager being destroyed from the Hades GC thread. That thread is not attached to the JVM, so would crash when trying to destroy this global_ref. Changelog: [Internal] Reviewed By: lenaic Differential Revision: D85143603 fbshipit-source-id: 2ecd42d57188e6f3d69a6124e21ee8913b3d5b89 --- .../src/main/jni/react/fabric/FabricMountingManager.cpp | 8 +++++++- .../src/main/jni/react/fabric/FabricMountingManager.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index e29be7f9cad..54b7f76572d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -35,6 +35,12 @@ FabricMountingManager::FabricMountingManager( jni::global_ref& javaUIManager) : javaUIManager_(javaUIManager) {} +FabricMountingManager::~FabricMountingManager() { + // Manually reset `javaUIManager_` since FabricMountingManager may be retained + // from a GC thread (destroyUnmountedShadowNode) + jni::ThreadScope::WithClassLoader([&]() { javaUIManager_.reset(); }); +} + void FabricMountingManager::onSurfaceStart(SurfaceId surfaceId) { std::lock_guard lock(allocatedViewsMutex_); allocatedViewRegistry_.emplace( @@ -905,7 +911,7 @@ void FabricMountingManager::destroyUnmountedShadowNode( // ThreadScope::WithClassLoader is necessary because // destroyUnmountedShadowNode is being called from a destructor thread - facebook::jni::ThreadScope::WithClassLoader([&]() { + jni::ThreadScope::WithClassLoader([&]() { static auto destroyUnmountedView = JFabricUIManager::javaClassStatic()->getMethod( "destroyUnmountedView"); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h index 61978317ff5..3ae20c2370f 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h @@ -25,6 +25,7 @@ class FabricMountingManager final { FabricMountingManager( jni::global_ref& javaUIManager); FabricMountingManager(const FabricMountingManager&) = delete; + ~FabricMountingManager(); void onSurfaceStart(SurfaceId surfaceId);