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_service_impl.h"
6
7 #include <algorithm>
8 #include <iterator>
9 #include <set>
10 #include <vector>
11
12 #include "base/callback.h"
13 #include "base/memory/ref_counted.h"
14 #include "content/browser/devtools/embedded_worker_devtools_manager.h"
15 #include "content/browser/renderer_host/render_process_host_impl.h"
16 #include "content/browser/shared_worker/shared_worker_host.h"
17 #include "content/browser/shared_worker/shared_worker_instance.h"
18 #include "content/browser/shared_worker/shared_worker_message_filter.h"
19 #include "content/browser/shared_worker/worker_document_set.h"
20 #include "content/common/view_messages.h"
21 #include "content/common/worker_messages.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/worker_service_observer.h"
24
25 namespace content {
26
GetInstance()27 WorkerService* WorkerService::GetInstance() {
28 return SharedWorkerServiceImpl::GetInstance();
29 }
30
31 namespace {
32
33 class ScopedWorkerDependencyChecker {
34 public:
ScopedWorkerDependencyChecker(SharedWorkerServiceImpl * service)35 explicit ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service)
36 : service_(service) {}
ScopedWorkerDependencyChecker(SharedWorkerServiceImpl * service,base::Closure done_closure)37 ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service,
38 base::Closure done_closure)
39 : service_(service), done_closure_(done_closure) {}
~ScopedWorkerDependencyChecker()40 ~ScopedWorkerDependencyChecker() {
41 service_->CheckWorkerDependency();
42 if (!done_closure_.is_null())
43 done_closure_.Run();
44 }
45
46 private:
47 SharedWorkerServiceImpl* service_;
48 base::Closure done_closure_;
49 DISALLOW_COPY_AND_ASSIGN(ScopedWorkerDependencyChecker);
50 };
51
UpdateWorkerDependencyOnUI(const std::vector<int> & added_ids,const std::vector<int> & removed_ids)52 void UpdateWorkerDependencyOnUI(const std::vector<int>& added_ids,
53 const std::vector<int>& removed_ids) {
54 for (size_t i = 0; i < added_ids.size(); ++i) {
55 RenderProcessHostImpl* render_process_host_impl =
56 static_cast<RenderProcessHostImpl*>(
57 RenderProcessHost::FromID(added_ids[i]));
58 if (!render_process_host_impl)
59 continue;
60 render_process_host_impl->IncrementWorkerRefCount();
61 }
62 for (size_t i = 0; i < removed_ids.size(); ++i) {
63 RenderProcessHostImpl* render_process_host_impl =
64 static_cast<RenderProcessHostImpl*>(
65 RenderProcessHost::FromID(removed_ids[i]));
66 if (!render_process_host_impl)
67 continue;
68 render_process_host_impl->DecrementWorkerRefCount();
69 }
70 }
71
UpdateWorkerDependency(const std::vector<int> & added_ids,const std::vector<int> & removed_ids)72 void UpdateWorkerDependency(const std::vector<int>& added_ids,
73 const std::vector<int>& removed_ids) {
74 BrowserThread::PostTask(
75 BrowserThread::UI,
76 FROM_HERE,
77 base::Bind(&UpdateWorkerDependencyOnUI, added_ids, removed_ids));
78 }
79
DecrementWorkerRefCount(int process_id)80 void DecrementWorkerRefCount(int process_id) {
81 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
82 BrowserThread::PostTask(BrowserThread::UI,
83 FROM_HERE,
84 base::Bind(&DecrementWorkerRefCount, process_id));
85 return;
86 }
87 RenderProcessHostImpl* render_process_host_impl =
88 static_cast<RenderProcessHostImpl*>(
89 RenderProcessHost::FromID(process_id));
90 if (render_process_host_impl)
91 render_process_host_impl->DecrementWorkerRefCount();
92 }
93
TryIncrementWorkerRefCount(int worker_process_id)94 bool TryIncrementWorkerRefCount(int worker_process_id) {
95 RenderProcessHostImpl* render_process = static_cast<RenderProcessHostImpl*>(
96 RenderProcessHost::FromID(worker_process_id));
97 if (!render_process || render_process->FastShutdownStarted()) {
98 return false;
99 }
100 render_process->IncrementWorkerRefCount();
101 return true;
102 }
103
104 } // namespace
105
106 class SharedWorkerServiceImpl::SharedWorkerPendingInstance {
107 public:
108 struct SharedWorkerPendingRequest {
SharedWorkerPendingRequestcontent::SharedWorkerServiceImpl::SharedWorkerPendingInstance::SharedWorkerPendingRequest109 SharedWorkerPendingRequest(SharedWorkerMessageFilter* filter,
110 int route_id,
111 unsigned long long document_id,
112 int render_process_id,
113 int render_frame_route_id)
114 : filter(filter),
115 route_id(route_id),
116 document_id(document_id),
117 render_process_id(render_process_id),
118 render_frame_route_id(render_frame_route_id) {}
119 SharedWorkerMessageFilter* const filter;
120 const int route_id;
121 const unsigned long long document_id;
122 const int render_process_id;
123 const int render_frame_route_id;
124 };
125
126 typedef ScopedVector<SharedWorkerPendingRequest> SharedWorkerPendingRequests;
127
SharedWorkerPendingInstance(scoped_ptr<SharedWorkerInstance> instance)128 explicit SharedWorkerPendingInstance(
129 scoped_ptr<SharedWorkerInstance> instance)
130 : instance_(instance.Pass()) {}
~SharedWorkerPendingInstance()131 ~SharedWorkerPendingInstance() {}
instance()132 SharedWorkerInstance* instance() { return instance_.get(); }
release_instance()133 SharedWorkerInstance* release_instance() { return instance_.release(); }
requests()134 SharedWorkerPendingRequests* requests() { return &requests_; }
FindFilter(int process_id)135 SharedWorkerMessageFilter* FindFilter(int process_id) {
136 for (size_t i = 0; i < requests_.size(); ++i) {
137 if (requests_[i]->render_process_id == process_id)
138 return requests_[i]->filter;
139 }
140 return NULL;
141 }
AddRequest(scoped_ptr<SharedWorkerPendingRequest> request_info)142 void AddRequest(scoped_ptr<SharedWorkerPendingRequest> request_info) {
143 requests_.push_back(request_info.release());
144 }
RemoveRequest(int process_id)145 void RemoveRequest(int process_id) {
146 for (SharedWorkerPendingRequests::iterator request_itr = requests_.begin();
147 request_itr != requests_.end();) {
148 if ((*request_itr)->render_process_id == process_id)
149 request_itr = requests_.erase(request_itr);
150 else
151 ++request_itr;
152 }
153 }
RegisterToSharedWorkerHost(SharedWorkerHost * host)154 void RegisterToSharedWorkerHost(SharedWorkerHost* host) {
155 for (size_t i = 0; i < requests_.size(); ++i) {
156 SharedWorkerPendingRequest* request = requests_[i];
157 host->AddFilter(request->filter, request->route_id);
158 host->worker_document_set()->Add(request->filter,
159 request->document_id,
160 request->render_process_id,
161 request->render_frame_route_id);
162 }
163 }
SendWorkerCreatedMessages()164 void SendWorkerCreatedMessages() {
165 for (size_t i = 0; i < requests_.size(); ++i) {
166 SharedWorkerPendingRequest* request = requests_[i];
167 request->filter->Send(new ViewMsg_WorkerCreated(request->route_id));
168 }
169 }
170
171 private:
172 scoped_ptr<SharedWorkerInstance> instance_;
173 SharedWorkerPendingRequests requests_;
174 DISALLOW_COPY_AND_ASSIGN(SharedWorkerPendingInstance);
175 };
176
177 class SharedWorkerServiceImpl::SharedWorkerReserver
178 : public base::RefCountedThreadSafe<SharedWorkerReserver> {
179 public:
SharedWorkerReserver(int pending_instance_id,int worker_process_id,int worker_route_id,bool is_new_worker,const SharedWorkerInstance & instance)180 SharedWorkerReserver(int pending_instance_id,
181 int worker_process_id,
182 int worker_route_id,
183 bool is_new_worker,
184 const SharedWorkerInstance& instance)
185 : worker_process_id_(worker_process_id),
186 worker_route_id_(worker_route_id),
187 is_new_worker_(is_new_worker),
188 instance_(instance) {}
189
TryReserve(const base::Callback<void (bool)> & success_cb,const base::Closure & failure_cb,bool (* try_increment_worker_ref_count)(int))190 void TryReserve(const base::Callback<void(bool)>& success_cb,
191 const base::Closure& failure_cb,
192 bool (*try_increment_worker_ref_count)(int)) {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
194 if (!try_increment_worker_ref_count(worker_process_id_)) {
195 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_cb);
196 return;
197 }
198 bool pause_on_start = false;
199 if (is_new_worker_) {
200 pause_on_start =
201 EmbeddedWorkerDevToolsManager::GetInstance()->SharedWorkerCreated(
202 worker_process_id_, worker_route_id_, instance_);
203 }
204 BrowserThread::PostTask(
205 BrowserThread::IO, FROM_HERE, base::Bind(success_cb, pause_on_start));
206 }
207
208 private:
209 friend class base::RefCountedThreadSafe<SharedWorkerReserver>;
~SharedWorkerReserver()210 ~SharedWorkerReserver() {}
211
212 const int worker_process_id_;
213 const int worker_route_id_;
214 const bool is_new_worker_;
215 const SharedWorkerInstance instance_;
216 };
217
218 // static
219 bool (*SharedWorkerServiceImpl::s_try_increment_worker_ref_count_)(int) =
220 TryIncrementWorkerRefCount;
221
GetInstance()222 SharedWorkerServiceImpl* SharedWorkerServiceImpl::GetInstance() {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
224 return Singleton<SharedWorkerServiceImpl>::get();
225 }
226
SharedWorkerServiceImpl()227 SharedWorkerServiceImpl::SharedWorkerServiceImpl()
228 : update_worker_dependency_(UpdateWorkerDependency),
229 next_pending_instance_id_(0) {
230 }
231
~SharedWorkerServiceImpl()232 SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {}
233
ResetForTesting()234 void SharedWorkerServiceImpl::ResetForTesting() {
235 last_worker_depended_renderers_.clear();
236 worker_hosts_.clear();
237 observers_.Clear();
238 update_worker_dependency_ = UpdateWorkerDependency;
239 s_try_increment_worker_ref_count_ = TryIncrementWorkerRefCount;
240 }
241
TerminateWorker(int process_id,int route_id)242 bool SharedWorkerServiceImpl::TerminateWorker(int process_id, int route_id) {
243 SharedWorkerHost* host =
244 worker_hosts_.get(std::make_pair(process_id, route_id));
245 if (!host || !host->instance())
246 return false;
247 host->TerminateWorker();
248 return true;
249 }
250
GetWorkers()251 std::vector<WorkerService::WorkerInfo> SharedWorkerServiceImpl::GetWorkers() {
252 std::vector<WorkerService::WorkerInfo> results;
253 for (WorkerHostMap::const_iterator iter = worker_hosts_.begin();
254 iter != worker_hosts_.end();
255 ++iter) {
256 SharedWorkerHost* host = iter->second;
257 const SharedWorkerInstance* instance = host->instance();
258 if (instance) {
259 WorkerService::WorkerInfo info;
260 info.url = instance->url();
261 info.name = instance->name();
262 info.route_id = host->worker_route_id();
263 info.process_id = host->process_id();
264 info.handle = host->container_render_filter()->PeerHandle();
265 results.push_back(info);
266 }
267 }
268 return results;
269 }
270
AddObserver(WorkerServiceObserver * observer)271 void SharedWorkerServiceImpl::AddObserver(WorkerServiceObserver* observer) {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
273 observers_.AddObserver(observer);
274 }
275
RemoveObserver(WorkerServiceObserver * observer)276 void SharedWorkerServiceImpl::RemoveObserver(WorkerServiceObserver* observer) {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
278 observers_.RemoveObserver(observer);
279 }
280
CreateWorker(const ViewHostMsg_CreateWorker_Params & params,int route_id,SharedWorkerMessageFilter * filter,ResourceContext * resource_context,const WorkerStoragePartitionId & partition_id,bool * url_mismatch)281 void SharedWorkerServiceImpl::CreateWorker(
282 const ViewHostMsg_CreateWorker_Params& params,
283 int route_id,
284 SharedWorkerMessageFilter* filter,
285 ResourceContext* resource_context,
286 const WorkerStoragePartitionId& partition_id,
287 bool* url_mismatch) {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
289 *url_mismatch = false;
290 scoped_ptr<SharedWorkerInstance> instance(
291 new SharedWorkerInstance(params.url,
292 params.name,
293 params.content_security_policy,
294 params.security_policy_type,
295 resource_context,
296 partition_id));
297 scoped_ptr<SharedWorkerPendingInstance::SharedWorkerPendingRequest> request(
298 new SharedWorkerPendingInstance::SharedWorkerPendingRequest(
299 filter,
300 route_id,
301 params.document_id,
302 filter->render_process_id(),
303 params.render_frame_route_id));
304 if (SharedWorkerPendingInstance* pending = FindPendingInstance(*instance)) {
305 if (params.url != pending->instance()->url()) {
306 *url_mismatch = true;
307 return;
308 }
309 pending->AddRequest(request.Pass());
310 return;
311 }
312 scoped_ptr<SharedWorkerPendingInstance> pending_instance(
313 new SharedWorkerPendingInstance(instance.Pass()));
314 pending_instance->AddRequest(request.Pass());
315 ReserveRenderProcessToCreateWorker(pending_instance.Pass(), url_mismatch);
316 }
317
ForwardToWorker(const IPC::Message & message,SharedWorkerMessageFilter * filter)318 void SharedWorkerServiceImpl::ForwardToWorker(
319 const IPC::Message& message,
320 SharedWorkerMessageFilter* filter) {
321 for (WorkerHostMap::const_iterator iter = worker_hosts_.begin();
322 iter != worker_hosts_.end();
323 ++iter) {
324 if (iter->second->FilterMessage(message, filter))
325 return;
326 }
327 }
328
DocumentDetached(unsigned long long document_id,SharedWorkerMessageFilter * filter)329 void SharedWorkerServiceImpl::DocumentDetached(
330 unsigned long long document_id,
331 SharedWorkerMessageFilter* filter) {
332 ScopedWorkerDependencyChecker checker(this);
333 for (WorkerHostMap::const_iterator iter = worker_hosts_.begin();
334 iter != worker_hosts_.end();
335 ++iter) {
336 iter->second->DocumentDetached(filter, document_id);
337 }
338 }
339
WorkerContextClosed(int worker_route_id,SharedWorkerMessageFilter * filter)340 void SharedWorkerServiceImpl::WorkerContextClosed(
341 int worker_route_id,
342 SharedWorkerMessageFilter* filter) {
343 ScopedWorkerDependencyChecker checker(this);
344 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
345 host->WorkerContextClosed();
346 }
347
WorkerContextDestroyed(int worker_route_id,SharedWorkerMessageFilter * filter)348 void SharedWorkerServiceImpl::WorkerContextDestroyed(
349 int worker_route_id,
350 SharedWorkerMessageFilter* filter) {
351 ScopedWorkerDependencyChecker checker(this);
352 scoped_ptr<SharedWorkerHost> host =
353 worker_hosts_.take_and_erase(std::make_pair(filter->render_process_id(),
354 worker_route_id));
355 if (!host)
356 return;
357 host->WorkerContextDestroyed();
358 }
359
WorkerReadyForInspection(int worker_route_id,SharedWorkerMessageFilter * filter)360 void SharedWorkerServiceImpl::WorkerReadyForInspection(
361 int worker_route_id,
362 SharedWorkerMessageFilter* filter) {
363 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
364 host->WorkerReadyForInspection();
365 }
366
WorkerScriptLoaded(int worker_route_id,SharedWorkerMessageFilter * filter)367 void SharedWorkerServiceImpl::WorkerScriptLoaded(
368 int worker_route_id,
369 SharedWorkerMessageFilter* filter) {
370 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
371 host->WorkerScriptLoaded();
372 }
373
WorkerScriptLoadFailed(int worker_route_id,SharedWorkerMessageFilter * filter)374 void SharedWorkerServiceImpl::WorkerScriptLoadFailed(
375 int worker_route_id,
376 SharedWorkerMessageFilter* filter) {
377 ScopedWorkerDependencyChecker checker(this);
378 scoped_ptr<SharedWorkerHost> host =
379 worker_hosts_.take_and_erase(std::make_pair(filter->render_process_id(),
380 worker_route_id));
381 if (!host)
382 return;
383 host->WorkerScriptLoadFailed();
384 }
385
WorkerConnected(int message_port_id,int worker_route_id,SharedWorkerMessageFilter * filter)386 void SharedWorkerServiceImpl::WorkerConnected(
387 int message_port_id,
388 int worker_route_id,
389 SharedWorkerMessageFilter* filter) {
390 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
391 host->WorkerConnected(message_port_id);
392 }
393
AllowDatabase(int worker_route_id,const GURL & url,const base::string16 & name,const base::string16 & display_name,unsigned long estimated_size,bool * result,SharedWorkerMessageFilter * filter)394 void SharedWorkerServiceImpl::AllowDatabase(
395 int worker_route_id,
396 const GURL& url,
397 const base::string16& name,
398 const base::string16& display_name,
399 unsigned long estimated_size,
400 bool* result,
401 SharedWorkerMessageFilter* filter) {
402 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
403 host->AllowDatabase(url, name, display_name, estimated_size, result);
404 }
405
AllowFileSystem(int worker_route_id,const GURL & url,IPC::Message * reply_msg,SharedWorkerMessageFilter * filter)406 void SharedWorkerServiceImpl::AllowFileSystem(
407 int worker_route_id,
408 const GURL& url,
409 IPC::Message* reply_msg,
410 SharedWorkerMessageFilter* filter) {
411 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) {
412 host->AllowFileSystem(url, make_scoped_ptr(reply_msg));
413 } else {
414 filter->Send(reply_msg);
415 return;
416 }
417 }
418
AllowIndexedDB(int worker_route_id,const GURL & url,const base::string16 & name,bool * result,SharedWorkerMessageFilter * filter)419 void SharedWorkerServiceImpl::AllowIndexedDB(
420 int worker_route_id,
421 const GURL& url,
422 const base::string16& name,
423 bool* result,
424 SharedWorkerMessageFilter* filter) {
425 if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
426 host->AllowIndexedDB(url, name, result);
427 }
428
OnSharedWorkerMessageFilterClosing(SharedWorkerMessageFilter * filter)429 void SharedWorkerServiceImpl::OnSharedWorkerMessageFilterClosing(
430 SharedWorkerMessageFilter* filter) {
431 ScopedWorkerDependencyChecker checker(this);
432 std::vector<ProcessRouteIdPair> remove_list;
433 for (WorkerHostMap::iterator iter = worker_hosts_.begin();
434 iter != worker_hosts_.end();
435 ++iter) {
436 iter->second->FilterShutdown(filter);
437 if (iter->first.first == filter->render_process_id())
438 remove_list.push_back(iter->first);
439 }
440 for (size_t i = 0; i < remove_list.size(); ++i) {
441 scoped_ptr<SharedWorkerHost> host =
442 worker_hosts_.take_and_erase(remove_list[i]);
443 }
444
445 std::vector<int> remove_pending_instance_list;
446 for (PendingInstaneMap::iterator iter = pending_instances_.begin();
447 iter != pending_instances_.end();
448 ++iter) {
449 iter->second->RemoveRequest(filter->render_process_id());
450 if (!iter->second->requests()->size())
451 remove_pending_instance_list.push_back(iter->first);
452 }
453 for (size_t i = 0; i < remove_pending_instance_list.size(); ++i)
454 pending_instances_.take_and_erase(remove_pending_instance_list[i]);
455 }
456
NotifyWorkerDestroyed(int worker_process_id,int worker_route_id)457 void SharedWorkerServiceImpl::NotifyWorkerDestroyed(int worker_process_id,
458 int worker_route_id) {
459 FOR_EACH_OBSERVER(WorkerServiceObserver,
460 observers_,
461 WorkerDestroyed(worker_process_id, worker_route_id));
462 }
463
ReserveRenderProcessToCreateWorker(scoped_ptr<SharedWorkerPendingInstance> pending_instance,bool * url_mismatch)464 void SharedWorkerServiceImpl::ReserveRenderProcessToCreateWorker(
465 scoped_ptr<SharedWorkerPendingInstance> pending_instance,
466 bool* url_mismatch) {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
468 DCHECK(!FindPendingInstance(*pending_instance->instance()));
469 if (url_mismatch)
470 *url_mismatch = false;
471 if (!pending_instance->requests()->size())
472 return;
473 int worker_process_id = -1;
474 int worker_route_id = MSG_ROUTING_NONE;
475 bool is_new_worker = true;
476 SharedWorkerHost* host = FindSharedWorkerHost(*pending_instance->instance());
477 if (host) {
478 if (pending_instance->instance()->url() != host->instance()->url()) {
479 if (url_mismatch)
480 *url_mismatch = true;
481 return;
482 }
483 worker_process_id = host->process_id();
484 worker_route_id = host->worker_route_id();
485 is_new_worker = false;
486 } else {
487 SharedWorkerMessageFilter* first_filter =
488 (*pending_instance->requests()->begin())->filter;
489 worker_process_id = first_filter->render_process_id();
490 worker_route_id = first_filter->GetNextRoutingID();
491 }
492 const int pending_instance_id = next_pending_instance_id_++;
493 scoped_refptr<SharedWorkerReserver> reserver(
494 new SharedWorkerReserver(pending_instance_id,
495 worker_process_id,
496 worker_route_id,
497 is_new_worker,
498 *pending_instance->instance()));
499 BrowserThread::PostTask(
500 BrowserThread::UI,
501 FROM_HERE,
502 base::Bind(
503 &SharedWorkerReserver::TryReserve,
504 reserver,
505 base::Bind(&SharedWorkerServiceImpl::RenderProcessReservedCallback,
506 base::Unretained(this),
507 pending_instance_id,
508 worker_process_id,
509 worker_route_id,
510 is_new_worker),
511 base::Bind(
512 &SharedWorkerServiceImpl::RenderProcessReserveFailedCallback,
513 base::Unretained(this),
514 pending_instance_id,
515 worker_process_id,
516 worker_route_id,
517 is_new_worker),
518 s_try_increment_worker_ref_count_));
519 pending_instances_.set(pending_instance_id, pending_instance.Pass());
520 }
521
RenderProcessReservedCallback(int pending_instance_id,int worker_process_id,int worker_route_id,bool is_new_worker,bool pause_on_start)522 void SharedWorkerServiceImpl::RenderProcessReservedCallback(
523 int pending_instance_id,
524 int worker_process_id,
525 int worker_route_id,
526 bool is_new_worker,
527 bool pause_on_start) {
528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
529 // To offset the TryIncrementWorkerRefCount called for the reservation,
530 // calls DecrementWorkerRefCount after CheckWorkerDependency in
531 // ScopeWorkerDependencyChecker's destructor.
532 ScopedWorkerDependencyChecker checker(
533 this, base::Bind(&DecrementWorkerRefCount, worker_process_id));
534 scoped_ptr<SharedWorkerPendingInstance> pending_instance =
535 pending_instances_.take_and_erase(pending_instance_id);
536 if (!pending_instance)
537 return;
538 if (!is_new_worker) {
539 SharedWorkerHost* existing_host =
540 worker_hosts_.get(std::make_pair(worker_process_id, worker_route_id));
541 if (!existing_host) {
542 // Retry reserving a renderer process if the existed Shared Worker was
543 // destroyed on IO thread while reserving the renderer process on UI
544 // thread.
545 ReserveRenderProcessToCreateWorker(pending_instance.Pass(), NULL);
546 return;
547 }
548 pending_instance->RegisterToSharedWorkerHost(existing_host);
549 pending_instance->SendWorkerCreatedMessages();
550 return;
551 }
552 SharedWorkerMessageFilter* filter =
553 pending_instance->FindFilter(worker_process_id);
554 if (!filter) {
555 pending_instance->RemoveRequest(worker_process_id);
556 // Retry reserving a renderer process if the requested renderer process was
557 // destroyed on IO thread while reserving the renderer process on UI thread.
558 ReserveRenderProcessToCreateWorker(pending_instance.Pass(), NULL);
559 return;
560 }
561 scoped_ptr<SharedWorkerHost> host(new SharedWorkerHost(
562 pending_instance->release_instance(), filter, worker_route_id));
563 pending_instance->RegisterToSharedWorkerHost(host.get());
564 const GURL url = host->instance()->url();
565 const base::string16 name = host->instance()->name();
566 host->Start(pause_on_start);
567 worker_hosts_.set(std::make_pair(worker_process_id, worker_route_id),
568 host.Pass());
569 FOR_EACH_OBSERVER(
570 WorkerServiceObserver,
571 observers_,
572 WorkerCreated(url, name, worker_process_id, worker_route_id));
573 }
574
RenderProcessReserveFailedCallback(int pending_instance_id,int worker_process_id,int worker_route_id,bool is_new_worker)575 void SharedWorkerServiceImpl::RenderProcessReserveFailedCallback(
576 int pending_instance_id,
577 int worker_process_id,
578 int worker_route_id,
579 bool is_new_worker) {
580 worker_hosts_.take_and_erase(
581 std::make_pair(worker_process_id, worker_route_id));
582 scoped_ptr<SharedWorkerPendingInstance> pending_instance =
583 pending_instances_.take_and_erase(pending_instance_id);
584 if (!pending_instance)
585 return;
586 pending_instance->RemoveRequest(worker_process_id);
587 // Retry reserving a renderer process.
588 ReserveRenderProcessToCreateWorker(pending_instance.Pass(), NULL);
589 }
590
FindSharedWorkerHost(SharedWorkerMessageFilter * filter,int worker_route_id)591 SharedWorkerHost* SharedWorkerServiceImpl::FindSharedWorkerHost(
592 SharedWorkerMessageFilter* filter,
593 int worker_route_id) {
594 return worker_hosts_.get(std::make_pair(filter->render_process_id(),
595 worker_route_id));
596 }
597
FindSharedWorkerHost(const SharedWorkerInstance & instance)598 SharedWorkerHost* SharedWorkerServiceImpl::FindSharedWorkerHost(
599 const SharedWorkerInstance& instance) {
600 for (WorkerHostMap::const_iterator iter = worker_hosts_.begin();
601 iter != worker_hosts_.end();
602 ++iter) {
603 SharedWorkerHost* host = iter->second;
604 if (host->instance() && !host->closed() &&
605 host->instance()->Matches(instance)) {
606 return iter->second;
607 }
608 }
609 return NULL;
610 }
611
612 SharedWorkerServiceImpl::SharedWorkerPendingInstance*
FindPendingInstance(const SharedWorkerInstance & instance)613 SharedWorkerServiceImpl::FindPendingInstance(
614 const SharedWorkerInstance& instance) {
615 for (PendingInstaneMap::iterator iter = pending_instances_.begin();
616 iter != pending_instances_.end();
617 ++iter) {
618 if (iter->second->instance()->Matches(instance))
619 return iter->second;
620 }
621 return NULL;
622 }
623
624 const std::set<int>
GetRenderersWithWorkerDependency()625 SharedWorkerServiceImpl::GetRenderersWithWorkerDependency() {
626 std::set<int> dependent_renderers;
627 for (WorkerHostMap::iterator host_iter = worker_hosts_.begin();
628 host_iter != worker_hosts_.end();
629 ++host_iter) {
630 const int process_id = host_iter->first.first;
631 if (dependent_renderers.count(process_id))
632 continue;
633 if (host_iter->second->instance() &&
634 host_iter->second->worker_document_set()->ContainsExternalRenderer(
635 process_id)) {
636 dependent_renderers.insert(process_id);
637 }
638 }
639 return dependent_renderers;
640 }
641
CheckWorkerDependency()642 void SharedWorkerServiceImpl::CheckWorkerDependency() {
643 const std::set<int> current_worker_depended_renderers =
644 GetRenderersWithWorkerDependency();
645 std::vector<int> added_items = base::STLSetDifference<std::vector<int> >(
646 current_worker_depended_renderers, last_worker_depended_renderers_);
647 std::vector<int> removed_items = base::STLSetDifference<std::vector<int> >(
648 last_worker_depended_renderers_, current_worker_depended_renderers);
649 if (!added_items.empty() || !removed_items.empty()) {
650 last_worker_depended_renderers_ = current_worker_depended_renderers;
651 update_worker_dependency_(added_items, removed_items);
652 }
653 }
654
ChangeUpdateWorkerDependencyFuncForTesting(UpdateWorkerDependencyFunc new_func)655 void SharedWorkerServiceImpl::ChangeUpdateWorkerDependencyFuncForTesting(
656 UpdateWorkerDependencyFunc new_func) {
657 update_worker_dependency_ = new_func;
658 }
659
ChangeTryIncrementWorkerRefCountFuncForTesting(bool (* new_func)(int))660 void SharedWorkerServiceImpl::ChangeTryIncrementWorkerRefCountFuncForTesting(
661 bool (*new_func)(int)) {
662 s_try_increment_worker_ref_count_ = new_func;
663 }
664
665 } // namespace content
666