1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/devtools/embedded_worker_devtools_agent_host.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/devtools/devtools_protocol.h"
9 #include "content/browser/devtools/devtools_protocol_constants.h"
10 #include "content/browser/service_worker/service_worker_context_core.h"
11 #include "content/browser/service_worker/service_worker_version.h"
12 #include "content/browser/shared_worker/shared_worker_service_impl.h"
13 #include "content/common/devtools_messages.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/render_process_host.h"
21 void TerminateSharedWorkerOnIO(
22 EmbeddedWorkerDevToolsAgentHost::WorkerId worker_id) {
23 SharedWorkerServiceImpl::GetInstance()->TerminateWorker(
24 worker_id.first, worker_id.second);
27 void StatusNoOp(ServiceWorkerStatusCode status) {
30 void TerminateServiceWorkerOnIO(
31 base::WeakPtr<ServiceWorkerContextCore> context_weak,
33 if (ServiceWorkerContextCore* context = context_weak.get()) {
34 if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id))
35 version->StopWorker(base::Bind(&StatusNoOp));
41 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
43 const SharedWorkerInstance& shared_worker)
44 : shared_worker_(new SharedWorkerInstance(shared_worker)),
45 state_(WORKER_UNINSPECTED),
46 worker_id_(worker_id) {
50 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
52 const ServiceWorkerIdentifier& service_worker,
53 bool debug_service_worker_on_start)
54 : service_worker_(new ServiceWorkerIdentifier(service_worker)),
55 state_(WORKER_UNINSPECTED),
56 worker_id_(worker_id) {
57 if (debug_service_worker_on_start)
58 state_ = WORKER_PAUSED_FOR_DEBUG_ON_START;
62 bool EmbeddedWorkerDevToolsAgentHost::IsWorker() const {
66 DevToolsAgentHost::Type EmbeddedWorkerDevToolsAgentHost::GetType() {
67 return shared_worker_ ? TYPE_SHARED_WORKER : TYPE_SERVICE_WORKER;
70 std::string EmbeddedWorkerDevToolsAgentHost::GetTitle() {
71 if (shared_worker_ && shared_worker_->name().length())
72 return base::UTF16ToUTF8(shared_worker_->name());
73 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
74 return base::StringPrintf("Worker pid:%d",
75 base::GetProcId(host->GetHandle()));
80 GURL EmbeddedWorkerDevToolsAgentHost::GetURL() {
82 return shared_worker_->url();
84 return service_worker_->url();
88 bool EmbeddedWorkerDevToolsAgentHost::Activate() {
92 bool EmbeddedWorkerDevToolsAgentHost::Close() {
94 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
95 base::Bind(&TerminateSharedWorkerOnIO, worker_id_));
98 if (service_worker_) {
99 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
100 base::Bind(&TerminateServiceWorkerOnIO,
101 service_worker_->context_weak(),
102 service_worker_->version_id()));
108 void EmbeddedWorkerDevToolsAgentHost::SendMessageToAgent(
109 IPC::Message* message_raw) {
110 scoped_ptr<IPC::Message> message(message_raw);
111 if (state_ != WORKER_INSPECTED)
113 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
114 message->set_routing_id(worker_id_.second);
115 host->Send(message.release());
119 void EmbeddedWorkerDevToolsAgentHost::Attach() {
120 if (state_ != WORKER_INSPECTED) {
121 state_ = WORKER_INSPECTED;
124 IPCDevToolsAgentHost::Attach();
127 void EmbeddedWorkerDevToolsAgentHost::OnClientDetached() {
128 if (state_ == WORKER_INSPECTED) {
129 state_ = WORKER_UNINSPECTED;
131 } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
132 state_ = WORKER_UNINSPECTED;
136 bool EmbeddedWorkerDevToolsAgentHost::OnMessageReceived(
137 const IPC::Message& msg) {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140 IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost, msg)
141 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
142 OnDispatchOnInspectorFrontend)
143 IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState,
144 OnSaveAgentRuntimeState)
145 IPC_MESSAGE_UNHANDLED(handled = false)
146 IPC_END_MESSAGE_MAP()
150 void EmbeddedWorkerDevToolsAgentHost::WorkerReadyForInspection() {
151 if (state_ == WORKER_PAUSED_FOR_DEBUG_ON_START) {
152 RenderProcessHost* rph = RenderProcessHost::FromID(worker_id_.first);
153 Inspect(rph->GetBrowserContext());
154 } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
155 DCHECK(IsAttached());
156 state_ = WORKER_INSPECTED;
158 Reattach(saved_agent_state_);
162 void EmbeddedWorkerDevToolsAgentHost::WorkerRestarted(WorkerId worker_id) {
163 DCHECK_EQ(WORKER_TERMINATED, state_);
164 state_ = IsAttached() ? WORKER_PAUSED_FOR_REATTACH : WORKER_UNINSPECTED;
165 worker_id_ = worker_id;
169 void EmbeddedWorkerDevToolsAgentHost::WorkerDestroyed() {
170 DCHECK_NE(WORKER_TERMINATED, state_);
171 if (state_ == WORKER_INSPECTED) {
172 DCHECK(IsAttached());
173 // Client host is debugging this worker agent host.
174 std::string notification =
175 DevToolsProtocol::CreateNotification(
176 devtools::Worker::disconnectedFromWorker::kName, NULL)->Serialize();
177 SendMessageToClient(notification);
180 state_ = WORKER_TERMINATED;
181 Release(); // Balanced in WorkerCreated()
184 bool EmbeddedWorkerDevToolsAgentHost::Matches(
185 const SharedWorkerInstance& other) {
186 return shared_worker_ && shared_worker_->Matches(other);
189 bool EmbeddedWorkerDevToolsAgentHost::Matches(
190 const ServiceWorkerIdentifier& other) {
191 return service_worker_ && service_worker_->Matches(other);
194 bool EmbeddedWorkerDevToolsAgentHost::IsTerminated() {
195 return state_ == WORKER_TERMINATED;
198 EmbeddedWorkerDevToolsAgentHost::~EmbeddedWorkerDevToolsAgentHost() {
199 DCHECK_EQ(WORKER_TERMINATED, state_);
200 EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
204 void EmbeddedWorkerDevToolsAgentHost::AttachToWorker() {
205 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
206 host->AddRoute(worker_id_.second, this);
209 void EmbeddedWorkerDevToolsAgentHost::DetachFromWorker() {
210 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
211 host->RemoveRoute(worker_id_.second);
214 void EmbeddedWorkerDevToolsAgentHost::WorkerCreated() {
215 AddRef(); // Balanced in WorkerDestroyed()
218 void EmbeddedWorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend(
219 const std::string& message,
224 ProcessChunkedMessageFromAgent(message, total_size);
227 void EmbeddedWorkerDevToolsAgentHost::OnSaveAgentRuntimeState(
228 const std::string& state) {
229 saved_agent_state_ = state;
232 } // namespace content