mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
RELAND [RN][CDP] [3/n] RuntimeTarget refactor - RuntimeAgent --> RuntimeAgentDelegate
Summary:
This is a resubmission of D53266707 with a fix in the OSS version of `HermesExecutorFactory` (it was incorrectly referencing `HermesRuntimeAgent.h` which doesn't exist anymore). The original diff summary follows.
---
Changelog: [Internal]
I'm refactoring the way the Runtime concept works in the modern CDP backend to bring it in line with the Page/Instance concepts.
Overall, this will let us:
* Integrate with engines that require us to instantiate a shared Target-like object (e.g. Hermes AsyncDebuggingAPI) in addition to an per-session Agent-like object.
* Access JSI in a CDP context (both at target setup/teardown time and during a CDP session) to implement our own engine-agnostic functionality (`console` interception, `Runtime.addBinding`, etc).
* Manage CDP execution contexts natively in RN, and (down the line) enable first-class debugging support for multiple Runtimes in an Instance.
The core diffs in this stack will:
* ~~Introduce a `RuntimeTarget` class similar to `{Page,Instance}Target`.~~ (D53233914)
* ~~Make runtime registration explicit (`InstanceTarget::registerRuntime` similar to `PageTarget::registerInstance`).~~ (D53233914)
* Rename the existing `RuntimeAgent` interface to `RuntimeAgentDelegate`. *← This diff*
* Create a new concrete `RuntimeAgent` class similar to `{Page,Instance}Agent`. *← Also in this diff*
* Provide `RuntimeTarget` and `RuntimeAgent` with primitives for safe JSI access, namely a `RuntimeExecutor` for scheduling work on the JS thread.
* We'll likely develop a similar mechanism for scheduling work on the "main" thread from the JS thread, for when we need to do more than just send a CDP message (which we can already do with the thread-safe `FrontendChannel`) in response to a JS event.
## Architecture diagrams
Before this stack:
https://pxl.cl/4h7m0
After this stack:
https://pxl.cl/4h7m7
Reviewed By: EdmondChuiHW
Differential Revision: D53748590
fbshipit-source-id: bd0cf9f74b95abc52b4903f8a7afddcefa303d8a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
b97f3e779a
commit
04eadf6a6c
@@ -35,10 +35,11 @@ double JSExecutor::performanceNow() {
|
||||
return duration / NANOSECONDS_IN_MILLISECOND;
|
||||
}
|
||||
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgent> JSExecutor::createAgent(
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
|
||||
JSExecutor::createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) {
|
||||
return std::make_unique<jsinspector_modern::FallbackRuntimeAgent>(
|
||||
return std::make_unique<jsinspector_modern::FallbackRuntimeAgentDelegate>(
|
||||
std::move(frontendChannel), sessionState, getDescription());
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ class RN_EXPORT JSExecutor : public jsinspector_modern::RuntimeTargetDelegate {
|
||||
/**
|
||||
* Returns whether or not the underlying executor supports debugging via the
|
||||
* Chrome remote debugging protocol. If true, the executor should also
|
||||
* override the \c createAgent method.
|
||||
* override the \c createAgentDelegate method.
|
||||
*/
|
||||
virtual bool isInspectable() {
|
||||
return false;
|
||||
@@ -141,9 +141,10 @@ class RN_EXPORT JSExecutor : public jsinspector_modern::RuntimeTargetDelegate {
|
||||
static double performanceNow();
|
||||
|
||||
/**
|
||||
* Create a RuntimeAgent that can be used to debug the JS VM instance.
|
||||
* Create a RuntimeAgentDelegate that can be used to debug the JS VM instance.
|
||||
*/
|
||||
virtual std::unique_ptr<jsinspector_modern::RuntimeAgent> createAgent(
|
||||
virtual std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
|
||||
createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) override;
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <jsi/decorator.h>
|
||||
#include <jsinspector-modern/InspectorFlags.h>
|
||||
|
||||
#include <hermes/inspector-modern/chrome/HermesRuntimeAgent.h>
|
||||
#include <hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h>
|
||||
#include <hermes/inspector-modern/chrome/Registration.h>
|
||||
#include <hermes/inspector/RuntimeAdapter.h>
|
||||
|
||||
@@ -257,12 +257,13 @@ HermesExecutor::HermesExecutor(
|
||||
runtime_(runtime),
|
||||
hermesRuntime_(hermesRuntime) {}
|
||||
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgent> HermesExecutor::createAgent(
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
|
||||
HermesExecutor::createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) {
|
||||
std::shared_ptr<HermesRuntime> hermesRuntimeShared(runtime_, &hermesRuntime_);
|
||||
return std::unique_ptr<jsinspector_modern::RuntimeAgent>(
|
||||
new jsinspector_modern::HermesRuntimeAgent(
|
||||
return std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>(
|
||||
new jsinspector_modern::HermesRuntimeAgentDelegate(
|
||||
frontendChannel,
|
||||
sessionState,
|
||||
hermesRuntimeShared,
|
||||
|
||||
@@ -54,7 +54,8 @@ class HermesExecutor : public JSIExecutor {
|
||||
RuntimeInstaller runtimeInstaller,
|
||||
hermes::HermesRuntime& hermesRuntime);
|
||||
|
||||
virtual std::unique_ptr<jsinspector_modern::RuntimeAgent> createAgent(
|
||||
virtual std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
|
||||
createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) override;
|
||||
|
||||
|
||||
+17
-15
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "HermesRuntimeAgent.h"
|
||||
#include "HermesRuntimeAgentDelegate.h"
|
||||
|
||||
// If HERMES_ENABLE_DEBUGGER isn't defined, we can't access any Hermes
|
||||
// CDPHandler headers or types.
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <hermes/inspector/RuntimeAdapter.h>
|
||||
#include <hermes/inspector/chrome/CDPHandler.h>
|
||||
#else // HERMES_ENABLE_DEBUGGER
|
||||
#include <jsinspector-modern/FallbackRuntimeAgent.h>
|
||||
#include <jsinspector-modern/FallbackRuntimeAgentDelegate.h>
|
||||
#endif // HERMES_ENABLE_DEBUGGER
|
||||
|
||||
#include <hermes/hermes.h>
|
||||
@@ -30,12 +30,12 @@ namespace {
|
||||
|
||||
/**
|
||||
* An implementation of the Hermes RuntimeAdapter interface (part of
|
||||
* Hermes's CDPHandler API) for use within a React Native RuntimeAgent.
|
||||
* Hermes's CDPHandler API) for use within a React Native RuntimeAgentDelegate.
|
||||
*/
|
||||
class HermesRuntimeAgentAdapter
|
||||
class HermesRuntimeAgentDelegateAdapter
|
||||
: public hermes::inspector_modern::RuntimeAdapter {
|
||||
public:
|
||||
HermesRuntimeAgentAdapter(
|
||||
HermesRuntimeAgentDelegateAdapter(
|
||||
std::shared_ptr<hermes::HermesRuntime> runtime,
|
||||
RuntimeExecutor runtimeExecutor)
|
||||
: runtime_(runtime), runtimeExecutor_(runtimeExecutor) {}
|
||||
@@ -60,10 +60,10 @@ class HermesRuntimeAgentAdapter
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* A RuntimeAgent that handles requests from the Chrome DevTools Protocol for
|
||||
* an instance of Hermes.
|
||||
* A RuntimeAgentDelegate that handles requests from the Chrome DevTools
|
||||
* Protocol for an instance of Hermes.
|
||||
*/
|
||||
class HermesRuntimeAgent::Impl final : public RuntimeAgent {
|
||||
class HermesRuntimeAgentDelegate::Impl final : public RuntimeAgentDelegate {
|
||||
using HermesCDPHandler = hermes::inspector_modern::chrome::CDPHandler;
|
||||
|
||||
public:
|
||||
@@ -84,7 +84,7 @@ class HermesRuntimeAgent::Impl final : public RuntimeAgent {
|
||||
std::shared_ptr<hermes::HermesRuntime> runtime,
|
||||
RuntimeExecutor runtimeExecutor)
|
||||
: hermes_(HermesCDPHandler::create(
|
||||
std::make_unique<HermesRuntimeAgentAdapter>(
|
||||
std::make_unique<HermesRuntimeAgentDelegateAdapter>(
|
||||
runtime,
|
||||
runtimeExecutor),
|
||||
/* waitForDebugger */ false,
|
||||
@@ -133,17 +133,18 @@ class HermesRuntimeAgent::Impl final : public RuntimeAgent {
|
||||
#else // !HERMES_ENABLE_DEBUGGER
|
||||
|
||||
/**
|
||||
* A stub for HermesRuntimeAgent when Hermes is compiled without debugging
|
||||
* support.
|
||||
* A stub for HermesRuntimeAgentDelegate when Hermes is compiled without
|
||||
* debugging support.
|
||||
*/
|
||||
class HermesRuntimeAgent::Impl final : public FallbackRuntimeAgent {
|
||||
class HermesRuntimeAgentDelegate::Impl final
|
||||
: public FallbackRuntimeAgentDelegate {
|
||||
public:
|
||||
Impl(
|
||||
FrontendChannel frontendChannel,
|
||||
SessionState& sessionState,
|
||||
std::shared_ptr<hermes::HermesRuntime> runtime,
|
||||
RuntimeExecutor)
|
||||
: FallbackRuntimeAgent(
|
||||
: FallbackRuntimeAgentDelegate(
|
||||
std::move(frontendChannel),
|
||||
sessionState,
|
||||
runtime->description()) {}
|
||||
@@ -151,7 +152,7 @@ class HermesRuntimeAgent::Impl final : public FallbackRuntimeAgent {
|
||||
|
||||
#endif // HERMES_ENABLE_DEBUGGER
|
||||
|
||||
HermesRuntimeAgent::HermesRuntimeAgent(
|
||||
HermesRuntimeAgentDelegate::HermesRuntimeAgentDelegate(
|
||||
FrontendChannel frontendChannel,
|
||||
SessionState& sessionState,
|
||||
std::shared_ptr<hermes::HermesRuntime> runtime,
|
||||
@@ -162,7 +163,8 @@ HermesRuntimeAgent::HermesRuntimeAgent(
|
||||
std::move(runtime),
|
||||
std::move(runtimeExecutor))) {}
|
||||
|
||||
bool HermesRuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
bool HermesRuntimeAgentDelegate::handleRequest(
|
||||
const cdp::PreparsedRequest& req) {
|
||||
return impl_->handleRequest(req);
|
||||
}
|
||||
|
||||
+4
-4
@@ -15,10 +15,10 @@
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* A RuntimeAgent that handles requests from the Chrome DevTools Protocol for
|
||||
* an instance of Hermes.
|
||||
* A RuntimeAgentDelegate that handles requests from the Chrome DevTools
|
||||
* Protocol for an instance of Hermes.
|
||||
*/
|
||||
class HermesRuntimeAgent : public RuntimeAgent {
|
||||
class HermesRuntimeAgentDelegate : public RuntimeAgentDelegate {
|
||||
public:
|
||||
/**
|
||||
* \param frontendChannel A channel used to send responses and events to the
|
||||
@@ -31,7 +31,7 @@ class HermesRuntimeAgent : public RuntimeAgent {
|
||||
* \c runtimeExecutor may drop scheduled work if the runtime is destroyed
|
||||
* first.
|
||||
*/
|
||||
HermesRuntimeAgent(
|
||||
HermesRuntimeAgentDelegate(
|
||||
FrontendChannel frontendChannel,
|
||||
SessionState& sessionState,
|
||||
std::shared_ptr<hermes::HermesRuntime> runtime,
|
||||
@@ -21,3 +21,7 @@ A single connection between a debugger frontend and a target. There can be multi
|
||||
### Agent
|
||||
|
||||
A handler for a subset of CDP messages for a specific target as part of a specific session.
|
||||
|
||||
### Agent Delegate
|
||||
|
||||
An interface between an Agent class and some integration-specific, per-session logic/state it relies on (that does not fit in a Target Delegate). For example, a RuntimeAgentDelegate is used by RuntimeAgent to host Hermes's native CDP handler and delegate messages to it. The interface may look exactly like an Agent (purely CDP messages in/out) or there may be a more involved API to expose state/functionality needed by the Agent.
|
||||
|
||||
+6
-5
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <jsinspector-modern/FallbackRuntimeAgent.h>
|
||||
#include "FallbackRuntimeAgentDelegate.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
@@ -22,7 +22,7 @@ namespace facebook::react::jsinspector_modern {
|
||||
#define ANSI_STYLE_RESET "\x1B[23m"
|
||||
#define ANSI_COLOR_BG_YELLOW "\x1B[48;2;253;247;231m"
|
||||
|
||||
FallbackRuntimeAgent::FallbackRuntimeAgent(
|
||||
FallbackRuntimeAgentDelegate::FallbackRuntimeAgentDelegate(
|
||||
FrontendChannel frontendChannel,
|
||||
const SessionState& sessionState,
|
||||
std::string engineDescription)
|
||||
@@ -32,7 +32,8 @@ FallbackRuntimeAgent::FallbackRuntimeAgent(
|
||||
}
|
||||
}
|
||||
|
||||
bool FallbackRuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
bool FallbackRuntimeAgentDelegate::handleRequest(
|
||||
const cdp::PreparsedRequest& req) {
|
||||
if (req.method == "Log.enable") {
|
||||
sendFallbackRuntimeWarning();
|
||||
|
||||
@@ -44,7 +45,7 @@ bool FallbackRuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void FallbackRuntimeAgent::sendFallbackRuntimeWarning() {
|
||||
void FallbackRuntimeAgentDelegate::sendFallbackRuntimeWarning() {
|
||||
sendWarningLogEntry(
|
||||
"The current JavaScript engine, " ANSI_STYLE_ITALIC + engineDescription_ +
|
||||
ANSI_STYLE_RESET
|
||||
@@ -52,7 +53,7 @@ void FallbackRuntimeAgent::sendFallbackRuntimeWarning() {
|
||||
"See https://reactnative.dev/docs/debugging for more information.");
|
||||
}
|
||||
|
||||
void FallbackRuntimeAgent::sendWarningLogEntry(std::string_view text) {
|
||||
void FallbackRuntimeAgentDelegate::sendWarningLogEntry(std::string_view text) {
|
||||
frontendChannel_(
|
||||
folly::toJson(folly::dynamic::object("method", "Log.entryAdded")(
|
||||
"params",
|
||||
+4
-4
@@ -15,10 +15,10 @@
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* A RuntimeAgent that handles requests from the Chrome DevTools Protocol for
|
||||
* a JavaScript runtime that does not support debugging.
|
||||
* A RuntimeAgentDelegate that handles requests from the Chrome DevTools
|
||||
* Protocol for a JavaScript runtime that does not support debugging.
|
||||
*/
|
||||
class FallbackRuntimeAgent : public RuntimeAgent {
|
||||
class FallbackRuntimeAgentDelegate : public RuntimeAgentDelegate {
|
||||
public:
|
||||
/**
|
||||
* \param frontendChannel A channel used to send responses and events to the
|
||||
@@ -27,7 +27,7 @@ class FallbackRuntimeAgent : public RuntimeAgent {
|
||||
* \param engineDescription A description of the JavaScript engine being
|
||||
* debugged. This string will be used in messages sent to the frontend.
|
||||
*/
|
||||
FallbackRuntimeAgent(
|
||||
FallbackRuntimeAgentDelegate(
|
||||
FrontendChannel frontendChannel,
|
||||
const SessionState& sessionState,
|
||||
std::string engineDescription);
|
||||
@@ -24,7 +24,7 @@ class InstanceTarget;
|
||||
* An Agent that handles requests from the Chrome DevTools Protocol for the
|
||||
* given InstanceTarget.
|
||||
*/
|
||||
class InstanceAgent {
|
||||
class InstanceAgent final {
|
||||
public:
|
||||
/**
|
||||
* \param frontendChannel A channel used to send responses and events to the
|
||||
|
||||
@@ -40,7 +40,7 @@ class InstanceTargetDelegate {
|
||||
/**
|
||||
* A Target that represents a single instance of React Native.
|
||||
*/
|
||||
class InstanceTarget {
|
||||
class InstanceTarget final {
|
||||
public:
|
||||
/**
|
||||
* \param delegate The object that will receive events from this target.
|
||||
|
||||
@@ -30,7 +30,7 @@ class InstanceTarget;
|
||||
* same thread, which is also the thread where the associated PageTarget is
|
||||
* constructed and managed.
|
||||
*/
|
||||
class PageAgent {
|
||||
class PageAgent final {
|
||||
public:
|
||||
/**
|
||||
* \param frontendChannel A channel used to send responses and events to the
|
||||
|
||||
@@ -78,7 +78,7 @@ class PageTargetDelegate {
|
||||
* The limited interface that PageTarget exposes to its associated
|
||||
* sessions/agents.
|
||||
*/
|
||||
class PageTargetController {
|
||||
class PageTargetController final {
|
||||
public:
|
||||
explicit PageTargetController(PageTarget& target);
|
||||
|
||||
@@ -95,7 +95,7 @@ class PageTargetController {
|
||||
* "Host" in React Native's architecture - the entity that manages the
|
||||
* lifecycle of a React Instance.
|
||||
*/
|
||||
class JSINSPECTOR_EXPORT PageTarget {
|
||||
class JSINSPECTOR_EXPORT PageTarget final {
|
||||
public:
|
||||
struct SessionMetadata {
|
||||
std::optional<std::string> integrationName;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jsinspector-modern/FallbackRuntimeAgent.h>
|
||||
#include <jsinspector-modern/FallbackRuntimeAgentDelegate.h>
|
||||
#include <jsinspector-modern/InstanceTarget.h>
|
||||
#include <jsinspector-modern/PageTarget.h>
|
||||
#include <jsinspector-modern/RuntimeTarget.h>
|
||||
|
||||
@@ -5,10 +5,28 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <jsinspector-modern/RuntimeAgent.h>
|
||||
#include "RuntimeAgent.h"
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
RuntimeAgent::~RuntimeAgent() {}
|
||||
RuntimeAgent::RuntimeAgent(
|
||||
FrontendChannel frontendChannel,
|
||||
RuntimeTarget& target,
|
||||
SessionState& sessionState,
|
||||
std::unique_ptr<RuntimeAgentDelegate> delegate)
|
||||
: frontendChannel_(std::move(frontendChannel)),
|
||||
target_(target),
|
||||
sessionState_(sessionState),
|
||||
delegate_(std::move(delegate)) {
|
||||
(void)target_;
|
||||
(void)sessionState_;
|
||||
}
|
||||
|
||||
bool RuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) {
|
||||
if (delegate_) {
|
||||
return delegate_->handleRequest(req);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -7,29 +7,59 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "InspectorInterfaces.h"
|
||||
#include "RuntimeAgentDelegate.h"
|
||||
#include "RuntimeTarget.h"
|
||||
#include "SessionState.h"
|
||||
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
class RuntimeTarget;
|
||||
|
||||
/**
|
||||
* An Agent interface that handles requests from the Chrome DevTools Protocol
|
||||
* for a particular JS runtime instance. The exact mechanism of sending
|
||||
* responses/events to the frontend is left up to the implementation, but
|
||||
* implementations SHOULD use FrontendChannel or a similar abstraction.
|
||||
* An Agent that handles requests from the Chrome DevTools Protocol
|
||||
* for a particular JS runtime instance. RuntimeAgent implements
|
||||
* engine-agnostic functionality based on interfaces available in JSI /
|
||||
* RuntimeTarget, and delegates engine-specific functionality to a
|
||||
* RuntimeAgentDelegate.
|
||||
*/
|
||||
class RuntimeAgent {
|
||||
class RuntimeAgent final {
|
||||
public:
|
||||
virtual ~RuntimeAgent();
|
||||
/**
|
||||
* \param frontendChannel A channel used to send responses and events to the
|
||||
* frontend.
|
||||
* \param target The RuntimeTarget that this agent is attached to. The
|
||||
* caller is responsible for ensuring that the RuntimeTarget outlives this
|
||||
* object.
|
||||
* \param sessionState The state of the session that created this agent.
|
||||
* \param delegate The RuntimeAgentDelegate providing engine-specific
|
||||
* CDP functionality.
|
||||
*/
|
||||
RuntimeAgent(
|
||||
FrontendChannel frontendChannel,
|
||||
RuntimeTarget& target,
|
||||
SessionState& sessionState,
|
||||
std::unique_ptr<RuntimeAgentDelegate> delegate);
|
||||
|
||||
/**
|
||||
* Handle a CDP request. This implementation must perform any synchronization
|
||||
* required between the thread on which this method is called and the thread
|
||||
* where the JS runtime is executing.
|
||||
* Handle a CDP request. The response will be sent over the provided
|
||||
* \c FrontendChannel synchronously or asynchronously. Performs any
|
||||
* synchronization required between the thread on which this method is
|
||||
* called and the thread where the JS runtime is executing.
|
||||
* \param req The parsed request.
|
||||
* \returns true if this agent has responded, or will respond asynchronously,
|
||||
* to the request (with either a success or error message). False if the
|
||||
* agent expects another agent to respond to the request instead.
|
||||
*/
|
||||
virtual bool handleRequest(const cdp::PreparsedRequest& req) = 0;
|
||||
bool handleRequest(const cdp::PreparsedRequest& req);
|
||||
|
||||
private:
|
||||
FrontendChannel frontendChannel_;
|
||||
RuntimeTarget& target_;
|
||||
SessionState& sessionState_;
|
||||
const std::unique_ptr<RuntimeAgentDelegate> delegate_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jsinspector-modern/Parsing.h>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* An Agent interface that handles requests from the Chrome DevTools Protocol
|
||||
* for a particular JS runtime instance. The exact mechanism of sending
|
||||
* responses/events to the frontend is left up to the implementation, but
|
||||
* implementations SHOULD use FrontendChannel or a similar abstraction.
|
||||
*/
|
||||
class RuntimeAgentDelegate {
|
||||
public:
|
||||
virtual ~RuntimeAgentDelegate() = default;
|
||||
|
||||
/**
|
||||
* Handle a CDP request. This implementation must perform any synchronization
|
||||
* required between the thread on which this method is called and the thread
|
||||
* where the JS runtime is executing.
|
||||
* \returns true if this agent has responded, or will respond asynchronously,
|
||||
* to the request (with either a success or error message). False if the
|
||||
* agent expects another agent to respond to the request instead.
|
||||
*/
|
||||
virtual bool handleRequest(const cdp::PreparsedRequest& req) = 0;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -14,7 +14,11 @@ RuntimeTarget::RuntimeTarget(RuntimeTargetDelegate& delegate)
|
||||
std::unique_ptr<RuntimeAgent> RuntimeTarget::createAgent(
|
||||
FrontendChannel channel,
|
||||
SessionState& sessionState) {
|
||||
return delegate_.createAgent(channel, sessionState);
|
||||
return std::make_unique<RuntimeAgent>(
|
||||
channel,
|
||||
*this,
|
||||
sessionState,
|
||||
delegate_.createAgentDelegate(channel, sessionState));
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
class RuntimeAgent;
|
||||
class RuntimeAgentDelegate;
|
||||
|
||||
/**
|
||||
* Receives events from a RuntimeTarget. This is a shared interface that
|
||||
* each React Native platform needs to implement in order to integrate with
|
||||
@@ -35,7 +38,7 @@ namespace facebook::react::jsinspector_modern {
|
||||
class RuntimeTargetDelegate {
|
||||
public:
|
||||
virtual ~RuntimeTargetDelegate() = default;
|
||||
virtual std::unique_ptr<RuntimeAgent> createAgent(
|
||||
virtual std::unique_ptr<RuntimeAgentDelegate> createAgentDelegate(
|
||||
FrontendChannel channel,
|
||||
SessionState& sessionState) = 0;
|
||||
};
|
||||
@@ -43,7 +46,7 @@ class RuntimeTargetDelegate {
|
||||
/**
|
||||
* A Target corresponding to a JavaScript runtime.
|
||||
*/
|
||||
class JSINSPECTOR_EXPORT RuntimeTarget {
|
||||
class JSINSPECTOR_EXPORT RuntimeTarget final {
|
||||
public:
|
||||
/**
|
||||
* \param delegate The object that will receive events from this target.
|
||||
|
||||
@@ -127,21 +127,21 @@ class MockRuntimeTargetDelegate : public RuntimeTargetDelegate {
|
||||
public:
|
||||
// RuntimeTargetDelegate methods
|
||||
MOCK_METHOD(
|
||||
std::unique_ptr<RuntimeAgent>,
|
||||
createAgent,
|
||||
std::unique_ptr<RuntimeAgentDelegate>,
|
||||
createAgentDelegate,
|
||||
(FrontendChannel channel, SessionState& sessionState),
|
||||
(override));
|
||||
};
|
||||
|
||||
class MockRuntimeAgent : public RuntimeAgent {
|
||||
class MockRuntimeAgentDelegate : public RuntimeAgentDelegate {
|
||||
public:
|
||||
inline MockRuntimeAgent(
|
||||
inline MockRuntimeAgentDelegate(
|
||||
FrontendChannel frontendChannel,
|
||||
SessionState& sessionState)
|
||||
: frontendChannel(std::move(frontendChannel)),
|
||||
sessionState(sessionState) {}
|
||||
|
||||
// RuntimeAgent methods
|
||||
// RuntimeAgentDelegate methods
|
||||
MOCK_METHOD(
|
||||
bool,
|
||||
handleRequest,
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace {
|
||||
class PageTargetTest : public Test {
|
||||
protected:
|
||||
PageTargetTest() {
|
||||
EXPECT_CALL(runtimeTargetDelegate_, createAgent(_, _))
|
||||
EXPECT_CALL(runtimeTargetDelegate_, createAgentDelegate(_, _))
|
||||
.WillRepeatedly(
|
||||
runtimeAgents_
|
||||
runtimeAgentDelegates_
|
||||
.lazily_make_unique<FrontendChannel, SessionState&>());
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class PageTargetTest : public Test {
|
||||
MockInstanceTargetDelegate instanceTargetDelegate_;
|
||||
MockRuntimeTargetDelegate runtimeTargetDelegate_;
|
||||
|
||||
UniquePtrFactory<StrictMock<MockRuntimeAgent>> runtimeAgents_;
|
||||
UniquePtrFactory<StrictMock<MockRuntimeAgentDelegate>> runtimeAgentDelegates_;
|
||||
|
||||
private:
|
||||
UniquePtrFactory<StrictMock<MockRemoteConnection>> remoteConnections_;
|
||||
@@ -258,8 +258,8 @@ TEST_F(PageTargetTest, ConnectToAlreadyRegisteredRuntimeWithEvents) {
|
||||
|
||||
InSequence s;
|
||||
|
||||
ASSERT_TRUE(runtimeAgents_[0]);
|
||||
EXPECT_CALL(*runtimeAgents_[0], handleRequest(_))
|
||||
ASSERT_TRUE(runtimeAgentDelegates_[0]);
|
||||
EXPECT_CALL(*runtimeAgentDelegates_[0], handleRequest(_))
|
||||
.WillOnce(Return(true))
|
||||
.RetiresOnSaturation();
|
||||
toPage_->sendMessage(R"({
|
||||
@@ -278,48 +278,48 @@ TEST_F(PageTargetTest, ConnectToAlreadyRegisteredRuntimeWithEvents) {
|
||||
})";
|
||||
EXPECT_CALL(fromPage(), onMessage(JsonEq(kFooResponse)))
|
||||
.RetiresOnSaturation();
|
||||
runtimeAgents_[0]->frontendChannel(kFooResponse);
|
||||
runtimeAgentDelegates_[0]->frontendChannel(kFooResponse);
|
||||
|
||||
instanceTarget.unregisterRuntime(runtimeTarget);
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
}
|
||||
|
||||
TEST_F(PageTargetProtocolTest, RuntimeAgentLifecycle) {
|
||||
TEST_F(PageTargetProtocolTest, RuntimeAgentDelegateLifecycle) {
|
||||
{
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
auto& runtimeTarget =
|
||||
instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
|
||||
EXPECT_TRUE(runtimeAgents_[0]);
|
||||
EXPECT_TRUE(runtimeAgentDelegates_[0]);
|
||||
|
||||
instanceTarget.unregisterRuntime(runtimeTarget);
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(runtimeAgents_[0]);
|
||||
EXPECT_FALSE(runtimeAgentDelegates_[0]);
|
||||
|
||||
{
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
auto& runtimeTarget =
|
||||
instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
|
||||
EXPECT_TRUE(runtimeAgents_[1]);
|
||||
EXPECT_TRUE(runtimeAgentDelegates_[1]);
|
||||
|
||||
instanceTarget.unregisterRuntime(runtimeTarget);
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(runtimeAgents_[1]);
|
||||
EXPECT_FALSE(runtimeAgentDelegates_[1]);
|
||||
}
|
||||
|
||||
TEST_F(PageTargetProtocolTest, MethodNotHandledByRuntimeAgent) {
|
||||
TEST_F(PageTargetProtocolTest, MethodNotHandledByRuntimeAgentDelegate) {
|
||||
InSequence s;
|
||||
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
auto& runtimeTarget = instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
|
||||
ASSERT_TRUE(runtimeAgents_[0]);
|
||||
EXPECT_CALL(*runtimeAgents_[0], handleRequest(_))
|
||||
ASSERT_TRUE(runtimeAgentDelegates_[0]);
|
||||
EXPECT_CALL(*runtimeAgentDelegates_[0], handleRequest(_))
|
||||
.WillOnce(Return(false))
|
||||
.RetiresOnSaturation();
|
||||
EXPECT_CALL(
|
||||
@@ -337,14 +337,14 @@ TEST_F(PageTargetProtocolTest, MethodNotHandledByRuntimeAgent) {
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
}
|
||||
|
||||
TEST_F(PageTargetProtocolTest, MethodHandledByRuntimeAgent) {
|
||||
TEST_F(PageTargetProtocolTest, MethodHandledByRuntimeAgentDelegate) {
|
||||
InSequence s;
|
||||
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
auto& runtimeTarget = instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
|
||||
ASSERT_TRUE(runtimeAgents_[0]);
|
||||
EXPECT_CALL(*runtimeAgents_[0], handleRequest(_))
|
||||
ASSERT_TRUE(runtimeAgentDelegates_[0]);
|
||||
EXPECT_CALL(*runtimeAgentDelegates_[0], handleRequest(_))
|
||||
.WillOnce(Return(true))
|
||||
.RetiresOnSaturation();
|
||||
toPage_->sendMessage(R"({
|
||||
@@ -363,13 +363,13 @@ TEST_F(PageTargetProtocolTest, MethodHandledByRuntimeAgent) {
|
||||
})";
|
||||
EXPECT_CALL(fromPage(), onMessage(JsonEq(kFooResponse)))
|
||||
.RetiresOnSaturation();
|
||||
runtimeAgents_[0]->frontendChannel(kFooResponse);
|
||||
runtimeAgentDelegates_[0]->frontendChannel(kFooResponse);
|
||||
|
||||
instanceTarget.unregisterRuntime(runtimeTarget);
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
}
|
||||
|
||||
TEST_F(PageTargetProtocolTest, MessageRoutingWhileNoRuntimeAgent) {
|
||||
TEST_F(PageTargetProtocolTest, MessageRoutingWhileNoRuntimeAgentDelegate) {
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(
|
||||
@@ -386,8 +386,8 @@ TEST_F(PageTargetProtocolTest, MessageRoutingWhileNoRuntimeAgent) {
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
auto& runtimeTarget = instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
|
||||
ASSERT_TRUE(runtimeAgents_[0]);
|
||||
EXPECT_CALL(*runtimeAgents_[0], handleRequest(_))
|
||||
ASSERT_TRUE(runtimeAgentDelegates_[0]);
|
||||
EXPECT_CALL(*runtimeAgentDelegates_[0], handleRequest(_))
|
||||
.WillOnce(Return(true))
|
||||
.RetiresOnSaturation();
|
||||
toPage_->sendMessage(R"({
|
||||
@@ -406,12 +406,12 @@ TEST_F(PageTargetProtocolTest, MessageRoutingWhileNoRuntimeAgent) {
|
||||
})";
|
||||
EXPECT_CALL(fromPage(), onMessage(JsonEq(kFooResponse)))
|
||||
.RetiresOnSaturation();
|
||||
runtimeAgents_[0]->frontendChannel(kFooResponse);
|
||||
runtimeAgentDelegates_[0]->frontendChannel(kFooResponse);
|
||||
|
||||
instanceTarget.unregisterRuntime(runtimeTarget);
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
|
||||
EXPECT_FALSE(runtimeAgents_[0]);
|
||||
EXPECT_FALSE(runtimeAgentDelegates_[0]);
|
||||
|
||||
EXPECT_CALL(
|
||||
fromPage(), onMessage(JsonParsed(AtJsonPtr("/error/code", Eq(-32601)))))
|
||||
@@ -425,16 +425,16 @@ TEST_F(PageTargetProtocolTest, MessageRoutingWhileNoRuntimeAgent) {
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(PageTargetProtocolTest, InstanceWithNullRuntimeAgent) {
|
||||
TEST_F(PageTargetProtocolTest, InstanceWithNullRuntimeAgentDelegate) {
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(runtimeTargetDelegate_, createAgent(_, _))
|
||||
EXPECT_CALL(runtimeTargetDelegate_, createAgentDelegate(_, _))
|
||||
.WillRepeatedly(ReturnNull());
|
||||
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
auto& runtimeTarget = instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
|
||||
EXPECT_FALSE(runtimeAgents_[0]);
|
||||
EXPECT_FALSE(runtimeAgentDelegates_[0]);
|
||||
|
||||
EXPECT_CALL(
|
||||
fromPage(), onMessage(JsonParsed(AtJsonPtr("/error/code", Eq(-32601)))))
|
||||
@@ -451,11 +451,11 @@ TEST_F(PageTargetProtocolTest, InstanceWithNullRuntimeAgent) {
|
||||
page_.unregisterInstance(instanceTarget);
|
||||
}
|
||||
|
||||
TEST_F(PageTargetProtocolTest, RuntimeAgentHasAccessToSessionState) {
|
||||
TEST_F(PageTargetProtocolTest, RuntimeAgentDelegateHasAccessToSessionState) {
|
||||
InSequence s;
|
||||
|
||||
// Send Runtime.enable before registering the Instance (which in turns creates
|
||||
// the RuntimeAgent).
|
||||
// the RuntimeAgentDelegate).
|
||||
EXPECT_CALL(fromPage(), onMessage(JsonEq(R"({
|
||||
"id": 1,
|
||||
"result": {}
|
||||
@@ -467,13 +467,13 @@ TEST_F(PageTargetProtocolTest, RuntimeAgentHasAccessToSessionState) {
|
||||
|
||||
auto& instanceTarget = page_.registerInstance(instanceTargetDelegate_);
|
||||
instanceTarget.registerRuntime(runtimeTargetDelegate_);
|
||||
ASSERT_TRUE(runtimeAgents_[0]);
|
||||
ASSERT_TRUE(runtimeAgentDelegates_[0]);
|
||||
|
||||
EXPECT_TRUE(runtimeAgents_[0]->sessionState.isRuntimeDomainEnabled);
|
||||
EXPECT_TRUE(runtimeAgentDelegates_[0]->sessionState.isRuntimeDomainEnabled);
|
||||
|
||||
// Send Runtime.disable while the RuntimeAgent exists - it receives the
|
||||
// message and can also observe the updated state.
|
||||
EXPECT_CALL(*runtimeAgents_[0], handleRequest(Eq(cdp::preparse(R"({
|
||||
// Send Runtime.disable while the RuntimeAgentDelegate exists - it receives
|
||||
// the message and can also observe the updated state.
|
||||
EXPECT_CALL(*runtimeAgentDelegates_[0], handleRequest(Eq(cdp::preparse(R"({
|
||||
"id": 2,
|
||||
"method": "Runtime.disable"
|
||||
})"))));
|
||||
@@ -486,7 +486,7 @@ TEST_F(PageTargetProtocolTest, RuntimeAgentHasAccessToSessionState) {
|
||||
"method": "Runtime.disable"
|
||||
})");
|
||||
|
||||
EXPECT_FALSE(runtimeAgents_[0]->sessionState.isRuntimeDomainEnabled);
|
||||
EXPECT_FALSE(runtimeAgentDelegates_[0]->sessionState.isRuntimeDomainEnabled);
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
|
||||
@@ -18,10 +18,11 @@ JSIRuntimeHolder::JSIRuntimeHolder(std::unique_ptr<jsi::Runtime> runtime)
|
||||
assert(runtime_ != nullptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgent> JSIRuntimeHolder::createAgent(
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
|
||||
JSIRuntimeHolder::createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) {
|
||||
return std::make_unique<jsinspector_modern::FallbackRuntimeAgent>(
|
||||
return std::make_unique<jsinspector_modern::FallbackRuntimeAgentDelegate>(
|
||||
std::move(frontendChannel), sessionState, runtime_->description());
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class JSRuntimeFactory {
|
||||
class JSIRuntimeHolder : public JSRuntime {
|
||||
public:
|
||||
jsi::Runtime& getRuntime() noexcept override;
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgent> createAgent(
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate> createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) override;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "HermesInstance.h"
|
||||
|
||||
#include <hermes/inspector-modern/chrome/HermesRuntimeAgent.h>
|
||||
#include <hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h>
|
||||
#include <jsi/jsilib.h>
|
||||
#include <jsinspector-modern/InspectorFlags.h>
|
||||
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
@@ -104,11 +104,11 @@ class HermesJSRuntime : public JSRuntime {
|
||||
return *runtime_;
|
||||
}
|
||||
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgent> createAgent(
|
||||
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate> createAgentDelegate(
|
||||
jsinspector_modern::FrontendChannel frontendChannel,
|
||||
jsinspector_modern::SessionState& sessionState) override {
|
||||
return std::unique_ptr<jsinspector_modern::RuntimeAgent>(
|
||||
new jsinspector_modern::HermesRuntimeAgent(
|
||||
return std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>(
|
||||
new jsinspector_modern::HermesRuntimeAgentDelegate(
|
||||
frontendChannel,
|
||||
sessionState,
|
||||
runtime_,
|
||||
|
||||
Reference in New Issue
Block a user