Defer HostTarget destruction until after the instance has been unregistered (#44767)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/44767

Changelog: [Internal]

Fixes a lifecycle bug in both the Bridge (`com.facebook.react.bridge`) and Bridgeless (`com.facebook.react.runtime`) integrations of Fusebox in React Native Android, whereby `HostTarget::unregisterInstance` gets called after the `HostTarget` has been destroyed.

The solution consists of two parts:

1. If a ReactHost / InstanceManager is asked to destroy itself while it contains no active ReactInstance / ReactContext, we destroy the `HostTarget` immediately.
2. Otherwise, if there *is* a live ReactInstance / ReactContext that has yet to be destroyed, we wait for that to happen before destroying the `HostTarget`. In practice, we do this by checking for the BEFORE_CREATE ( = Host destroyed) lifecycle state every time we destroy a ReactInstance / ReactContext.

Reviewed By: javache

Differential Revision: D58031215

fbshipit-source-id: 321c73e85afd17a1b38c63f73aee5ebb59c00686
This commit is contained in:
Moti Zilberman
2024-06-06 07:38:23 -07:00
committed by Facebook GitHub Bot
parent 9744fa9283
commit bbf8a87ce7
2 changed files with 26 additions and 5 deletions
@@ -701,7 +701,6 @@ public class ReactInstanceManager {
@Deprecated
public void onHostDestroy() {
UiThreadUtil.assertOnUiThread();
destroyInspectorTarget();
if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
@@ -752,7 +751,6 @@ public class ReactInstanceManager {
}
mHasStartedDestroying = true;
destroyInspectorTarget();
if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
@@ -782,6 +780,12 @@ public class ReactInstanceManager {
}
}
// If the host is being destroyed, now that the current context/instance
// has been destroyed, we can safely destroy the host's inspector target.
if (mLifecycleState == LifecycleState.BEFORE_CREATE) {
destroyInspectorHostTarget();
}
mHasStartedCreatingInitialContext = false;
if (!mKeepActivity) {
mCurrentActivity = null;
@@ -835,6 +839,10 @@ public class ReactInstanceManager {
if (mLifecycleState == LifecycleState.BEFORE_RESUME) {
currentContext.onHostDestroy(mKeepActivity);
}
} else {
// There's no current context that requires the host inspector target to
// be kept alive, so we can destroy it immediately.
destroyInspectorHostTarget();
}
mLifecycleState = LifecycleState.BEFORE_CREATE;
}
@@ -1542,7 +1550,8 @@ public class ReactInstanceManager {
return mInspectorTarget;
}
private void destroyInspectorTarget() {
@ThreadConfined(UI)
private void destroyInspectorHostTarget() {
if (mInspectorTarget != null) {
mInspectorTarget.close();
mInspectorTarget = null;
@@ -887,7 +887,11 @@ public class ReactHostImpl implements ReactHost {
@ThreadConfined(UI)
private void moveToHostDestroy(@Nullable ReactContext currentContext) {
mReactLifecycleStateManager.moveToOnHostDestroy(currentContext);
destroyReactHostInspectorTarget();
if (currentContext == null) {
// There's no current context/instance that requires the host inspector
// target to be kept alive, so we can destroy it immediately.
destroyInspectorHostTarget();
}
setCurrentActivity(null);
}
@@ -1664,13 +1668,15 @@ public class ReactHostImpl implements ReactHost {
return mReactHostInspectorTarget;
}
private void destroyReactHostInspectorTarget() {
@ThreadConfined(UI)
private void destroyInspectorHostTarget() {
if (mReactHostInspectorTarget != null) {
mReactHostInspectorTarget.close();
mReactHostInspectorTarget = null;
}
}
@ThreadConfined(UI)
private void unregisterInstanceFromInspector(final @Nullable ReactInstance reactInstance) {
if (reactInstance != null) {
if (InspectorFlags.getFuseboxEnabled()) {
@@ -1680,5 +1686,11 @@ public class ReactHostImpl implements ReactHost {
}
reactInstance.unregisterFromInspector();
}
if (mReactLifecycleStateManager.getLifecycleState() == LifecycleState.BEFORE_CREATE) {
// If the host is being destroyed, now that the current context/instance
// has been unregistered, we can safely destroy the host's inspector
// target.
destroyInspectorHostTarget();
}
}
}