blob: d02bd173c6f188c58865a3b1c943ae6cb47e4740 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/workers/WorkerInspectorProxy.h"
#include "base/location.h"
#include "core/frame/FrameConsole.h"
#include "core/inspector/IdentifiersFactory.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "core/inspector/InspectorWorkerAgent.h"
#include "core/inspector/WorkerInspectorController.h"
#include "core/probe/CoreProbes.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/workers/WorkerThread.h"
#include "platform/CrossThreadFunctional.h"
#include "platform/WebTaskRunner.h"
#include "platform/instrumentation/tracing/TraceEvent.h"
#include "platform/weborigin/KURL.h"
namespace blink {
namespace {
static WorkerInspectorProxy::WorkerInspectorProxySet& InspectorProxies() {
DEFINE_STATIC_LOCAL(WorkerInspectorProxy::WorkerInspectorProxySet, proxies,
());
return proxies;
}
} // namespace
const WorkerInspectorProxy::WorkerInspectorProxySet&
WorkerInspectorProxy::AllProxies() {
return InspectorProxies();
}
WorkerInspectorProxy::WorkerInspectorProxy()
: worker_thread_(nullptr), execution_context_(nullptr) {}
WorkerInspectorProxy* WorkerInspectorProxy::Create() {
return new WorkerInspectorProxy();
}
WorkerInspectorProxy::~WorkerInspectorProxy() = default;
const String& WorkerInspectorProxy::InspectorId() {
if (inspector_id_.IsEmpty())
inspector_id_ = "dedicated:" + IdentifiersFactory::CreateIdentifier();
return inspector_id_;
}
WorkerInspectorProxy::PauseOnWorkerStart
WorkerInspectorProxy::ShouldPauseOnWorkerStart(
ExecutionContext* execution_context) {
bool result = false;
probe::shouldWaitForDebuggerOnWorkerStart(execution_context, &result);
return result ? PauseOnWorkerStart::kPause : PauseOnWorkerStart::kDontPause;
}
void WorkerInspectorProxy::WorkerThreadCreated(
ExecutionContext* execution_context,
WorkerThread* worker_thread,
const KURL& url) {
worker_thread_ = worker_thread;
execution_context_ = execution_context;
url_ = url.GetString();
InspectorProxies().insert(this);
// We expect everyone starting worker thread to synchronously ask for
// ShouldPauseOnWorkerStart() right before.
bool waiting_for_debugger = false;
probe::shouldWaitForDebuggerOnWorkerStart(execution_context_,
&waiting_for_debugger);
probe::didStartWorker(execution_context_, this, waiting_for_debugger);
}
void WorkerInspectorProxy::WorkerThreadTerminated() {
if (worker_thread_) {
DCHECK(InspectorProxies().Contains(this));
InspectorProxies().erase(this);
probe::workerTerminated(execution_context_, this);
}
worker_thread_ = nullptr;
page_inspectors_.clear();
execution_context_ = nullptr;
}
void WorkerInspectorProxy::DispatchMessageFromWorker(int session_id,
const String& message) {
auto it = page_inspectors_.find(session_id);
if (it != page_inspectors_.end())
it->value->DispatchMessageFromWorker(this, session_id, message);
}
void WorkerInspectorProxy::AddConsoleMessageFromWorker(
MessageLevel level,
const String& message,
std::unique_ptr<SourceLocation> location) {
execution_context_->AddConsoleMessage(ConsoleMessage::CreateFromWorker(
level, message, std::move(location), inspector_id_));
}
static void ConnectToWorkerGlobalScopeInspectorTask(
WorkerThread* worker_thread,
int session_id,
const String& parent_instrumentation_token) {
if (WorkerInspectorController* inspector =
worker_thread->GetWorkerInspectorController()) {
inspector->ConnectFrontend(session_id, parent_instrumentation_token);
}
}
void WorkerInspectorProxy::ConnectToInspector(
int session_id,
const String& parent_instrumentation_token,
WorkerInspectorProxy::PageInspector* page_inspector) {
if (!worker_thread_)
return;
DCHECK(page_inspectors_.find(session_id) == page_inspectors_.end());
page_inspectors_.insert(session_id, page_inspector);
worker_thread_->AppendDebuggerTask(
CrossThreadBind(ConnectToWorkerGlobalScopeInspectorTask,
CrossThreadUnretained(worker_thread_), session_id,
parent_instrumentation_token));
}
static void DisconnectFromWorkerGlobalScopeInspectorTask(
WorkerThread* worker_thread,
int session_id) {
if (WorkerInspectorController* inspector =
worker_thread->GetWorkerInspectorController()) {
inspector->DisconnectFrontend(session_id);
}
}
void WorkerInspectorProxy::DisconnectFromInspector(
int session_id,
WorkerInspectorProxy::PageInspector* page_inspector) {
DCHECK(page_inspectors_.at(session_id) == page_inspector);
page_inspectors_.erase(session_id);
if (worker_thread_) {
worker_thread_->AppendDebuggerTask(
CrossThreadBind(DisconnectFromWorkerGlobalScopeInspectorTask,
CrossThreadUnretained(worker_thread_), session_id));
}
}
static void DispatchOnInspectorBackendTask(int session_id,
const String& message,
WorkerThread* worker_thread) {
if (WorkerInspectorController* inspector =
worker_thread->GetWorkerInspectorController()) {
inspector->DispatchMessageFromFrontend(session_id, message);
}
}
void WorkerInspectorProxy::SendMessageToInspector(int session_id,
const String& message) {
if (worker_thread_) {
worker_thread_->AppendDebuggerTask(
CrossThreadBind(DispatchOnInspectorBackendTask, session_id, message,
CrossThreadUnretained(worker_thread_)));
}
}
void WorkerInspectorProxy::WriteTimelineStartedEvent(
const String& tracing_session_id) {
if (!worker_thread_)
return;
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
"TracingSessionIdForWorker", TRACE_EVENT_SCOPE_THREAD,
"data",
InspectorTracingSessionIdForWorkerEvent::Data(
tracing_session_id, InspectorId(), worker_thread_));
}
void WorkerInspectorProxy::Trace(blink::Visitor* visitor) {
visitor->Trace(execution_context_);
}
} // namespace blink