forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create HermesRuntimeAgent (facebook#42747)
Summary: Changelog: [Internal] Implements a `RuntimeAgent` (D51231326) for Hermes for the modern CDP backend, based on the `CDPHandler` API that Hermes exposes currently. ## A note on `console` We unfortunately have to disable `console` interception (D51234334 / equivalently D52971652) because `CDPHandler`'s current implementation is not aligned with the Agent concept: * Agents are only created once a session has started, but the `console` interceptor needs to be injected at VM startup. * Agents should not clobber each other's shared state (nor consume excessive resources per Agent), but each `CDPHandler` would install its own independent `console` interceptor if enabled. We will enable CDP `console` support in the modern backend in future work. This will require either some additional plumbing in RN (e.g. to safely access JSI from an Agent/Target) or some additional work in Hermes. ## Conditional compilation based on `HERMES_ENABLE_DEBUGGER` `HermesRuntimeAgent.cpp` compiles both with and without `-DHERMES_ENABLE_DEBUGGER`, which is the flag Hermes uses to control the availability of `CDPHandler` (and its containing Buck library). If the debugger is not enabled, `HermesRuntimeAgent` reduces to a `FallbackRuntimeAgent`. In either case, no Hermes debugger headers leak into `HermesRuntimeAgent.h`, so callers don't need to check `#ifdef HERMES_ENABLE_DEBUGGER`, and the overall CDP backend infra is not gated on whether the Hermes debugger is compiled in. Reviewed By: huntie Differential Revision: D51234333
- Loading branch information
1 parent
12155c4
commit d6554c6
Showing
11 changed files
with
336 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,4 +33,5 @@ target_link_libraries(hermes_inspector_modern | |
fb | ||
glog | ||
hermes-engine::libhermes | ||
jsi) | ||
jsi | ||
runtimeexecutor) |
169 changes: 169 additions & 0 deletions
169
packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgent.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
#include "HermesRuntimeAgent.h" | ||
|
||
// If HERMES_ENABLE_DEBUGGER isn't defined, we can't access any Hermes | ||
// CDPHandler headers or types. | ||
|
||
#ifdef HERMES_ENABLE_DEBUGGER | ||
#include <hermes/inspector/RuntimeAdapter.h> | ||
#include <hermes/inspector/chrome/CDPHandler.h> | ||
#else // HERMES_ENABLE_DEBUGGER | ||
#include <jsinspector-modern/FallbackRuntimeAgent.h> | ||
#endif // HERMES_ENABLE_DEBUGGER | ||
|
||
#include <hermes/hermes.h> | ||
#include <jsinspector-modern/ReactCdp.h> | ||
|
||
using namespace facebook::hermes; | ||
|
||
namespace facebook::react::jsinspector_modern { | ||
|
||
#ifdef HERMES_ENABLE_DEBUGGER | ||
|
||
namespace { | ||
|
||
/** | ||
* An implementation of the Hermes RuntimeAdapter interface (part of | ||
* Hermes's CDPHandler API) for use within a React Native RuntimeAgent. | ||
*/ | ||
class HermesRuntimeAgentAdapter | ||
: public hermes::inspector_modern::RuntimeAdapter { | ||
public: | ||
HermesRuntimeAgentAdapter( | ||
std::shared_ptr<hermes::HermesRuntime> runtime, | ||
RuntimeExecutor runtimeExecutor) | ||
: runtime_(runtime), runtimeExecutor_(runtimeExecutor) {} | ||
|
||
HermesRuntime& getRuntime() override { | ||
return *runtime_; | ||
} | ||
|
||
void tickleJs() override { | ||
runtimeExecutor_([](jsi::Runtime& runtime) { | ||
jsi::Function func = | ||
runtime.global().getPropertyAsFunction(runtime, "__tickleJs"); | ||
func.call(runtime); | ||
}); | ||
} | ||
|
||
private: | ||
std::shared_ptr<hermes::HermesRuntime> runtime_; | ||
RuntimeExecutor runtimeExecutor_; | ||
}; | ||
|
||
} // namespace | ||
|
||
/** | ||
* A RuntimeAgent that handles requests from the Chrome DevTools Protocol for | ||
* an instance of Hermes. | ||
*/ | ||
class HermesRuntimeAgent::Impl final : public RuntimeAgent { | ||
using HermesCDPHandler = hermes::inspector_modern::chrome::CDPHandler; | ||
|
||
public: | ||
/** | ||
* \param frontendChannel A channel used to send responses and events to the | ||
* frontend. | ||
* \param sessionState The state of the current CDP session. This will only | ||
* be accessed on the main thread (during the constructor, in handleRequest, | ||
* etc). | ||
* \param runtime The HermesRuntime that this agent is attached to. | ||
* \param runtimeExecutor A callback for scheduling work on the JS thread. | ||
* \c runtimeExecutor may drop scheduled work if the runtime is destroyed | ||
* first. | ||
*/ | ||
Impl( | ||
FrontendChannel frontendChannel, | ||
SessionState& sessionState, | ||
std::shared_ptr<hermes::HermesRuntime> runtime, | ||
RuntimeExecutor runtimeExecutor) | ||
: hermes_(HermesCDPHandler::create( | ||
std::make_unique<HermesRuntimeAgentAdapter>( | ||
runtime, | ||
runtimeExecutor), | ||
/* waitForDebugger */ false, | ||
/* enableConsoleAPICapturing */ false, | ||
/* state */ nullptr, | ||
{.isRuntimeDomainEnabled = sessionState.isRuntimeDomainEnabled})) { | ||
hermes_->registerCallbacks( | ||
/* msgCallback */ | ||
[frontendChannel = | ||
std::move(frontendChannel)](const std::string& messageFromHermes) { | ||
frontendChannel(messageFromHermes); | ||
; | ||
}, | ||
/* onUnregister */ | ||
[]() {}); | ||
} | ||
|
||
/** | ||
* Handle a CDP request. The response will be sent over the provided | ||
* \c FrontendChannel synchronously or asynchronously. | ||
* \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. | ||
*/ | ||
bool handleRequest(const cdp::PreparsedRequest& req) override { | ||
// TODO: Change to string::starts_with when we're on C++20. | ||
if (req.method.rfind("Log.", 0) == 0) { | ||
// Since we know Hermes doesn't do anything useful with Log messages, but | ||
// our containing PageAgent will, just bail out early. | ||
// TODO: We need a way to negotiate this more dynamically with Hermes | ||
// through the API. | ||
return false; | ||
} | ||
// Forward everything else to Hermes's CDPHandler. | ||
hermes_->handle(req.toJson()); | ||
// Let the call know that this request is handled (i.e. it is Hermes's | ||
// responsibility to respond with either success or an error). | ||
return true; | ||
} | ||
|
||
private: | ||
std::shared_ptr<HermesCDPHandler> hermes_; | ||
}; | ||
|
||
#else // !HERMES_ENABLE_DEBUGGER | ||
|
||
/** | ||
* A stub for HermesRuntimeAgent when Hermes is compiled without debugging | ||
* support. | ||
*/ | ||
class HermesRuntimeAgent::Impl final : public FallbackRuntimeAgent { | ||
public: | ||
Impl( | ||
FrontendChannel frontendChannel, | ||
SessionState& sessionState, | ||
std::shared_ptr<hermes::HermesRuntime> runtime, | ||
RuntimeExecutor) | ||
: FallbackRuntimeAgent( | ||
std::move(frontendChannel), | ||
sessionState, | ||
runtime->description()) {} | ||
}; | ||
|
||
#endif // HERMES_ENABLE_DEBUGGER | ||
|
||
HermesRuntimeAgent::HermesRuntimeAgent( | ||
FrontendChannel frontendChannel, | ||
SessionState& sessionState, | ||
std::shared_ptr<hermes::HermesRuntime> runtime, | ||
RuntimeExecutor runtimeExecutor) | ||
: impl_(std::make_unique<Impl>( | ||
std::move(frontendChannel), | ||
sessionState, | ||
std::move(runtime), | ||
std::move(runtimeExecutor))) {} | ||
|
||
bool HermesRuntimeAgent::handleRequest(const cdp::PreparsedRequest& req) { | ||
return impl_->handleRequest(req); | ||
} | ||
|
||
} // namespace facebook::react::jsinspector_modern |
58 changes: 58 additions & 0 deletions
58
packages/react-native/ReactCommon/hermes/inspector-modern/chrome/HermesRuntimeAgent.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* 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 <ReactCommon/RuntimeExecutor.h> | ||
|
||
#include <hermes/hermes.h> | ||
#include <jsinspector-modern/ReactCdp.h> | ||
|
||
namespace facebook::react::jsinspector_modern { | ||
|
||
/** | ||
* A RuntimeAgent that handles requests from the Chrome DevTools Protocol for | ||
* an instance of Hermes. | ||
*/ | ||
class HermesRuntimeAgent : public RuntimeAgent { | ||
public: | ||
/** | ||
* \param frontendChannel A channel used to send responses and events to the | ||
* frontend. | ||
* \param sessionState The state of the current CDP session. This will only | ||
* be accessed on the main thread (during the constructor, in handleRequest, | ||
* etc). | ||
* \param runtime The HermesRuntime that this agent is attached to. | ||
* \param runtimeExecutor A callback for scheduling work on the JS thread. | ||
* \c runtimeExecutor may drop scheduled work if the runtime is destroyed | ||
* first. | ||
*/ | ||
HermesRuntimeAgent( | ||
FrontendChannel frontendChannel, | ||
SessionState& sessionState, | ||
std::shared_ptr<hermes::HermesRuntime> runtime, | ||
RuntimeExecutor runtimeExecutor); | ||
|
||
/** | ||
* Handle a CDP request. The response will be sent over the provided | ||
* \c FrontendChannel synchronously or asynchronously. | ||
* \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. | ||
*/ | ||
bool handleRequest(const cdp::PreparsedRequest& req) override; | ||
|
||
private: | ||
// We use the private implementation idiom to keep HERMES_ENABLE_DEBUGGER | ||
// checks out of the header. | ||
class Impl; | ||
|
||
const std::unique_ptr<Impl> impl_; | ||
}; | ||
|
||
} // namespace facebook::react::jsinspector_modern |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.