Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / shared_worker / shared_worker_host.cc
bloba54ecc33aff031ac76776d0cca1c6d345c6e9d11
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/shared_worker/shared_worker_host.h"
7 #include "base/metrics/histogram.h"
8 #include "content/browser/devtools/embedded_worker_devtools_manager.h"
9 #include "content/browser/frame_host/render_frame_host_delegate.h"
10 #include "content/browser/frame_host/render_frame_host_impl.h"
11 #include "content/browser/message_port_service.h"
12 #include "content/browser/shared_worker/shared_worker_instance.h"
13 #include "content/browser/shared_worker/shared_worker_message_filter.h"
14 #include "content/browser/shared_worker/shared_worker_service_impl.h"
15 #include "content/browser/shared_worker/worker_document_set.h"
16 #include "content/common/view_messages.h"
17 #include "content/common/worker_messages.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/common/content_client.h"
23 namespace content {
24 namespace {
26 // Notifies RenderViewHost that one or more worker objects crashed.
27 void WorkerCrashCallback(int render_process_unique_id, int render_frame_id) {
28 RenderFrameHostImpl* host =
29 RenderFrameHostImpl::FromID(render_process_unique_id, render_frame_id);
30 if (host)
31 host->delegate()->WorkerCrashed(host);
34 void NotifyWorkerReadyForInspection(int worker_process_id,
35 int worker_route_id) {
36 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
37 BrowserThread::PostTask(BrowserThread::UI,
38 FROM_HERE,
39 base::Bind(NotifyWorkerReadyForInspection,
40 worker_process_id,
41 worker_route_id));
42 return;
44 EmbeddedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
45 worker_process_id, worker_route_id);
48 void NotifyWorkerContextStarted(int worker_process_id, int worker_route_id) {
49 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
50 BrowserThread::PostTask(
51 BrowserThread::UI,
52 FROM_HERE,
53 base::Bind(
54 NotifyWorkerContextStarted, worker_process_id, worker_route_id));
55 return;
57 EmbeddedWorkerDevToolsManager::GetInstance()->WorkerContextStarted(
58 worker_process_id, worker_route_id);
61 void NotifyWorkerDestroyed(int worker_process_id, int worker_route_id) {
62 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
63 BrowserThread::PostTask(
64 BrowserThread::UI,
65 FROM_HERE,
66 base::Bind(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
67 return;
69 EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
70 worker_process_id, worker_route_id);
73 } // namespace
75 SharedWorkerHost::SharedWorkerHost(SharedWorkerInstance* instance,
76 SharedWorkerMessageFilter* filter,
77 int worker_route_id)
78 : instance_(instance),
79 worker_document_set_(new WorkerDocumentSet()),
80 weak_factory_(this),
81 container_render_filter_(filter),
82 worker_process_id_(filter->render_process_id()),
83 worker_route_id_(worker_route_id),
84 load_failed_(false),
85 closed_(false),
86 creation_time_(base::TimeTicks::Now()) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
90 SharedWorkerHost::~SharedWorkerHost() {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92 UMA_HISTOGRAM_LONG_TIMES("SharedWorker.TimeToDeleted",
93 base::TimeTicks::Now() - creation_time_);
94 // If we crashed, tell the RenderViewHosts.
95 if (instance_ && !load_failed_) {
96 const WorkerDocumentSet::DocumentInfoSet& parents =
97 worker_document_set_->documents();
98 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
99 parents.begin();
100 parent_iter != parents.end();
101 ++parent_iter) {
102 BrowserThread::PostTask(BrowserThread::UI,
103 FROM_HERE,
104 base::Bind(&WorkerCrashCallback,
105 parent_iter->render_process_id(),
106 parent_iter->render_frame_id()));
109 if (!closed_)
110 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
111 SharedWorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
112 worker_process_id_, worker_route_id_);
115 bool SharedWorkerHost::Send(IPC::Message* message) {
116 if (!container_render_filter_) {
117 delete message;
118 return false;
120 return container_render_filter_->Send(message);
123 void SharedWorkerHost::Start(bool pause_on_start) {
124 WorkerProcessMsg_CreateWorker_Params params;
125 params.url = instance_->url();
126 params.name = instance_->name();
127 params.content_security_policy = instance_->content_security_policy();
128 params.security_policy_type = instance_->security_policy_type();
129 params.pause_on_start = pause_on_start;
130 params.route_id = worker_route_id_;
131 Send(new WorkerProcessMsg_CreateWorker(params));
133 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
134 ++i) {
135 i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
139 bool SharedWorkerHost::FilterMessage(const IPC::Message& message,
140 SharedWorkerMessageFilter* filter) {
141 if (!instance_)
142 return false;
144 if (!closed_ && HasFilter(filter, message.routing_id())) {
145 RelayMessage(message, filter);
146 return true;
149 return false;
152 void SharedWorkerHost::FilterShutdown(SharedWorkerMessageFilter* filter) {
153 if (!instance_)
154 return;
155 RemoveFilters(filter);
156 worker_document_set_->RemoveAll(filter);
157 if (worker_document_set_->IsEmpty()) {
158 // This worker has no more associated documents - shut it down.
159 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
163 void SharedWorkerHost::DocumentDetached(SharedWorkerMessageFilter* filter,
164 unsigned long long document_id) {
165 if (!instance_)
166 return;
167 // Walk all instances and remove the document from their document set.
168 worker_document_set_->Remove(filter, document_id);
169 if (worker_document_set_->IsEmpty()) {
170 // This worker has no more associated documents - shut it down.
171 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
175 void SharedWorkerHost::WorkerContextClosed() {
176 if (!instance_)
177 return;
178 // Set the closed flag - this will stop any further messages from
179 // being sent to the worker (messages can still be sent from the worker,
180 // for exception reporting, etc).
181 closed_ = true;
182 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
185 void SharedWorkerHost::WorkerContextDestroyed() {
186 if (!instance_)
187 return;
188 instance_.reset();
189 worker_document_set_ = NULL;
192 void SharedWorkerHost::WorkerReadyForInspection() {
193 NotifyWorkerReadyForInspection(worker_process_id_, worker_route_id_);
196 void SharedWorkerHost::WorkerScriptLoaded() {
197 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoaded",
198 base::TimeTicks::Now() - creation_time_);
199 NotifyWorkerContextStarted(worker_process_id_, worker_route_id_);
202 void SharedWorkerHost::WorkerScriptLoadFailed() {
203 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoadFailed",
204 base::TimeTicks::Now() - creation_time_);
205 if (!instance_)
206 return;
207 load_failed_ = true;
208 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
209 ++i) {
210 i->filter()->Send(new ViewMsg_WorkerScriptLoadFailed(i->route_id()));
214 void SharedWorkerHost::WorkerConnected(int message_port_id) {
215 if (!instance_)
216 return;
217 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
218 ++i) {
219 if (i->message_port_id() != message_port_id)
220 continue;
221 i->filter()->Send(new ViewMsg_WorkerConnected(i->route_id()));
222 return;
226 void SharedWorkerHost::AllowDatabase(const GURL& url,
227 const base::string16& name,
228 const base::string16& display_name,
229 unsigned long estimated_size,
230 bool* result) {
231 if (!instance_)
232 return;
233 *result = GetContentClient()->browser()->AllowWorkerDatabase(
234 url,
235 name,
236 display_name,
237 estimated_size,
238 instance_->resource_context(),
239 GetRenderFrameIDsForWorker());
242 void SharedWorkerHost::AllowFileSystem(const GURL& url,
243 scoped_ptr<IPC::Message> reply_msg) {
244 if (!instance_)
245 return;
246 GetContentClient()->browser()->AllowWorkerFileSystem(
247 url,
248 instance_->resource_context(),
249 GetRenderFrameIDsForWorker(),
250 base::Bind(&SharedWorkerHost::AllowFileSystemResponse,
251 weak_factory_.GetWeakPtr(),
252 base::Passed(&reply_msg)));
255 void SharedWorkerHost::AllowFileSystemResponse(
256 scoped_ptr<IPC::Message> reply_msg,
257 bool allowed) {
258 WorkerProcessHostMsg_RequestFileSystemAccessSync::WriteReplyParams(
259 reply_msg.get(),
260 allowed);
261 Send(reply_msg.release());
264 void SharedWorkerHost::AllowIndexedDB(const GURL& url,
265 const base::string16& name,
266 bool* result) {
267 if (!instance_)
268 return;
269 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
270 url, name, instance_->resource_context(), GetRenderFrameIDsForWorker());
273 void SharedWorkerHost::RelayMessage(
274 const IPC::Message& message,
275 SharedWorkerMessageFilter* incoming_filter) {
276 if (!instance_)
277 return;
278 if (message.type() == WorkerMsg_Connect::ID) {
279 // Crack the SharedWorker Connect message to setup routing for the port.
280 WorkerMsg_Connect::Param param;
281 if (!WorkerMsg_Connect::Read(&message, &param))
282 return;
283 int sent_message_port_id = param.a;
284 int new_routing_id = param.b;
286 DCHECK(container_render_filter_);
287 new_routing_id = container_render_filter_->GetNextRoutingID();
288 MessagePortService::GetInstance()->UpdateMessagePort(
289 sent_message_port_id,
290 container_render_filter_->message_port_message_filter(),
291 new_routing_id);
292 SetMessagePortID(
293 incoming_filter, message.routing_id(), sent_message_port_id);
294 // Resend the message with the new routing id.
295 Send(new WorkerMsg_Connect(
296 worker_route_id_, sent_message_port_id, new_routing_id));
298 // Send any queued messages for the sent port.
299 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
300 sent_message_port_id);
301 } else {
302 IPC::Message* new_message = new IPC::Message(message);
303 new_message->set_routing_id(worker_route_id_);
304 Send(new_message);
305 return;
309 void SharedWorkerHost::TerminateWorker() {
310 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
313 std::vector<std::pair<int, int> >
314 SharedWorkerHost::GetRenderFrameIDsForWorker() {
315 std::vector<std::pair<int, int> > result;
316 if (!instance_)
317 return result;
318 const WorkerDocumentSet::DocumentInfoSet& documents =
319 worker_document_set_->documents();
320 for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
321 documents.begin();
322 doc != documents.end();
323 ++doc) {
324 result.push_back(
325 std::make_pair(doc->render_process_id(), doc->render_frame_id()));
327 return result;
330 void SharedWorkerHost::AddFilter(SharedWorkerMessageFilter* filter,
331 int route_id) {
332 CHECK(filter);
333 if (!HasFilter(filter, route_id)) {
334 FilterInfo info(filter, route_id);
335 filters_.push_back(info);
339 void SharedWorkerHost::RemoveFilters(SharedWorkerMessageFilter* filter) {
340 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
341 if (i->filter() == filter)
342 i = filters_.erase(i);
343 else
344 ++i;
348 bool SharedWorkerHost::HasFilter(SharedWorkerMessageFilter* filter,
349 int route_id) const {
350 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
351 ++i) {
352 if (i->filter() == filter && i->route_id() == route_id)
353 return true;
355 return false;
358 void SharedWorkerHost::SetMessagePortID(SharedWorkerMessageFilter* filter,
359 int route_id,
360 int message_port_id) {
361 for (FilterList::iterator i = filters_.begin(); i != filters_.end(); ++i) {
362 if (i->filter() == filter && i->route_id() == route_id) {
363 i->set_message_port_id(message_port_id);
364 return;
369 } // namespace content