Register ReactInstance with modern CDP backend

Summary:
Changelog: [Internal]

This implements the integration of `ReactInstance` with the modern CDP backend.

This is the last missing piece to complete the integration of bridgeless with the modern CDP backend, and now we can test it end to end.

Reviewed By: huntie

Differential Revision: D51459050

fbshipit-source-id: 54e8972ee199cbcc8e5e73d7215a34f008feeaa3
This commit is contained in:
Rubén Norte
2024-02-28 09:53:18 -08:00
committed by Facebook GitHub Bot
parent 65c394f33a
commit 11394e7c88
5 changed files with 95 additions and 34 deletions
@@ -915,7 +915,8 @@ public class ReactHostImpl implements ReactHost {
devSupportManager,
mQueueThreadExceptionHandler,
mReactJsExceptionHandler,
mUseDevSupport);
mUseDevSupport,
mReactHostInspectorTarget);
if (ReactFeatureFlags
.unstable_bridgelessArchitectureMemoryPressureHackyBoltsFix) {
@@ -1200,6 +1201,10 @@ public class ReactHostImpl implements ReactHost {
final ReactInstance reactInstance =
reactInstanceTaskUnwrapper.unwrap(task, "1: Starting reload");
if (reactInstance != null) {
reactInstance.unregisterFromInspector();
}
final ReactContext reactContext = mBridgelessReactContextRef.getNullable();
if (reactContext == null) {
raiseSoftException(method, "ReactContext is null. Reload reason: " + reason);
@@ -1373,6 +1378,10 @@ public class ReactHostImpl implements ReactHost {
final ReactInstance reactInstance =
reactInstanceTaskUnwrapper.unwrap(task, "1: Starting destroy");
if (reactInstance != null) {
reactInstance.unregisterFromInspector();
}
// Step 1: Destroy DevSupportManager
if (mUseDevSupport) {
log(method, "DevSupportManager cleanup");
@@ -114,7 +114,8 @@ final class ReactInstance {
DevSupportManager devSupportManager,
QueueThreadExceptionHandler exceptionHandler,
ReactJsExceptionHandler reactExceptionManager,
boolean useDevSupport) {
boolean useDevSupport,
ReactHostInspectorTarget reactHostInspectorTarget) {
mBridgelessReactContext = bridgelessReactContext;
mDelegate = delegate;
@@ -182,7 +183,8 @@ final class ReactInstance {
jsTimerExecutor,
reactExceptionManager,
bindingsInstaller,
isProfiling);
isProfiling,
reactHostInspectorTarget);
mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
@@ -463,7 +465,8 @@ final class ReactInstance {
JSTimerExecutor jsTimerExecutor,
ReactJsExceptionHandler jReactExceptionsManager,
@Nullable BindingsInstaller jBindingsInstaller,
boolean isProfiling);
boolean isProfiling,
ReactHostInspectorTarget reactHostInspectorTarget);
@DoNotStrip
private static native JSTimerExecutor createJSTimerExecutor();
@@ -494,6 +497,9 @@ final class ReactInstance {
private native void handleMemoryPressureJs(int pressureLevel);
@ThreadConfined(ThreadConfined.UI)
/* package */ native void unregisterFromInspector();
public void handleMemoryPressure(int level) {
try {
handleMemoryPressureJs(level);
@@ -36,7 +36,9 @@ JReactInstance::JReactInstance(
jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,
jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,
jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,
bool isProfiling) noexcept {
bool isProfiling,
jni::alias_ref<JReactHostInspectorTarget::javaobject>
jReactHostInspectorTarget) noexcept {
// TODO(janzer): Lazily create runtime
auto sharedJSMessageQueueThread =
std::make_shared<JMessageQueueThread>(jsMessageQueueThread);
@@ -64,7 +66,8 @@ JReactInstance::JReactInstance(
jsRuntimeFactory->cthis()->createJSRuntime(sharedJSMessageQueueThread),
sharedJSMessageQueueThread,
timerManager,
std::move(jsErrorHandlingFunc));
std::move(jsErrorHandlingFunc),
jReactHostInspectorTarget->cthis()->getInspectorTarget());
auto bufferedRuntimeExecutor = instance_->getBufferedRuntimeExecutor();
timerManager->setRuntimeExecutor(bufferedRuntimeExecutor);
@@ -115,7 +118,9 @@ jni::local_ref<JReactInstance::jhybriddata> JReactInstance::initHybrid(
jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,
jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,
jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,
bool isProfiling) {
bool isProfiling,
jni::alias_ref<JReactHostInspectorTarget::javaobject>
jReactHostInspectorTarget) {
return makeCxxInstance(
jsRuntimeFactory,
jsMessageQueueThread,
@@ -124,7 +129,8 @@ jni::local_ref<JReactInstance::jhybriddata> JReactInstance::initHybrid(
jsTimerExecutor,
jReactExceptionManager,
jBindingsInstaller,
isProfiling);
isProfiling,
jReactHostInspectorTarget);
}
void JReactInstance::loadJSBundleFromAssets(
@@ -205,6 +211,10 @@ jlong JReactInstance::getJavaScriptContext() {
return (jlong)(intptr_t)instance_->getJavaScriptContext();
}
void JReactInstance::unregisterFromInspector() {
instance_->unregisterFromInspector();
}
void JReactInstance::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", JReactInstance::initHybrid),
@@ -229,14 +239,14 @@ void JReactInstance::registerNatives() {
JReactInstance::getBufferedRuntimeExecutor),
makeNativeMethod(
"getRuntimeScheduler", JReactInstance::getRuntimeScheduler),
makeNativeMethod(
"registerSegmentNative", JReactInstance::registerSegment),
makeNativeMethod(
"handleMemoryPressureJs", JReactInstance::handleMemoryPressureJs),
makeNativeMethod(
"getJavaScriptContext", JReactInstance::getJavaScriptContext),
makeNativeMethod(
"unregisterFromInspector", JReactInstance::unregisterFromInspector),
});
}
} // namespace facebook::react
@@ -27,6 +27,7 @@
#include "JJSTimerExecutor.h"
#include "JJavaTimerManager.h"
#include "JReactExceptionManager.h"
#include "JReactHostInspectorTarget.h"
namespace facebook::react {
@@ -45,7 +46,9 @@ class JReactInstance : public jni::HybridClass<JReactInstance> {
jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,
jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,
jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,
bool isProfiling);
bool isProfiling,
jni::alias_ref<JReactHostInspectorTarget::javaobject>
jReactHostInspectorTarget);
/*
* Instantiates and returns an instance of `JSTimerExecutor`.
@@ -78,6 +81,8 @@ class JReactInstance : public jni::HybridClass<JReactInstance> {
void handleMemoryPressureJs(jint level);
void unregisterFromInspector();
private:
friend HybridBase;
@@ -90,7 +95,9 @@ class JReactInstance : public jni::HybridClass<JReactInstance> {
jni::alias_ref<JJSTimerExecutor::javaobject> jsTimerExecutor,
jni::alias_ref<JReactExceptionManager::javaobject> jReactExceptionManager,
jni::alias_ref<JBindingsInstaller::javaobject> jBindingsInstaller,
bool isProfiling) noexcept;
bool isProfiling,
jni::alias_ref<JReactHostInspectorTarget::javaobject>
jReactHostInspectorTarget) noexcept;
jni::alias_ref<CallInvokerHolder::javaobject> getJSCallInvokerHolder();
jni::alias_ref<NativeMethodCallInvokerHolder::javaobject>
@@ -7,6 +7,7 @@
#include "ReactInstance.h"
#include <ReactCommon/RuntimeExecutor.h>
#include <cxxreact/ErrorUtils.h>
#include <cxxreact/JSBigString.h>
#include <cxxreact/JSExecutor.h>
@@ -15,11 +16,13 @@
#include <glog/logging.h>
#include <jsi/JSIDynamic.h>
#include <jsi/instrumentation.h>
#include <jsinspector-modern/HostTarget.h>
#include <jsireact/JSIExecutor.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/runtimescheduler/RuntimeSchedulerBinding.h>
#include <react/utils/jsi.h>
#include <iostream>
#include <memory>
#include <tuple>
#include <utility>
@@ -37,16 +40,13 @@ ReactInstance::ReactInstance(
jsErrorHandler_(jsErrorHandlingFunc),
hasFatalJsError_(std::make_shared<bool>(false)),
parentInspectorTarget_(parentInspectorTarget) {
auto runtimeExecutor = [weakRuntime = std::weak_ptr<JSRuntime>(runtime_),
weakTimerManager =
std::weak_ptr<TimerManager>(timerManager_),
weakJsMessageQueueThread =
std::weak_ptr<MessageQueueThread>(
jsMessageQueueThread_),
weakHasFatalJsError =
std::weak_ptr<bool>(hasFatalJsError_)](
std::function<void(jsi::Runtime & runtime)>&&
callback) {
RuntimeExecutor runtimeExecutor = [weakRuntime = std::weak_ptr(runtime_),
weakTimerManager =
std::weak_ptr(timerManager_),
weakJsMessageQueueThread =
std::weak_ptr(jsMessageQueueThread_),
weakHasFatalJsError = std::weak_ptr(
hasFatalJsError_)](auto callback) {
if (std::shared_ptr<bool> sharedHasFatalJsError =
weakHasFatalJsError.lock()) {
if (*sharedHasFatalJsError) {
@@ -85,13 +85,40 @@ ReactInstance::ReactInstance(
};
if (parentInspectorTarget_) {
inspectorTarget_ = &parentInspectorTarget_->registerInstance(*this);
runtimeInspectorTarget_ =
&inspectorTarget_->registerRuntime(*runtime_, runtimeExecutor);
auto executor = parentInspectorTarget_->executorFromThis();
auto runtimeExecutorThatWaitsForInspectorSetup =
std::make_shared<BufferedRuntimeExecutor>(runtimeExecutor);
// This code can execute from any thread, so we need to make sure we set up
// the inspector logic in the right one. The callback executes immediately
// if we are already in the right thread.
executor([this, runtimeExecutor, runtimeExecutorThatWaitsForInspectorSetup](
jsinspector_modern::HostTarget& hostTarget) {
// Callbacks scheduled through the page target executor are generally
// not guaranteed to run (e.g.: if the page target is destroyed)
// but in this case it is because the page target cannot be destroyed
// before the instance finishes its setup:
// * On iOS it's because we do the setup synchronously.
// * On Android it's because we explicitly wait for the instance
// creation task to finish before starting the destruction.
inspectorTarget_ = &hostTarget.registerInstance(*this);
runtimeInspectorTarget_ =
&inspectorTarget_->registerRuntime(*runtime_, runtimeExecutor);
runtimeExecutorThatWaitsForInspectorSetup->flush();
});
// We decorate the runtime executor used everywhere else to wait for the
// inspector to finish its setup.
runtimeExecutor =
[runtimeExecutorThatWaitsForInspectorSetup](
std::function<void(jsi::Runtime & runtime)>&& callback) {
runtimeExecutorThatWaitsForInspectorSetup->execute(
std::move(callback));
};
}
runtimeScheduler_ =
std::make_shared<RuntimeScheduler>(std::move(runtimeExecutor));
runtimeScheduler_ = std::make_shared<RuntimeScheduler>(runtimeExecutor);
auto pipedRuntimeExecutor =
[runtimeScheduler = runtimeScheduler_.get()](
@@ -104,13 +131,15 @@ ReactInstance::ReactInstance(
}
void ReactInstance::unregisterFromInspector() {
if (inspectorTarget_) {
assert(runtimeInspectorTarget_);
inspectorTarget_->unregisterRuntime(*runtimeInspectorTarget_);
assert(parentInspectorTarget_);
parentInspectorTarget_->unregisterInstance(*inspectorTarget_);
inspectorTarget_ = nullptr;
}
assert(inspectorTarget_);
assert(runtimeInspectorTarget_);
inspectorTarget_->unregisterRuntime(*runtimeInspectorTarget_);
assert(parentInspectorTarget_);
parentInspectorTarget_->unregisterInstance(*inspectorTarget_);
inspectorTarget_ = nullptr;
}
RuntimeExecutor ReactInstance::getUnbufferedRuntimeExecutor() noexcept {