Skip to content

Commit 4928f44

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
tear down surfaces when React Native instance is destoyed (facebook#44209)
Summary: Pull Request resolved: facebook#44209 ## Changelog: [Android] [Fixed] - When React Native is destroyed, unmount all Fabric surfaces. Previously, Fabric surfaces would not be torn down. Meaning that passive and layout effects wouldn't be unmounted and surface infra wouldn't be cleaned up. For example: ``` useEffect(() => { return () => { console.log('unmounted'); } )}; ``` When calling `ReactNativeHost.clear()` on Android in native code, the above effect should be unmounted. This is a requirement for Fabric. Reviewed By: javache Differential Revision: D56238947 fbshipit-source-id: 5dbf5cdef520f34c78953c2b8f2d42349549e893
1 parent c884d19 commit 4928f44

20 files changed

+151
-37
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
9494
import com.facebook.react.internal.AndroidChoreographerProvider;
9595
import com.facebook.react.internal.ChoreographerProvider;
96+
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
9697
import com.facebook.react.internal.turbomodule.core.TurboModuleManager;
9798
import com.facebook.react.internal.turbomodule.core.TurboModuleManagerDelegate;
9899
import com.facebook.react.modules.appearance.AppearanceModule;
@@ -763,10 +764,21 @@ public void destroy() {
763764
unregisterCxxErrorHandlerFunc();
764765

765766
mCreateReactContextThread = null;
766-
synchronized (mReactContextLock) {
767-
if (mCurrentReactContext != null) {
768-
mCurrentReactContext.destroy();
769-
mCurrentReactContext = null;
767+
synchronized (mAttachedReactRoots) {
768+
synchronized (mReactContextLock) {
769+
if (mCurrentReactContext != null) {
770+
if (ReactNativeFeatureFlags.destroyFabricSurfacesInReactInstanceManager()) {
771+
for (ReactRoot reactRoot : mAttachedReactRoots) {
772+
// Fabric surfaces must be cleaned up when React Native is destroyed.
773+
if (reactRoot.getUIManagerType() == UIManagerType.FABRIC) {
774+
detachRootViewFromInstance(reactRoot, mCurrentReactContext);
775+
}
776+
}
777+
}
778+
779+
mCurrentReactContext.destroy();
780+
mCurrentReactContext = null;
781+
}
770782
}
771783
}
772784

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<8915b173bf7bc423cff555366f522615>>
7+
* @generated SignedSource<<cf91b15910f94812cc0d4628fea91f97>>
88
*/
99

1010
/**
@@ -40,6 +40,12 @@ public object ReactNativeFeatureFlags {
4040
@JvmStatic
4141
public fun batchRenderingUpdatesInEventLoop(): Boolean = accessor.batchRenderingUpdatesInEventLoop()
4242

43+
/**
44+
* When enabled, ReactInstanceManager will clean up Fabric surfaces on destroy().
45+
*/
46+
@JvmStatic
47+
public fun destroyFabricSurfacesInReactInstanceManager(): Boolean = accessor.destroyFabricSurfacesInReactInstanceManager()
48+
4349
/**
4450
* Enables the use of a background executor to compute layout and commit updates on Fabric (this system is deprecated and should not be used).
4551
*/

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<f7e306b346e95ea68be34c7d7708c316>>
7+
* @generated SignedSource<<d23f1c4cd3f8960397455c495ed240ba>>
88
*/
99

1010
/**
@@ -22,6 +22,7 @@ package com.facebook.react.internal.featureflags
2222
public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccessor {
2323
private var commonTestFlagCache: Boolean? = null
2424
private var batchRenderingUpdatesInEventLoopCache: Boolean? = null
25+
private var destroyFabricSurfacesInReactInstanceManagerCache: Boolean? = null
2526
private var enableBackgroundExecutorCache: Boolean? = null
2627
private var enableCleanTextInputYogaNodeCache: Boolean? = null
2728
private var enableCustomDrawOrderFabricCache: Boolean? = null
@@ -55,6 +56,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
5556
return cached
5657
}
5758

59+
override fun destroyFabricSurfacesInReactInstanceManager(): Boolean {
60+
var cached = destroyFabricSurfacesInReactInstanceManagerCache
61+
if (cached == null) {
62+
cached = ReactNativeFeatureFlagsCxxInterop.destroyFabricSurfacesInReactInstanceManager()
63+
destroyFabricSurfacesInReactInstanceManagerCache = cached
64+
}
65+
return cached
66+
}
67+
5868
override fun enableBackgroundExecutor(): Boolean {
5969
var cached = enableBackgroundExecutorCache
6070
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<43d74c7b95ae537455e1aafe7daeb397>>
7+
* @generated SignedSource<<4470db3808c33009365864c597ceaf16>>
88
*/
99

1010
/**
@@ -32,6 +32,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
3232

3333
@DoNotStrip @JvmStatic public external fun batchRenderingUpdatesInEventLoop(): Boolean
3434

35+
@DoNotStrip @JvmStatic public external fun destroyFabricSurfacesInReactInstanceManager(): Boolean
36+
3537
@DoNotStrip @JvmStatic public external fun enableBackgroundExecutor(): Boolean
3638

3739
@DoNotStrip @JvmStatic public external fun enableCleanTextInputYogaNode(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<c6c02b3249add27dd868af02151235aa>>
7+
* @generated SignedSource<<f9ed3dc67e050bc741efd3dc82f4b62c>>
88
*/
99

1010
/**
@@ -27,6 +27,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
2727

2828
override fun batchRenderingUpdatesInEventLoop(): Boolean = false
2929

30+
override fun destroyFabricSurfacesInReactInstanceManager(): Boolean = false
31+
3032
override fun enableBackgroundExecutor(): Boolean = false
3133

3234
override fun enableCleanTextInputYogaNode(): Boolean = false

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<919173dae59866dbd93ccbfa3a7f9118>>
7+
* @generated SignedSource<<17d6ac9c31290ac19caa64d87ce7215b>>
88
*/
99

1010
/**
@@ -26,6 +26,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
2626

2727
private var commonTestFlagCache: Boolean? = null
2828
private var batchRenderingUpdatesInEventLoopCache: Boolean? = null
29+
private var destroyFabricSurfacesInReactInstanceManagerCache: Boolean? = null
2930
private var enableBackgroundExecutorCache: Boolean? = null
3031
private var enableCleanTextInputYogaNodeCache: Boolean? = null
3132
private var enableCustomDrawOrderFabricCache: Boolean? = null
@@ -61,6 +62,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
6162
return cached
6263
}
6364

65+
override fun destroyFabricSurfacesInReactInstanceManager(): Boolean {
66+
var cached = destroyFabricSurfacesInReactInstanceManagerCache
67+
if (cached == null) {
68+
cached = currentProvider.destroyFabricSurfacesInReactInstanceManager()
69+
accessedFeatureFlags.add("destroyFabricSurfacesInReactInstanceManager")
70+
destroyFabricSurfacesInReactInstanceManagerCache = cached
71+
}
72+
return cached
73+
}
74+
6475
override fun enableBackgroundExecutor(): Boolean {
6576
var cached = enableBackgroundExecutorCache
6677
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<a022c7f29ebb4b7351253a32efe6203a>>
7+
* @generated SignedSource<<5ab1ec5a95d9fd6b66b30c38c7f8f199>>
88
*/
99

1010
/**
@@ -27,6 +27,8 @@ public interface ReactNativeFeatureFlagsProvider {
2727

2828
@DoNotStrip public fun batchRenderingUpdatesInEventLoop(): Boolean
2929

30+
@DoNotStrip public fun destroyFabricSurfacesInReactInstanceManager(): Boolean
31+
3032
@DoNotStrip public fun enableBackgroundExecutor(): Boolean
3133

3234
@DoNotStrip public fun enableCleanTextInputYogaNode(): Boolean

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<63bb565e7ab5a1e16ce5f9a7d0b93303>>
7+
* @generated SignedSource<<65395bf89177951ff8f66f9567fd4399>>
88
*/
99

1010
/**
@@ -51,6 +51,12 @@ class ReactNativeFeatureFlagsProviderHolder
5151
return method(javaProvider_);
5252
}
5353

54+
bool destroyFabricSurfacesInReactInstanceManager() override {
55+
static const auto method =
56+
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("destroyFabricSurfacesInReactInstanceManager");
57+
return method(javaProvider_);
58+
}
59+
5460
bool enableBackgroundExecutor() override {
5561
static const auto method =
5662
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableBackgroundExecutor");
@@ -149,6 +155,11 @@ bool JReactNativeFeatureFlagsCxxInterop::batchRenderingUpdatesInEventLoop(
149155
return ReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop();
150156
}
151157

158+
bool JReactNativeFeatureFlagsCxxInterop::destroyFabricSurfacesInReactInstanceManager(
159+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
160+
return ReactNativeFeatureFlags::destroyFabricSurfacesInReactInstanceManager();
161+
}
162+
152163
bool JReactNativeFeatureFlagsCxxInterop::enableBackgroundExecutor(
153164
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
154165
return ReactNativeFeatureFlags::enableBackgroundExecutor();
@@ -242,6 +253,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
242253
makeNativeMethod(
243254
"batchRenderingUpdatesInEventLoop",
244255
JReactNativeFeatureFlagsCxxInterop::batchRenderingUpdatesInEventLoop),
256+
makeNativeMethod(
257+
"destroyFabricSurfacesInReactInstanceManager",
258+
JReactNativeFeatureFlagsCxxInterop::destroyFabricSurfacesInReactInstanceManager),
245259
makeNativeMethod(
246260
"enableBackgroundExecutor",
247261
JReactNativeFeatureFlagsCxxInterop::enableBackgroundExecutor),

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<c676d8771641013158d8b07a19ba556b>>
7+
* @generated SignedSource<<4d8c4b2a92dac45194b7e7b6ab9bab58>>
88
*/
99

1010
/**
@@ -36,6 +36,9 @@ class JReactNativeFeatureFlagsCxxInterop
3636
static bool batchRenderingUpdatesInEventLoop(
3737
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
3838

39+
static bool destroyFabricSurfacesInReactInstanceManager(
40+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
41+
3942
static bool enableBackgroundExecutor(
4043
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
4144

packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<e0775f2263b3a9dd8e69dde74557ba2a>>
7+
* @generated SignedSource<<491afbd43963ba14bb2d4741e23e0879>>
88
*/
99

1010
/**
@@ -29,6 +29,10 @@ bool ReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop() {
2929
return getAccessor().batchRenderingUpdatesInEventLoop();
3030
}
3131

32+
bool ReactNativeFeatureFlags::destroyFabricSurfacesInReactInstanceManager() {
33+
return getAccessor().destroyFabricSurfacesInReactInstanceManager();
34+
}
35+
3236
bool ReactNativeFeatureFlags::enableBackgroundExecutor() {
3337
return getAccessor().enableBackgroundExecutor();
3438
}

0 commit comments

Comments
 (0)