diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-16 13:18:03 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-16 13:18:03 +0000 |
commit | f56fb35d0305ad053d08f7b366d8338375f50112 (patch) | |
tree | 7dc53680dbf2cc02cf609ae9fc0bad4e2a88a9de /content | |
parent | dfc613d04ae69dde45d4e99c100feac6447fe9de (diff) | |
download | chromium_src-f56fb35d0305ad053d08f7b366d8338375f50112.zip chromium_src-f56fb35d0305ad053d08f7b366d8338375f50112.tar.gz chromium_src-f56fb35d0305ad053d08f7b366d8338375f50112.tar.bz2 |
Retry: Stop ServiceWorker context when no controllee is associated
Re-landing https://codereview.chromium.org/272183005
with leak fix.
BUG=372673
TBR=michaeln@chromium.org,horo@chromium.org
Review URL: https://codereview.chromium.org/282263008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271004 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
6 files changed, 55 insertions, 15 deletions
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index 24d2a95..891fc22 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc @@ -22,6 +22,8 @@ struct SecondGreater { } // namespace EmbeddedWorkerInstance::~EmbeddedWorkerInstance() { + if (status_ == STARTING || status_ == RUNNING) + Stop(); registry_->RemoveWorker(process_id_, embedded_worker_id_); } diff --git a/content/browser/service_worker/embedded_worker_registry.cc b/content/browser/service_worker/embedded_worker_registry.cc index a859268..6889672 100644 --- a/content/browser/service_worker/embedded_worker_registry.cc +++ b/content/browser/service_worker/embedded_worker_registry.cc @@ -249,13 +249,14 @@ void EmbeddedWorkerRegistry::StartWorkerWithProcessId( } ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send( - int process_id, IPC::Message* message) { + int process_id, IPC::Message* message_ptr) { + scoped_ptr<IPC::Message> message(message_ptr); if (!context_) return SERVICE_WORKER_ERROR_ABORT; ProcessToSenderMap::iterator found = process_sender_map_.find(process_id); if (found == process_sender_map_.end()) return SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND; - if (!found->second->Send(message)) + if (!found->second->Send(message.release())) return SERVICE_WORKER_ERROR_IPC_FAILED; return SERVICE_WORKER_OK; } diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc index 3d8790f..c43808b 100644 --- a/content/browser/service_worker/embedded_worker_test_helper.cc +++ b/content/browser/service_worker/embedded_worker_test_helper.cc @@ -154,8 +154,8 @@ void EmbeddedWorkerTestHelper::SimulateWorkerStarted( void EmbeddedWorkerTestHelper::SimulateWorkerStopped( int embedded_worker_id) { EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); - ASSERT_TRUE(worker != NULL); - registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); + if (worker != NULL) + registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); } void EmbeddedWorkerTestHelper::SimulateSend( diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc index 6a8088b..1afb47d 100644 --- a/content/browser/service_worker/service_worker_context_unittest.cc +++ b/content/browser/service_worker/service_worker_context_unittest.cc @@ -13,6 +13,7 @@ #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_storage.h" +#include "content/common/service_worker/embedded_worker_messages.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" @@ -150,11 +151,15 @@ TEST_F(ServiceWorkerContextTest, Register) { base::RunLoop().RunUntilIdle(); EXPECT_TRUE(called); - EXPECT_EQ(3UL, helper_->ipc_sink()->message_count()); + EXPECT_EQ(4UL, helper_->ipc_sink()->message_count()); + EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching( + EmbeddedWorkerMsg_StartWorker::ID)); EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( ServiceWorkerMsg_InstallEvent::ID)); EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( ServiceWorkerMsg_ActivateEvent::ID)); + EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching( + EmbeddedWorkerMsg_StopWorker::ID)); EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id); EXPECT_NE(kInvalidServiceWorkerVersionId, version_id); @@ -189,11 +194,15 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) { base::RunLoop().RunUntilIdle(); EXPECT_TRUE(called); - EXPECT_EQ(2UL, helper_->ipc_sink()->message_count()); + EXPECT_EQ(3UL, helper_->ipc_sink()->message_count()); + EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching( + EmbeddedWorkerMsg_StartWorker::ID)); EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( ServiceWorkerMsg_InstallEvent::ID)); EXPECT_FALSE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( ServiceWorkerMsg_ActivateEvent::ID)); + EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching( + EmbeddedWorkerMsg_StopWorker::ID)); EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id); EXPECT_NE(kInvalidServiceWorkerVersionId, version_id); @@ -228,11 +237,15 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) { base::RunLoop().RunUntilIdle(); EXPECT_TRUE(called); - EXPECT_EQ(3UL, helper_->ipc_sink()->message_count()); + EXPECT_EQ(4UL, helper_->ipc_sink()->message_count()); + EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching( + EmbeddedWorkerMsg_StartWorker::ID)); EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( ServiceWorkerMsg_InstallEvent::ID)); EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( ServiceWorkerMsg_ActivateEvent::ID)); + EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching( + EmbeddedWorkerMsg_StopWorker::ID)); EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id); EXPECT_NE(kInvalidServiceWorkerVersionId, version_id); diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 0bcec89..274daf0 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc @@ -11,6 +11,7 @@ #include "content/browser/service_worker/embedded_worker_registry.h" #include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_registration.h" +#include "content/browser/service_worker/service_worker_utils.h" #include "content/common/service_worker/service_worker_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" @@ -22,6 +23,12 @@ typedef ServiceWorkerVersion::MessageCallback MessageCallback; namespace { +// Default delay to stop the worker context after all documents that +// are associated to the worker are closed. +// (Note that if all references to the version is dropped the worker +// is also stopped without delay) +const int64 kStopWorkerDelay = 30; // 30 secs. + void RunSoon(const base::Closure& callback) { if (!callback.is_null()) base::MessageLoop::current()->PostTask(FROM_HERE, callback); @@ -103,12 +110,10 @@ ServiceWorkerVersion::ServiceWorkerVersion( } ServiceWorkerVersion::~ServiceWorkerVersion() { - if (embedded_worker_) { - embedded_worker_->RemoveListener(this); - embedded_worker_.reset(); - } + embedded_worker_->RemoveListener(this); if (context_) context_->RemoveLiveVersion(version_id_); + // EmbeddedWorker's dtor sends StopWorker if it's still running. } void ServiceWorkerVersion::SetStatus(Status status) { @@ -148,7 +153,6 @@ void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) { void ServiceWorkerVersion::StartWorkerWithCandidateProcesses( const std::vector<int>& possible_process_ids, const StatusCallback& callback) { - DCHECK(embedded_worker_); switch (running_status()) { case RUNNING: RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); @@ -173,7 +177,6 @@ void ServiceWorkerVersion::StartWorkerWithCandidateProcesses( } void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) { - DCHECK(embedded_worker_); if (running_status() == STOPPED) { RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); return; @@ -190,7 +193,6 @@ void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) { void ServiceWorkerVersion::SendMessage( const IPC::Message& message, const StatusCallback& callback) { - DCHECK(embedded_worker_); if (running_status() != RUNNING) { // Schedule calling this method after starting the worker. StartWorker(base::Bind(&RunTaskAfterStartWorker, @@ -318,6 +320,8 @@ void ServiceWorkerVersion::AddControllee( 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(); } void ServiceWorkerVersion::RemoveControllee( @@ -327,6 +331,8 @@ void ServiceWorkerVersion::RemoveControllee( controllee_by_id_.Remove(found->second); controllee_map_.erase(found); RemoveProcessFromWorker(provider_host->process_id()); + if (!HasControllee()) + ScheduleStopWorker(); // TODO(kinuko): Fire NoControllees notification when the # of controllees // reaches 0, so that a new pending version can be activated (which will // deactivate this version). @@ -565,4 +571,18 @@ void ServiceWorkerVersion::OnPostMessageToDocument( provider_host->PostMessage(message, sent_message_port_ids); } +void ServiceWorkerVersion::ScheduleStopWorker() { + if (running_status() != RUNNING) + return; + if (stop_worker_timer_.IsRunning()) { + stop_worker_timer_.Reset(); + return; + } + stop_worker_timer_.Start( + FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay), + base::Bind(&ServiceWorkerVersion::StopWorker, + weak_factory_.GetWeakPtr(), + base::Bind(&ServiceWorkerUtils::NoOpStatusCallback))); +} + } // namespace content diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 56c5cf2..e0dde76 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h @@ -14,6 +14,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" +#include "base/timer/timer.h" #include "content/browser/service_worker/embedded_worker_instance.h" #include "content/browser/service_worker/service_worker_script_cache_map.h" #include "content/common/content_export.h" @@ -188,7 +189,7 @@ class CONTENT_EXPORT ServiceWorkerVersion void AddPendingControllee(ServiceWorkerProviderHost* provider_host); void RemovePendingControllee(ServiceWorkerProviderHost* provider_host); - // Returns if it has (non-pending) controllee. + // Returns if it has controllee. bool HasControllee() const { return !controllee_map_.empty(); } // Adds and removes Listeners. @@ -240,6 +241,8 @@ class CONTENT_EXPORT ServiceWorkerVersion const base::string16& message, const std::vector<int>& sent_message_port_ids); + void ScheduleStopWorker(); + const int64 version_id_; int64 registration_id_; GURL script_url_; @@ -261,6 +264,7 @@ class CONTENT_EXPORT ServiceWorkerVersion base::WeakPtr<ServiceWorkerContextCore> context_; ObserverList<Listener> listeners_; ServiceWorkerScriptCacheMap script_cache_map_; + base::OneShotTimer<ServiceWorkerVersion> stop_worker_timer_; base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_; |