| // 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 "content/browser/devtools/service_worker_devtools_agent_host.h" |
| |
| #include "base/strings/stringprintf.h" |
| #include "content/browser/devtools/devtools_session.h" |
| #include "content/browser/devtools/protocol/inspector_handler.h" |
| #include "content/browser/devtools/protocol/network_handler.h" |
| #include "content/browser/devtools/protocol/protocol.h" |
| #include "content/browser/devtools/protocol/schema_handler.h" |
| #include "content/browser/devtools/service_worker_devtools_manager.h" |
| #include "content/browser/service_worker/service_worker_context_core.h" |
| #include "content/browser/service_worker/service_worker_version.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_process_host.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| void TerminateServiceWorkerOnIO( |
| base::WeakPtr<ServiceWorkerContextCore> context_weak, |
| int64_t version_id) { |
| if (ServiceWorkerContextCore* context = context_weak.get()) { |
| if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id)) |
| version->StopWorker(base::BindOnce(&base::DoNothing)); |
| } |
| } |
| |
| void SetDevToolsAttachedOnIO( |
| base::WeakPtr<ServiceWorkerContextCore> context_weak, |
| int64_t version_id, |
| bool attached) { |
| if (ServiceWorkerContextCore* context = context_weak.get()) { |
| if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id)) |
| version->SetDevToolsAttached(attached); |
| } |
| } |
| |
| } // namespace |
| |
| ServiceWorkerDevToolsAgentHost::ServiceWorkerDevToolsAgentHost( |
| int worker_process_id, |
| int worker_route_id, |
| const ServiceWorkerContextCore* context, |
| base::WeakPtr<ServiceWorkerContextCore> context_weak, |
| int64_t version_id, |
| const GURL& url, |
| const GURL& scope, |
| bool is_installed_version, |
| const base::UnguessableToken& devtools_worker_token) |
| : DevToolsAgentHostImpl(devtools_worker_token.ToString()), |
| state_(WORKER_NOT_READY), |
| devtools_worker_token_(devtools_worker_token), |
| worker_process_id_(worker_process_id), |
| worker_route_id_(worker_route_id), |
| context_(context), |
| context_weak_(context_weak), |
| version_id_(version_id), |
| url_(url), |
| scope_(scope), |
| version_installed_time_(is_installed_version ? base::Time::Now() |
| : base::Time()) { |
| NotifyCreated(); |
| } |
| |
| BrowserContext* ServiceWorkerDevToolsAgentHost::GetBrowserContext() { |
| RenderProcessHost* rph = RenderProcessHost::FromID(worker_process_id_); |
| return rph ? rph->GetBrowserContext() : nullptr; |
| } |
| |
| std::string ServiceWorkerDevToolsAgentHost::GetType() { |
| return kTypeServiceWorker; |
| } |
| |
| std::string ServiceWorkerDevToolsAgentHost::GetTitle() { |
| return "Service Worker " + url_.spec(); |
| } |
| |
| GURL ServiceWorkerDevToolsAgentHost::GetURL() { |
| return url_; |
| } |
| |
| bool ServiceWorkerDevToolsAgentHost::Activate() { |
| return false; |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::Reload() { |
| } |
| |
| bool ServiceWorkerDevToolsAgentHost::Close() { |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, |
| base::BindOnce(&TerminateServiceWorkerOnIO, context_weak_, version_id_)); |
| return true; |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::WorkerVersionInstalled() { |
| version_installed_time_ = base::Time::Now(); |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::WorkerVersionDoomed() { |
| version_doomed_time_ = base::Time::Now(); |
| } |
| |
| bool ServiceWorkerDevToolsAgentHost::Matches( |
| const ServiceWorkerContextCore* context, |
| int64_t version_id) { |
| return context_ == context && version_id_ == version_id; |
| } |
| |
| ServiceWorkerDevToolsAgentHost::~ServiceWorkerDevToolsAgentHost() { |
| ServiceWorkerDevToolsManager::GetInstance()->AgentHostDestroyed(this); |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) { |
| if (state_ == WORKER_READY) { |
| if (sessions().size() == 1) { |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::BindOnce(&SetDevToolsAttachedOnIO, |
| context_weak_, version_id_, true)); |
| } |
| // RenderProcessHost should not be null here, but even if it _is_ null, |
| // session does not depend on the process to do messaging. |
| session->SetRenderer(RenderProcessHost::FromID(worker_process_id_), |
| nullptr); |
| session->AttachToAgent(agent_ptr_); |
| } |
| session->SetFallThroughForNotFound(true); |
| session->AddHandler(base::WrapUnique(new protocol::InspectorHandler())); |
| session->AddHandler(base::WrapUnique(new protocol::NetworkHandler(GetId()))); |
| session->AddHandler(base::WrapUnique(new protocol::SchemaHandler())); |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::DetachSession(DevToolsSession* session) { |
| // Destroying session automatically detaches in renderer. |
| if (state_ == WORKER_READY && sessions().empty()) { |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::BindOnce(&SetDevToolsAttachedOnIO, |
| context_weak_, version_id_, false)); |
| } |
| } |
| |
| bool ServiceWorkerDevToolsAgentHost::DispatchProtocolMessage( |
| DevToolsSession* session, |
| const std::string& message) { |
| int call_id = 0; |
| std::string method; |
| if (session->Dispatch(message, &call_id, &method) != |
| protocol::Response::kFallThrough) { |
| return true; |
| } |
| |
| session->DispatchProtocolMessageToAgent(call_id, method, message); |
| session->waiting_messages()[call_id] = {method, message}; |
| return true; |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::WorkerReadyForInspection( |
| blink::mojom::DevToolsAgentAssociatedPtrInfo devtools_agent_ptr_info) { |
| DCHECK_EQ(WORKER_NOT_READY, state_); |
| state_ = WORKER_READY; |
| agent_ptr_.Bind(std::move(devtools_agent_ptr_info)); |
| if (!sessions().empty()) { |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| base::BindOnce(&SetDevToolsAttachedOnIO, |
| context_weak_, version_id_, true)); |
| } |
| |
| // RenderProcessHost should not be null here, but even if it _is_ null, |
| // session does not depend on the process to do messaging. |
| RenderProcessHost* host = RenderProcessHost::FromID(worker_process_id_); |
| for (DevToolsSession* session : sessions()) { |
| session->SetRenderer(host, nullptr); |
| session->ReattachToAgent(agent_ptr_); |
| for (const auto& pair : session->waiting_messages()) { |
| int call_id = pair.first; |
| const DevToolsSession::Message& message = pair.second; |
| session->DispatchProtocolMessageToAgent(call_id, message.method, |
| message.message); |
| } |
| } |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::WorkerRestarted(int worker_process_id, |
| int worker_route_id) { |
| DCHECK_EQ(WORKER_TERMINATED, state_); |
| state_ = WORKER_NOT_READY; |
| worker_process_id_ = worker_process_id; |
| worker_route_id_ = worker_route_id; |
| RenderProcessHost* host = RenderProcessHost::FromID(worker_process_id_); |
| for (DevToolsSession* session : sessions()) |
| session->SetRenderer(host, nullptr); |
| } |
| |
| void ServiceWorkerDevToolsAgentHost::WorkerDestroyed() { |
| DCHECK_NE(WORKER_TERMINATED, state_); |
| state_ = WORKER_TERMINATED; |
| agent_ptr_.reset(); |
| for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) |
| inspector->TargetCrashed(); |
| for (DevToolsSession* session : sessions()) |
| session->SetRenderer(nullptr, nullptr); |
| } |
| |
| } // namespace content |