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:
Moti Zilberman
2024-02-14 04:19:35 -08:00
committed by Facebook GitHub Bot
parent b97f3e779a
commit 04eadf6a6c
24 changed files with 207 additions and 105 deletions
@@ -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;
@@ -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);
}
@@ -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.
@@ -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",
@@ -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_,