diff options
author | xiang.long <xiang.long@intel.com> | 2014-09-09 22:47:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-10 05:48:55 +0000 |
commit | 3c4d6ceb7f29eaa4024bfe268e033a2ea296066b (patch) | |
tree | be0160f853fe565aabedca50e098624a6bf37074 | |
parent | 575bc4ccd83d265e46e6214f8e1d2dea1b406432 (diff) | |
download | chromium_src-3c4d6ceb7f29eaa4024bfe268e033a2ea296066b.zip chromium_src-3c4d6ceb7f29eaa4024bfe268e033a2ea296066b.tar.gz chromium_src-3c4d6ceb7f29eaa4024bfe268e033a2ea296066b.tar.bz2 |
ServiceWorker: Move worker candidate process knowledge to ServiceWorkerProcessManager.
Before this CL:
Candidate processes info is saved in EmbeddedWorkerInstance, when a new
worker instance is created for a same scope, the info will be absent for
the new worker. E.g., periodic update will spawn a new process every time.
After this CL:
Candidate processes info will be saved in ServiceWorkerProcessManager
key by registration scope. Then different versions with the same scope could
share this info.
BUG=399982
TEST=content_unittests --gtest_filter=ServiceWorker*
Review URL: https://codereview.chromium.org/443593002
Cr-Commit-Position: refs/heads/master@{#294113}
27 files changed, 354 insertions, 361 deletions
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index 7cf0f18..ee909a5 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc @@ -127,7 +127,6 @@ void EmbeddedWorkerInstance::Start(int64 service_worker_version_id, const GURL& scope, const GURL& script_url, bool pause_after_download, - const std::vector<int>& possible_process_ids, const StatusCallback& callback) { if (!context_) { callback.Run(SERVICE_WORKER_ERROR_ABORT); @@ -151,7 +150,7 @@ void EmbeddedWorkerInstance::Start(int64 service_worker_version_id, params->wait_for_debugger = false; context_->process_manager()->AllocateWorkerProcess( embedded_worker_id_, - SortProcesses(possible_process_ids), + scope, script_url, base::Bind(&EmbeddedWorkerInstance::RunProcessAllocated, weak_factory_.GetWeakPtr(), @@ -186,23 +185,6 @@ ServiceWorkerStatusCode EmbeddedWorkerInstance::SendMessage( thread_id_, embedded_worker_id_, message)); } -void EmbeddedWorkerInstance::AddProcessReference(int process_id) { - ProcessRefMap::iterator found = process_refs_.find(process_id); - if (found == process_refs_.end()) - found = process_refs_.insert(std::make_pair(process_id, 0)).first; - ++found->second; -} - -void EmbeddedWorkerInstance::ReleaseProcessReference(int process_id) { - ProcessRefMap::iterator found = process_refs_.find(process_id); - if (found == process_refs_.end()) { - NOTREACHED() << "Releasing unknown process ref " << process_id; - return; - } - if (--found->second == 0) - process_refs_.erase(found); -} - EmbeddedWorkerInstance::EmbeddedWorkerInstance( base::WeakPtr<ServiceWorkerContextCore> context, int embedded_worker_id) @@ -366,26 +348,4 @@ void EmbeddedWorkerInstance::RemoveListener(Listener* listener) { listener_list_.RemoveObserver(listener); } -std::vector<int> EmbeddedWorkerInstance::SortProcesses( - const std::vector<int>& possible_process_ids) const { - // Add the |possible_process_ids| to the existing process_refs_ since each one - // is likely to take a reference once the SW starts up. - ProcessRefMap refs_with_new_ids = process_refs_; - for (std::vector<int>::const_iterator it = possible_process_ids.begin(); - it != possible_process_ids.end(); - ++it) { - refs_with_new_ids[*it]++; - } - - std::vector<std::pair<int, int> > counted(refs_with_new_ids.begin(), - refs_with_new_ids.end()); - // Sort descending by the reference count. - std::sort(counted.begin(), counted.end(), SecondGreater()); - - std::vector<int> result(counted.size()); - for (size_t i = 0; i < counted.size(); ++i) - result[i] = counted[i].first; - return result; -} - } // namespace content diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h index 9abde46..510e72b 100644 --- a/content/browser/service_worker/embedded_worker_instance.h +++ b/content/browser/service_worker/embedded_worker_instance.h @@ -76,7 +76,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance { const GURL& scope, const GURL& script_url, bool pause_after_download, - const std::vector<int>& possible_process_ids, const StatusCallback& callback); // Stops the worker. It is invalid to call this when the worker is @@ -91,12 +90,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance { void ResumeAfterDownload(); - // Add or remove |process_id| to the internal process set where this - // worker can be started. - void AddProcessReference(int process_id); - void ReleaseProcessReference(int process_id); - bool HasProcessToRun() const { return !process_refs_.empty(); } - int embedded_worker_id() const { return embedded_worker_id_; } Status status() const { return status_; } int process_id() const { return process_id_; } @@ -113,9 +106,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance { friend class EmbeddedWorkerRegistry; FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop); - FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, SortProcesses); - - typedef std::map<int, int> ProcessRefMap; // Constructor is called via EmbeddedWorkerRegistry::CreateWorker(). // This instance holds a ref of |registry|. @@ -185,11 +175,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance { int line_number, const GURL& source_url); - // Chooses a list of processes to try to start this worker in, ordered by how - // many clients are currently in those processes. - std::vector<int> SortProcesses( - const std::vector<int>& possible_process_ids) const; - base::WeakPtr<ServiceWorkerContextCore> context_; scoped_refptr<EmbeddedWorkerRegistry> registry_; const int embedded_worker_id_; @@ -200,7 +185,6 @@ class CONTENT_EXPORT EmbeddedWorkerInstance { int thread_id_; int worker_devtools_agent_route_id_; - ProcessRefMap process_refs_; ListenerList listener_list_; base::WeakPtrFactory<EmbeddedWorkerInstance> weak_factory_; diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc index 7f1fcca..be2fb59 100644 --- a/content/browser/service_worker/embedded_worker_instance_unittest.cc +++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc @@ -60,23 +60,21 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) { embedded_worker_registry()->CreateWorker(); EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); - const int embedded_worker_id = worker->embedded_worker_id(); const int64 service_worker_version_id = 55L; - const GURL scope("http://example.com/"); + const GURL pattern("http://example.com/"); const GURL url("http://example.com/worker.js"); - // Simulate adding one process to the worker. - helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId); + // Simulate adding one process to the pattern. + helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId); // Start should succeed. ServiceWorkerStatusCode status; base::RunLoop run_loop; worker->Start( service_worker_version_id, - scope, + pattern, url, false, - std::vector<int>(), base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure())); run_loop.Run(); EXPECT_EQ(SERVICE_WORKER_OK, status); @@ -108,20 +106,19 @@ TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) { EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); const int64 service_worker_version_id = 55L; - const GURL scope("http://example.com/"); + const GURL pattern("http://example.com/"); const GURL url("http://example.com/worker.js"); ServiceWorkerStatusCode status; base::RunLoop run_loop; // Begin starting the worker. - std::vector<int> available_process; - available_process.push_back(kRenderProcessId); + context()->process_manager()->AddProcessReferenceToPattern( + pattern, kRenderProcessId); worker->Start( service_worker_version_id, - scope, + pattern, url, false, - available_process, base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure())); // But destroy it before it gets a chance to complete. worker.reset(); @@ -133,38 +130,4 @@ TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) { ipc_sink()->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID)); } -TEST_F(EmbeddedWorkerInstanceTest, SortProcesses) { - scoped_ptr<EmbeddedWorkerInstance> worker = - embedded_worker_registry()->CreateWorker(); - EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status()); - - // Simulate adding processes to the worker. - // Process 1 has 1 ref, 2 has 2 refs and 3 has 3 refs. - const int embedded_worker_id = worker->embedded_worker_id(); - helper_->SimulateAddProcessToWorker(embedded_worker_id, 1); - helper_->SimulateAddProcessToWorker(embedded_worker_id, 2); - helper_->SimulateAddProcessToWorker(embedded_worker_id, 2); - helper_->SimulateAddProcessToWorker(embedded_worker_id, 3); - helper_->SimulateAddProcessToWorker(embedded_worker_id, 3); - helper_->SimulateAddProcessToWorker(embedded_worker_id, 3); - - // Process 3 has the biggest # of references and it should be chosen. - EXPECT_THAT(worker->SortProcesses(std::vector<int>()), - testing::ElementsAre(3, 2, 1)); - EXPECT_EQ(-1, worker->process_id()); - - // Argument processes are added to the existing set, but only for a single - // call. - std::vector<int> registering_processes; - registering_processes.push_back(1); - registering_processes.push_back(1); - registering_processes.push_back(1); - registering_processes.push_back(4); - EXPECT_THAT(worker->SortProcesses(registering_processes), - testing::ElementsAre(1, 3, 2, 4)); - - EXPECT_THAT(worker->SortProcesses(std::vector<int>()), - testing::ElementsAre(3, 2, 1)); -} - } // namespace content diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index b0f05c7..97adcf1 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc @@ -37,13 +37,12 @@ EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() { wrapper_->Shutdown(); } -void EmbeddedWorkerTestHelper::SimulateAddProcessToWorker( - int embedded_worker_id, +void EmbeddedWorkerTestHelper::SimulateAddProcessToPattern( + const GURL& pattern, int process_id) { - EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker); registry()->AddChildProcessSender(process_id, this); - worker->AddProcessReference(process_id); + wrapper_->process_manager()->AddProcessReferenceToPattern( + pattern, process_id); } bool EmbeddedWorkerTestHelper::Send(IPC::Message* message) { diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h index 0034b5c..c36773d 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.h +++ b/content/browser/service_worker/embedded_worker_test_helper.h @@ -48,9 +48,9 @@ class EmbeddedWorkerTestHelper : public IPC::Sender, explicit EmbeddedWorkerTestHelper(int mock_render_process_id); virtual ~EmbeddedWorkerTestHelper(); - // Call this to simulate add/associate a process to a worker. + // Call this to simulate add/associate a process to a pattern. // This also registers this sender for the process. - void SimulateAddProcessToWorker(int embedded_worker_id, int process_id); + void SimulateAddProcessToPattern(const GURL& pattern, int process_id); // IPC::Sender implementation. virtual bool Send(IPC::Message* message) OVERRIDE; diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc index 6355340..8ad27e9 100644 --- a/content/browser/service_worker/service_worker_browsertest.cc +++ b/content/browser/service_worker/service_worker_browsertest.cc @@ -294,9 +294,9 @@ class ServiceWorkerBrowserTest : public ContentBrowserTest { ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); } ServiceWorkerContext* public_context() { return wrapper(); } - void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) { - worker->AddProcessReference( - shell()->web_contents()->GetRenderProcessHost()->GetID()); + void AssociateRendererProcessToPattern(const GURL& pattern) { + wrapper_->process_manager()->AddProcessReferenceToPattern( + pattern, shell()->web_contents()->GetRenderProcessHost()->GetID()); } private: @@ -326,21 +326,20 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest, EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status()); worker_->AddListener(this); - AssociateRendererProcessToWorker(worker_.get()); const int64 service_worker_version_id = 33L; - const GURL scope = embedded_test_server()->GetURL("/"); + const GURL pattern = embedded_test_server()->GetURL("/"); const GURL script_url = embedded_test_server()->GetURL( "/service_worker/worker.js"); - std::vector<int> processes; - processes.push_back( - shell()->web_contents()->GetRenderProcessHost()->GetID()); + AssociateRendererProcessToPattern(pattern); + int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID(); + wrapper()->process_manager()->AddProcessReferenceToPattern( + pattern, process_id); worker_->Start( service_worker_version_id, - scope, + pattern, script_url, pause_mode_ != DONT_PAUSE, - processes, base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this)); } void StartOnIOThread2(ServiceWorkerStatusCode status) { @@ -503,8 +502,9 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest { } void SetUpRegistrationOnIOThread(const std::string& worker_url) { + const GURL pattern = embedded_test_server()->GetURL("/"); registration_ = new ServiceWorkerRegistration( - embedded_test_server()->GetURL("/"), + pattern, wrapper()->context()->storage()->NewRegistrationId(), wrapper()->context()->AsWeakPtr()); version_ = new ServiceWorkerVersion( @@ -512,7 +512,7 @@ class ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest { embedded_test_server()->GetURL(worker_url), wrapper()->context()->storage()->NewVersionId(), wrapper()->context()->AsWeakPtr()); - AssociateRendererProcessToWorker(version_->embedded_worker()); + AssociateRendererProcessToPattern(pattern); } void StartOnIOThread(const base::Closure& done, diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index 5647ef9..4615f8e 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc @@ -175,7 +175,6 @@ ServiceWorkerContextCore::GetProviderHostIterator() { void ServiceWorkerContextCore::RegisterServiceWorker( const GURL& pattern, const GURL& script_url, - int source_process_id, ServiceWorkerProviderHost* provider_host, const RegistrationCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -186,13 +185,10 @@ void ServiceWorkerContextCore::RegisterServiceWorker( return; } - // TODO(kinuko): Wire the provider_host so that we can tell which document - // is calling .register. - job_coordinator_->Register( pattern, script_url, - source_process_id, + provider_host, base::Bind(&ServiceWorkerContextCore::RegistrationComplete, AsWeakPtr(), pattern, @@ -408,7 +404,9 @@ void ServiceWorkerContextCore::OnReportConsoleMessage( } ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() { - return wrapper_->process_manager(); + if (wrapper_) + return wrapper_->process_manager(); + return NULL; } } // namespace content diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h index d3d9898..83ef2f6 100644 --- a/content/browser/service_worker/service_worker_context_core.h +++ b/content/browser/service_worker/service_worker_context_core.h @@ -145,11 +145,9 @@ class CONTENT_EXPORT ServiceWorkerContextCore // A child process of |source_process_id| may be used to run the created // worker for initial installation. - // Non-null |provider_host| must be given if this is called from a document, - // whose process_id() must match with |source_process_id|. + // Non-null |provider_host| must be given if this is called from a document. void RegisterServiceWorker(const GURL& pattern, const GURL& script_url, - int source_process_id, ServiceWorkerProviderHost* provider_host, const RegistrationCallback& callback); void UnregisterServiceWorker(const GURL& pattern, diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc index ad550f8..0fb2fb9 100644 --- a/content/browser/service_worker/service_worker_context_unittest.cc +++ b/content/browser/service_worker/service_worker_context_unittest.cc @@ -144,7 +144,6 @@ TEST_F(ServiceWorkerContextTest, Register) { context()->RegisterServiceWorker( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, ®istration_id, &version_id)); @@ -187,7 +186,6 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) { context()->RegisterServiceWorker( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, ®istration_id, &version_id)); @@ -230,7 +228,6 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) { context()->RegisterServiceWorker( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, ®istration_id, &version_id)); @@ -271,7 +268,6 @@ TEST_F(ServiceWorkerContextTest, Unregister) { context()->RegisterServiceWorker( pattern, GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, ®istration_id, &version_id)); @@ -311,7 +307,6 @@ TEST_F(ServiceWorkerContextTest, RegisterNewScript) { context()->RegisterServiceWorker( pattern, GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, &old_registration_id, &old_version_id)); @@ -327,7 +322,6 @@ TEST_F(ServiceWorkerContextTest, RegisterNewScript) { context()->RegisterServiceWorker( pattern, GURL("http://www.example.com/service_worker_new.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, &new_registration_id, &new_version_id)); @@ -353,7 +347,6 @@ TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) { context()->RegisterServiceWorker( pattern, script_url, - render_process_id_, NULL, MakeRegisteredCallback(&called, &old_registration_id, &old_version_id)); @@ -369,7 +362,6 @@ TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) { context()->RegisterServiceWorker( pattern, script_url, - render_process_id_, NULL, MakeRegisteredCallback(&called, &new_registration_id, &new_version_id)); @@ -388,7 +380,6 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) { context()->RegisterServiceWorker( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, ®istration_id, &version_id)); @@ -436,7 +427,6 @@ TEST_F(ServiceWorkerContextTest, DeleteAndStartOver) { context()->RegisterServiceWorker( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, NULL, MakeRegisteredCallback(&called, ®istration_id, &version_id)); diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index c21e459..bedf37e 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc @@ -106,7 +106,6 @@ void ServiceWorkerContextWrapper::RegisterServiceWorker( context()->RegisterServiceWorker( pattern, script_url, - -1, NULL /* provider_host */, base::Bind(&FinishRegistrationOnIO, continuation)); } diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc index a0bdabf..42e2ae1 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.cc +++ b/content/browser/service_worker/service_worker_dispatcher_host.cc @@ -245,7 +245,6 @@ void ServiceWorkerDispatcherHost::OnRegisterServiceWorker( GetContext()->RegisterServiceWorker( pattern, script_url, - render_process_id_, provider_host, base::Bind(&ServiceWorkerDispatcherHost::RegistrationComplete, this, diff --git a/content/browser/service_worker/service_worker_handle_unittest.cc b/content/browser/service_worker/service_worker_handle_unittest.cc index 75b3016..3368dc1 100644 --- a/content/browser/service_worker/service_worker_handle_unittest.cc +++ b/content/browser/service_worker/service_worker_handle_unittest.cc @@ -46,8 +46,9 @@ class ServiceWorkerHandleTest : public testing::Test { virtual void SetUp() OVERRIDE { helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId)); + const GURL pattern("http://www.example.com/"); registration_ = new ServiceWorkerRegistration( - GURL("http://www.example.com/"), + pattern, 1L, helper_->context()->AsWeakPtr()); version_ = new ServiceWorkerVersion( @@ -56,9 +57,7 @@ class ServiceWorkerHandleTest : public testing::Test { 1L, helper_->context()->AsWeakPtr()); - // Simulate adding one process to the worker. - int embedded_worker_id = version_->embedded_worker()->embedded_worker_id(); - helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId); + helper_->SimulateAddProcessToPattern(pattern, kRenderProcessId); } virtual void TearDown() OVERRIDE { diff --git a/content/browser/service_worker/service_worker_job_coordinator.cc b/content/browser/service_worker/service_worker_job_coordinator.cc index e5e8962..c3bfb39 100644 --- a/content/browser/service_worker/service_worker_job_coordinator.cc +++ b/content/browser/service_worker/service_worker_job_coordinator.cc @@ -71,14 +71,14 @@ ServiceWorkerJobCoordinator::~ServiceWorkerJobCoordinator() { void ServiceWorkerJobCoordinator::Register( const GURL& pattern, const GURL& script_url, - int source_process_id, + ServiceWorkerProviderHost* provider_host, const ServiceWorkerRegisterJob::RegistrationCallback& callback) { scoped_ptr<ServiceWorkerRegisterJobBase> job( new ServiceWorkerRegisterJob(context_, pattern, script_url)); ServiceWorkerRegisterJob* queued_job = static_cast<ServiceWorkerRegisterJob*>( job_queues_[pattern].Push(job.Pass())); - queued_job->AddCallback(callback, source_process_id); + queued_job->AddCallback(callback, provider_host); } void ServiceWorkerJobCoordinator::Unregister( diff --git a/content/browser/service_worker/service_worker_job_coordinator.h b/content/browser/service_worker/service_worker_job_coordinator.h index fa33562..b85a84b 100644 --- a/content/browser/service_worker/service_worker_job_coordinator.h +++ b/content/browser/service_worker/service_worker_job_coordinator.h @@ -16,6 +16,7 @@ namespace content { class EmbeddedWorkerRegistry; +class ServiceWorkerProviderHost; class ServiceWorkerRegistration; class ServiceWorkerStorage; @@ -28,7 +29,7 @@ class CONTENT_EXPORT ServiceWorkerJobCoordinator { void Register(const GURL& pattern, const GURL& script_url, - int source_process_id, + ServiceWorkerProviderHost* provider_host, const ServiceWorkerRegisterJob::RegistrationCallback& callback); void Unregister( diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc index 8793169..2cda8e0 100644 --- a/content/browser/service_worker/service_worker_job_unittest.cc +++ b/content/browser/service_worker/service_worker_job_unittest.cc @@ -132,7 +132,7 @@ TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) { job_coordinator()->Register( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration)); EXPECT_FALSE(called); base::RunLoop().RunUntilIdle(); @@ -159,7 +159,7 @@ TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) { job_coordinator()->Register( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, &original_registration)); EXPECT_FALSE(called); base::RunLoop().RunUntilIdle(); @@ -190,7 +190,7 @@ TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) { job_coordinator()->Register( GURL("http://www.example.com/one/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called1, &original_registration1)); bool called2; @@ -198,7 +198,7 @@ TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) { job_coordinator()->Register( GURL("http://www.example.com/two/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called2, &original_registration2)); EXPECT_FALSE(called1); @@ -229,7 +229,7 @@ TEST_F(ServiceWorkerJobTest, Register) { job_coordinator()->Register( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); ASSERT_FALSE(called); @@ -248,7 +248,7 @@ TEST_F(ServiceWorkerJobTest, Unregister) { job_coordinator()->Register( pattern, GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); ASSERT_FALSE(called); @@ -298,7 +298,7 @@ TEST_F(ServiceWorkerJobTest, RegisterNewScript) { job_coordinator()->Register( pattern, GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration)); ASSERT_FALSE(called); @@ -322,7 +322,7 @@ TEST_F(ServiceWorkerJobTest, RegisterNewScript) { job_coordinator()->Register( pattern, GURL("http://www.example.com/service_worker_new.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration)); ASSERT_FALSE(called); @@ -355,7 +355,7 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) { job_coordinator()->Register( pattern, script_url, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, &old_registration)); ASSERT_FALSE(called); @@ -377,7 +377,7 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) { job_coordinator()->Register( pattern, script_url, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, &new_registration)); ASSERT_FALSE(called); @@ -424,7 +424,7 @@ TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) { job_coordinator()->Register( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration( SERVICE_WORKER_ERROR_START_WORKER_FAILED, &called, ®istration)); @@ -446,7 +446,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) { job_coordinator()->Register( pattern, script_url, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, ®istration_called, ®istration)); bool unregistration_called = false; @@ -483,7 +483,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) { job_coordinator()->Register( pattern, script_url1, - render_process_id_, + NULL, SaveRegistration( SERVICE_WORKER_OK, ®istration1_called, ®istration1)); @@ -493,7 +493,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) { job_coordinator()->Register( pattern, script_url2, - render_process_id_, + NULL, SaveRegistration( SERVICE_WORKER_OK, ®istration2_called, ®istration2)); @@ -527,7 +527,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) { job_coordinator()->Register( pattern, script_url, - render_process_id_, + NULL, SaveRegistration( SERVICE_WORKER_OK, ®istration1_called, ®istration1)); @@ -536,7 +536,7 @@ TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) { job_coordinator()->Register( pattern, script_url, - render_process_id_, + NULL, SaveRegistration( SERVICE_WORKER_OK, ®istration2_called, ®istration2)); @@ -604,7 +604,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_Register) { job_coordinator()->Register( pattern1, script_url1, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_ERROR_ABORT, ®istration_called1, ®istration1)); @@ -613,7 +613,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_Register) { job_coordinator()->Register( pattern2, script_url2, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_ERROR_ABORT, ®istration_called2, ®istration2)); @@ -679,7 +679,7 @@ TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) { job_coordinator()->Register( pattern, script_url, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_ERROR_ABORT, ®istration_called, ®istration)); @@ -717,7 +717,7 @@ TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) { job_coordinator()->Register( GURL("http://www.example.com/"), script_url, - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(called); @@ -758,7 +758,7 @@ TEST_F(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) { job_coordinator()->Register( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(called); @@ -789,7 +789,7 @@ TEST_F(ServiceWorkerJobTest, job_coordinator()->Register( GURL("http://www.example.com/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); base::RunLoop().RunUntilIdle(); ASSERT_TRUE(called); @@ -913,7 +913,7 @@ class UpdateJobTestHelper job_coordinator()->Register( test_origin.Resolve(kScope), test_origin.Resolve(kScript), - mock_render_process_id(), + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(called); @@ -1128,7 +1128,7 @@ TEST_F(ServiceWorkerJobTest, Update_NewestVersionChanged) { job_coordinator()->Register( GURL("http://www.example.com/one/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); EXPECT_FALSE(called); @@ -1161,7 +1161,7 @@ TEST_F(ServiceWorkerJobTest, Update_UninstallingRegistration) { job_coordinator()->Register( GURL("http://www.example.com/one/"), GURL("http://www.example.com/service_worker.js"), - render_process_id_, + NULL, SaveRegistration(SERVICE_WORKER_OK, &called, ®istration)); EXPECT_FALSE(called); diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc index ab6012a..16e585b 100644 --- a/content/browser/service_worker/service_worker_process_manager.cc +++ b/content/browser/service_worker/service_worker_process_manager.cc @@ -12,6 +12,18 @@ namespace content { +namespace { + +// Functor to sort by the .second element of a struct. +struct SecondGreater { + template <typename Value> + bool operator()(const Value& lhs, const Value& rhs) { + return lhs.second > rhs.second; + } +}; + +} // namespace + static bool IncrementWorkerRefCountByPid(int process_id) { RenderProcessHost* rph = RenderProcessHost::FromID(process_id); if (!rph || rph->FastShutdownStarted()) @@ -61,9 +73,66 @@ void ServiceWorkerProcessManager::Shutdown() { instance_info_.clear(); } +void ServiceWorkerProcessManager::AddProcessReferenceToPattern( + const GURL& pattern, int process_id) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&ServiceWorkerProcessManager::AddProcessReferenceToPattern, + weak_this_, + pattern, + process_id)); + return; + } + + ProcessRefMap& process_refs = pattern_processes_[pattern]; + ++process_refs[process_id]; +} + +void ServiceWorkerProcessManager::RemoveProcessReferenceFromPattern( + const GURL& pattern, int process_id) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &ServiceWorkerProcessManager::RemoveProcessReferenceFromPattern, + weak_this_, + pattern, + process_id)); + return; + } + + PatternProcessRefMap::iterator it = pattern_processes_.find(pattern); + if (it == pattern_processes_.end()) { + NOTREACHED() << "process refrences not found for pattern: " << pattern; + return; + } + ProcessRefMap& process_refs = it->second; + ProcessRefMap::iterator found = process_refs.find(process_id); + if (found == process_refs.end()) { + NOTREACHED() << "Releasing unknown process ref " << process_id; + return; + } + if (--found->second == 0) { + process_refs.erase(found); + if (process_refs.empty()) + pattern_processes_.erase(it); + } +} + +bool ServiceWorkerProcessManager::PatternHasProcessToRun( + const GURL& pattern) const { + PatternProcessRefMap::const_iterator it = pattern_processes_.find(pattern); + if (it == pattern_processes_.end()) + return false; + return !it->second.empty(); +} + void ServiceWorkerProcessManager::AllocateWorkerProcess( int embedded_worker_id, - const std::vector<int>& process_ids, + const GURL& pattern, const GURL& script_url, const base::Callback<void(ServiceWorkerStatusCode, int process_id)>& callback) { @@ -74,7 +143,7 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess( base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess, weak_this_, embedded_worker_id, - process_ids, + pattern, script_url, callback)); return; @@ -93,17 +162,18 @@ void ServiceWorkerProcessManager::AllocateWorkerProcess( DCHECK(!ContainsKey(instance_info_, embedded_worker_id)) << embedded_worker_id << " already has a process allocated"; - for (std::vector<int>::const_iterator it = process_ids.begin(); - it != process_ids.end(); + std::vector<int> sorted_candidates = SortProcessesForPattern(pattern); + for (std::vector<int>::const_iterator it = sorted_candidates.begin(); + it != sorted_candidates.end(); ++it) { - if (IncrementWorkerRefCountByPid(*it)) { - instance_info_.insert( - std::make_pair(embedded_worker_id, ProcessInfo(*it))); - BrowserThread::PostTask(BrowserThread::IO, - FROM_HERE, - base::Bind(callback, SERVICE_WORKER_OK, *it)); - return; - } + if (!IncrementWorkerRefCountByPid(*it)) + continue; + instance_info_.insert( + std::make_pair(embedded_worker_id, ProcessInfo(*it))); + BrowserThread::PostTask(BrowserThread::IO, + FROM_HERE, + base::Bind(callback, SERVICE_WORKER_OK, *it)); + return; } if (!browser_context_) { @@ -179,6 +249,22 @@ void ServiceWorkerProcessManager::ReleaseWorkerProcess(int embedded_worker_id) { instance_info_.erase(info); } +std::vector<int> ServiceWorkerProcessManager::SortProcessesForPattern( + const GURL& pattern) const { + PatternProcessRefMap::const_iterator it = pattern_processes_.find(pattern); + if (it == pattern_processes_.end()) + return std::vector<int>(); + + std::vector<std::pair<int, int> > counted( + it->second.begin(), it->second.end()); + std::sort(counted.begin(), counted.end(), SecondGreater()); + + std::vector<int> result(counted.size()); + for (size_t i = 0; i < counted.size(); ++i) + result[i] = counted[i].first; + return result; +} + } // namespace content namespace base { diff --git a/content/browser/service_worker/service_worker_process_manager.h b/content/browser/service_worker/service_worker_process_manager.h index 85fbcc1..edfef42 100644 --- a/content/browser/service_worker/service_worker_process_manager.h +++ b/content/browser/service_worker/service_worker_process_manager.h @@ -9,6 +9,7 @@ #include <vector> #include "base/callback.h" +#include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "content/common/service_worker/service_worker_status_code.h" @@ -21,9 +22,9 @@ class BrowserContext; class SiteInstance; // Interacts with the UI thread to keep RenderProcessHosts alive while the -// ServiceWorker system is using them. Each instance of -// ServiceWorkerProcessManager is destroyed on the UI thread shortly after its -// ServiceWorkerContextWrapper is destroyed. +// ServiceWorker system is using them. It also tracks candidate processes +// for each pattern. Each instance of ServiceWorkerProcessManager is destroyed +// on the UI thread shortly after its ServiceWorkerContextWrapper is destroyed. class CONTENT_EXPORT ServiceWorkerProcessManager { public: // |*this| must be owned by a ServiceWorkerContextWrapper in a @@ -38,16 +39,14 @@ class CONTENT_EXPORT ServiceWorkerProcessManager { void Shutdown(); // Returns a reference to a running process suitable for starting the Service - // Worker at |script_url|. Processes in |process_ids| will be checked in order - // for existence, and if none exist, then a new process will be created. Posts - // |callback| to the IO thread to indicate whether creation succeeded and the - // process ID that has a new reference. + // Worker at |script_url|. Posts |callback| to the IO thread to indicate + // whether creation succeeded and the process ID that has a new reference. // // Allocation can fail with SERVICE_WORKER_ERROR_START_WORKER_FAILED if // RenderProcessHost::Init fails. void AllocateWorkerProcess( int embedded_worker_id, - const std::vector<int>& process_ids, + const GURL& pattern, const GURL& script_url, const base::Callback<void(ServiceWorkerStatusCode, int process_id)>& callback); @@ -65,7 +64,17 @@ class CONTENT_EXPORT ServiceWorkerProcessManager { process_id_for_test_ = process_id; } + // Adds/removes process reference for the |pattern|, the process with highest + // references count will be chosen to start a worker. + void AddProcessReferenceToPattern(const GURL& pattern, int process_id); + void RemoveProcessReferenceFromPattern(const GURL& pattern, int process_id); + + // Returns true if the |pattern| has at least one process to run. + bool PatternHasProcessToRun(const GURL& pattern) const; + private: + FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProcessManagerTest, SortProcess); + // Information about the process for an EmbeddedWorkerInstance. struct ProcessInfo { explicit ProcessInfo(const scoped_refptr<SiteInstance>& site_instance); @@ -84,6 +93,15 @@ class CONTENT_EXPORT ServiceWorkerProcessManager { int process_id; }; + // Maps the process ID to its reference count. + typedef std::map<int, int> ProcessRefMap; + + // Maps registration scope pattern to ProcessRefMap. + typedef std::map<const GURL, ProcessRefMap> PatternProcessRefMap; + + // Returns a process vector sorted by the reference count for the |pattern|. + std::vector<int> SortProcessesForPattern(const GURL& pattern) const; + // These fields are only accessed on the UI thread. BrowserContext* browser_context_; @@ -100,6 +118,10 @@ class CONTENT_EXPORT ServiceWorkerProcessManager { // EmbeddedWorkerInstances. int process_id_for_test_; + // Candidate processes info for each pattern, should be accessed on the + // UI thread. + PatternProcessRefMap pattern_processes_; + // Used to double-check that we don't access *this after it's destroyed. base::WeakPtrFactory<ServiceWorkerProcessManager> weak_this_factory_; const base::WeakPtr<ServiceWorkerProcessManager> weak_this_; diff --git a/content/browser/service_worker/service_worker_process_manager_unittest.cc b/content/browser/service_worker/service_worker_process_manager_unittest.cc new file mode 100644 index 0000000..aedc1eb --- /dev/null +++ b/content/browser/service_worker/service_worker_process_manager_unittest.cc @@ -0,0 +1,56 @@ +// 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 "base/basictypes.h" +#include "content/browser/service_worker/service_worker_process_manager.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { + +class ServiceWorkerProcessManagerTest : public testing::Test { + public: + ServiceWorkerProcessManagerTest() {} + + virtual void SetUp() OVERRIDE { + process_manager_.reset(new ServiceWorkerProcessManager(NULL)); + pattern_ = GURL("http://www.example.com/"); + } + + virtual void TearDown() OVERRIDE { + process_manager_.reset(); + } + + protected: + scoped_ptr<ServiceWorkerProcessManager> process_manager_; + GURL pattern_; + + private: + content::TestBrowserThreadBundle thread_bundle_; + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProcessManagerTest); +}; + +TEST_F(ServiceWorkerProcessManagerTest, SortProcess) { + // Process 1 has 2 ref, 2 has 3 refs and 3 has 1 refs. + process_manager_->AddProcessReferenceToPattern(pattern_, 1); + process_manager_->AddProcessReferenceToPattern(pattern_, 1); + process_manager_->AddProcessReferenceToPattern(pattern_, 2); + process_manager_->AddProcessReferenceToPattern(pattern_, 2); + process_manager_->AddProcessReferenceToPattern(pattern_, 2); + process_manager_->AddProcessReferenceToPattern(pattern_, 3); + + // Process 2 has the biggest # of references and it should be chosen. + EXPECT_THAT(process_manager_->SortProcessesForPattern(pattern_), + testing::ElementsAre(2, 1, 3)); + + process_manager_->RemoveProcessReferenceFromPattern(pattern_, 1); + process_manager_->RemoveProcessReferenceFromPattern(pattern_, 1); + // Scores for each process: 2 : 3, 3 : 1, process 1 is removed. + EXPECT_THAT(process_manager_->SortProcessesForPattern(pattern_), + testing::ElementsAre(2, 3)); +} + +} // namespace content diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index bd0c5ea..4cc054a 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc @@ -37,14 +37,14 @@ ServiceWorkerProviderHost::~ServiceWorkerProviderHost() { document_url_ = GURL(); if (controlling_version_.get()) controlling_version_->RemoveControllee(this); - if (active_version_.get()) - active_version_->RemovePotentialControllee(this); - if (waiting_version_.get()) - waiting_version_->RemovePotentialControllee(this); - if (installing_version_.get()) - installing_version_->RemovePotentialControllee(this); - if (associated_registration_.get()) + if (associated_registration_.get()) { + DecreaseProcessReference(associated_registration_->pattern()); associated_registration_->RemoveListener(this); + } + for (std::vector<GURL>::iterator it = associated_patterns_.begin(); + it != associated_patterns_.end(); ++it) { + DecreaseProcessReference(*it); + } } void ServiceWorkerProviderHost::OnVersionAttributesChanged( @@ -52,9 +52,9 @@ void ServiceWorkerProviderHost::OnVersionAttributesChanged( ChangedVersionAttributesMask changed_mask, const ServiceWorkerRegistrationInfo& info) { DCHECK_EQ(associated_registration_.get(), registration); - UpdatePotentialControllees(registration->installing_version(), - registration->waiting_version(), - registration->active_version()); + installing_version_ = registration->installing_version(); + waiting_version_ = registration->waiting_version(); + active_version_ = registration->active_version(); } void ServiceWorkerProviderHost::OnRegistrationFailed( @@ -68,38 +68,6 @@ void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) { document_url_ = url; } -void ServiceWorkerProviderHost::UpdatePotentialControllees( - ServiceWorkerVersion* installing_version, - ServiceWorkerVersion* waiting_version, - ServiceWorkerVersion* active_version) { - if (installing_version != installing_version_.get()) { - scoped_refptr<ServiceWorkerVersion> previous_version = installing_version_; - if (previous_version.get()) - previous_version->RemovePotentialControllee(this); - if (installing_version) - installing_version->AddPotentialControllee(this); - installing_version_ = installing_version; - } - - if (waiting_version != waiting_version_.get()) { - scoped_refptr<ServiceWorkerVersion> previous_version = waiting_version_; - if (previous_version.get()) - previous_version->RemovePotentialControllee(this); - if (waiting_version) - waiting_version->AddPotentialControllee(this); - waiting_version_ = waiting_version; - } - - if (active_version != active_version_.get()) { - scoped_refptr<ServiceWorkerVersion> previous_version = active_version_; - if (previous_version.get()) - previous_version->RemovePotentialControllee(this); - if (active_version) - active_version->AddPotentialControllee(this); - active_version_ = active_version; - } -} - void ServiceWorkerProviderHost::SetControllerVersionAttribute( ServiceWorkerVersion* version) { if (version == controlling_version_.get()) @@ -144,20 +112,27 @@ bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) { void ServiceWorkerProviderHost::AssociateRegistration( ServiceWorkerRegistration* registration) { DCHECK(CanAssociateRegistration(registration)); + if (associated_registration_.get()) + DecreaseProcessReference(associated_registration_->pattern()); + IncreaseProcessReference(registration->pattern()); + associated_registration_ = registration; registration->AddListener(this); - UpdatePotentialControllees(registration->installing_version(), - registration->waiting_version(), - registration->active_version()); + installing_version_ = registration->installing_version(); + waiting_version_ = registration->waiting_version(); + active_version_ = registration->active_version(); SetControllerVersionAttribute(registration->active_version()); } void ServiceWorkerProviderHost::UnassociateRegistration() { if (!associated_registration_.get()) return; + DecreaseProcessReference(associated_registration_->pattern()); associated_registration_->RemoveListener(this); associated_registration_ = NULL; - UpdatePotentialControllees(NULL, NULL, NULL); + installing_version_ = NULL; + waiting_version_ = NULL; + active_version_ = NULL; SetControllerVersionAttribute(NULL); } @@ -210,6 +185,12 @@ void ServiceWorkerProviderHost::PostMessage( new_routing_ids)); } +void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern( + const GURL& pattern) { + associated_patterns_.push_back(pattern); + IncreaseProcessReference(pattern); +} + ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass( ServiceWorkerVersion* version) { ServiceWorkerObjectInfo info; @@ -226,6 +207,22 @@ ServiceWorkerObjectInfo ServiceWorkerProviderHost::CreateHandleAndPass( return info; } +void ServiceWorkerProviderHost::IncreaseProcessReference( + const GURL& pattern) { + if (context_ && context_->process_manager()) { + context_->process_manager()->AddProcessReferenceToPattern( + pattern, process_id_); + } +} + +void ServiceWorkerProviderHost::DecreaseProcessReference( + const GURL& pattern) { + if (context_ && context_->process_manager()) { + context_->process_manager()->RemoveProcessReferenceFromPattern( + pattern, process_id_); + } +} + bool ServiceWorkerProviderHost::IsContextAlive() { return context_ != NULL; } diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 6a6134a..a005e0a 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h @@ -107,6 +107,10 @@ class CONTENT_EXPORT ServiceWorkerProviderHost void PostMessage(const base::string16& message, const std::vector<int>& sent_message_port_ids); + // Adds reference of this host's process to the |pattern|, the reference will + // be removed in destructor. + void AddScopedProcessReferenceToPattern(const GURL& pattern); + private: friend class ServiceWorkerProviderHostTest; FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest, @@ -122,13 +126,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost virtual void OnRegistrationFailed( ServiceWorkerRegistration* registration) OVERRIDE; - // Adds this provider host to the potential controllee list of the given - // versions and removes it from the previous versions. - void UpdatePotentialControllees( - ServiceWorkerVersion* installing_version, - ServiceWorkerVersion* waiting_version, - ServiceWorkerVersion* active_version); - // Sets the controller version field to |version| or if |version| is NULL, // clears the field. void SetControllerVersionAttribute(ServiceWorkerVersion* version); @@ -138,10 +135,15 @@ class CONTENT_EXPORT ServiceWorkerProviderHost // provider is responsible for releasing the handle. ServiceWorkerObjectInfo CreateHandleAndPass(ServiceWorkerVersion* version); + // Increase/decrease this host's process reference for |pattern|. + void IncreaseProcessReference(const GURL& pattern); + void DecreaseProcessReference(const GURL& pattern); + const int process_id_; const int provider_id_; GURL document_url_; + std::vector<GURL> associated_patterns_; scoped_refptr<ServiceWorkerRegistration> associated_registration_; scoped_refptr<ServiceWorkerVersion> controlling_version_; diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc index c4b2cd8..181ecf7 100644 --- a/content/browser/service_worker/service_worker_provider_host_unittest.cc +++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc @@ -5,6 +5,7 @@ #include "base/basictypes.h" #include "base/memory/weak_ptr.h" #include "base/thread_task_runner_handle.h" +#include "content/browser/service_worker/embedded_worker_test_helper.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_provider_host.h" #include "content/browser/service_worker/service_worker_register_job.h" @@ -24,19 +25,12 @@ class ServiceWorkerProviderHostTest : public testing::Test { virtual ~ServiceWorkerProviderHostTest() {} virtual void SetUp() OVERRIDE { - context_.reset( - new ServiceWorkerContextCore(base::FilePath(), - base::ThreadTaskRunnerHandle::Get(), - base::ThreadTaskRunnerHandle::Get(), - base::ThreadTaskRunnerHandle::Get(), - NULL, - NULL, - NULL)); - - scope_ = GURL("http://www.example.com/"); + helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId)); + context_ = helper_->context(); + pattern_ = GURL("http://www.example.com/"); script_url_ = GURL("http://www.example.com/service_worker.js"); registration_ = new ServiceWorkerRegistration( - scope_, 1L, context_->AsWeakPtr()); + pattern_, 1L, context_->AsWeakPtr()); version_ = new ServiceWorkerVersion( registration_.get(), script_url_, 1L, context_->AsWeakPtr()); @@ -56,7 +50,11 @@ class ServiceWorkerProviderHostTest : public testing::Test { virtual void TearDown() OVERRIDE { version_ = 0; registration_ = 0; - context_.reset(); + helper_.reset(); + } + + bool HasProcessToRun() const { + return context_->process_manager()->PatternHasProcessToRun(pattern_); } void VerifyVersionAttributes( @@ -71,12 +69,13 @@ class ServiceWorkerProviderHostTest : public testing::Test { } content::TestBrowserThreadBundle thread_bundle_; - scoped_ptr<ServiceWorkerContextCore> context_; + scoped_ptr<EmbeddedWorkerTestHelper> helper_; + ServiceWorkerContextCore* context_; scoped_refptr<ServiceWorkerRegistration> registration_; scoped_refptr<ServiceWorkerVersion> version_; base::WeakPtr<ServiceWorkerProviderHost> provider_host1_; base::WeakPtr<ServiceWorkerProviderHost> provider_host2_; - GURL scope_; + GURL pattern_; GURL script_url_; private: @@ -85,80 +84,80 @@ class ServiceWorkerProviderHostTest : public testing::Test { TEST_F(ServiceWorkerProviderHostTest, SetActiveVersion_ProcessStatus) { provider_host1_->AssociateRegistration(registration_.get()); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Associating version_ to a provider_host's active version will internally // add the provider_host's process ref to the version. registration_->SetActiveVersion(version_.get()); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Re-associating the same version and provider_host should just work too. registration_->SetActiveVersion(version_.get()); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Resetting the provider_host's active version should remove process refs // from the version. provider_host1_->UnassociateRegistration(); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_FALSE(HasProcessToRun()); } TEST_F(ServiceWorkerProviderHostTest, SetActiveVersion_MultipleHostsForSameProcess) { provider_host1_->AssociateRegistration(registration_.get()); provider_host2_->AssociateRegistration(registration_.get()); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Associating version_ to two providers as active version. registration_->SetActiveVersion(version_.get()); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Disassociating one provider_host shouldn't remove all process refs // from the version yet. provider_host1_->UnassociateRegistration(); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Disassociating the other provider_host will remove all process refs. provider_host2_->UnassociateRegistration(); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_FALSE(HasProcessToRun()); } TEST_F(ServiceWorkerProviderHostTest, SetWaitingVersion_ProcessStatus) { provider_host1_->AssociateRegistration(registration_.get()); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Associating version_ to a provider_host's waiting version will internally // add the provider_host's process ref to the version. registration_->SetWaitingVersion(version_.get()); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Re-associating the same version and provider_host should just work too. registration_->SetWaitingVersion(version_.get()); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Resetting the provider_host's waiting version should remove process refs // from the version. provider_host1_->UnassociateRegistration(); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_FALSE(HasProcessToRun()); } TEST_F(ServiceWorkerProviderHostTest, SetWaitingVersion_MultipleHostsForSameProcess) { provider_host1_->AssociateRegistration(registration_.get()); provider_host2_->AssociateRegistration(registration_.get()); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Associating version_ to two providers as waiting version. registration_->SetWaitingVersion(version_.get()); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Disassociating one provider_host shouldn't remove all process refs // from the version yet. provider_host1_->UnassociateRegistration(); - ASSERT_TRUE(version_->HasProcessToRun()); + ASSERT_TRUE(HasProcessToRun()); // Disassociating the other provider_host will remove all process refs. provider_host2_->UnassociateRegistration(); - ASSERT_FALSE(version_->HasProcessToRun()); + ASSERT_FALSE(HasProcessToRun()); } TEST_F(ServiceWorkerProviderHostTest, diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc index 5c96d87..c19da94 100644 --- a/content/browser/service_worker/service_worker_register_job.cc +++ b/content/browser/service_worker/service_worker_register_job.cc @@ -58,12 +58,13 @@ ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() { << "Jobs should only be interrupted during shutdown."; } -void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback, - int process_id) { +void ServiceWorkerRegisterJob::AddCallback( + const RegistrationCallback& callback, + ServiceWorkerProviderHost* provider_host) { if (!is_promise_resolved_) { callbacks_.push_back(callback); - if (process_id != -1 && (phase_ < UPDATE || !new_version())) - pending_process_ids_.push_back(process_id); + if (provider_host) + provider_host->AddScopedProcessReferenceToPattern(pattern_); return; } RunSoon(base::Bind( @@ -323,8 +324,7 @@ void ServiceWorkerRegisterJob::UpdateAndContinue() { bool pause_after_download = job_type_ == UPDATE_JOB; if (pause_after_download) new_version()->embedded_worker()->AddListener(this); - new_version()->StartWorkerWithCandidateProcesses( - pending_process_ids_, + new_version()->StartWorker( pause_after_download, base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished, weak_factory_.GetWeakPtr())); diff --git a/content/browser/service_worker/service_worker_register_job.h b/content/browser/service_worker/service_worker_register_job.h index 7153fa1..c281ed2 100644 --- a/content/browser/service_worker/service_worker_register_job.h +++ b/content/browser/service_worker/service_worker_register_job.h @@ -55,11 +55,11 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase, virtual ~ServiceWorkerRegisterJob(); // Registers a callback to be called when the promise would resolve (whether - // successfully or not). Multiple callbacks may be registered. If |process_id| - // is not -1, it's added to the existing clients when deciding in which - // process to create the Service Worker instance. If there are no existing - // clients, a new RenderProcessHost will be created. - void AddCallback(const RegistrationCallback& callback, int process_id); + // successfully or not). Multiple callbacks may be registered. + // If |provider_host| is not NULL, its process will be regarded as a candidate + // process to run the worker. + void AddCallback(const RegistrationCallback& callback, + ServiceWorkerProviderHost* provider_host); // ServiceWorkerRegisterJobBase implementation: virtual void Start() OVERRIDE; @@ -158,7 +158,6 @@ class ServiceWorkerRegisterJob : public ServiceWorkerRegisterJobBase, const GURL pattern_; const GURL script_url_; std::vector<RegistrationCallback> callbacks_; - std::vector<int> pending_process_ids_; Phase phase_; Internal internal_; bool is_promise_resolved_; diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 82bb676..88d8e48 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc @@ -160,11 +160,10 @@ ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() { } void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) { - StartWorkerWithCandidateProcesses(std::vector<int>(), false, callback); + StartWorker(false, callback); } -void ServiceWorkerVersion::StartWorkerWithCandidateProcesses( - const std::vector<int>& possible_process_ids, +void ServiceWorkerVersion::StartWorker( bool pause_after_download, const StatusCallback& callback) { switch (running_status()) { @@ -183,7 +182,6 @@ void ServiceWorkerVersion::StartWorkerWithCandidateProcesses( scope_, script_url_, pause_after_download, - possible_process_ids, base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError, weak_factory_.GetWeakPtr())); } @@ -376,24 +374,11 @@ void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback, } } -void ServiceWorkerVersion::AddProcessToWorker(int process_id) { - embedded_worker_->AddProcessReference(process_id); -} - -void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) { - embedded_worker_->ReleaseProcessReference(process_id); -} - -bool ServiceWorkerVersion::HasProcessToRun() const { - return embedded_worker_->HasProcessToRun(); -} - void ServiceWorkerVersion::AddControllee( ServiceWorkerProviderHost* provider_host) { DCHECK(!ContainsKey(controllee_map_, provider_host)); int controllee_id = controllee_by_id_.Add(provider_host); controllee_map_[provider_host] = controllee_id; - AddProcessToWorker(provider_host->process_id()); if (stop_worker_timer_.IsRunning()) stop_worker_timer_.Stop(); } @@ -404,7 +389,6 @@ void ServiceWorkerVersion::RemoveControllee( DCHECK(found != controllee_map_.end()); controllee_by_id_.Remove(found->second); controllee_map_.erase(found); - RemoveProcessFromWorker(provider_host->process_id()); if (HasControllee()) return; FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this)); @@ -415,16 +399,6 @@ void ServiceWorkerVersion::RemoveControllee( ScheduleStopWorker(); } -void ServiceWorkerVersion::AddPotentialControllee( - ServiceWorkerProviderHost* provider_host) { - AddProcessToWorker(provider_host->process_id()); -} - -void ServiceWorkerVersion::RemovePotentialControllee( - ServiceWorkerProviderHost* provider_host) { - RemoveProcessFromWorker(provider_host->process_id()); -} - void ServiceWorkerVersion::AddListener(Listener* listener) { listeners_.AddObserver(listener); } diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index ee1194e..9d0b342 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h @@ -123,13 +123,11 @@ class CONTENT_EXPORT ServiceWorkerVersion void StartWorker(const StatusCallback& callback); // Starts an embedded worker for this version. - // |potential_process_ids| is a list of processes in which to start the - // worker. + // |pause_after_download| notifies worker to pause after download finished + // which could be resumed by EmbeddedWorkerInstance::ResumeAfterDownload. // This returns OK (success) if the worker is already running. - void StartWorkerWithCandidateProcesses( - const std::vector<int>& potential_process_ids, - bool pause_after_download, - const StatusCallback& callback); + void StartWorker(bool pause_after_download, + const StatusCallback& callback); // Stops an embedded worker for this version. // This returns OK (success) if the worker is already stopped. @@ -199,22 +197,11 @@ class CONTENT_EXPORT ServiceWorkerVersion void DispatchPushEvent(const StatusCallback& callback, const std::string& data); - // These are expected to be called when a renderer process host for the - // same-origin as for this ServiceWorkerVersion is created. The added - // processes are used to run an in-renderer embedded worker. - void AddProcessToWorker(int process_id); - void RemoveProcessFromWorker(int process_id); - - // Returns true if this has at least one process to run. - bool HasProcessToRun() const; - // Adds and removes |provider_host| as a controllee of this ServiceWorker. // A potential controllee is a host having the version as its .installing // or .waiting version. void AddControllee(ServiceWorkerProviderHost* provider_host); void RemoveControllee(ServiceWorkerProviderHost* provider_host); - void AddPotentialControllee(ServiceWorkerProviderHost* provider_host); - void RemovePotentialControllee(ServiceWorkerProviderHost* provider_host); // Returns if it has controllee. bool HasControllee() const { return !controllee_map_.empty(); } diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc index 11e5440..3fcc13f 100644 --- a/content/browser/service_worker/service_worker_version_unittest.cc +++ b/content/browser/service_worker/service_worker_version_unittest.cc @@ -119,8 +119,9 @@ class ServiceWorkerVersionTest : public testing::Test { virtual void SetUp() OVERRIDE { helper_.reset(new MessageReceiver()); + pattern_ = GURL("http://www.example.com/"); registration_ = new ServiceWorkerRegistration( - GURL("http://www.example.com/"), + pattern_, 1L, helper_->context()->AsWeakPtr()); version_ = new ServiceWorkerVersion( @@ -129,10 +130,10 @@ class ServiceWorkerVersionTest : public testing::Test { 1L, helper_->context()->AsWeakPtr()); - // Simulate adding one process to the worker. - int embedded_worker_id = version_->embedded_worker()->embedded_worker_id(); - helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId); - ASSERT_TRUE(version_->HasProcessToRun()); + // Simulate adding one process to the pattern. + helper_->SimulateAddProcessToPattern(pattern_, kRenderProcessId); + ASSERT_TRUE(helper_->context()->process_manager() + ->PatternHasProcessToRun(pattern_)); } virtual void TearDown() OVERRIDE { @@ -145,6 +146,7 @@ class ServiceWorkerVersionTest : public testing::Test { scoped_ptr<MessageReceiver> helper_; scoped_refptr<ServiceWorkerRegistration> registration_; scoped_refptr<ServiceWorkerVersion> version_; + GURL pattern_; private: DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersionTest); @@ -327,28 +329,6 @@ TEST_F(ServiceWorkerVersionTest, RepeatedlyObserveStatusChanges) { ASSERT_EQ(ServiceWorkerVersion::REDUNDANT, statuses[4]); } -TEST_F(ServiceWorkerVersionTest, AddAndRemoveProcesses) { - // Preparation (to reset the process count to 0). - ASSERT_TRUE(version_->HasProcessToRun()); - version_->RemoveProcessFromWorker(kRenderProcessId); - ASSERT_FALSE(version_->HasProcessToRun()); - - // Add another process to the worker twice, and then remove process once. - const int another_process_id = kRenderProcessId + 1; - version_->AddProcessToWorker(another_process_id); - version_->AddProcessToWorker(another_process_id); - version_->RemoveProcessFromWorker(another_process_id); - - // We're ref-counting the process internally, so adding the same process - // multiple times should be handled correctly. - ASSERT_TRUE(version_->HasProcessToRun()); - - // Removing the process again (so that # of AddProcess == # of RemoveProcess - // for the process) should remove all process references. - version_->RemoveProcessFromWorker(another_process_id); - ASSERT_FALSE(version_->HasProcessToRun()); -} - TEST_F(ServiceWorkerVersionTest, ScheduleStopWorker) { // Verify the timer is not running when version initializes its status. version_->SetStatus(ServiceWorkerVersion::ACTIVATED); diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 835f4fe..b13ee86 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -597,6 +597,7 @@ 'browser/service_worker/service_worker_dispatcher_host_unittest.cc', 'browser/service_worker/service_worker_handle_unittest.cc', 'browser/service_worker/service_worker_job_unittest.cc', + 'browser/service_worker/service_worker_process_manager_unittest.cc', 'browser/service_worker/service_worker_provider_host_unittest.cc', 'browser/service_worker/service_worker_registration_unittest.cc', 'browser/service_worker/service_worker_request_handler_unittest.cc', |