Skip to content

Commit e32307e

Browse files
lavenzgmeta-codesync[bot]
authored andcommitted
Revert deletion of old Hermes CDPHandler (facebook#54078)
Summary: Pull Request resolved: facebook#54078 Changelog: [General][Fixed] 6e1c0a removed old Hermes CDPHandler, which is a breaking change, revert here. Reviewed By: cipolleschi Differential Revision: D84076229 fbshipit-source-id: 7ac426178754d6320c1803a50d57afa10e3126e5
1 parent 31bff4e commit e32307e

File tree

8 files changed

+465
-1
lines changed

8 files changed

+465
-1
lines changed

packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,55 @@
1515

1616
#include <hermes/inspector-modern/chrome/HermesRuntimeTargetDelegate.h>
1717

18+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
19+
#include <hermes/inspector-modern/chrome/Registration.h>
20+
#include <hermes/inspector/RuntimeAdapter.h>
21+
#endif
22+
1823
using namespace facebook::hermes;
1924
using namespace facebook::jsi;
2025

2126
namespace facebook::react {
2227

2328
namespace {
2429

30+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
31+
32+
class HermesExecutorRuntimeAdapter
33+
: public facebook::hermes::inspector_modern::RuntimeAdapter {
34+
public:
35+
HermesExecutorRuntimeAdapter(
36+
std::shared_ptr<HermesRuntime> runtime,
37+
std::shared_ptr<MessageQueueThread> thread)
38+
: runtime_(runtime), thread_(std::move(thread)) {}
39+
40+
virtual ~HermesExecutorRuntimeAdapter() = default;
41+
42+
HermesRuntime& getRuntime() override {
43+
return *runtime_;
44+
}
45+
46+
void tickleJs() override {
47+
thread_->runOnQueue(
48+
[weakRuntime = std::weak_ptr<HermesRuntime>(runtime_)]() {
49+
auto runtime = weakRuntime.lock();
50+
if (!runtime) {
51+
return;
52+
}
53+
jsi::Function func =
54+
runtime->global().getPropertyAsFunction(*runtime, "__tickleJs");
55+
func.call(*runtime);
56+
});
57+
}
58+
59+
private:
60+
std::shared_ptr<HermesRuntime> runtime_;
61+
62+
std::shared_ptr<MessageQueueThread> thread_;
63+
};
64+
65+
#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
66+
2567
struct ReentrancyCheck {
2668
// This is effectively a very subtle and complex assert, so only
2769
// include it in builds which would include asserts.
@@ -105,17 +147,42 @@ class DecoratedRuntime : public jsi::WithRuntimeDecorator<ReentrancyCheck> {
105147
const std::string& debuggerName)
106148
: jsi::WithRuntimeDecorator<ReentrancyCheck>(*runtime, reentrancyCheck_),
107149
runtime_(std::move(runtime)) {
150+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
151+
enableDebugger_ = enableDebugger;
152+
if (enableDebugger_) {
153+
std::shared_ptr<HermesRuntime> rt(runtime_, &hermesRuntime);
154+
auto adapter =
155+
std::make_unique<HermesExecutorRuntimeAdapter>(rt, jsQueue);
156+
debugToken_ = facebook::hermes::inspector_modern::chrome::enableDebugging(
157+
std::move(adapter), debuggerName);
158+
}
159+
#else
108160
(void)jsQueue;
161+
#endif // HERMES_ENABLE_DEBUGGER
109162
}
110163

111-
~DecoratedRuntime() {}
164+
~DecoratedRuntime() {
165+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
166+
if (enableDebugger_) {
167+
facebook::hermes::inspector_modern::chrome::disableDebugging(debugToken_);
168+
}
169+
#endif // HERMES_ENABLE_DEBUGGER
170+
}
112171

113172
private:
114173
// runtime_ is a potentially decorated Runtime.
115174
// hermesRuntime is a reference to a HermesRuntime managed by runtime_.
175+
//
176+
// HermesExecutorRuntimeAdapter requirements are kept, because the
177+
// dtor will disable debugging on the HermesRuntime before the
178+
// member managing it is destroyed.
116179

117180
std::shared_ptr<Runtime> runtime_;
118181
ReentrancyCheck reentrancyCheck_;
182+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
183+
bool enableDebugger_;
184+
facebook::hermes::inspector_modern::chrome::DebugSessionToken debugToken_;
185+
#endif // HERMES_ENABLE_DEBUGGER
119186
};
120187

121188
} // namespace
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "ConnectionDemux.h"
9+
10+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
11+
12+
#include <hermes/inspector/RuntimeAdapter.h>
13+
#include <hermes/inspector/chrome/CDPHandler.h>
14+
15+
#include <jsinspector-modern/InspectorInterfaces.h>
16+
17+
#include <utility>
18+
19+
namespace facebook::hermes::inspector_modern::chrome {
20+
21+
using ::facebook::react::jsinspector_modern::ILocalConnection;
22+
using ::facebook::react::jsinspector_modern::IRemoteConnection;
23+
24+
namespace {
25+
26+
class LocalConnection : public ILocalConnection {
27+
public:
28+
LocalConnection(
29+
std::shared_ptr<hermes::inspector_modern::chrome::CDPHandler> conn,
30+
std::shared_ptr<std::unordered_set<std::string>> inspectedContexts);
31+
~LocalConnection() override;
32+
33+
void sendMessage(std::string message) override;
34+
void disconnect() override;
35+
36+
private:
37+
std::shared_ptr<hermes::inspector_modern::chrome::CDPHandler> conn_;
38+
std::shared_ptr<std::unordered_set<std::string>> inspectedContexts_;
39+
};
40+
41+
LocalConnection::LocalConnection(
42+
std::shared_ptr<hermes::inspector_modern::chrome::CDPHandler> conn,
43+
std::shared_ptr<std::unordered_set<std::string>> inspectedContexts)
44+
: conn_(conn), inspectedContexts_(std::move(inspectedContexts)) {
45+
inspectedContexts_->insert(conn->getTitle());
46+
}
47+
48+
LocalConnection::~LocalConnection() = default;
49+
50+
void LocalConnection::sendMessage(std::string message) {
51+
conn_->handle(std::move(message));
52+
}
53+
54+
void LocalConnection::disconnect() {
55+
inspectedContexts_->erase(conn_->getTitle());
56+
conn_->unregisterCallbacks();
57+
}
58+
59+
} // namespace
60+
61+
ConnectionDemux::ConnectionDemux(
62+
facebook::react::jsinspector_modern::IInspector& inspector)
63+
: globalInspector_(inspector),
64+
inspectedContexts_(std::make_shared<std::unordered_set<std::string>>()) {}
65+
66+
ConnectionDemux::~ConnectionDemux() = default;
67+
68+
DebugSessionToken ConnectionDemux::enableDebugging(
69+
std::unique_ptr<RuntimeAdapter> adapter,
70+
const std::string& title) {
71+
std::scoped_lock lock(mutex_);
72+
73+
// TODO(#22976087): workaround for ComponentScript contexts never being
74+
// destroyed.
75+
//
76+
// After a reload, the old ComponentScript VM instance stays alive. When we
77+
// register the new CS VM instance, check for any previous CS VM (via strcmp
78+
// of title) and remove them.
79+
std::vector<int> pagesToDelete;
80+
for (auto& conn : conns_) {
81+
if (conn.second->getTitle() == title) {
82+
pagesToDelete.push_back(conn.first);
83+
}
84+
}
85+
86+
for (auto pageId : pagesToDelete) {
87+
removePage(pageId);
88+
}
89+
90+
auto waitForDebugger =
91+
(inspectedContexts_->find(title) != inspectedContexts_->end());
92+
return addPage(hermes::inspector_modern::chrome::CDPHandler::create(
93+
std::move(adapter), title, waitForDebugger));
94+
}
95+
96+
void ConnectionDemux::disableDebugging(DebugSessionToken session) {
97+
std::scoped_lock lock(mutex_);
98+
if (conns_.find(session) == conns_.end()) {
99+
return;
100+
}
101+
removePage(session);
102+
}
103+
104+
int ConnectionDemux::addPage(
105+
std::shared_ptr<hermes::inspector_modern::chrome::CDPHandler> conn) {
106+
auto connectFunc = [conn, this](std::unique_ptr<IRemoteConnection> remoteConn)
107+
-> std::unique_ptr<ILocalConnection> {
108+
// This cannot be unique_ptr as std::function is copyable but unique_ptr
109+
// isn't. TODO: Change the CDPHandler API to accommodate this and not
110+
// require a copyable callback?
111+
std::shared_ptr<IRemoteConnection> sharedConn = std::move(remoteConn);
112+
if (!conn->registerCallbacks(
113+
[sharedConn](const std::string& message) {
114+
sharedConn->onMessage(message);
115+
},
116+
[sharedConn]() { sharedConn->onDisconnect(); })) {
117+
return nullptr;
118+
}
119+
120+
return std::make_unique<LocalConnection>(conn, inspectedContexts_);
121+
};
122+
123+
int pageId = globalInspector_.addPage(
124+
conn->getTitle(), "Hermes", std::move(connectFunc));
125+
conns_[pageId] = std::move(conn);
126+
127+
return pageId;
128+
}
129+
130+
void ConnectionDemux::removePage(int pageId) {
131+
globalInspector_.removePage(pageId);
132+
133+
auto conn = conns_.at(pageId);
134+
std::string title = conn->getTitle();
135+
inspectedContexts_->erase(title);
136+
conn->unregisterCallbacks();
137+
conns_.erase(pageId);
138+
}
139+
140+
} // namespace facebook::hermes::inspector_modern::chrome
141+
142+
#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
11+
12+
#include <memory>
13+
#include <mutex>
14+
#include <string>
15+
#include <unordered_map>
16+
#include <unordered_set>
17+
18+
#include <hermes/hermes.h>
19+
#include <hermes/inspector-modern/chrome/Registration.h>
20+
#include <hermes/inspector/RuntimeAdapter.h>
21+
#include <hermes/inspector/chrome/CDPHandler.h>
22+
#include <jsinspector-modern/InspectorInterfaces.h>
23+
24+
namespace facebook::hermes::inspector_modern::chrome {
25+
26+
/*
27+
* ConnectionDemux keeps track of all debuggable Hermes runtimes (called
28+
* "pages" in the higher-level React Native API) in this process. See
29+
* Registration.h for documentation of the public API.
30+
*/
31+
class ConnectionDemux {
32+
public:
33+
explicit ConnectionDemux(
34+
facebook::react::jsinspector_modern::IInspector& inspector);
35+
~ConnectionDemux();
36+
37+
ConnectionDemux(const ConnectionDemux&) = delete;
38+
ConnectionDemux& operator=(const ConnectionDemux&) = delete;
39+
40+
DebugSessionToken enableDebugging(
41+
std::unique_ptr<RuntimeAdapter> adapter,
42+
const std::string& title);
43+
void disableDebugging(DebugSessionToken session);
44+
45+
private:
46+
int addPage(
47+
std::shared_ptr<hermes::inspector_modern::chrome::CDPHandler> conn);
48+
void removePage(int pageId);
49+
50+
facebook::react::jsinspector_modern::IInspector& globalInspector_;
51+
52+
std::mutex mutex_;
53+
std::unordered_map<
54+
int,
55+
std::shared_ptr<hermes::inspector_modern::chrome::CDPHandler>>
56+
conns_;
57+
std::shared_ptr<std::unordered_set<std::string>> inspectedContexts_;
58+
};
59+
60+
} // namespace facebook::hermes::inspector_modern::chrome
61+
62+
#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "Registration.h"
9+
#include "ConnectionDemux.h"
10+
11+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
12+
13+
namespace facebook::hermes::inspector_modern::chrome {
14+
15+
namespace {
16+
17+
ConnectionDemux& demux() {
18+
static ConnectionDemux instance{
19+
facebook::react::jsinspector_modern::getInspectorInstance()};
20+
return instance;
21+
}
22+
23+
} // namespace
24+
25+
DebugSessionToken enableDebugging(
26+
std::unique_ptr<RuntimeAdapter> adapter,
27+
const std::string& title) {
28+
return demux().enableDebugging(std::move(adapter), title);
29+
}
30+
31+
void disableDebugging(DebugSessionToken session) {
32+
demux().disableDebugging(session);
33+
}
34+
35+
} // namespace facebook::hermes::inspector_modern::chrome
36+
37+
#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#if defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)
11+
12+
#include <memory>
13+
#include <string>
14+
15+
#include <hermes/hermes.h>
16+
#include <hermes/inspector/RuntimeAdapter.h>
17+
18+
namespace facebook::hermes::inspector_modern::chrome {
19+
20+
using DebugSessionToken = int;
21+
22+
/*
23+
* enableDebugging adds this runtime to the list of debuggable JS targets
24+
* (called "pages" in the higher-level React Native API) in this process. It
25+
* should be called before any JS runs in the runtime. The returned token
26+
* can be used to disable debugging for this runtime.
27+
*/
28+
extern DebugSessionToken enableDebugging(
29+
std::unique_ptr<RuntimeAdapter> adapter,
30+
const std::string& title);
31+
32+
/*
33+
* disableDebugging removes this runtime from the list of debuggable JS targets
34+
* in this process. The runtime to remove is identified by the token returned
35+
* from enableDebugging.
36+
*/
37+
extern void disableDebugging(DebugSessionToken session);
38+
39+
} // namespace facebook::hermes::inspector_modern::chrome
40+
41+
#endif // defined(HERMES_ENABLE_DEBUGGER) && !defined(HERMES_V1_ENABLED)

0 commit comments

Comments
 (0)