diff --git a/packages/react-native/React/Inspector/RCTInspector.mm b/packages/react-native/React/Inspector/RCTInspector.mm index 896cf4ec8ea..0c47f6da779 100644 --- a/packages/react-native/React/Inspector/RCTInspector.mm +++ b/packages/react-native/React/Inspector/RCTInspector.mm @@ -9,7 +9,7 @@ #if RCT_DEV || RCT_REMOTE_PROFILE -#include +#include #import #import @@ -17,6 +17,7 @@ #import using namespace facebook::react; +using namespace facebook::react::jsinspector_modern; // This is a port of the Android impl, at // react-native-github/ReactAndroid/src/main/java/com/facebook/react/bridge/Inspector.java @@ -57,7 +58,7 @@ class RemoteConnection : public IRemoteConnection { static IInspector *getInstance() { - return &facebook::react::getInspectorInstance(); + return &facebook::react::jsinspector_modern::getInspectorInstance(); } @implementation RCTInspector diff --git a/packages/react-native/ReactAndroid/build.gradle b/packages/react-native/ReactAndroid/build.gradle index 7adfa7ebaea..39555f48e59 100644 --- a/packages/react-native/ReactAndroid/build.gradle +++ b/packages/react-native/ReactAndroid/build.gradle @@ -246,7 +246,7 @@ final def preparePrefab = tasks.register("preparePrefab", PreparePrefabHeadersTa ), new PrefabPreprocessingEntry( "jsinspector", - new Pair("../ReactCommon/jsinspector/", "jsinspector/"), + new Pair("../ReactCommon/jsinspector-modern/", "jsinspector-modern/"), ), ] ) diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index 6da7a5d592c..f0f408ee44b 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -66,7 +66,7 @@ add_react_common_subdir(jsc) add_react_common_subdir(jsi) add_react_common_subdir(butter) add_react_common_subdir(callinvoker) -add_react_common_subdir(jsinspector) +add_react_common_subdir(jsinspector-modern) add_react_common_subdir(hermes/executor) add_react_common_subdir(hermes/inspector-modern) add_react_common_subdir(react/renderer/runtimescheduler) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp index cd4400b22c1..d1e7a61c150 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.cpp @@ -15,7 +15,7 @@ namespace facebook::react { namespace { -class RemoteConnection : public IRemoteConnection { +class RemoteConnection : public jsinspector_modern::IRemoteConnection { public: RemoteConnection(jni::alias_ref connection) : connection_(jni::make_global(connection)) {} @@ -56,7 +56,8 @@ void JRemoteConnection::onDisconnect() const { method(self()); } -JLocalConnection::JLocalConnection(std::unique_ptr connection) +JLocalConnection::JLocalConnection( + std::unique_ptr connection) : connection_(std::move(connection)) {} void JLocalConnection::sendMessage(std::string message) { @@ -76,13 +77,13 @@ void JLocalConnection::registerNatives() { jni::global_ref JInspector::instance( jni::alias_ref) { - static auto instance = - jni::make_global(newObjectCxxArgs(&getInspectorInstance())); + static auto instance = jni::make_global( + newObjectCxxArgs(&jsinspector_modern::getInspectorInstance())); return instance; } jni::local_ref> JInspector::getPages() { - std::vector pages = inspector_->getPages(); + std::vector pages = inspector_->getPages(); auto array = jni::JArrayClass::newArray(pages.size()); for (size_t i = 0; i < pages.size(); i++) { (*array)[i] = JPage::create(pages[i].id, pages[i].title, pages[i].vm); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h index 221e012d603..982f2af655c 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/JInspector.h @@ -9,7 +9,7 @@ #ifdef WITH_INSPECTOR -#include +#include #include @@ -40,7 +40,8 @@ class JLocalConnection : public jni::HybridClass { static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/Inspector$LocalConnection;"; - JLocalConnection(std::unique_ptr connection); + JLocalConnection( + std::unique_ptr connection); void sendMessage(std::string message); void disconnect(); @@ -48,7 +49,7 @@ class JLocalConnection : public jni::HybridClass { static void registerNatives(); private: - std::unique_ptr connection_; + std::unique_ptr connection_; }; class JInspector : public jni::HybridClass { @@ -69,9 +70,10 @@ class JInspector : public jni::HybridClass { private: friend HybridBase; - JInspector(IInspector* inspector) : inspector_(inspector) {} + JInspector(jsinspector_modern::IInspector* inspector) + : inspector_(inspector) {} - IInspector* inspector_; + jsinspector_modern::IInspector* inspector_; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.cpp index 52c7667b539..9bc07895e3b 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.cpp +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.cpp @@ -30,8 +30,8 @@ namespace hermes { namespace inspector_modern { namespace chrome { -using ::facebook::react::ILocalConnection; -using ::facebook::react::IRemoteConnection; +using ::facebook::react::jsinspector_modern::ILocalConnection; +using ::facebook::react::jsinspector_modern::IRemoteConnection; using ::folly::Unit; namespace debugger = ::facebook::hermes::debugger; diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.h b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.h index 809eb9def4d..0718ede70cf 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.h +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Connection.h @@ -16,7 +16,7 @@ #include #include -#include +#include namespace facebook { namespace hermes { @@ -45,7 +45,8 @@ class INSPECTOR_EXPORT Connection { /// the debugger sent via send(). Replies and notifications from the debugger /// are sent back to the client via IRemoteConnection::onMessage. bool connect( - std::unique_ptr<::facebook::react::IRemoteConnection> remoteConn); + std::unique_ptr<::facebook::react::jsinspector_modern::IRemoteConnection> + remoteConn); /// disconnect disconnects this connection from the runtime's debugger bool disconnect(); diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp index 70012de777d..8a7dabf3e15 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.cpp @@ -8,16 +8,16 @@ #include "ConnectionDemux.h" #include "Connection.h" -#include +#include namespace facebook { namespace hermes { namespace inspector_modern { namespace chrome { -using ::facebook::react::IInspector; -using ::facebook::react::ILocalConnection; -using ::facebook::react::IRemoteConnection; +using ::facebook::react::jsinspector_modern::IInspector; +using ::facebook::react::jsinspector_modern::ILocalConnection; +using ::facebook::react::jsinspector_modern::IRemoteConnection; namespace { @@ -56,7 +56,8 @@ void LocalConnection::disconnect() { } // namespace -ConnectionDemux::ConnectionDemux(facebook::react::IInspector &inspector) +ConnectionDemux::ConnectionDemux( + facebook::react::jsinspector_modern::IInspector &inspector) : globalInspector_(inspector), inspectedContexts_(std::make_shared>()) {} diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h index cff2f5e5e68..8f30c685a45 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/ConnectionDemux.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include namespace facebook { namespace hermes { @@ -31,7 +31,8 @@ namespace chrome { */ class ConnectionDemux { public: - explicit ConnectionDemux(facebook::react::IInspector &inspector); + explicit ConnectionDemux( + facebook::react::jsinspector_modern::IInspector &inspector); ~ConnectionDemux(); ConnectionDemux(const ConnectionDemux &) = delete; @@ -46,7 +47,7 @@ class ConnectionDemux { int addPage(std::shared_ptr conn); void removePage(int pageId); - facebook::react::IInspector &globalInspector_; + facebook::react::jsinspector_modern::IInspector &globalInspector_; std::mutex mutex_; std::unordered_map> conns_; diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp index ab00c02c34b..3a8c99153ef 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/Registration.cpp @@ -16,7 +16,8 @@ namespace chrome { namespace { ConnectionDemux &demux() { - static ConnectionDemux instance{facebook::react::getInspectorInstance()}; + static ConnectionDemux instance{ + facebook::react::jsinspector_modern::getInspectorInstance()}; return instance; } diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp index 26a19c118f3..f60e9bd5fb0 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/ConnectionDemuxTests.cpp @@ -15,16 +15,16 @@ #include #include #include -#include +#include namespace facebook { namespace hermes { namespace inspector_modern { namespace chrome { -using ::facebook::react::IInspector; -using ::facebook::react::InspectorPage; -using ::facebook::react::IRemoteConnection; +using ::facebook::react::jsinspector_modern::IInspector; +using ::facebook::react::jsinspector_modern::InspectorPage; +using ::facebook::react::jsinspector_modern::IRemoteConnection; namespace { @@ -93,7 +93,8 @@ TEST(ConnectionDemuxTests, TestEnableDisable) { facebook::hermes::makeHermesRuntime()); std::shared_ptr runtime2( facebook::hermes::makeHermesRuntime()); - auto inspector = facebook::react::makeTestInspectorInstance(); + auto inspector = + facebook::react::jsinspector_modern::makeTestInspectorInstance(); ConnectionDemux demux{*inspector}; diff --git a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/SyncConnection.cpp b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/SyncConnection.cpp index c6c113ec7ee..c990aa3f904 100644 --- a/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/SyncConnection.cpp +++ b/packages/react-native/ReactCommon/hermes/inspector-modern/chrome/tests/SyncConnection.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace facebook { namespace hermes { @@ -21,7 +21,7 @@ namespace inspector_modern { namespace chrome { using namespace std::placeholders; -using ::facebook::react::IRemoteConnection; +using ::facebook::react::jsinspector_modern::IRemoteConnection; namespace { diff --git a/packages/react-native/ReactCommon/jsinspector-modern/.clang-tidy b/packages/react-native/ReactCommon/jsinspector-modern/.clang-tidy new file mode 100644 index 00000000000..9f33ef5a06d --- /dev/null +++ b/packages/react-native/ReactCommon/jsinspector-modern/.clang-tidy @@ -0,0 +1,6 @@ +--- +Checks: '> +clang-diagnostic-*, +' +InheritParentConfig: true +... diff --git a/packages/react-native/ReactCommon/jsinspector/CMakeLists.txt b/packages/react-native/ReactCommon/jsinspector-modern/CMakeLists.txt similarity index 100% rename from packages/react-native/ReactCommon/jsinspector/CMakeLists.txt rename to packages/react-native/ReactCommon/jsinspector-modern/CMakeLists.txt diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp new file mode 100644 index 00000000000..ba054f9fa50 --- /dev/null +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.cpp @@ -0,0 +1,106 @@ +/* + * 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 "InspectorInterfaces.h" + +#include +#include +#include + +namespace facebook::react::jsinspector_modern { + +// pure destructors in C++ are odd. You would think they don't want an +// implementation, but in fact the linker requires one. Define them to be +// empty so that people don't count on them for any particular behaviour. +IDestructible::~IDestructible() {} +ILocalConnection::~ILocalConnection() {} +IRemoteConnection::~IRemoteConnection() {} +IInspector::~IInspector() {} + +namespace { + +class InspectorImpl : public IInspector { + public: + int addPage( + const std::string& title, + const std::string& vm, + ConnectFunc connectFunc) override; + void removePage(int pageId) override; + + std::vector getPages() const override; + std::unique_ptr connect( + int pageId, + std::unique_ptr remote) override; + + private: + mutable std::mutex mutex_; + int nextPageId_{1}; + std::unordered_map> titles_; + std::unordered_map connectFuncs_; +}; + +int InspectorImpl::addPage( + const std::string& title, + const std::string& vm, + ConnectFunc connectFunc) { + std::scoped_lock lock(mutex_); + + int pageId = nextPageId_++; + titles_[pageId] = std::make_tuple(title, vm); + connectFuncs_[pageId] = std::move(connectFunc); + + return pageId; +} + +void InspectorImpl::removePage(int pageId) { + std::scoped_lock lock(mutex_); + + titles_.erase(pageId); + connectFuncs_.erase(pageId); +} + +std::vector InspectorImpl::getPages() const { + std::scoped_lock lock(mutex_); + + std::vector inspectorPages; + for (auto& it : titles_) { + inspectorPages.push_back(InspectorPage{ + it.first, std::get<0>(it.second), std::get<1>(it.second)}); + } + + return inspectorPages; +} + +std::unique_ptr InspectorImpl::connect( + int pageId, + std::unique_ptr remote) { + IInspector::ConnectFunc connectFunc; + + { + std::scoped_lock lock(mutex_); + + auto it = connectFuncs_.find(pageId); + if (it != connectFuncs_.end()) { + connectFunc = it->second; + } + } + + return connectFunc ? connectFunc(std::move(remote)) : nullptr; +} + +} // namespace + +IInspector& getInspectorInstance() { + static InspectorImpl instance; + return instance; +} + +std::unique_ptr makeTestInspectorInstance() { + return std::make_unique(); +} + +} // namespace facebook::react::jsinspector_modern diff --git a/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h new file mode 100644 index 00000000000..3bd91918bb9 --- /dev/null +++ b/packages/react-native/ReactCommon/jsinspector-modern/InspectorInterfaces.h @@ -0,0 +1,92 @@ +/* + * 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 +#include +#include +#include + +#ifndef JSINSPECTOR_EXPORT +#ifdef _MSC_VER +#ifdef CREATE_SHARED_LIBRARY +#define JSINSPECTOR_EXPORT __declspec(dllexport) +#else +#define JSINSPECTOR_EXPORT +#endif // CREATE_SHARED_LIBRARY +#else // _MSC_VER +#define JSINSPECTOR_EXPORT __attribute__((visibility("default"))) +#endif // _MSC_VER +#endif // !defined(JSINSPECTOR_EXPORT) + +namespace facebook::react::jsinspector_modern { + +class IDestructible { + public: + virtual ~IDestructible() = 0; +}; + +struct InspectorPage { + const int id; + const std::string title; + const std::string vm; +}; + +/// IRemoteConnection allows the VM to send debugger messages to the client. +class JSINSPECTOR_EXPORT IRemoteConnection : public IDestructible { + public: + virtual ~IRemoteConnection() = 0; + virtual void onMessage(std::string message) = 0; + virtual void onDisconnect() = 0; +}; + +/// ILocalConnection allows the client to send debugger messages to the VM. +class JSINSPECTOR_EXPORT ILocalConnection : public IDestructible { + public: + virtual ~ILocalConnection() = 0; + virtual void sendMessage(std::string message) = 0; + virtual void disconnect() = 0; +}; + +/// IInspector tracks debuggable JavaScript targets (pages). +class JSINSPECTOR_EXPORT IInspector : public IDestructible { + public: + using ConnectFunc = std::function( + std::unique_ptr)>; + + virtual ~IInspector() = 0; + + /// addPage is called by the VM to add a page to the list of debuggable pages. + virtual int addPage( + const std::string& title, + const std::string& vm, + ConnectFunc connectFunc) = 0; + + /// removePage is called by the VM to remove a page from the list of + /// debuggable pages. + virtual void removePage(int pageId) = 0; + + /// getPages is called by the client to list all debuggable pages. + virtual std::vector getPages() const = 0; + + /// connect is called by the client to initiate a debugging session on the + /// given page. + virtual std::unique_ptr connect( + int pageId, + std::unique_ptr remote) = 0; +}; + +/// getInspectorInstance retrieves the singleton inspector that tracks all +/// debuggable pages in this process. +extern IInspector& getInspectorInstance(); + +/// makeTestInspectorInstance creates an independent inspector instance that +/// should only be used in tests. +extern std::unique_ptr makeTestInspectorInstance(); + +} // namespace facebook::react::jsinspector_modern diff --git a/packages/react-native/ReactCommon/jsinspector/React-jsinspector.podspec b/packages/react-native/ReactCommon/jsinspector-modern/React-jsinspector.podspec similarity index 100% rename from packages/react-native/ReactCommon/jsinspector/React-jsinspector.podspec rename to packages/react-native/ReactCommon/jsinspector-modern/React-jsinspector.podspec diff --git a/packages/react-native/scripts/react_native_pods.rb b/packages/react-native/scripts/react_native_pods.rb index d6c80d0544d..a3ab54130d4 100644 --- a/packages/react-native/scripts/react_native_pods.rb +++ b/packages/react-native/scripts/react_native_pods.rb @@ -131,7 +131,7 @@ def use_react_native! ( end pod 'React-jsiexecutor', :path => "#{prefix}/ReactCommon/jsiexecutor" - pod 'React-jsinspector', :path => "#{prefix}/ReactCommon/jsinspector" + pod 'React-jsinspector', :path => "#{prefix}/ReactCommon/jsinspector-modern" pod 'React-callinvoker', :path => "#{prefix}/ReactCommon/callinvoker" pod 'React-runtimeexecutor', :path => "#{prefix}/ReactCommon/runtimeexecutor"