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
25namespace content {
26
27WorkerService* WorkerService::GetInstance() {
28  return SharedWorkerServiceImpl::GetInstance();
29}
30
31namespace {
32
33class ScopedWorkerDependencyChecker {
34 public:
35  explicit ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service)
36      : service_(service) {}
37  ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service,
38                                base::Closure done_closure)
39      : service_(service), done_closure_(done_closure) {}
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
52void 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
72void 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
80void 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
94bool 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
106class SharedWorkerServiceImpl::SharedWorkerPendingInstance {
107 public:
108  struct SharedWorkerPendingRequest {
109    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
128  explicit SharedWorkerPendingInstance(
129      scoped_ptr<SharedWorkerInstance> instance)
130      : instance_(instance.Pass()) {}
131  ~SharedWorkerPendingInstance() {}
132  SharedWorkerInstance* instance() { return instance_.get(); }
133  SharedWorkerInstance* release_instance() { return instance_.release(); }
134  SharedWorkerPendingRequests* requests() { return &requests_; }
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  }
142  void AddRequest(scoped_ptr<SharedWorkerPendingRequest> request_info) {
143    requests_.push_back(request_info.release());
144  }
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  }
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  }
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
177class SharedWorkerServiceImpl::SharedWorkerReserver
178    : public base::RefCountedThreadSafe<SharedWorkerReserver> {
179 public:
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
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>;
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
219bool (*SharedWorkerServiceImpl::s_try_increment_worker_ref_count_)(int) =
220    TryIncrementWorkerRefCount;
221
222SharedWorkerServiceImpl* SharedWorkerServiceImpl::GetInstance() {
223  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
224  return Singleton<SharedWorkerServiceImpl>::get();
225}
226
227SharedWorkerServiceImpl::SharedWorkerServiceImpl()
228    : update_worker_dependency_(UpdateWorkerDependency),
229      next_pending_instance_id_(0) {
230}
231
232SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {}
233
234void 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
242bool 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
251std::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
271void SharedWorkerServiceImpl::AddObserver(WorkerServiceObserver* observer) {
272  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
273  observers_.AddObserver(observer);
274}
275
276void SharedWorkerServiceImpl::RemoveObserver(WorkerServiceObserver* observer) {
277  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
278  observers_.RemoveObserver(observer);
279}
280
281void 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
318void 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
329void 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
340void 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
348void 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
360void SharedWorkerServiceImpl::WorkerReadyForInspection(
361    int worker_route_id,
362    SharedWorkerMessageFilter* filter) {
363  if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
364    host->WorkerReadyForInspection();
365}
366
367void SharedWorkerServiceImpl::WorkerScriptLoaded(
368    int worker_route_id,
369    SharedWorkerMessageFilter* filter) {
370  if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id))
371    host->WorkerScriptLoaded();
372}
373
374void 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
386void 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
394void 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
406void 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
419void 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
429void 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
457void 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
464void 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
522void 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
575void 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
591SharedWorkerHost* 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
598SharedWorkerHost* 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
612SharedWorkerServiceImpl::SharedWorkerPendingInstance*
613SharedWorkerServiceImpl::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
624const std::set<int>
625SharedWorkerServiceImpl::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
642void 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
655void SharedWorkerServiceImpl::ChangeUpdateWorkerDependencyFuncForTesting(
656    UpdateWorkerDependencyFunc new_func) {
657  update_worker_dependency_ = new_func;
658}
659
660void SharedWorkerServiceImpl::ChangeTryIncrementWorkerRefCountFuncForTesting(
661    bool (*new_func)(int)) {
662  s_try_increment_worker_ref_count_ = new_func;
663}
664
665}  // namespace content
666