Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / shared_worker / shared_worker_host.cc
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/shared_worker/shared_worker_host.h"
6
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"
22
23 namespace content {
24 namespace {
25
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);
32 }
33
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;
43   }
44   EmbeddedWorkerDevToolsManager::GetInstance()->WorkerReadyForInspection(
45       worker_process_id, worker_route_id);
46 }
47
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;
55   }
56   EmbeddedWorkerDevToolsManager::GetInstance()->WorkerDestroyed(
57       worker_process_id, worker_route_id);
58 }
59
60 }  // namespace
61
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));
75 }
76
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()));
94     }
95   }
96   if (!closed_)
97     NotifyWorkerDestroyed(worker_process_id_, worker_route_id_);
98   SharedWorkerServiceImpl::GetInstance()->NotifyWorkerDestroyed(
99       worker_process_id_, worker_route_id_);
100 }
101
102 bool SharedWorkerHost::Send(IPC::Message* message) {
103   if (!container_render_filter_) {
104     delete message;
105     return false;
106   }
107   return container_render_filter_->Send(message);
108 }
109
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));
119
120   for (FilterList::const_iterator i = filters_.begin(); i != filters_.end();
121        ++i) {
122     i->filter()->Send(new ViewMsg_WorkerCreated(i->route_id()));
123   }
124 }
125
126 bool SharedWorkerHost::FilterMessage(const IPC::Message& message,
127                                      SharedWorkerMessageFilter* filter) {
128   if (!instance_)
129     return false;
130
131   if (!closed_ && HasFilter(filter, message.routing_id())) {
132     RelayMessage(message, filter);
133     return true;
134   }
135
136   return false;
137 }
138
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_));
147   }
148 }
149
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_));
159   }
160 }
161
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_);
170 }
171
172 void SharedWorkerHost::WorkerContextDestroyed() {
173   if (!instance_)
174     return;
175   instance_.reset();
176   worker_document_set_ = NULL;
177 }
178
179 void SharedWorkerHost::WorkerReadyForInspection() {
180   NotifyWorkerReadyForInspection(worker_process_id_, worker_route_id_);
181 }
182
183 void SharedWorkerHost::WorkerScriptLoaded() {
184   UMA_HISTOGRAM_TIMES("SharedWorker.TimeToScriptLoaded",
185                       base::TimeTicks::Now() - creation_time_);
186 }
187
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()));
197   }
198 }
199
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;
209   }
210 }
211
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());
226 }
227
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)));
239 }
240
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());
248 }
249
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());
257 }
258
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;
271
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));
283
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;
292   }
293 }
294
295 void SharedWorkerHost::TerminateWorker() {
296   Send(new WorkerMsg_TerminateWorkerContext(worker_route_id_));
297 }
298
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()));
312   }
313   return result;
314 }
315
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);
322   }
323 }
324
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;
331   }
332 }
333
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;
340   }
341   return false;
342 }
343
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;
351     }
352   }
353 }
354
355 }  // namespace content