• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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