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/protocol/devtools_protocol_handler_impl.h"
9 #include "content/browser/service_worker/service_worker_context_core.h"
10 #include "content/browser/service_worker/service_worker_version.h"
11 #include "content/browser/shared_worker/shared_worker_service_impl.h"
12 #include "content/common/devtools_messages.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/render_process_host.h"
20 void TerminateSharedWorkerOnIO(
21 EmbeddedWorkerDevToolsAgentHost::WorkerId worker_id
) {
22 SharedWorkerServiceImpl::GetInstance()->TerminateWorker(
23 worker_id
.first
, worker_id
.second
);
26 void StatusNoOp(ServiceWorkerStatusCode status
) {
29 void TerminateServiceWorkerOnIO(
30 base::WeakPtr
<ServiceWorkerContextCore
> context_weak
,
32 if (ServiceWorkerContextCore
* context
= context_weak
.get()) {
33 if (ServiceWorkerVersion
* version
= context
->GetLiveVersion(version_id
))
34 version
->StopWorker(base::Bind(&StatusNoOp
));
40 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
42 const SharedWorkerInstance
& shared_worker
)
43 : shared_worker_(new SharedWorkerInstance(shared_worker
)),
44 state_(WORKER_UNINSPECTED
),
45 worker_id_(worker_id
) {
49 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
51 const ServiceWorkerIdentifier
& service_worker
,
52 bool debug_service_worker_on_start
)
53 : service_worker_(new ServiceWorkerIdentifier(service_worker
)),
54 state_(WORKER_UNINSPECTED
),
55 worker_id_(worker_id
) {
56 if (debug_service_worker_on_start
)
57 state_
= WORKER_PAUSED_FOR_DEBUG_ON_START
;
61 bool EmbeddedWorkerDevToolsAgentHost::IsWorker() const {
65 DevToolsAgentHost::Type
EmbeddedWorkerDevToolsAgentHost::GetType() {
66 return shared_worker_
? TYPE_SHARED_WORKER
: TYPE_SERVICE_WORKER
;
69 std::string
EmbeddedWorkerDevToolsAgentHost::GetTitle() {
70 if (shared_worker_
&& shared_worker_
->name().length())
71 return base::UTF16ToUTF8(shared_worker_
->name());
72 if (RenderProcessHost
* host
= RenderProcessHost::FromID(worker_id_
.first
)) {
73 return base::StringPrintf("Worker pid:%d",
74 base::GetProcId(host
->GetHandle()));
79 GURL
EmbeddedWorkerDevToolsAgentHost::GetURL() {
81 return shared_worker_
->url();
83 return service_worker_
->url();
87 bool EmbeddedWorkerDevToolsAgentHost::Activate() {
91 bool EmbeddedWorkerDevToolsAgentHost::Close() {
93 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
94 base::Bind(&TerminateSharedWorkerOnIO
, worker_id_
));
97 if (service_worker_
) {
98 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
99 base::Bind(&TerminateServiceWorkerOnIO
,
100 service_worker_
->context_weak(),
101 service_worker_
->version_id()));
107 void EmbeddedWorkerDevToolsAgentHost::SendMessageToAgent(
108 IPC::Message
* message_raw
) {
109 scoped_ptr
<IPC::Message
> message(message_raw
);
110 if (state_
!= WORKER_INSPECTED
)
112 if (RenderProcessHost
* host
= RenderProcessHost::FromID(worker_id_
.first
)) {
113 message
->set_routing_id(worker_id_
.second
);
114 host
->Send(message
.release());
118 void EmbeddedWorkerDevToolsAgentHost::Attach() {
119 if (state_
!= WORKER_INSPECTED
) {
120 state_
= WORKER_INSPECTED
;
123 IPCDevToolsAgentHost::Attach();
126 void EmbeddedWorkerDevToolsAgentHost::OnClientAttached() {
127 DevToolsAgentHostImpl::NotifyCallbacks(this, true);
130 void EmbeddedWorkerDevToolsAgentHost::OnClientDetached() {
131 if (state_
== WORKER_INSPECTED
) {
132 state_
= WORKER_UNINSPECTED
;
134 } else if (state_
== WORKER_PAUSED_FOR_REATTACH
) {
135 state_
= WORKER_UNINSPECTED
;
137 DevToolsAgentHostImpl::NotifyCallbacks(this, false);
140 bool EmbeddedWorkerDevToolsAgentHost::OnMessageReceived(
141 const IPC::Message
& msg
) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
144 IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost
, msg
)
145 IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend
,
146 OnDispatchOnInspectorFrontend
)
147 IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState
,
148 OnSaveAgentRuntimeState
)
149 IPC_MESSAGE_UNHANDLED(handled
= false)
150 IPC_END_MESSAGE_MAP()
154 void EmbeddedWorkerDevToolsAgentHost::WorkerReadyForInspection() {
155 if (state_
== WORKER_PAUSED_FOR_DEBUG_ON_START
) {
156 RenderProcessHost
* rph
= RenderProcessHost::FromID(worker_id_
.first
);
157 Inspect(rph
->GetBrowserContext());
158 } else if (state_
== WORKER_PAUSED_FOR_REATTACH
) {
159 DCHECK(IsAttached());
160 state_
= WORKER_INSPECTED
;
162 Reattach(saved_agent_state_
);
166 void EmbeddedWorkerDevToolsAgentHost::WorkerRestarted(WorkerId worker_id
) {
167 DCHECK_EQ(WORKER_TERMINATED
, state_
);
168 state_
= IsAttached() ? WORKER_PAUSED_FOR_REATTACH
: WORKER_UNINSPECTED
;
169 worker_id_
= worker_id
;
173 void EmbeddedWorkerDevToolsAgentHost::WorkerDestroyed() {
174 DCHECK_NE(WORKER_TERMINATED
, state_
);
175 if (state_
== WORKER_INSPECTED
) {
176 DCHECK(IsAttached());
177 // Client host is debugging this worker agent host.
178 base::Callback
<void(const std::string
&)> raw_message_callback(
179 base::Bind(&EmbeddedWorkerDevToolsAgentHost::SendMessageToClient
,
180 base::Unretained(this)));
181 devtools::worker::Client
worker(raw_message_callback
);
182 worker
.DisconnectedFromWorker(
183 devtools::worker::DisconnectedFromWorkerParams::Create());
186 state_
= WORKER_TERMINATED
;
187 Release(); // Balanced in WorkerCreated()
190 bool EmbeddedWorkerDevToolsAgentHost::Matches(
191 const SharedWorkerInstance
& other
) {
192 return shared_worker_
&& shared_worker_
->Matches(other
);
195 bool EmbeddedWorkerDevToolsAgentHost::Matches(
196 const ServiceWorkerIdentifier
& other
) {
197 return service_worker_
&& service_worker_
->Matches(other
);
200 bool EmbeddedWorkerDevToolsAgentHost::IsTerminated() {
201 return state_
== WORKER_TERMINATED
;
204 EmbeddedWorkerDevToolsAgentHost::~EmbeddedWorkerDevToolsAgentHost() {
205 DCHECK_EQ(WORKER_TERMINATED
, state_
);
206 EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
210 void EmbeddedWorkerDevToolsAgentHost::AttachToWorker() {
211 if (RenderProcessHost
* host
= RenderProcessHost::FromID(worker_id_
.first
))
212 host
->AddRoute(worker_id_
.second
, this);
215 void EmbeddedWorkerDevToolsAgentHost::DetachFromWorker() {
216 if (RenderProcessHost
* host
= RenderProcessHost::FromID(worker_id_
.first
))
217 host
->RemoveRoute(worker_id_
.second
);
220 void EmbeddedWorkerDevToolsAgentHost::WorkerCreated() {
221 AddRef(); // Balanced in WorkerDestroyed()
224 void EmbeddedWorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend(
225 const std::string
& message
,
230 ProcessChunkedMessageFromAgent(message
, total_size
);
233 BrowserContext
* EmbeddedWorkerDevToolsAgentHost::GetBrowserContext() {
234 RenderProcessHost
* rph
= RenderProcessHost::FromID(worker_id_
.first
);
235 return rph
? rph
->GetBrowserContext() : nullptr;
238 void EmbeddedWorkerDevToolsAgentHost::OnSaveAgentRuntimeState(
239 const std::string
& state
) {
240 saved_agent_state_
= state
;
243 } // namespace content