Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ void JReactHostInspectorTarget::onSetPausedInDebuggerMessage(
}
}

void JReactHostInspectorTarget::unstable_onPerfMonitorUpdate(
const PerfMonitorUpdateRequest& /* unused */) {}

void JReactHostInspectorTarget::loadNetworkResource(
const jsinspector_modern::LoadNetworkResourceRequest& params,
jsinspector_modern::ScopedExecutor<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class JReactHostInspectorTarget
void onReload(const PageReloadRequest& request) override;
void onSetPausedInDebuggerMessage(
const OverlaySetPausedInDebuggerMessageRequest&) override;
void unstable_onPerfMonitorUpdate(
const PerfMonitorUpdateRequest& /* unused */) override;
void loadNetworkResource(
const jsinspector_modern::LoadNetworkResourceRequest& params,
jsinspector_modern::ScopedExecutor<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,53 @@ class HostCommandSender {
std::unique_ptr<ILocalConnection> connection_;
};

/**
* Enables the caller to install and subscribe to a named CDP runtime binding
* on the HostTarget via a callback. Note: Per CDP spec, this does not need to
* check if the `Runtime` domain is enabled.
*/
class HostRuntimeBinding {
public:
explicit HostRuntimeBinding(
HostTarget& target,
std::string name,
std::function<void(std::string)> callback)
: connection_(target.connect(std::make_unique<CallbackRemoteConnection>(
[callback = std::move(callback)](const std::string& message) {
auto parsedMessage = folly::parseJson(message);

// Ignore initial Runtime.addBinding response
if (parsedMessage["id"] == 0 &&
parsedMessage["result"].isObject() &&
parsedMessage["result"].empty()) {
return;
}

// Assert that we only intercept bindingCalled responses
assert(
parsedMessage["method"].asString() ==
"Runtime.bindingCalled");
callback(parsedMessage["params"]["payload"].asString());
}))) {
// Install runtime binding
connection_->sendMessage(cdp::jsonRequest(
0,
"Runtime.addBinding",
folly::dynamic::object("name", std::move(name))));
}

private:
std::unique_ptr<ILocalConnection> connection_;
};

std::shared_ptr<HostTarget> HostTarget::create(
HostTargetDelegate& delegate,
VoidExecutor executor) {
std::shared_ptr<HostTarget> hostTarget{new HostTarget(delegate)};
hostTarget->setExecutor(std::move(executor));
if (InspectorFlags::getInstance().getPerfMonitorV2Enabled()) {
hostTarget->installPerfMetricsBinding();
}
return hostTarget;
}

Expand Down Expand Up @@ -212,6 +254,19 @@ void HostTarget::sendCommand(HostCommand command) {
});
}

void HostTarget::installPerfMetricsBinding() {
perfMetricsBinding_ = std::make_unique<HostRuntimeBinding>(
*this, // Used immediately
"__chromium_devtools_metrics_reporter",
[this](const std::string& message) {
auto payload = folly::parseJson(message);
HostTargetDelegate::PerfMonitorUpdateRequest request{
.interactionName = payload["eventName"].asString(),
.durationMs = static_cast<uint16_t>(payload["duration"].asInt())};
delegate_.unstable_onPerfMonitorUpdate(request);
});
}

HostTargetController::HostTargetController(HostTarget& target)
: target_(target) {}

Expand Down
21 changes: 21 additions & 0 deletions packages/react-native/ReactCommon/jsinspector-modern/HostTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace facebook::react::jsinspector_modern {
class HostTargetSession;
class HostAgent;
class HostCommandSender;
class HostRuntimeBinding;
class HostTarget;

struct HostTargetMetadata {
Expand Down Expand Up @@ -93,6 +94,11 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate {
}
};

struct PerfMonitorUpdateRequest {
std::string interactionName;
uint16_t durationMs;
};

virtual ~HostTargetDelegate() override;

/**
Expand Down Expand Up @@ -121,6 +127,13 @@ class HostTargetDelegate : public LoadNetworkResourceDelegate {
virtual void onSetPausedInDebuggerMessage(
const OverlaySetPausedInDebuggerMessageRequest& request) = 0;

/**
* [Experimental] Called when the runtime has new data for the V2 Perf
* Monitor overlay. This is called on the inspector thread.
*/
virtual void unstable_onPerfMonitorUpdate(
const PerfMonitorUpdateRequest& /*request*/) {}

/**
* Called by NetworkIOAgent on handling a `Network.loadNetworkResource` CDP
* request. Platform implementations should override this to perform a
Expand Down Expand Up @@ -256,6 +269,7 @@ class JSINSPECTOR_EXPORT HostTarget
std::shared_ptr<ExecutionContextManager> executionContextManager_;
std::shared_ptr<InstanceTarget> currentInstance_{nullptr};
std::unique_ptr<HostCommandSender> commandSender_;
std::unique_ptr<HostRuntimeBinding> perfMetricsBinding_;

inline HostTargetDelegate& getDelegate() {
return delegate_;
Expand All @@ -265,6 +279,13 @@ class JSINSPECTOR_EXPORT HostTarget
return currentInstance_ != nullptr;
}

/**
* Install a runtime binding subscribing to the Interaction to Next Paint
* (INP) live metric, which we broadcast to the V2 Perf Monitor overlay
* via \ref HostTargetDelegate::unstable_onPerfMonitorUpdate.
*/
void installPerfMetricsBinding();

// Necessary to allow HostAgent to access HostTarget's internals in a
// controlled way (i.e. only HostTargetController gets friend access, while
// HostAgent itself doesn't).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ bool InspectorFlags::getNetworkInspectionEnabled() const {
return loadFlagsAndAssertUnchanged().networkInspectionEnabled;
}

bool InspectorFlags::getPerfMonitorV2Enabled() const {
return loadFlagsAndAssertUnchanged().perfMonitorV2Enabled;
}

void InspectorFlags::dangerouslyResetFlags() {
*this = InspectorFlags{};
}
Expand All @@ -59,6 +63,9 @@ const InspectorFlags::Values& InspectorFlags::loadFlagsAndAssertUnchanged()
.networkInspectionEnabled =
ReactNativeFeatureFlags::enableBridgelessArchitecture() &&
ReactNativeFeatureFlags::fuseboxNetworkInspectionEnabled(),
.perfMonitorV2Enabled =
ReactNativeFeatureFlags::enableBridgelessArchitecture() &&
ReactNativeFeatureFlags::perfMonitorV2Enabled(),
};

if (cachedValues_.has_value() && !inconsistentFlagsStateLogged_) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class InspectorFlags {
*/
bool getNetworkInspectionEnabled() const;

/**
* Flag determining if the V2 in-app Performance Monitor is enabled.
*/
bool getPerfMonitorV2Enabled() const;

/**
* Forcibly disable the main `getFuseboxEnabled()` flag. This should ONLY be
* used by `ReactInstanceIntegrationTest`.
Expand All @@ -52,6 +57,7 @@ class InspectorFlags {
bool fuseboxEnabled;
bool isProfilingBuild;
bool networkInspectionEnabled;
bool perfMonitorV2Enabled;
bool operator==(const Values&) const = default;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ void CallbackLocalConnection::disconnect() {
handler_ = nullptr;
}

CallbackRemoteConnection::CallbackRemoteConnection(
std::function<void(std::string)> handler)
: handler_(std::move(handler)) {}

void CallbackRemoteConnection::onMessage(std::string message) {
handler_(std::move(message));
}

RAIIRemoteConnection::RAIIRemoteConnection(
std::unique_ptr<IRemoteConnection> remote)
: remote_(std::move(remote)) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ class CallbackLocalConnection : public ILocalConnection {
std::function<void(std::string)> handler_;
};

/**
* Wraps a callback function in IRemoteConnection.
*/
class CallbackRemoteConnection : public IRemoteConnection {
public:
/**
* Creates a new Connection that uses the given callback to receive messages
* from the backend.
*/
explicit CallbackRemoteConnection(std::function<void(std::string)> handler);

void onMessage(std::string message) override;

void onDisconnect() override {}

private:
std::function<void(std::string)> handler_;
};

/**
* Wraps an IRemoteConnection in a simpler interface that calls `onDisconnect`
* implicitly upon destruction.
Expand Down
Loading