Commit f56fb35d authored by kinuko@chromium.org's avatar kinuko@chromium.org

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
parent dfc613d0
...@@ -22,6 +22,8 @@ struct SecondGreater { ...@@ -22,6 +22,8 @@ struct SecondGreater {
} // namespace } // namespace
EmbeddedWorkerInstance::~EmbeddedWorkerInstance() { EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
if (status_ == STARTING || status_ == RUNNING)
Stop();
registry_->RemoveWorker(process_id_, embedded_worker_id_); registry_->RemoveWorker(process_id_, embedded_worker_id_);
} }
......
...@@ -249,13 +249,14 @@ void EmbeddedWorkerRegistry::StartWorkerWithProcessId( ...@@ -249,13 +249,14 @@ void EmbeddedWorkerRegistry::StartWorkerWithProcessId(
} }
ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send( 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_) if (!context_)
return SERVICE_WORKER_ERROR_ABORT; return SERVICE_WORKER_ERROR_ABORT;
ProcessToSenderMap::iterator found = process_sender_map_.find(process_id); ProcessToSenderMap::iterator found = process_sender_map_.find(process_id);
if (found == process_sender_map_.end()) if (found == process_sender_map_.end())
return SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND; 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_ERROR_IPC_FAILED;
return SERVICE_WORKER_OK; return SERVICE_WORKER_OK;
} }
......
...@@ -154,8 +154,8 @@ void EmbeddedWorkerTestHelper::SimulateWorkerStarted( ...@@ -154,8 +154,8 @@ void EmbeddedWorkerTestHelper::SimulateWorkerStarted(
void EmbeddedWorkerTestHelper::SimulateWorkerStopped( void EmbeddedWorkerTestHelper::SimulateWorkerStopped(
int embedded_worker_id) { int embedded_worker_id) {
EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id); EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
ASSERT_TRUE(worker != NULL); if (worker != NULL)
registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id); registry()->OnWorkerStopped(worker->process_id(), embedded_worker_id);
} }
void EmbeddedWorkerTestHelper::SimulateSend( void EmbeddedWorkerTestHelper::SimulateSend(
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "content/browser/service_worker/service_worker_context_core.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_registration.h"
#include "content/browser/service_worker/service_worker_storage.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/common/service_worker/service_worker_messages.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
...@@ -150,11 +151,15 @@ TEST_F(ServiceWorkerContextTest, Register) { ...@@ -150,11 +151,15 @@ TEST_F(ServiceWorkerContextTest, Register) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(called); 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( EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_InstallEvent::ID)); ServiceWorkerMsg_InstallEvent::ID));
EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_ActivateEvent::ID)); ServiceWorkerMsg_ActivateEvent::ID));
EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
EmbeddedWorkerMsg_StopWorker::ID));
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id); EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id); EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
...@@ -189,11 +194,15 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) { ...@@ -189,11 +194,15 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(called); 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( EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_InstallEvent::ID)); ServiceWorkerMsg_InstallEvent::ID));
EXPECT_FALSE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( EXPECT_FALSE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_ActivateEvent::ID)); ServiceWorkerMsg_ActivateEvent::ID));
EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
EmbeddedWorkerMsg_StopWorker::ID));
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id); EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id); EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
...@@ -228,11 +237,15 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) { ...@@ -228,11 +237,15 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
EXPECT_TRUE(called); 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( EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_InstallEvent::ID)); ServiceWorkerMsg_InstallEvent::ID));
EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching( EXPECT_TRUE(helper_->inner_ipc_sink()->GetUniqueMessageMatching(
ServiceWorkerMsg_ActivateEvent::ID)); ServiceWorkerMsg_ActivateEvent::ID));
EXPECT_TRUE(helper_->ipc_sink()->GetUniqueMessageMatching(
EmbeddedWorkerMsg_StopWorker::ID));
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id); EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id); EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "content/browser/service_worker/embedded_worker_registry.h" #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_context_core.h"
#include "content/browser/service_worker/service_worker_registration.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/common/service_worker/service_worker_messages.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
...@@ -22,6 +23,12 @@ typedef ServiceWorkerVersion::MessageCallback MessageCallback; ...@@ -22,6 +23,12 @@ typedef ServiceWorkerVersion::MessageCallback MessageCallback;
namespace { 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) { void RunSoon(const base::Closure& callback) {
if (!callback.is_null()) if (!callback.is_null())
base::MessageLoop::current()->PostTask(FROM_HERE, callback); base::MessageLoop::current()->PostTask(FROM_HERE, callback);
...@@ -103,12 +110,10 @@ ServiceWorkerVersion::ServiceWorkerVersion( ...@@ -103,12 +110,10 @@ ServiceWorkerVersion::ServiceWorkerVersion(
} }
ServiceWorkerVersion::~ServiceWorkerVersion() { ServiceWorkerVersion::~ServiceWorkerVersion() {
if (embedded_worker_) { embedded_worker_->RemoveListener(this);
embedded_worker_->RemoveListener(this);
embedded_worker_.reset();
}
if (context_) if (context_)
context_->RemoveLiveVersion(version_id_); context_->RemoveLiveVersion(version_id_);
// EmbeddedWorker's dtor sends StopWorker if it's still running.
} }
void ServiceWorkerVersion::SetStatus(Status status) { void ServiceWorkerVersion::SetStatus(Status status) {
...@@ -148,7 +153,6 @@ void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) { ...@@ -148,7 +153,6 @@ void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
void ServiceWorkerVersion::StartWorkerWithCandidateProcesses( void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
const std::vector<int>& possible_process_ids, const std::vector<int>& possible_process_ids,
const StatusCallback& callback) { const StatusCallback& callback) {
DCHECK(embedded_worker_);
switch (running_status()) { switch (running_status()) {
case RUNNING: case RUNNING:
RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
...@@ -173,7 +177,6 @@ void ServiceWorkerVersion::StartWorkerWithCandidateProcesses( ...@@ -173,7 +177,6 @@ void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
} }
void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) { void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
DCHECK(embedded_worker_);
if (running_status() == STOPPED) { if (running_status() == STOPPED) {
RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
return; return;
...@@ -190,7 +193,6 @@ void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) { ...@@ -190,7 +193,6 @@ void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
void ServiceWorkerVersion::SendMessage( void ServiceWorkerVersion::SendMessage(
const IPC::Message& message, const StatusCallback& callback) { const IPC::Message& message, const StatusCallback& callback) {
DCHECK(embedded_worker_);
if (running_status() != RUNNING) { if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker. // Schedule calling this method after starting the worker.
StartWorker(base::Bind(&RunTaskAfterStartWorker, StartWorker(base::Bind(&RunTaskAfterStartWorker,
...@@ -318,6 +320,8 @@ void ServiceWorkerVersion::AddControllee( ...@@ -318,6 +320,8 @@ void ServiceWorkerVersion::AddControllee(
int controllee_id = controllee_by_id_.Add(provider_host); int controllee_id = controllee_by_id_.Add(provider_host);
controllee_map_[provider_host] = controllee_id; controllee_map_[provider_host] = controllee_id;
AddProcessToWorker(provider_host->process_id()); AddProcessToWorker(provider_host->process_id());
if (stop_worker_timer_.IsRunning())
stop_worker_timer_.Stop();
} }
void ServiceWorkerVersion::RemoveControllee( void ServiceWorkerVersion::RemoveControllee(
...@@ -327,6 +331,8 @@ void ServiceWorkerVersion::RemoveControllee( ...@@ -327,6 +331,8 @@ void ServiceWorkerVersion::RemoveControllee(
controllee_by_id_.Remove(found->second); controllee_by_id_.Remove(found->second);
controllee_map_.erase(found); controllee_map_.erase(found);
RemoveProcessFromWorker(provider_host->process_id()); RemoveProcessFromWorker(provider_host->process_id());
if (!HasControllee())
ScheduleStopWorker();
// TODO(kinuko): Fire NoControllees notification when the # of controllees // TODO(kinuko): Fire NoControllees notification when the # of controllees
// reaches 0, so that a new pending version can be activated (which will // reaches 0, so that a new pending version can be activated (which will
// deactivate this version). // deactivate this version).
...@@ -565,4 +571,18 @@ void ServiceWorkerVersion::OnPostMessageToDocument( ...@@ -565,4 +571,18 @@ void ServiceWorkerVersion::OnPostMessageToDocument(
provider_host->PostMessage(message, sent_message_port_ids); 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 } // namespace content
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/observer_list.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/embedded_worker_instance.h"
#include "content/browser/service_worker/service_worker_script_cache_map.h" #include "content/browser/service_worker/service_worker_script_cache_map.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
...@@ -188,7 +189,7 @@ class CONTENT_EXPORT ServiceWorkerVersion ...@@ -188,7 +189,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
void AddPendingControllee(ServiceWorkerProviderHost* provider_host); void AddPendingControllee(ServiceWorkerProviderHost* provider_host);
void RemovePendingControllee(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(); } bool HasControllee() const { return !controllee_map_.empty(); }
// Adds and removes Listeners. // Adds and removes Listeners.
...@@ -240,6 +241,8 @@ class CONTENT_EXPORT ServiceWorkerVersion ...@@ -240,6 +241,8 @@ class CONTENT_EXPORT ServiceWorkerVersion
const base::string16& message, const base::string16& message,
const std::vector<int>& sent_message_port_ids); const std::vector<int>& sent_message_port_ids);
void ScheduleStopWorker();
const int64 version_id_; const int64 version_id_;
int64 registration_id_; int64 registration_id_;
GURL script_url_; GURL script_url_;
...@@ -261,6 +264,7 @@ class CONTENT_EXPORT ServiceWorkerVersion ...@@ -261,6 +264,7 @@ class CONTENT_EXPORT ServiceWorkerVersion
base::WeakPtr<ServiceWorkerContextCore> context_; base::WeakPtr<ServiceWorkerContextCore> context_;
ObserverList<Listener> listeners_; ObserverList<Listener> listeners_;
ServiceWorkerScriptCacheMap script_cache_map_; ServiceWorkerScriptCacheMap script_cache_map_;
base::OneShotTimer<ServiceWorkerVersion> stop_worker_timer_;
base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_; base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment