| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/shared_worker/shared_worker_service_impl.h" |
| |
| #include <algorithm> |
| #include <iterator> |
| #include <set> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/memory/ref_counted.h" |
| #include "content/browser/devtools/shared_worker_devtools_manager.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| #include "content/browser/shared_worker/shared_worker_host.h" |
| #include "content/browser/shared_worker/shared_worker_instance.h" |
| #include "content/browser/shared_worker/shared_worker_message_filter.h" |
| #include "content/browser/worker_host/worker_document_set.h" |
| #include "content/common/view_messages.h" |
| #include "content/common/worker_messages.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/worker_service_observer.h" |
| |
| namespace content { |
| namespace { |
| |
| class ScopedWorkerDependencyChecker { |
| public: |
| explicit ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service) |
| : service_(service) {} |
| ScopedWorkerDependencyChecker(SharedWorkerServiceImpl* service, |
| base::Closure done_closure) |
| : service_(service), done_closure_(done_closure) {} |
| ~ScopedWorkerDependencyChecker() { |
| service_->CheckWorkerDependency(); |
| if (!done_closure_.is_null()) |
| done_closure_.Run(); |
| } |
| |
| private: |
| SharedWorkerServiceImpl* service_; |
| base::Closure done_closure_; |
| DISALLOW_COPY_AND_ASSIGN(ScopedWorkerDependencyChecker); |
| }; |
| |
| void UpdateWorkerDependencyOnUI(const std::vector<int>& added_ids, |
| const std::vector<int>& removed_ids) { |
| for (size_t i = 0; i < added_ids.size(); ++i) { |
| RenderProcessHostImpl* render_process_host_impl = |
| static_cast<RenderProcessHostImpl*>( |
| RenderProcessHost::FromID(added_ids[i])); |
| if (!render_process_host_impl) |
| continue; |
| render_process_host_impl->IncrementWorkerRefCount(); |
| } |
| for (size_t i = 0; i < removed_ids.size(); ++i) { |
| RenderProcessHostImpl* render_process_host_impl = |
| static_cast<RenderProcessHostImpl*>( |
| RenderProcessHost::FromID(removed_ids[i])); |
| if (!render_process_host_impl) |
| continue; |
| render_process_host_impl->DecrementWorkerRefCount(); |
| } |
| } |
| |
| void UpdateWorkerDependency(const std::vector<int>& added_ids, |
| const std::vector<int>& removed_ids) { |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(&UpdateWorkerDependencyOnUI, added_ids, removed_ids)); |
| } |
| |
| void DecrementWorkerRefCount(int process_id) { |
| if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| BrowserThread::PostTask(BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(&DecrementWorkerRefCount, process_id)); |
| return; |
| } |
| RenderProcessHostImpl* render_process_host_impl = |
| static_cast<RenderProcessHostImpl*>( |
| RenderProcessHost::FromID(process_id)); |
| if (render_process_host_impl) |
| render_process_host_impl->DecrementWorkerRefCount(); |
| } |
| |
| bool TryIncrementWorkerRefCount(int worker_process_id) { |
| RenderProcessHostImpl* render_process = static_cast<RenderProcessHostImpl*>( |
| RenderProcessHost::FromID(worker_process_id)); |
| if (!render_process || render_process->FastShutdownStarted()) { |
| return false; |
| } |
| render_process->IncrementWorkerRefCount(); |
| return true; |
| } |
| |
| } // namespace |
| |
| class SharedWorkerServiceImpl::SharedWorkerPendingInstance { |
| public: |
| struct SharedWorkerPendingRequest { |
| SharedWorkerPendingRequest(SharedWorkerMessageFilter* filter, |
| int route_id, |
| unsigned long long document_id, |
| int render_process_id, |
| int render_frame_route_id) |
| : filter(filter), |
| route_id(route_id), |
| document_id(document_id), |
| render_process_id(render_process_id), |
| render_frame_route_id(render_frame_route_id) {} |
| SharedWorkerMessageFilter* const filter; |
| const int route_id; |
| const unsigned long long document_id; |
| const int render_process_id; |
| const int render_frame_route_id; |
| }; |
| |
| typedef ScopedVector<SharedWorkerPendingRequest> SharedWorkerPendingRequests; |
| |
| explicit SharedWorkerPendingInstance( |
| scoped_ptr<SharedWorkerInstance> instance) |
| : instance_(instance.Pass()) {} |
| ~SharedWorkerPendingInstance() {} |
| SharedWorkerInstance* instance() { return instance_.get(); } |
| SharedWorkerInstance* release_instance() { return instance_.release(); } |
| SharedWorkerPendingRequests* requests() { return &requests_; } |
| SharedWorkerMessageFilter* FindFilter(int process_id) { |
| for (size_t i = 0; i < requests_.size(); ++i) { |
| if (requests_[i]->render_process_id == process_id) |
| return requests_[i]->filter; |
| } |
| return NULL; |
| } |
| void AddRequest(scoped_ptr<SharedWorkerPendingRequest> request_info) { |
| requests_.push_back(request_info.release()); |
| } |
| void RemoveRequest(int process_id) { |
| for (SharedWorkerPendingRequests::iterator request_itr = requests_.begin(); |
| request_itr != requests_.end();) { |
| if ((*request_itr)->render_process_id == process_id) |
| request_itr = requests_.erase(request_itr); |
| else |
| ++request_itr; |
| } |
| } |
| void RegisterToSharedWorkerHost(SharedWorkerHost* host) { |
| for (size_t i = 0; i < requests_.size(); ++i) { |
| SharedWorkerPendingRequest* request = requests_[i]; |
| host->AddFilter(request->filter, request->route_id); |
| host->worker_document_set()->Add(request->filter, |
| request->document_id, |
| request->render_process_id, |
| request->render_frame_route_id); |
| } |
| } |
| void SendWorkerCreatedMessages() { |
| for (size_t i = 0; i < requests_.size(); ++i) { |
| SharedWorkerPendingRequest* request = requests_[i]; |
| request->filter->Send(new ViewMsg_WorkerCreated(request->route_id)); |
| } |
| } |
| |
| private: |
| scoped_ptr<SharedWorkerInstance> instance_; |
| SharedWorkerPendingRequests requests_; |
| DISALLOW_COPY_AND_ASSIGN(SharedWorkerPendingInstance); |
| }; |
| |
| class SharedWorkerServiceImpl::SharedWorkerReserver |
| : public base::RefCountedThreadSafe<SharedWorkerReserver> { |
| public: |
| SharedWorkerReserver(int pending_instance_id, |
| int worker_process_id, |
| int worker_route_id, |
| bool is_new_worker, |
| const SharedWorkerInstance& instance) |
| : worker_process_id_(worker_process_id), |
| worker_route_id_(worker_route_id), |
| is_new_worker_(is_new_worker), |
| instance_(instance) {} |
| |
| void TryReserve(const base::Callback<void(bool)>& success_cb, |
| const base::Closure& failure_cb, |
| bool (*try_increment_worker_ref_count)(int)) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (!try_increment_worker_ref_count(worker_process_id_)) { |
| BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, failure_cb); |
| return; |
| } |
| bool pause_on_start = false; |
| if (is_new_worker_) { |
| pause_on_start = |
| SharedWorkerDevToolsManager::GetInstance()->WorkerCreated( |
| worker_process_id_, worker_route_id_, instance_); |
| } |
| BrowserThread::PostTask( |
| BrowserThread::IO, FROM_HERE, base::Bind(success_cb, pause_on_start)); |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<SharedWorkerReserver>; |
| ~SharedWorkerReserver() {} |
| |
| const int worker_process_id_; |
| const int worker_route_id_; |
| const bool is_new_worker_; |
| const SharedWorkerInstance instance_; |
| }; |
| |
| // static |
| bool (*SharedWorkerServiceImpl::s_try_increment_worker_ref_count_)(int) = |
| TryIncrementWorkerRefCount; |
| |
| SharedWorkerServiceImpl* SharedWorkerServiceImpl::GetInstance() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| return Singleton<SharedWorkerServiceImpl>::get(); |
| } |
| |
| SharedWorkerServiceImpl::SharedWorkerServiceImpl() |
| : update_worker_dependency_(UpdateWorkerDependency), |
| next_pending_instance_id_(0) { |
| } |
| |
| SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {} |
| |
| void SharedWorkerServiceImpl::ResetForTesting() { |
| last_worker_depended_renderers_.clear(); |
| worker_hosts_.clear(); |
| observers_.Clear(); |
| update_worker_dependency_ = UpdateWorkerDependency; |
| s_try_increment_worker_ref_count_ = TryIncrementWorkerRefCount; |
| } |
| |
| bool SharedWorkerServiceImpl::TerminateWorker(int process_id, int route_id) { |
| SharedWorkerHost* host = |
| worker_hosts_.get(std::make_pair(process_id, route_id)); |
| if (!host || !host->instance()) |
| return false; |
| host->TerminateWorker(); |
| return true; |
| } |
| |
| std::vector<WorkerService::WorkerInfo> SharedWorkerServiceImpl::GetWorkers() { |
| std::vector<WorkerService::WorkerInfo> results; |
| for (WorkerHostMap::const_iterator iter = worker_hosts_.begin(); |
| iter != worker_hosts_.end(); |
| ++iter) { |
| SharedWorkerHost* host = iter->second; |
| const SharedWorkerInstance* instance = host->instance(); |
| if (instance) { |
| WorkerService::WorkerInfo info; |
| info.url = instance->url(); |
| info.name = instance->name(); |
| info.route_id = host->worker_route_id(); |
| info.process_id = host->process_id(); |
| info.handle = host->container_render_filter()->PeerHandle(); |
| results.push_back(info); |
| } |
| } |
| return results; |
| } |
| |
| void SharedWorkerServiceImpl::AddObserver(WorkerServiceObserver* observer) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| observers_.AddObserver(observer); |
| } |
| |
| void SharedWorkerServiceImpl::RemoveObserver(WorkerServiceObserver* observer) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| observers_.RemoveObserver(observer); |
| } |
| |
| void SharedWorkerServiceImpl::CreateWorker( |
| const ViewHostMsg_CreateWorker_Params& params, |
| int route_id, |
| SharedWorkerMessageFilter* filter, |
| ResourceContext* resource_context, |
| const WorkerStoragePartitionId& partition_id, |
| bool* url_mismatch) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| *url_mismatch = false; |
| scoped_ptr<SharedWorkerInstance> instance( |
| new SharedWorkerInstance(params.url, |
| params.name, |
| params.content_security_policy, |
| params.security_policy_type, |
| resource_context, |
| partition_id)); |
| scoped_ptr<SharedWorkerPendingInstance::SharedWorkerPendingRequest> request( |
| new SharedWorkerPendingInstance::SharedWorkerPendingRequest( |
| filter, |
| route_id, |
| params.document_id, |
| filter->render_process_id(), |
| params.render_frame_route_id)); |
| if (SharedWorkerPendingInstance* pending = FindPendingInstance(*instance)) { |
| if (params.url != pending->instance()->url()) { |
| *url_mismatch = true; |
| return; |
| } |
| pending->AddRequest(request.Pass()); |
| return; |
| } |
| scoped_ptr<SharedWorkerPendingInstance> pending_instance( |
| new SharedWorkerPendingInstance(instance.Pass())); |
| pending_instance->AddRequest(request.Pass()); |
| ReserveRenderProcessToCreateWorker(pending_instance.Pass(), url_mismatch); |
| } |
| |
| void SharedWorkerServiceImpl::ForwardToWorker( |
| const IPC::Message& message, |
| SharedWorkerMessageFilter* filter) { |
| for (WorkerHostMap::const_iterator iter = worker_hosts_.begin(); |
| iter != worker_hosts_.end(); |
| ++iter) { |
| if (iter->second->FilterMessage(message, filter)) |
| return; |
| } |
| } |
| |
| void SharedWorkerServiceImpl::DocumentDetached( |
| unsigned long long document_id, |
| SharedWorkerMessageFilter* filter) { |
| ScopedWorkerDependencyChecker checker(this); |
| for (WorkerHostMap::const_iterator iter = worker_hosts_.begin(); |
| iter != worker_hosts_.end(); |
| ++iter) { |
| iter->second->DocumentDetached(filter, document_id); |
| } |
| } |
| |
| void SharedWorkerServiceImpl::WorkerContextClosed( |
| int worker_route_id, |
| SharedWorkerMessageFilter* filter) { |
| ScopedWorkerDependencyChecker checker(this); |
| if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) |
| host->WorkerContextClosed(); |
| } |
| |
| void SharedWorkerServiceImpl::WorkerContextDestroyed( |
| int worker_route_id, |
| SharedWorkerMessageFilter* filter) { |
| ScopedWorkerDependencyChecker checker(this); |
| scoped_ptr<SharedWorkerHost> host = |
| worker_hosts_.take_and_erase(std::make_pair(filter->render_process_id(), |
| worker_route_id)); |
| if (!host) |
| return; |
| host->WorkerContextDestroyed(); |
| } |
| |
| void SharedWorkerServiceImpl::WorkerScriptLoaded( |
| int worker_route_id, |
| SharedWorkerMessageFilter* filter) { |
| if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) |
| host->WorkerScriptLoaded(); |
| } |
| |
| void SharedWorkerServiceImpl::WorkerScriptLoadFailed( |
| int worker_route_id, |
| SharedWorkerMessageFilter* filter) { |
| ScopedWorkerDependencyChecker checker(this); |
| scoped_ptr<SharedWorkerHost> host = |
| worker_hosts_.take_and_erase(std::make_pair(filter->render_process_id(), |
| worker_route_id)); |
| if (!host) |
| return; |
| host->WorkerScriptLoadFailed(); |
| } |
| |
| void SharedWorkerServiceImpl::WorkerConnected( |
| int message_port_id, |
| int worker_route_id, |
| SharedWorkerMessageFilter* filter) { |
| if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) |
| host->WorkerConnected(message_port_id); |
| } |
| |
| void SharedWorkerServiceImpl::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) { |
| if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) |
| host->AllowDatabase(url, name, display_name, estimated_size, result); |
| } |
| |
| void SharedWorkerServiceImpl::AllowFileSystem( |
| int worker_route_id, |
| const GURL& url, |
| bool* result, |
| SharedWorkerMessageFilter* filter) { |
| if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) |
| host->AllowFileSystem(url, result); |
| } |
| |
| void SharedWorkerServiceImpl::AllowIndexedDB( |
| int worker_route_id, |
| const GURL& url, |
| const base::string16& name, |
| bool* result, |
| SharedWorkerMessageFilter* filter) { |
| if (SharedWorkerHost* host = FindSharedWorkerHost(filter, worker_route_id)) |
| host->AllowIndexedDB(url, name, result); |
| } |
| |
| void SharedWorkerServiceImpl::OnSharedWorkerMessageFilterClosing( |
| SharedWorkerMessageFilter* filter) { |
| ScopedWorkerDependencyChecker checker(this); |
| std::vector<ProcessRouteIdPair> remove_list; |
| for (WorkerHostMap::iterator iter = worker_hosts_.begin(); |
| iter != worker_hosts_.end(); |
| ++iter) { |
| iter->second->FilterShutdown(filter); |
| if (iter->first.first == filter->render_process_id()) |
| remove_list.push_back(iter->first); |
| } |
| for (size_t i = 0; i < remove_list.size(); ++i) { |
| scoped_ptr<SharedWorkerHost> host = |
| worker_hosts_.take_and_erase(remove_list[i]); |
| } |
| |
| std::vector<int> remove_pending_instance_list; |
| for (PendingInstaneMap::iterator iter = pending_instances_.begin(); |
| iter != pending_instances_.end(); |
| ++iter) { |
| iter->second->RemoveRequest(filter->render_process_id()); |
| if (!iter->second->requests()->size()) |
| remove_pending_instance_list.push_back(iter->first); |
| } |
| for (size_t i = 0; i < remove_pending_instance_list.size(); ++i) |
| pending_instances_.take_and_erase(remove_pending_instance_list[i]); |
| } |
| |
| void SharedWorkerServiceImpl::NotifyWorkerDestroyed(int worker_process_id, |
| int worker_route_id) { |
| FOR_EACH_OBSERVER(WorkerServiceObserver, |
| observers_, |
| WorkerDestroyed(worker_process_id, worker_route_id)); |
| } |
| |
| void SharedWorkerServiceImpl::ReserveRenderProcessToCreateWorker( |
| scoped_ptr<SharedWorkerPendingInstance> pending_instance, |
| bool* url_mismatch) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| DCHECK(!FindPendingInstance(*pending_instance->instance())); |
| if (url_mismatch) |
| *url_mismatch = false; |
| if (!pending_instance->requests()->size()) |
| return; |
| int worker_process_id = -1; |
| int worker_route_id = MSG_ROUTING_NONE; |
| bool is_new_worker = true; |
| SharedWorkerHost* host = FindSharedWorkerHost(*pending_instance->instance()); |
| if (host) { |
| if (pending_instance->instance()->url() != host->instance()->url()) { |
| if (url_mismatch) |
| *url_mismatch = true; |
| return; |
| } |
| worker_process_id = host->process_id(); |
| worker_route_id = host->worker_route_id(); |
| is_new_worker = false; |
| } else { |
| SharedWorkerMessageFilter* first_filter = |
| (*pending_instance->requests()->begin())->filter; |
| worker_process_id = first_filter->render_process_id(); |
| worker_route_id = first_filter->GetNextRoutingID(); |
| } |
| const int pending_instance_id = next_pending_instance_id_++; |
| scoped_refptr<SharedWorkerReserver> reserver( |
| new SharedWorkerReserver(pending_instance_id, |
| worker_process_id, |
| worker_route_id, |
| is_new_worker, |
| *pending_instance->instance())); |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| base::Bind( |
| &SharedWorkerReserver::TryReserve, |
| reserver, |
| base::Bind(&SharedWorkerServiceImpl::RenderProcessReservedCallback, |
| base::Unretained(this), |
| pending_instance_id, |
| worker_process_id, |
| worker_route_id, |
| is_new_worker), |
| base::Bind( |
| &SharedWorkerServiceImpl::RenderProcessReserveFailedCallback, |
| base::Unretained(this), |
| pending_instance_id, |
| worker_process_id, |
| worker_route_id, |
| is_new_worker), |
| s_try_increment_worker_ref_count_)); |
| pending_instances_.set(pending_instance_id, pending_instance.Pass()); |
| } |
| |
| void SharedWorkerServiceImpl::RenderProcessReservedCallback( |
| int pending_instance_id, |
| int worker_process_id, |
| int worker_route_id, |
| bool is_new_worker, |
| bool pause_on_start) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| // To offset the TryIncrementWorkerRefCount called for the reservation, |
| // calls DecrementWorkerRefCount after CheckWorkerDependency in |
| // ScopeWorkerDependencyChecker's destructor. |
| ScopedWorkerDependencyChecker checker( |
| this, base::Bind(&DecrementWorkerRefCount, worker_process_id)); |
| scoped_ptr<SharedWorkerPendingInstance> pending_instance = |
| pending_instances_.take_and_erase(pending_instance_id); |
| if (!pending_instance) |
| return; |
| if (!is_new_worker) { |
| SharedWorkerHost* existing_host = |
| worker_hosts_.get(std::make_pair(worker_process_id, worker_route_id)); |
| if (!existing_host) { |
| // Retry reserving a renderer process if the existed Shared Worker was |
| // destroyed on IO thread while reserving the renderer process on UI |
| // thread. |
| ReserveRenderProcessToCreateWorker(pending_instance.Pass(), NULL); |
| return; |
| } |
| pending_instance->RegisterToSharedWorkerHost(existing_host); |
| pending_instance->SendWorkerCreatedMessages(); |
| return; |
| } |
| SharedWorkerMessageFilter* filter = |
| pending_instance->FindFilter(worker_process_id); |
| if (!filter) { |
| pending_instance->RemoveRequest(worker_process_id); |
| // Retry reserving a renderer process if the requested renderer process was |
| // destroyed on IO thread while reserving the renderer process on UI thread. |
| ReserveRenderProcessToCreateWorker(pending_instance.Pass(), NULL); |
| return; |
| } |
| scoped_ptr<SharedWorkerHost> host(new SharedWorkerHost( |
| pending_instance->release_instance(), filter, worker_route_id)); |
| pending_instance->RegisterToSharedWorkerHost(host.get()); |
| const GURL url = host->instance()->url(); |
| const base::string16 name = host->instance()->name(); |
| host->Start(pause_on_start); |
| worker_hosts_.set(std::make_pair(worker_process_id, worker_route_id), |
| host.Pass()); |
| FOR_EACH_OBSERVER( |
| WorkerServiceObserver, |
| observers_, |
| WorkerCreated(url, name, worker_process_id, worker_route_id)); |
| } |
| |
| void SharedWorkerServiceImpl::RenderProcessReserveFailedCallback( |
| int pending_instance_id, |
| int worker_process_id, |
| int worker_route_id, |
| bool is_new_worker) { |
| worker_hosts_.take_and_erase( |
| std::make_pair(worker_process_id, worker_route_id)); |
| scoped_ptr<SharedWorkerPendingInstance> pending_instance = |
| pending_instances_.take_and_erase(pending_instance_id); |
| if (!pending_instance) |
| return; |
| pending_instance->RemoveRequest(worker_process_id); |
| // Retry reserving a renderer process. |
| ReserveRenderProcessToCreateWorker(pending_instance.Pass(), NULL); |
| } |
| |
| SharedWorkerHost* SharedWorkerServiceImpl::FindSharedWorkerHost( |
| SharedWorkerMessageFilter* filter, |
| int worker_route_id) { |
| return worker_hosts_.get(std::make_pair(filter->render_process_id(), |
| worker_route_id)); |
| } |
| |
| SharedWorkerHost* SharedWorkerServiceImpl::FindSharedWorkerHost( |
| const SharedWorkerInstance& instance) { |
| for (WorkerHostMap::const_iterator iter = worker_hosts_.begin(); |
| iter != worker_hosts_.end(); |
| ++iter) { |
| SharedWorkerHost* host = iter->second; |
| if (host->instance() && !host->closed() && |
| host->instance()->Matches(instance)) { |
| return iter->second; |
| } |
| } |
| return NULL; |
| } |
| |
| SharedWorkerServiceImpl::SharedWorkerPendingInstance* |
| SharedWorkerServiceImpl::FindPendingInstance( |
| const SharedWorkerInstance& instance) { |
| for (PendingInstaneMap::iterator iter = pending_instances_.begin(); |
| iter != pending_instances_.end(); |
| ++iter) { |
| if (iter->second->instance()->Matches(instance)) |
| return iter->second; |
| } |
| return NULL; |
| } |
| |
| const std::set<int> |
| SharedWorkerServiceImpl::GetRenderersWithWorkerDependency() { |
| std::set<int> dependent_renderers; |
| for (WorkerHostMap::iterator host_iter = worker_hosts_.begin(); |
| host_iter != worker_hosts_.end(); |
| ++host_iter) { |
| const int process_id = host_iter->first.first; |
| if (dependent_renderers.count(process_id)) |
| continue; |
| if (host_iter->second->instance() && |
| host_iter->second->worker_document_set()->ContainsExternalRenderer( |
| process_id)) { |
| dependent_renderers.insert(process_id); |
| } |
| } |
| return dependent_renderers; |
| } |
| |
| void SharedWorkerServiceImpl::CheckWorkerDependency() { |
| const std::set<int> current_worker_depended_renderers = |
| GetRenderersWithWorkerDependency(); |
| std::vector<int> added_items; |
| std::vector<int> removed_items; |
| std::set_difference(current_worker_depended_renderers.begin(), |
| current_worker_depended_renderers.end(), |
| last_worker_depended_renderers_.begin(), |
| last_worker_depended_renderers_.end(), |
| std::back_inserter(added_items)); |
| std::set_difference(last_worker_depended_renderers_.begin(), |
| last_worker_depended_renderers_.end(), |
| current_worker_depended_renderers.begin(), |
| current_worker_depended_renderers.end(), |
| std::back_inserter(removed_items)); |
| if (!added_items.empty() || !removed_items.empty()) { |
| last_worker_depended_renderers_ = current_worker_depended_renderers; |
| update_worker_dependency_(added_items, removed_items); |
| } |
| } |
| |
| void SharedWorkerServiceImpl::ChangeUpdateWorkerDependencyFuncForTesting( |
| UpdateWorkerDependencyFunc new_func) { |
| update_worker_dependency_ = new_func; |
| } |
| |
| void SharedWorkerServiceImpl::ChangeTryIncrementWorkerRefCountFuncForTesting( |
| bool (*new_func)(int)) { |
| s_try_increment_worker_ref_count_ = new_func; |
| } |
| |
| } // namespace content |