Skip to content

Commit

Permalink
Refactor: ReactHost: Delete old task creation methods (#42168)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #42168

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D52495533

fbshipit-source-id: 787919fa68a0308d5e5bc803c7f5f1221675cd09
  • Loading branch information
RSNara authored and facebook-github-bot committed Jan 10, 2024
1 parent 2e6afdc commit af004ce
Showing 1 changed file with 40 additions and 299 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -201,12 +200,7 @@ public LifecycleState getLifecycleState() {
*/
@Override
public TaskInterface<Void> start() {
if (ReactFeatureFlags.enableBridgelessArchitectureNewCreateReloadDestroy) {
return Task.call(this::newGetOrCreateStartTask, mBGExecutor)
.continueWithTask(Task::getResult);
}

return Task.call(this::oldGetOrCreateStartTask, mBGExecutor).continueWithTask(Task::getResult);
return Task.call(this::newGetOrCreateStartTask, mBGExecutor).continueWithTask(Task::getResult);
}

/** Initialize and run a React Native surface in a background without mounting real views. */
Expand Down Expand Up @@ -441,36 +435,32 @@ public void removeReactInstanceEventListener(ReactInstanceEventListener listener
@Override
public TaskInterface<Void> reload(String reason) {
final String method = "reload()";
if (ReactFeatureFlags.enableBridgelessArchitectureNewCreateReloadDestroy) {
return Task.call(
() -> {
Task<Void> reloadTask = null;
if (mDestroyTask != null) {
log(method, "Waiting for destroy to finish, before reloading React Native.");
reloadTask =
mDestroyTask
.continueWithTask(task -> newGetOrCreateReloadTask(reason), mBGExecutor)
.makeVoid();
} else {
reloadTask = newGetOrCreateReloadTask(reason).makeVoid();
}

return reloadTask.continueWithTask(
task -> {
if (task.isFaulted()) {
mReactHostDelegate.handleInstanceException(task.getError());
return newGetOrCreateDestroyTask("Reload failed", task.getError());
}
return Task.call(
() -> {
Task<Void> reloadTask = null;
if (mDestroyTask != null) {
log(method, "Waiting for destroy to finish, before reloading React Native.");
reloadTask =
mDestroyTask
.continueWithTask(task -> newGetOrCreateReloadTask(reason), mBGExecutor)
.makeVoid();
} else {
reloadTask = newGetOrCreateReloadTask(reason).makeVoid();
}

return task;
},
mBGExecutor);
},
mBGExecutor)
.continueWithTask(Task::getResult);
}
return reloadTask.continueWithTask(
task -> {
if (task.isFaulted()) {
mReactHostDelegate.handleInstanceException(task.getError());
return newGetOrCreateDestroyTask("Reload failed", task.getError());
}

return oldReload(reason);
return task;
},
mBGExecutor);
},
mBGExecutor)
.continueWithTask(Task::getResult);
}

/**
Expand All @@ -486,24 +476,19 @@ public TaskInterface<Void> reload(String reason) {
@Override
public TaskInterface<Void> destroy(String reason, @Nullable Exception ex) {
final String method = "destroy()";
if (ReactFeatureFlags.enableBridgelessArchitectureNewCreateReloadDestroy) {
return Task.call(
() -> {
if (mReloadTask != null) {
log(
method,
"Reloading React Native. Waiting for reload to finish before destroying React Native.");
return mReloadTask.continueWithTask(
task -> newGetOrCreateDestroyTask(reason, ex), mBGExecutor);
}
return newGetOrCreateDestroyTask(reason, ex);
},
mBGExecutor)
.continueWithTask(Task::getResult);
}

oldDestroy(reason, ex);
return Task.forResult(nullsafeFIXME(null, "Empty Destroy Task"));
return Task.call(
() -> {
if (mReloadTask != null) {
log(
method,
"Reloading React Native. Waiting for reload to finish before destroying React Native.");
return mReloadTask.continueWithTask(
task -> newGetOrCreateDestroyTask(reason, ex), mBGExecutor);
}
return newGetOrCreateDestroyTask(reason, ex);
},
mBGExecutor)
.continueWithTask(Task::getResult);
}

private MemoryPressureListener createMemoryPressureListener(ReactInstance reactInstance) {
Expand Down Expand Up @@ -720,30 +705,6 @@ public void removeBeforeDestroyListener(@NonNull Function0<Unit> onBeforeDestroy
@ThreadConfined("ReactHost")
private @Nullable Task<Void> mStartTask = null;

@ThreadConfined("ReactHost")
private Task<Void> oldGetOrCreateStartTask() {
if (mStartTask == null) {
final String method = "oldGetOrCreateStartTask()";
log(method, "Schedule");
mStartTask =
getOrCreateReactInstance()
.continueWithTask(
task -> {
if (task.isFaulted()) {
destroy(
"oldGetOrCreateStartTask() failure: " + task.getError().getMessage(),
task.getError());
mReactHostDelegate.handleInstanceException(task.getError());
}

return task;
},
mBGExecutor)
.makeVoid();
}
return mStartTask;
}

@ThreadConfined("ReactHost")
private Task<Void> newGetOrCreateStartTask() {
if (mStartTask == null) {
Expand Down Expand Up @@ -857,12 +818,8 @@ private BridgelessReactContext getOrCreateReactContext() {
* destroying, will wait until destroy is finished, before creating.
*/
private Task<ReactInstance> getOrCreateReactInstance() {
if (ReactFeatureFlags.enableBridgelessArchitectureNewCreateReloadDestroy) {
return Task.call(this::waitThenCallNewGetOrCreateReactInstanceTask, mBGExecutor)
.continueWithTask(Task::getResult);
}

return oldGetOrCreateReactInstanceTask();
return Task.call(this::waitThenCallNewGetOrCreateReactInstanceTask, mBGExecutor)
.continueWithTask(Task::getResult);
}

@ThreadConfined("ReactHost")
Expand Down Expand Up @@ -1021,87 +978,6 @@ class Result {
});
}

private Task<ReactInstance> oldGetOrCreateReactInstanceTask() {
final String method = "oldGetOrCreateReactInstanceTask()";
log(method);

return mReactInstanceTaskRef.getOrCreate(
() -> {
log(method, "Start");
ReactMarker.logMarker(
ReactMarkerConstants.REACT_BRIDGELESS_LOADING_START, BRIDGELESS_MARKER_INSTANCE_KEY);

final BridgelessReactContext reactContext = getOrCreateReactContext();
final DevSupportManager devSupportManager = getDevSupportManager();
reactContext.setJSExceptionHandler(devSupportManager);

return getJsBundleLoader()
.onSuccess(
task -> {
final JSBundleLoader bundleLoader = task.getResult();
log(method, "Creating ReactInstance");
final ReactInstance instance =
new ReactInstance(
reactContext,
mReactHostDelegate,
mComponentFactory,
devSupportManager,
mQueueThreadExceptionHandler,
mReactJsExceptionHandler,
mUseDevSupport);

if (ReactFeatureFlags
.unstable_bridgelessArchitectureMemoryPressureHackyBoltsFix) {
mMemoryPressureListener = createMemoryPressureListener(instance);
}
mMemoryPressureRouter.addMemoryPressureListener(mMemoryPressureListener);

log(method, "Loading JS Bundle");
instance.loadJSBundle(bundleLoader);

log(
method,
"Calling DevSupportManagerBase.onNewReactContextCreated(reactContext)");
devSupportManager.onNewReactContextCreated(reactContext);
reactContext.runOnJSQueueThread(
() -> {
// Executing on the JS thread to ensurethat we're done
// loading the JS bundle.
// TODO T76081936 Move this if we switchto a sync RTE
ReactMarker.logMarker(
ReactMarkerConstants.REACT_BRIDGELESS_LOADING_END,
BRIDGELESS_MARKER_INSTANCE_KEY);
});
return instance;
},
mBGExecutor)
.onSuccess(
task -> {
/*
Call ReactContext.onHostResume() only when already in the resumed state which
aligns with the bridge https://fburl.com/diffusion/2qhxmudv.
*/
mReactLifecycleStateManager.resumeReactContextIfHostResumed(
reactContext, getCurrentActivity());

ReactInstanceEventListener[] listeners =
new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
final ReactInstanceEventListener[] finalListeners =
mReactInstanceEventListeners.toArray(listeners);

log(method, "Executing ReactInstanceEventListeners");
for (ReactInstanceEventListener listener : finalListeners) {
if (listener != null) {
listener.onReactContextInitialized(reactContext);
}
}

return task.getResult();
},
mUIExecutor);
});
}

private Task<JSBundleLoader> getJsBundleLoader() {
final String method = "getJSBundleLoader()";
log(method);
Expand Down Expand Up @@ -1604,141 +1480,6 @@ private Task<Void> newGetOrCreateDestroyTask(final String reason, @Nullable Exce
return mDestroyTask;
}

/** Destroy and recreate the ReactInstance and context. */
private Task<Void> oldReload(String reason) {
final String method = "oldReload()";
log(method);

// Log how React Native is destroyed
// TODO(T136397487): Remove after Venice is shipped to 100%
raiseSoftException(method, reason);

synchronized (mReactInstanceTaskRef) {
mMemoryPressureRouter.removeMemoryPressureListener(mMemoryPressureListener);
oldDestroyReactInstanceAndContext(method, reason);

return callAfterGetOrCreateReactInstance(
method,
reactInstance -> {
// Restart any attached surfaces
log(method, "Restarting Surfaces");
synchronized (mAttachedSurfaces) {
for (ReactSurfaceImpl surface : mAttachedSurfaces) {
reactInstance.startSurface(surface);
}
}
});
}
}

/** Destroy the specified instance and context. */
private void oldDestroy(String reason, @Nullable Exception ex) {
final String method = "oldDestroy()";
log(method);

// Log how React Native is destroyed
// TODO(T136397487): Remove after Venice is shipped to 100%
raiseSoftException(method, reason, ex);

synchronized (mReactInstanceTaskRef) {
// Prevent re-destroy when ReactInstance has been reset already, which could happen when
// calling destroy multiple times on the same thread
ReactInstance reactInstance = mReactInstanceTaskRef.get().getResult();
if (reactInstance == null) {
return;
}

// Retain a reference to current ReactContext before de-referenced by mReactContextRef
final ReactContext reactContext = getCurrentReactContext();

if (reactContext != null) {
mMemoryPressureRouter.destroy(reactContext);
}

oldDestroyReactInstanceAndContext(method, reason);

// Remove all attached surfaces
log(method, "Clearing attached surfaces");
synchronized (mAttachedSurfaces) {
mAttachedSurfaces.clear();
}

Task.call(
(Callable<Void>)
() -> {
moveToHostDestroy(reactContext);
return null;
},
mUIExecutor);
}
}

private void oldDestroyReactInstanceAndContext(final String callingMethod, final String reason) {
final String method = "oldDestroyReactInstanceAndContext(" + callingMethod + ")";
log(method);

synchronized (mReactInstanceTaskRef) {
Task<ReactInstance> task = mReactInstanceTaskRef.getAndReset();
if (!task.isFaulted() && !task.isCancelled()) {
final ReactInstance instance = task.getResult();

// Noop on redundant calls to destroyReactInstance()
if (instance == null) {
log(method, "ReactInstance is null");
return;
}

/*
* The surfaces should be stopped before the instance destroy.
* Calling stop directly on instance ensures we keep the list of attached surfaces for restart.
*/
log(method, "Stopping surfaces");
synchronized (mAttachedSurfaces) {
for (ReactSurfaceImpl surface : mAttachedSurfaces) {
instance.stopSurface(surface);
surface.clear();
}
}

ReactContext reactContext = getCurrentReactContext();

// Reset the ReactContext inside the DevSupportManager
if (reactContext != null) {
log(method, "DevSupportManager.onReactInstanceDestroyed()");
getDevSupportManager().onReactInstanceDestroyed(reactContext);
log(method, "Destroy ReactContext");
mBridgelessReactContextRef.reset();
}

mBGExecutor.execute(
() -> {
// instance.destroy() is time consuming and is confined to ReactHost thread.
log(method, "Destroy ReactInstance");
instance.destroy();

// Re-enable preloads
log(method, "Resetting Preload task ref");
mStartTask = null;
});
} else {
raiseSoftException(
method,
("Not cleaning up ReactInstance: task.isFaulted() = "
+ task.isFaulted()
+ ", task.isCancelled() = "
+ task.isCancelled())
+ ". Reason: "
+ reason);

mBGExecutor.execute(
() -> {
log(method, "Resetting Preload task ref");
mStartTask = null;
});
}
}
}

@Nullable
@Override
public JSEngineResolutionAlgorithm getJsEngineResolutionAlgorithm() {
Expand Down

0 comments on commit af004ce

Please sign in to comment.