Commit eab48ceb authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

DevTools: Set up DevToolsAgent with an interrupting connection

When a worker is stuck in JS when we call AttachDevToolsSession, the
the call won't go through until JS execution finishes as there is no
interrupting mechanism (equivalent to io_session) at the Agent level.

This CL adds different behaviour to DevToolsAgent for the worker and
non-worker cases. Non-workers now use the IO thread to dispatch calls
from the browser over the DevToolsAgent mojo interface. This is similar
to how IOSession works and achieves the same results.

We also send all protocol messages on IOSession for workers. We can't do
this for non-workers as they need to have an ordering guarantee with
page navigation. This is done through using associated mojo channels for
Session, Agent and FrameNavigationControl. We don't associate the mojo
channel for workers though.

Bug: 1010534
Change-Id: Id6b3d2ee0cf86f1a0b046b4e59ec1851ca07d7eb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1951003Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarMike West <mkwst@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarSigurd Schneider <sigurds@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#733963}
parent 2eadf076
...@@ -38,7 +38,8 @@ void DevToolsRendererChannel::SetRenderer( ...@@ -38,7 +38,8 @@ void DevToolsRendererChannel::SetRenderer(
agent_remote_.set_disconnect_handler(std::move(connection_error)); agent_remote_.set_disconnect_handler(std::move(connection_error));
if (host_receiver) if (host_receiver)
receiver_.Bind(std::move(host_receiver)); receiver_.Bind(std::move(host_receiver));
SetRendererInternal(agent, process_id, nullptr); const bool force_using_io = true;
SetRendererInternal(agent, process_id, nullptr, force_using_io);
} }
void DevToolsRendererChannel::SetRendererAssociated( void DevToolsRendererChannel::SetRendererAssociated(
...@@ -55,7 +56,8 @@ void DevToolsRendererChannel::SetRendererAssociated( ...@@ -55,7 +56,8 @@ void DevToolsRendererChannel::SetRendererAssociated(
} }
if (host_receiver) if (host_receiver)
associated_receiver_.Bind(std::move(host_receiver)); associated_receiver_.Bind(std::move(host_receiver));
SetRendererInternal(agent, process_id, frame_host); const bool force_using_io = false;
SetRendererInternal(agent, process_id, frame_host, force_using_io);
} }
void DevToolsRendererChannel::CleanupConnection() { void DevToolsRendererChannel::CleanupConnection() {
...@@ -73,7 +75,8 @@ void DevToolsRendererChannel::ForceDetachWorkerSessions() { ...@@ -73,7 +75,8 @@ void DevToolsRendererChannel::ForceDetachWorkerSessions() {
void DevToolsRendererChannel::SetRendererInternal( void DevToolsRendererChannel::SetRendererInternal(
blink::mojom::DevToolsAgent* agent, blink::mojom::DevToolsAgent* agent,
int process_id, int process_id,
RenderFrameHostImpl* frame_host) { RenderFrameHostImpl* frame_host,
bool force_using_io) {
ReportChildWorkersCallback(); ReportChildWorkersCallback();
process_id_ = process_id; process_id_ = process_id;
frame_host_ = frame_host; frame_host_ = frame_host;
...@@ -85,7 +88,7 @@ void DevToolsRendererChannel::SetRendererInternal( ...@@ -85,7 +88,7 @@ void DevToolsRendererChannel::SetRendererInternal(
for (DevToolsSession* session : owner_->sessions()) { for (DevToolsSession* session : owner_->sessions()) {
for (auto& pair : session->handlers()) for (auto& pair : session->handlers())
pair.second->SetRenderer(process_id_, frame_host_); pair.second->SetRenderer(process_id_, frame_host_);
session->AttachToAgent(agent); session->AttachToAgent(agent, force_using_io);
} }
} }
...@@ -95,9 +98,9 @@ void DevToolsRendererChannel::AttachSession(DevToolsSession* session) { ...@@ -95,9 +98,9 @@ void DevToolsRendererChannel::AttachSession(DevToolsSession* session) {
for (auto& pair : session->handlers()) for (auto& pair : session->handlers())
pair.second->SetRenderer(process_id_, frame_host_); pair.second->SetRenderer(process_id_, frame_host_);
if (agent_remote_) if (agent_remote_)
session->AttachToAgent(agent_remote_.get()); session->AttachToAgent(agent_remote_.get(), true);
else if (associated_agent_remote_) else if (associated_agent_remote_)
session->AttachToAgent(associated_agent_remote_.get()); session->AttachToAgent(associated_agent_remote_.get(), false);
} }
void DevToolsRendererChannel::InspectElement(const gfx::Point& point) { void DevToolsRendererChannel::InspectElement(const gfx::Point& point) {
......
...@@ -80,7 +80,8 @@ class CONTENT_EXPORT DevToolsRendererChannel ...@@ -80,7 +80,8 @@ class CONTENT_EXPORT DevToolsRendererChannel
void CleanupConnection(); void CleanupConnection();
void SetRendererInternal(blink::mojom::DevToolsAgent* agent, void SetRendererInternal(blink::mojom::DevToolsAgent* agent,
int process_id, int process_id,
RenderFrameHostImpl* frame_host); RenderFrameHostImpl* frame_host,
bool force_using_io);
void ReportChildWorkersCallback(); void ReportChildWorkersCallback();
DevToolsAgentHostImpl* owner_; DevToolsAgentHostImpl* owner_;
......
...@@ -117,7 +117,8 @@ void DevToolsSession::TurnIntoExternalProxy( ...@@ -117,7 +117,8 @@ void DevToolsSession::TurnIntoExternalProxy(
proxy_delegate_->Attach(this); proxy_delegate_->Attach(this);
} }
void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent) { void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent,
bool force_using_io_session) {
DCHECK(agent_host_); DCHECK(agent_host_);
if (!agent) { if (!agent) {
receiver_.reset(); receiver_.reset();
...@@ -134,6 +135,7 @@ void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent) { ...@@ -134,6 +135,7 @@ void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent) {
io_session_.reset(); io_session_.reset();
} }
use_io_session_ = force_using_io_session;
agent->AttachDevToolsSession(receiver_.BindNewEndpointAndPassRemote(), agent->AttachDevToolsSession(receiver_.BindNewEndpointAndPassRemote(),
session_.BindNewEndpointAndPassReceiver(), session_.BindNewEndpointAndPassReceiver(),
io_session_.BindNewPipeAndPassReceiver(), io_session_.BindNewPipeAndPassReceiver(),
...@@ -290,7 +292,9 @@ void DevToolsSession::fallThrough(int call_id, ...@@ -290,7 +292,9 @@ void DevToolsSession::fallThrough(int call_id,
void DevToolsSession::DispatchToAgent(const PendingMessage& message) { void DevToolsSession::DispatchToAgent(const PendingMessage& message) {
DCHECK(!browser_only_); DCHECK(!browser_only_);
if (ShouldSendOnIO(message.method)) { // We send all messages on the IO channel for workers so that messages like
// Debugger.pause don't get stuck behind other blocking messages.
if (ShouldSendOnIO(message.method) || use_io_session_) {
if (io_session_) { if (io_session_) {
TRACE_EVENT_WITH_FLOW2( TRACE_EVENT_WITH_FLOW2(
"devtools", "DevToolsSession::DispatchToAgent on IO", message.call_id, "devtools", "DevToolsSession::DispatchToAgent on IO", message.call_id,
......
...@@ -52,7 +52,8 @@ class DevToolsSession : public protocol::FrontendChannel, ...@@ -52,7 +52,8 @@ class DevToolsSession : public protocol::FrontendChannel,
void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler); void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler);
void TurnIntoExternalProxy(DevToolsExternalAgentProxyDelegate* delegate); void TurnIntoExternalProxy(DevToolsExternalAgentProxyDelegate* delegate);
void AttachToAgent(blink::mojom::DevToolsAgent* agent); void AttachToAgent(blink::mojom::DevToolsAgent* agent,
bool force_using_io_session);
bool DispatchProtocolMessage(base::span<const uint8_t> message); bool DispatchProtocolMessage(base::span<const uint8_t> message);
void SuspendSendingMessagesToAgent(); void SuspendSendingMessagesToAgent();
void ResumeSendingMessagesToAgent(); void ResumeSendingMessagesToAgent();
...@@ -124,6 +125,7 @@ class DevToolsSession : public protocol::FrontendChannel, ...@@ -124,6 +125,7 @@ class DevToolsSession : public protocol::FrontendChannel,
mojo::AssociatedReceiver<blink::mojom::DevToolsSessionHost> receiver_{this}; mojo::AssociatedReceiver<blink::mojom::DevToolsSessionHost> receiver_{this};
mojo::AssociatedRemote<blink::mojom::DevToolsSession> session_; mojo::AssociatedRemote<blink::mojom::DevToolsSession> session_;
mojo::Remote<blink::mojom::DevToolsSession> io_session_; mojo::Remote<blink::mojom::DevToolsSession> io_session_;
bool use_io_session_{false};
DevToolsAgentHostImpl* agent_host_ = nullptr; DevToolsAgentHostImpl* agent_host_ = nullptr;
DevToolsAgentHostClient* client_; DevToolsAgentHostClient* client_;
bool browser_only_ = false; bool browser_only_ = false;
......
...@@ -38,7 +38,7 @@ WorkerDevToolsAgentHost::WorkerDevToolsAgentHost( ...@@ -38,7 +38,7 @@ WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(
std::move(connection_error)); std::move(connection_error));
} }
WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() {} WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() = default;
void WorkerDevToolsAgentHost::Disconnected() { void WorkerDevToolsAgentHost::Disconnected() {
ForceDetachAllSessions(); ForceDetachAllSessions();
......
...@@ -94,10 +94,10 @@ interface DevToolsAgent { ...@@ -94,10 +94,10 @@ interface DevToolsAgent {
ReportChildWorkers(bool report, bool wait_for_debugger) => (); ReportChildWorkers(bool report, bool wait_for_debugger) => ();
}; };
// This interface is implemented in browser and is notified by DevToolsAgent // This interface is implemented in the browser and is notified by
// when new child worker is available for future debugging. // DevToolsAgent when a new child worker is available for future debugging.
interface DevToolsAgentHost { interface DevToolsAgentHost {
// Informs the host about new child worker and gives its DevToolsAgent // Informs the host about the new child worker and gives its DevToolsAgent
// for debugging. // for debugging.
// |devtools_worker_token| is a unique token identifying this worker. // |devtools_worker_token| is a unique token identifying this worker.
// |waiting_for_debugger| is true if worker was paused on startup and // |waiting_for_debugger| is true if worker was paused on startup and
......
...@@ -20,8 +20,20 @@ ...@@ -20,8 +20,20 @@
#include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
#include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/core/workers/worker_thread.h"
#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace WTF {
using StatePtr = mojo::StructPtr<blink::mojom::blink::DevToolsSessionState>;
template <>
struct CrossThreadCopier<StatePtr>
: public CrossThreadCopierByValuePassThrough<StatePtr> {
STATIC_ONLY(CrossThreadCopier);
};
} // namespace WTF
namespace blink { namespace blink {
namespace { namespace {
...@@ -49,6 +61,73 @@ DevToolsAgent* DevToolsAgentFromContext(ExecutionContext* execution_context) { ...@@ -49,6 +61,73 @@ DevToolsAgent* DevToolsAgentFromContext(ExecutionContext* execution_context) {
} // namespace } // namespace
class DevToolsAgent::IOAgent : public mojom::blink::DevToolsAgent {
public:
IOAgent(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<InspectorTaskRunner> inspector_task_runner,
CrossThreadWeakPersistent<::blink::DevToolsAgent> agent,
mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver)
: io_task_runner_(io_task_runner),
inspector_task_runner_(inspector_task_runner),
agent_(std::move(agent)) {
// Binds on the IO thread and receive messages there too. Messages are
// posted to the worker thread in a way that interrupts V8 execution. This
// is necessary so that AttachDevToolsSession can be called on a worker
// which has already started and is stuck in JS, e.g. polling using
// Atomics.wait() which is a common pattern.
PostCrossThreadTask(
*io_task_runner_, FROM_HERE,
CrossThreadBindOnce(&IOAgent::BindInterface,
CrossThreadUnretained(this), std::move(receiver)));
}
void BindInterface(
mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver) {
receiver_.Bind(std::move(receiver), io_task_runner_);
}
void DeleteSoon() { io_task_runner_->DeleteSoon(FROM_HERE, this); }
~IOAgent() override = default;
// mojom::blink::DevToolsAgent implementation.
void AttachDevToolsSession(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
main_session,
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
bool client_expects_binary_responses) override {
DCHECK(receiver_.is_bound());
inspector_task_runner_->AppendTask(CrossThreadBindOnce(
&::blink::DevToolsAgent::AttachDevToolsSessionImpl, agent_,
std::move(host), std::move(main_session), std::move(io_session),
std::move(reattach_session_state), client_expects_binary_responses));
}
void InspectElement(const gfx::Point& point) override {
// InspectElement on a worker doesn't make sense.
NOTREACHED();
}
void ReportChildWorkers(bool report,
bool wait_for_debugger,
base::OnceClosure callback) override {
DCHECK(receiver_.is_bound());
inspector_task_runner_->AppendTask(CrossThreadBindOnce(
&::blink::DevToolsAgent::ReportChildWorkersPostCallbackToIO, agent_,
report, wait_for_debugger, CrossThreadBindOnce(std::move(callback))));
}
private:
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
CrossThreadWeakPersistent<::blink::DevToolsAgent> agent_;
mojo::Receiver<mojom::blink::DevToolsAgent> receiver_{this};
DISALLOW_COPY_AND_ASSIGN(IOAgent);
};
DevToolsAgent::DevToolsAgent( DevToolsAgent::DevToolsAgent(
Client* client, Client* client,
InspectedFrames* inspected_frames, InspectedFrames* inspected_frames,
...@@ -76,23 +155,25 @@ void DevToolsAgent::Dispose() { ...@@ -76,23 +155,25 @@ void DevToolsAgent::Dispose() {
CleanupConnection(); CleanupConnection();
} }
void DevToolsAgent::BindReceiver( void DevToolsAgent::BindReceiverForWorker(
mojo::PendingRemote<mojom::blink::DevToolsAgentHost> host_remote, mojo::PendingRemote<mojom::blink::DevToolsAgentHost> host_remote,
mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver, mojo::PendingReceiver<mojom::blink::DevToolsAgent> receiver,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) { scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DCHECK(!receiver_.is_bound());
DCHECK(!associated_receiver_.is_bound()); DCHECK(!associated_receiver_.is_bound());
receiver_.Bind(std::move(receiver), std::move(task_runner));
host_remote_.Bind(std::move(host_remote)); host_remote_.Bind(std::move(host_remote));
host_remote_.set_disconnect_handler( host_remote_.set_disconnect_handler(
WTF::Bind(&DevToolsAgent::CleanupConnection, WrapWeakPersistent(this))); WTF::Bind(&DevToolsAgent::CleanupConnection, WrapWeakPersistent(this)));
io_agent_ =
new IOAgent(io_task_runner_, inspector_task_runner_,
WrapCrossThreadWeakPersistent(this), std::move(receiver));
} }
void DevToolsAgent::BindReceiver( void DevToolsAgent::BindReceiver(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host_remote, mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host_remote,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver, mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) { scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
DCHECK(!receiver_.is_bound());
DCHECK(!associated_receiver_.is_bound()); DCHECK(!associated_receiver_.is_bound());
associated_receiver_.Bind(std::move(receiver), std::move(task_runner)); associated_receiver_.Bind(std::move(receiver), std::move(task_runner));
associated_host_remote_.Bind(std::move(host_remote)); associated_host_remote_.Bind(std::move(host_remote));
...@@ -100,13 +181,14 @@ void DevToolsAgent::BindReceiver( ...@@ -100,13 +181,14 @@ void DevToolsAgent::BindReceiver(
WTF::Bind(&DevToolsAgent::CleanupConnection, WrapWeakPersistent(this))); WTF::Bind(&DevToolsAgent::CleanupConnection, WrapWeakPersistent(this)));
} }
void DevToolsAgent::AttachDevToolsSession( void DevToolsAgent::AttachDevToolsSessionImpl(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host, mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession> mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
session_receiver, session_receiver,
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver, mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver,
mojom::blink::DevToolsSessionStatePtr reattach_session_state, mojom::blink::DevToolsSessionStatePtr reattach_session_state,
bool client_expects_binary_responses) { bool client_expects_binary_responses) {
TRACE_EVENT0("devtools", "Agent::AttachDevToolsSessionImpl");
client_->DebuggerTaskStarted(); client_->DebuggerTaskStarted();
DevToolsSession* session = MakeGarbageCollected<DevToolsSession>( DevToolsSession* session = MakeGarbageCollected<DevToolsSession>(
this, std::move(host), std::move(session_receiver), this, std::move(host), std::move(session_receiver),
...@@ -116,18 +198,63 @@ void DevToolsAgent::AttachDevToolsSession( ...@@ -116,18 +198,63 @@ void DevToolsAgent::AttachDevToolsSession(
client_->DebuggerTaskFinished(); client_->DebuggerTaskFinished();
} }
void DevToolsAgent::InspectElement(const gfx::Point& point) { void DevToolsAgent::AttachDevToolsSession(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost> host,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
session_receiver,
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session_receiver,
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
bool client_expects_binary_responses) {
TRACE_EVENT0("devtools", "Agent::AttachDevToolsSession");
if (associated_receiver_.is_bound()) {
AttachDevToolsSessionImpl(std::move(host), std::move(session_receiver),
std::move(io_session_receiver),
std::move(reattach_session_state),
client_expects_binary_responses);
} else {
io_agent_->AttachDevToolsSession(
std::move(host), std::move(session_receiver),
std::move(io_session_receiver), std::move(reattach_session_state),
client_expects_binary_responses);
}
}
void DevToolsAgent::InspectElementImpl(const gfx::Point& point) {
client_->InspectElement(point); client_->InspectElement(point);
} }
void DevToolsAgent::InspectElement(const gfx::Point& point) {
if (associated_receiver_.is_bound()) {
client_->InspectElement(point);
} else {
// InspectElement on a worker doesn't make sense.
NOTREACHED();
}
}
void DevToolsAgent::FlushProtocolNotifications() { void DevToolsAgent::FlushProtocolNotifications() {
for (auto& session : sessions_) for (auto& session : sessions_)
session->FlushProtocolNotifications(); session->FlushProtocolNotifications();
} }
void DevToolsAgent::ReportChildWorkers(bool report, void DevToolsAgent::ReportChildWorkersPostCallbackToIO(
bool wait_for_debugger, bool report,
base::OnceClosure callback) { bool wait_for_debugger,
CrossThreadOnceClosure callback) {
TRACE_EVENT0("devtools", "Agent::ReportChildWorkersPostCallbackToIO");
ReportChildWorkersImpl(report, wait_for_debugger, base::DoNothing());
// This message originally came from the IOAgent for a worker which means the
// response needs to be sent on the IO thread as well, so we post the callback
// task back there to be run. In the non-IO case, this callback would be run
// synchronously at the end of ReportChildWorkersImpl, so the ordering between
// ReportChildWorkers and running the callback is preserved.
PostCrossThreadTask(*io_task_runner_, FROM_HERE, std::move(callback));
}
void DevToolsAgent::ReportChildWorkersImpl(bool report,
bool wait_for_debugger,
base::OnceClosure callback) {
TRACE_EVENT0("devtools", "Agent::ReportChildWorkersImpl");
report_child_workers_ = report; report_child_workers_ = report;
pause_child_workers_on_start_ = wait_for_debugger; pause_child_workers_on_start_ = wait_for_debugger;
if (report_child_workers_) { if (report_child_workers_) {
...@@ -138,6 +265,18 @@ void DevToolsAgent::ReportChildWorkers(bool report, ...@@ -138,6 +265,18 @@ void DevToolsAgent::ReportChildWorkers(bool report,
std::move(callback).Run(); std::move(callback).Run();
} }
void DevToolsAgent::ReportChildWorkers(bool report,
bool wait_for_debugger,
base::OnceClosure callback) {
TRACE_EVENT0("devtools", "Agent::ReportChildWorkers");
if (associated_receiver_.is_bound()) {
ReportChildWorkersImpl(report, wait_for_debugger, std::move(callback));
} else {
io_agent_->ReportChildWorkers(report, wait_for_debugger,
std::move(callback));
}
}
// static // static
std::unique_ptr<WorkerDevToolsParams> DevToolsAgent::WorkerThreadCreated( std::unique_ptr<WorkerDevToolsParams> DevToolsAgent::WorkerThreadCreated(
ExecutionContext* parent_context, ExecutionContext* parent_context,
...@@ -192,7 +331,10 @@ void DevToolsAgent::ReportChildWorker(std::unique_ptr<WorkerData> data) { ...@@ -192,7 +331,10 @@ void DevToolsAgent::ReportChildWorker(std::unique_ptr<WorkerData> data) {
} }
void DevToolsAgent::CleanupConnection() { void DevToolsAgent::CleanupConnection() {
receiver_.reset(); if (io_agent_) {
io_agent_->DeleteSoon();
io_agent_ = nullptr;
}
associated_receiver_.reset(); associated_receiver_.reset();
host_remote_.reset(); host_remote_.reset();
associated_host_remote_.reset(); associated_host_remote_.reset();
......
...@@ -59,9 +59,16 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>, ...@@ -59,9 +59,16 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
void Dispose(); void Dispose();
void FlushProtocolNotifications(); void FlushProtocolNotifications();
void BindReceiver(mojo::PendingRemote<mojom::blink::DevToolsAgentHost>, // For workers, we use the IO thread similar to DevToolsSession::IOSession to
mojo::PendingReceiver<mojom::blink::DevToolsAgent>, // ensure that we can always interrupt a worker that is stuck in JS. We don't
scoped_refptr<base::SingleThreadTaskRunner>); // use an associated channel for workers, meaning we don't have the ordering
// constraints related to navigation that the non-worker agents have.
void BindReceiverForWorker(
mojo::PendingRemote<mojom::blink::DevToolsAgentHost>,
mojo::PendingReceiver<mojom::blink::DevToolsAgent>,
scoped_refptr<base::SingleThreadTaskRunner>);
// Used for non-worker agents. These do not use the IO thread like we do for
// workers, and they use associated mojo interfaces.
void BindReceiver( void BindReceiver(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost>, mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost>,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent>, mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent>,
...@@ -70,6 +77,7 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>, ...@@ -70,6 +77,7 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
private: private:
friend class DevToolsSession; friend class DevToolsSession;
class IOAgent;
// mojom::blink::DevToolsAgent implementation. // mojom::blink::DevToolsAgent implementation.
void AttachDevToolsSession( void AttachDevToolsSession(
...@@ -84,6 +92,10 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>, ...@@ -84,6 +92,10 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
bool wait_for_debugger, bool wait_for_debugger,
base::OnceClosure callback) override; base::OnceClosure callback) override;
void ReportChildWorkersPostCallbackToIO(bool report,
bool wait_for_debugger,
CrossThreadOnceClosure callback);
struct WorkerData { struct WorkerData {
KURL url; KURL url;
mojo::PendingRemote<mojom::blink::DevToolsAgent> agent_remote; mojo::PendingRemote<mojom::blink::DevToolsAgent> agent_remote;
...@@ -96,8 +108,19 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>, ...@@ -96,8 +108,19 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
void CleanupConnection(); void CleanupConnection();
void AttachDevToolsSessionImpl(
mojo::PendingAssociatedRemote<mojom::blink::DevToolsSessionHost>,
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsSession>
main_session,
mojo::PendingReceiver<mojom::blink::DevToolsSession> io_session,
mojom::blink::DevToolsSessionStatePtr reattach_session_state,
bool client_expects_binary_responses);
void InspectElementImpl(const gfx::Point& point);
void ReportChildWorkersImpl(bool report,
bool wait_for_debugger,
base::OnceClosure callback);
Client* client_; Client* client_;
mojo::Receiver<mojom::blink::DevToolsAgent> receiver_{this};
mojo::AssociatedReceiver<mojom::blink::DevToolsAgent> associated_receiver_{ mojo::AssociatedReceiver<mojom::blink::DevToolsAgent> associated_receiver_{
this}; this};
mojo::Remote<mojom::blink::DevToolsAgentHost> host_remote_; mojo::Remote<mojom::blink::DevToolsAgentHost> host_remote_;
...@@ -110,6 +133,7 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>, ...@@ -110,6 +133,7 @@ class CORE_EXPORT DevToolsAgent : public GarbageCollected<DevToolsAgent>,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
HashMap<WorkerThread*, std::unique_ptr<WorkerData>> HashMap<WorkerThread*, std::unique_ptr<WorkerData>>
unreported_child_worker_threads_; unreported_child_worker_threads_;
IOAgent* io_agent_{nullptr};
bool report_child_workers_ = false; bool report_child_workers_ = false;
bool pause_child_workers_on_start_ = false; bool pause_child_workers_on_start_ = false;
}; };
......
...@@ -39,7 +39,12 @@ bool ShouldInterruptForMethod(const String& method) { ...@@ -39,7 +39,12 @@ bool ShouldInterruptForMethod(const String& method) {
method == "Performance.getMetrics" || method == "Page.crash" || method == "Performance.getMetrics" || method == "Page.crash" ||
method == "Runtime.terminateExecution" || method == "Runtime.terminateExecution" ||
method == "Debugger.getStackTrace" || method == "Debugger.getStackTrace" ||
method == "Emulation.setScriptExecutionDisabled"; method == "Emulation.setScriptExecutionDisabled" ||
// Needed to start/stop the performance timeline.
method == "HeapProfiler.enable" || method == "Debugger.disable" ||
method == "Debugger.setAsyncCallStackDepth" ||
method == "Debugger.enable" ||
method == "Debugger.setPauseOnExceptions";
} }
std::vector<uint8_t> Get8BitStringFrom(v8_inspector::StringBuffer* msg) { std::vector<uint8_t> Get8BitStringFrom(v8_inspector::StringBuffer* msg) {
......
...@@ -87,9 +87,10 @@ WorkerInspectorController::WorkerInspectorController( ...@@ -87,9 +87,10 @@ WorkerInspectorController::WorkerInspectorController(
agent_ = MakeGarbageCollected<DevToolsAgent>( agent_ = MakeGarbageCollected<DevToolsAgent>(
this, inspected_frames_.Get(), probe_sink_.Get(), this, inspected_frames_.Get(), probe_sink_.Get(),
std::move(inspector_task_runner), std::move(io_task_runner)); std::move(inspector_task_runner), std::move(io_task_runner));
agent_->BindReceiver(std::move(devtools_params->agent_host_remote), agent_->BindReceiverForWorker(
std::move(devtools_params->agent_receiver), std::move(devtools_params->agent_host_remote),
thread->GetTaskRunner(TaskType::kInternalInspector)); std::move(devtools_params->agent_receiver),
thread->GetTaskRunner(TaskType::kInternalInspector));
} }
trace_event::AddEnabledStateObserver(this); trace_event::AddEnabledStateObserver(this);
EmitTraceEvent(); EmitTraceEvent();
......
...@@ -69,6 +69,12 @@ struct SyncToken; ...@@ -69,6 +69,12 @@ struct SyncToken;
namespace mojo { namespace mojo {
template <typename Interface> template <typename Interface>
class PendingReceiver; class PendingReceiver;
template <typename Interface>
class PendingRemote;
template <typename Interface>
class PendingAssociatedRemote;
template <typename Interface>
class PendingAssociatedReceiver;
} }
namespace WTF { namespace WTF {
...@@ -80,6 +86,15 @@ struct CrossThreadCopierPassThrough { ...@@ -80,6 +86,15 @@ struct CrossThreadCopierPassThrough {
static Type Copy(const T& parameter) { return parameter; } static Type Copy(const T& parameter) { return parameter; }
}; };
template <typename T>
struct CrossThreadCopierByValuePassThrough {
STATIC_ONLY(CrossThreadCopierByValuePassThrough);
typedef T Type;
static Type Copy(T receiver) {
return receiver; // This is in fact a move.
}
};
template <typename T, bool isArithmeticOrEnum> template <typename T, bool isArithmeticOrEnum>
struct CrossThreadCopierBase; struct CrossThreadCopierBase;
...@@ -273,12 +288,31 @@ struct CrossThreadCopier<String> { ...@@ -273,12 +288,31 @@ struct CrossThreadCopier<String> {
}; };
template <typename Interface> template <typename Interface>
struct CrossThreadCopier<mojo::PendingReceiver<Interface>> { struct CrossThreadCopier<mojo::PendingReceiver<Interface>>
: public CrossThreadCopierByValuePassThrough<
mojo::PendingReceiver<Interface>> {
STATIC_ONLY(CrossThreadCopier);
};
template <typename Interface>
struct CrossThreadCopier<mojo::PendingRemote<Interface>>
: public CrossThreadCopierByValuePassThrough<
mojo::PendingRemote<Interface>> {
STATIC_ONLY(CrossThreadCopier);
};
template <typename Interface>
struct CrossThreadCopier<mojo::PendingAssociatedRemote<Interface>>
: public CrossThreadCopierByValuePassThrough<
mojo::PendingAssociatedRemote<Interface>> {
STATIC_ONLY(CrossThreadCopier);
};
template <typename Interface>
struct CrossThreadCopier<mojo::PendingAssociatedReceiver<Interface>>
: public CrossThreadCopierByValuePassThrough<
mojo::PendingAssociatedReceiver<Interface>> {
STATIC_ONLY(CrossThreadCopier); STATIC_ONLY(CrossThreadCopier);
using Type = mojo::PendingReceiver<Interface>;
static Type Copy(Type receiver) {
return receiver; // This is in fact a move.
}
}; };
template <> template <>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment