cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / shared_worker / shared_worker_host.cc
blob40499930675640e8450c73b82d9647f51a89f46b
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 NotifyWorkerDestroyed(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(NotifyWorkerDestroyed, worker_process_id, worker_route_id));
54 return;
56 EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
57 worker_process_id, worker_route_id);
60 } // namespace
62 SharedWorkerHost::SharedWorkerHost(SharedWorkerInstance* instance,
63 SharedWorkerMessageFilter* filter,
64 int worker_route_id)
65 : instance_(instance),
66 worker_document_set_(new WorkerDocumentSet()),
67 container_render_filter_(filter),
68 worker_process_id_(filter->render_process_id()),
69 worker_route_id_(worker_route_id),
70 load_failed_(false),
71 closed_(false),
72 creation_time_(base::TimeTicks::Now()),
73 weak_factory_(this) {
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
77 SharedWorkerHost::~SharedWorkerHost() {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
79 UMA_HISTOGRAM_LONG_TIMES("SharedWorker.TimeToDeleted",
80 base::TimeTicks::Now() - creation_time_);
81 // If we crashed, tell the RenderViewHosts.
82 if (instance_ && !load_failed_) {
83 const WorkerDocumentSet::DocumentInfoSet& parents =
84 worker_document_set_->documents();
85 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
86 parents.begin();
87 parent_iter != parents.end();
88 ++parent_iter) {
89 BrowserThread::PostTask(BrowserThread::UI,
90 FROM_HERE,
91 base::Bind(&WorkerCrashCallback,
92 parent_iter->render_process_id(),
93 parent_iter->render_frame_id()));
96 if (!closed_)
97 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
98 SharedWorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
99 worker_process_id_, worker_route_id_);
102 bool SharedWorkerHost::Send(IPC::Message* message) {
103 if (!container_render_filter_) {
104 delete message;
105 return false;
107 return container_render_filter_->Send(message);
110 void SharedWorkerHost::Start(bool pause_on_start) {
111 WorkerProcessMsg_CreateWorker_Params params;
112 params.url = instance_->url();
113 params.name = instance_->name();
114 params.content_security_policy = instance_->content_security_policy();
115 params.security_policy_type = instance_->security_policy_type();
116 params.pause_on_start = pause_on_start;
117 params.route_id = worker_route_id_;
118 Send(new WorkerProcessMsg_CreateWorker(params));
120 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
121 ++i) {
122 i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
126 bool SharedWorkerHost::FilterMessage(const IPC::Message& message,
127 SharedWorkerMessageFilter* filter) {
128 if (!instance_)
129 return false;
131 if (!closed_ && HasFilter(filter, message.routing_id())) {
132 RelayMessage(message, filter);
133 return true;
136 return false;
139 void SharedWorkerHost::FilterShutdown(SharedWorkerMessageFilter* filter) {
140 if (!instance_)
141 return;
142 RemoveFilters(filter);
143 worker_document_set_->RemoveAll(filter);
144 if (worker_document_set_->IsEmpty()) {
145 // This worker has no more associated documents - shut it down.
146 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
150 void SharedWorkerHost::DocumentDetached(SharedWorkerMessageFilter* filter,
151 unsigned long long document_id) {
152 if (!instance_)
153 return;
154 // Walk all instances and remove the document from their document set.
155 worker_document_set_->Remove(filter, document_id);
156 if (worker_document_set_->IsEmpty()) {
157 // This worker has no more associated documents - shut it down.
158 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
162 void SharedWorkerHost::WorkerContextClosed() {
163 if (!instance_)
164 return;
165 // Set the closed flag - this will stop any further messages from
166 // being sent to the worker (messages can still be sent from the worker,
167 // for exception reporting, etc).
168 closed_ = true;
169 NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
172 void SharedWorkerHost::WorkerContextDestroyed() {
173 if (!instance_)
174 return;
175 instance_.reset();
176 worker_document_set_ = NULL;
179 void SharedWorkerHost::WorkerReadyForInspection() {
180 NotifyWorkerReadyForInspection(worker_process_id_, worker_route_id_);
183 void SharedWorkerHost::WorkerScriptLoaded() {
184 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoaded",
185 base::TimeTicks::Now() - creation_time_);
188 void SharedWorkerHost::WorkerScriptLoadFailed() {
189 UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoadFailed",
190 base::TimeTicks::Now() - creation_time_);
191 if (!instance_)
192 return;
193 load_failed_ = true;
194 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
195 ++i) {
196 i->filter()->Send(new ViewMsg_WorkerScriptLoadFailed(i->route_id()));
200 void SharedWorkerHost::WorkerConnected(int message_port_id) {
201 if (!instance_)
202 return;
203 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
204 ++i) {
205 if (i->message_port_id() != message_port_id)
206 continue;
207 i->filter()->Send(new ViewMsg_WorkerConnected(i->route_id()));
208 return;
212 void SharedWorkerHost::AllowDatabase(const GURL& url,
213 const base::string16& name,
214 const base::string16& display_name,
215 unsigned long estimated_size,
216 bool* result) {
217 if (!instance_)
218 return;
219 *result = GetContentClient()->browser()->AllowWorkerDatabase(
220 url,
221 name,
222 display_name,
223 estimated_size,
224 instance_->resource_context(),
225 GetRenderFrameIDsForWorker());
228 void SharedWorkerHost::AllowFileSystem(const GURL& url,
229 scoped_ptr<IPC::Message> reply_msg) {
230 if (!instance_)
231 return;
232 GetContentClient()->browser()->AllowWorkerFileSystem(
233 url,
234 instance_->resource_context(),
235 GetRenderFrameIDsForWorker(),
236 base::Bind(&SharedWorkerHost::AllowFileSystemResponse,
237 weak_factory_.GetWeakPtr(),
238 base::Passed(&reply_msg)));
241 void SharedWorkerHost::AllowFileSystemResponse(
242 scoped_ptr<IPC::Message> reply_msg,
243 bool allowed) {
244 WorkerProcessHostMsg_RequestFileSystemAccessSync::WriteReplyParams(
245 reply_msg.get(),
246 allowed);
247 Send(reply_msg.release());
250 void SharedWorkerHost::AllowIndexedDB(const GURL& url,
251 const base::string16& name,
252 bool* result) {
253 if (!instance_)
254 return;
255 *result = GetContentClient()->browser()->AllowWorkerIndexedDB(
256 url, name, instance_->resource_context(), GetRenderFrameIDsForWorker());
259 void SharedWorkerHost::RelayMessage(
260 const IPC::Message& message,
261 SharedWorkerMessageFilter* incoming_filter) {
262 if (!instance_)
263 return;
264 if (message.type() == WorkerMsg_Connect::ID) {
265 // Crack the SharedWorker Connect message to setup routing for the port.
266 WorkerMsg_Connect::Param param;
267 if (!WorkerMsg_Connect::Read(&message, &param))
268 return;
269 int sent_message_port_id = param.a;
270 int new_routing_id = param.b;
272 DCHECK(container_render_filter_);
273 new_routing_id = container_render_filter_->GetNextRoutingID();
274 MessagePortService::GetInstance()->UpdateMessagePort(
275 sent_message_port_id,
276 container_render_filter_->message_port_message_filter(),
277 new_routing_id);
278 SetMessagePortID(
279 incoming_filter, message.routing_id(), sent_message_port_id);
280 // Resend the message with the new routing id.
281 Send(new WorkerMsg_Connect(
282 worker_route_id_, sent_message_port_id, new_routing_id));
284 // Send any queued messages for the sent port.
285 MessagePortService::GetInstance()->SendQueuedMessagesIfPossible(
286 sent_message_port_id);
287 } else {
288 IPC::Message* new_message = new IPC::Message(message);
289 new_message->set_routing_id(worker_route_id_);
290 Send(new_message);
291 return;
295 void SharedWorkerHost::TerminateWorker() {
296 Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
299 std::vector<std::pair<int, int> >
300 SharedWorkerHost::GetRenderFrameIDsForWorker() {
301 std::vector<std::pair<int, int> > result;
302 if (!instance_)
303 return result;
304 const WorkerDocumentSet::DocumentInfoSet& documents =
305 worker_document_set_->documents();
306 for (WorkerDocumentSet::DocumentInfoSet::const_iterator doc =
307 documents.begin();
308 doc != documents.end();
309 ++doc) {
310 result.push_back(
311 std::make_pair(doc->render_process_id(), doc->render_frame_id()));
313 return result;
316 void SharedWorkerHost::AddFilter(SharedWorkerMessageFilter* filter,
317 int route_id) {
318 CHECK(filter);
319 if (!HasFilter(filter, route_id)) {
320 FilterInfo info(filter, route_id);
321 filters_.push_back(info);
325 void SharedWorkerHost::RemoveFilters(SharedWorkerMessageFilter* filter) {
326 for (FilterList::iterator i = filters_.begin(); i != filters_.end();) {
327 if (i->filter() == filter)
328 i = filters_.erase(i);
329 else
330 ++i;
334 bool SharedWorkerHost::HasFilter(SharedWorkerMessageFilter* filter,
335 int route_id) const {
336 for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
337 ++i) {
338 if (i->filter() == filter && i->route_id() == route_id)
339 return true;
341 return false;
344 void SharedWorkerHost::SetMessagePortID(SharedWorkerMessageFilter* filter,
345 int route_id,
346 int message_port_id) {
347 for (FilterList::iterator i = filters_.begin(); i != filters_.end(); ++i) {
348 if (i->filter() == filter && i->route_id() == route_id) {
349 i->set_message_port_id(message_port_id);
350 return;
355 } // namespace content