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.
4
5 #include "content/browser/devtools/embedded_worker_devtools_agent_host.h"
6
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"
16
17 namespace content {
18
19 namespace {
20
TerminateSharedWorkerOnIO(EmbeddedWorkerDevToolsAgentHost::WorkerId worker_id)21 void TerminateSharedWorkerOnIO(
22 EmbeddedWorkerDevToolsAgentHost::WorkerId worker_id) {
23 SharedWorkerServiceImpl::GetInstance()->TerminateWorker(
24 worker_id.first, worker_id.second);
25 }
26
StatusNoOp(ServiceWorkerStatusCode status)27 void StatusNoOp(ServiceWorkerStatusCode status) {
28 }
29
TerminateServiceWorkerOnIO(base::WeakPtr<ServiceWorkerContextCore> context_weak,int64 version_id)30 void TerminateServiceWorkerOnIO(
31 base::WeakPtr<ServiceWorkerContextCore> context_weak,
32 int64 version_id) {
33 if (ServiceWorkerContextCore* context = context_weak.get()) {
34 if (ServiceWorkerVersion* version = context->GetLiveVersion(version_id))
35 version->StopWorker(base::Bind(&StatusNoOp));
36 }
37 }
38
39 }
40
EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id,const SharedWorkerInstance & shared_worker)41 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
42 WorkerId worker_id,
43 const SharedWorkerInstance& shared_worker)
44 : shared_worker_(new SharedWorkerInstance(shared_worker)),
45 state_(WORKER_UNINSPECTED),
46 worker_id_(worker_id) {
47 WorkerCreated();
48 }
49
EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id,const ServiceWorkerIdentifier & service_worker,bool debug_service_worker_on_start)50 EmbeddedWorkerDevToolsAgentHost::EmbeddedWorkerDevToolsAgentHost(
51 WorkerId worker_id,
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;
59 WorkerCreated();
60 }
61
IsWorker() const62 bool EmbeddedWorkerDevToolsAgentHost::IsWorker() const {
63 return true;
64 }
65
GetType()66 DevToolsAgentHost::Type EmbeddedWorkerDevToolsAgentHost::GetType() {
67 return shared_worker_ ? TYPE_SHARED_WORKER : TYPE_SERVICE_WORKER;
68 }
69
GetTitle()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()));
76 }
77 return "";
78 }
79
GetURL()80 GURL EmbeddedWorkerDevToolsAgentHost::GetURL() {
81 if (shared_worker_)
82 return shared_worker_->url();
83 if (service_worker_)
84 return service_worker_->url();
85 return GURL();
86 }
87
Activate()88 bool EmbeddedWorkerDevToolsAgentHost::Activate() {
89 return false;
90 }
91
Close()92 bool EmbeddedWorkerDevToolsAgentHost::Close() {
93 if (shared_worker_) {
94 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
95 base::Bind(&TerminateSharedWorkerOnIO, worker_id_));
96 return true;
97 }
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()));
103 return true;
104 }
105 return false;
106 }
107
SendMessageToAgent(IPC::Message * message_raw)108 void EmbeddedWorkerDevToolsAgentHost::SendMessageToAgent(
109 IPC::Message* message_raw) {
110 scoped_ptr<IPC::Message> message(message_raw);
111 if (state_ != WORKER_INSPECTED)
112 return;
113 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
114 message->set_routing_id(worker_id_.second);
115 host->Send(message.release());
116 }
117 }
118
Attach()119 void EmbeddedWorkerDevToolsAgentHost::Attach() {
120 if (state_ != WORKER_INSPECTED) {
121 state_ = WORKER_INSPECTED;
122 AttachToWorker();
123 }
124 IPCDevToolsAgentHost::Attach();
125 }
126
OnClientDetached()127 void EmbeddedWorkerDevToolsAgentHost::OnClientDetached() {
128 if (state_ == WORKER_INSPECTED) {
129 state_ = WORKER_UNINSPECTED;
130 DetachFromWorker();
131 } else if (state_ == WORKER_PAUSED_FOR_REATTACH) {
132 state_ = WORKER_UNINSPECTED;
133 }
134 }
135
OnMessageReceived(const IPC::Message & msg)136 bool EmbeddedWorkerDevToolsAgentHost::OnMessageReceived(
137 const IPC::Message& msg) {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139 bool handled = true;
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()
147 return handled;
148 }
149
WorkerReadyForInspection()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;
157 AttachToWorker();
158 Reattach(saved_agent_state_);
159 }
160 }
161
WorkerContextStarted()162 void EmbeddedWorkerDevToolsAgentHost::WorkerContextStarted() {
163 }
164
WorkerRestarted(WorkerId worker_id)165 void EmbeddedWorkerDevToolsAgentHost::WorkerRestarted(WorkerId worker_id) {
166 DCHECK_EQ(WORKER_TERMINATED, state_);
167 state_ = IsAttached() ? WORKER_PAUSED_FOR_REATTACH : WORKER_UNINSPECTED;
168 worker_id_ = worker_id;
169 WorkerCreated();
170 }
171
WorkerDestroyed()172 void EmbeddedWorkerDevToolsAgentHost::WorkerDestroyed() {
173 DCHECK_NE(WORKER_TERMINATED, state_);
174 if (state_ == WORKER_INSPECTED) {
175 DCHECK(IsAttached());
176 // Client host is debugging this worker agent host.
177 std::string notification =
178 DevToolsProtocol::CreateNotification(
179 devtools::Worker::disconnectedFromWorker::kName, NULL)->Serialize();
180 SendMessageToClient(notification);
181 DetachFromWorker();
182 }
183 state_ = WORKER_TERMINATED;
184 Release(); // Balanced in WorkerCreated()
185 }
186
Matches(const SharedWorkerInstance & other)187 bool EmbeddedWorkerDevToolsAgentHost::Matches(
188 const SharedWorkerInstance& other) {
189 return shared_worker_ && shared_worker_->Matches(other);
190 }
191
Matches(const ServiceWorkerIdentifier & other)192 bool EmbeddedWorkerDevToolsAgentHost::Matches(
193 const ServiceWorkerIdentifier& other) {
194 return service_worker_ && service_worker_->Matches(other);
195 }
196
IsTerminated()197 bool EmbeddedWorkerDevToolsAgentHost::IsTerminated() {
198 return state_ == WORKER_TERMINATED;
199 }
200
~EmbeddedWorkerDevToolsAgentHost()201 EmbeddedWorkerDevToolsAgentHost::~EmbeddedWorkerDevToolsAgentHost() {
202 DCHECK_EQ(WORKER_TERMINATED, state_);
203 EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData(
204 worker_id_);
205 }
206
AttachToWorker()207 void EmbeddedWorkerDevToolsAgentHost::AttachToWorker() {
208 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
209 host->AddRoute(worker_id_.second, this);
210 }
211
DetachFromWorker()212 void EmbeddedWorkerDevToolsAgentHost::DetachFromWorker() {
213 if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
214 host->RemoveRoute(worker_id_.second);
215 }
216
WorkerCreated()217 void EmbeddedWorkerDevToolsAgentHost::WorkerCreated() {
218 AddRef(); // Balanced in WorkerDestroyed()
219 }
220
OnDispatchOnInspectorFrontend(const std::string & message)221 void EmbeddedWorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend(
222 const std::string& message) {
223 SendMessageToClient(message);
224 }
225
OnSaveAgentRuntimeState(const std::string & state)226 void EmbeddedWorkerDevToolsAgentHost::OnSaveAgentRuntimeState(
227 const std::string& state) {
228 saved_agent_state_ = state;
229 }
230
231 } // namespace content
232