summaryrefslogtreecommitdiffstats
path: root/content/browser/service_worker
diff options
context:
space:
mode:
authorjyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 10:15:12 +0000
committerjyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 10:15:12 +0000
commitf2ccbae41c71d3982c9134a74b4d717d9226f9ca (patch)
treea0a6992cb6e2ce8c6b7c4b526c695ba0b735a605 /content/browser/service_worker
parentddaee297f7442191af336357628585b750b5ff03 (diff)
downloadchromium_src-f2ccbae41c71d3982c9134a74b4d717d9226f9ca.zip
chromium_src-f2ccbae41c71d3982c9134a74b4d717d9226f9ca.tar.gz
chromium_src-f2ccbae41c71d3982c9134a74b4d717d9226f9ca.tar.bz2
Teach EmbeddedWorkerInstance to create a process when it needs one.
This saves the BrowserContext into the ServiceWorkerContextWrapper, and uses it when no process is available. We always choose a renderer process on the UI thread and take a reference to it before asking the renderer to start the SW thread. This also fixes a race where a process might die before we have a chance to use it. We'll probably need to thread more process IDs through in cases where there might not be a ProviderHost, but that can wait for a subsequent CL. BUG=359811,362060, 362058 Review URL: https://codereview.chromium.org/238043002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266825 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/service_worker')
-rw-r--r--content/browser/service_worker/embedded_worker_instance.cc82
-rw-r--r--content/browser/service_worker/embedded_worker_instance.h27
-rw-r--r--content/browser/service_worker/embedded_worker_instance_unittest.cc81
-rw-r--r--content/browser/service_worker/embedded_worker_registry.cc78
-rw-r--r--content/browser/service_worker/embedded_worker_registry.h26
-rw-r--r--content/browser/service_worker/embedded_worker_test_helper.cc32
-rw-r--r--content/browser/service_worker/embedded_worker_test_helper.h15
-rw-r--r--content/browser/service_worker/service_worker_browsertest.cc16
-rw-r--r--content/browser/service_worker/service_worker_context_core.cc13
-rw-r--r--content/browser/service_worker/service_worker_context_core.h14
-rw-r--r--content/browser/service_worker/service_worker_context_unittest.cc52
-rw-r--r--content/browser/service_worker/service_worker_context_wrapper.cc25
-rw-r--r--content/browser/service_worker/service_worker_context_wrapper.h23
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host.cc25
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host.h14
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host_unittest.cc25
-rw-r--r--content/browser/service_worker/service_worker_handle_unittest.cc19
-rw-r--r--content/browser/service_worker/service_worker_job_unittest.cc20
-rw-r--r--content/browser/service_worker/service_worker_process_manager.cc145
-rw-r--r--content/browser/service_worker/service_worker_process_manager.h84
-rw-r--r--content/browser/service_worker/service_worker_provider_host_unittest.cc6
-rw-r--r--content/browser/service_worker/service_worker_register_job.cc16
-rw-r--r--content/browser/service_worker/service_worker_register_job.h7
-rw-r--r--content/browser/service_worker/service_worker_registration_unittest.cc6
-rw-r--r--content/browser/service_worker/service_worker_storage_unittest.cc6
-rw-r--r--content/browser/service_worker/service_worker_url_request_job_unittest.cc17
-rw-r--r--content/browser/service_worker/service_worker_version.cc124
-rw-r--r--content/browser/service_worker/service_worker_version.h14
-rw-r--r--content/browser/service_worker/service_worker_version_unittest.cc15
29 files changed, 767 insertions, 260 deletions
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 6ee4356..8bad509 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -11,29 +11,34 @@
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
+
EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
registry_->RemoveWorker(process_id_, embedded_worker_id_);
}
-ServiceWorkerStatusCode EmbeddedWorkerInstance::Start(
- int64 service_worker_version_id,
- const GURL& scope,
- const GURL& script_url) {
+void EmbeddedWorkerInstance::Start(int64 service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ const std::vector<int>& possible_process_ids,
+ const StatusCallback& callback) {
DCHECK(status_ == STOPPED);
- if (!ChooseProcess())
- return SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND;
status_ = STARTING;
- ServiceWorkerStatusCode status =
- registry_->StartWorker(process_id_,
- embedded_worker_id_,
- service_worker_version_id,
- scope,
- script_url);
- if (status != SERVICE_WORKER_OK) {
- status_ = STOPPED;
- process_id_ = -1;
- }
- return status;
+ std::vector<int> ordered_process_ids = SortProcesses(possible_process_ids);
+ registry_->StartWorker(ordered_process_ids,
+ embedded_worker_id_,
+ service_worker_version_id,
+ scope,
+ script_url,
+ callback);
}
ServiceWorkerStatusCode EmbeddedWorkerInstance::Stop() {
@@ -80,6 +85,16 @@ EmbeddedWorkerInstance::EmbeddedWorkerInstance(
thread_id_(-1) {
}
+void EmbeddedWorkerInstance::RecordProcessId(int process_id,
+ ServiceWorkerStatusCode status) {
+ DCHECK_EQ(process_id_, -1);
+ if (status == SERVICE_WORKER_OK) {
+ process_id_ = process_id;
+ } else {
+ status_ = STOPPED;
+ }
+}
+
void EmbeddedWorkerInstance::OnStarted(int thread_id) {
// Stop is requested before OnStarted is sent back from the worker.
if (status_ == STOPPING)
@@ -138,21 +153,26 @@ void EmbeddedWorkerInstance::RemoveListener(Listener* listener) {
listener_list_.RemoveObserver(listener);
}
-bool EmbeddedWorkerInstance::ChooseProcess() {
- DCHECK_EQ(-1, process_id_);
- // Naive implementation; chooses a process which has the biggest number of
- // associated providers (so that hopefully likely live longer).
- ProcessRefMap::iterator max_ref_iter = process_refs_.end();
- for (ProcessRefMap::iterator iter = process_refs_.begin();
- iter != process_refs_.end(); ++iter) {
- if (max_ref_iter == process_refs_.end() ||
- max_ref_iter->second < iter->second)
- max_ref_iter = iter;
+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]++;
}
- if (max_ref_iter == process_refs_.end())
- return false;
- process_id_ = max_ref_iter->first;
- return true;
+
+ 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 b57bc8f..c4ed7fc 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_
#include <map>
+#include <vector>
#include "base/basictypes.h"
#include "base/callback_forward.h"
@@ -33,6 +34,7 @@ struct ServiceWorkerFetchRequest;
// AddProcessReference().
class CONTENT_EXPORT EmbeddedWorkerInstance {
public:
+ typedef base::Callback<void(ServiceWorkerStatusCode)> StatusCallback;
enum Status {
STOPPED,
STARTING,
@@ -62,11 +64,15 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
~EmbeddedWorkerInstance();
- // Starts the worker. It is invalid to call this when the worker is
- // not in STOPPED status.
- ServiceWorkerStatusCode Start(int64 service_worker_version_id,
- const GURL& scope,
- const GURL& script_url);
+ // Starts the worker. It is invalid to call this when the worker is not in
+ // STOPPED status. |callback| is invoked when the worker's process is created
+ // if necessary and the IPC to evaluate the worker's script is sent.
+ // Observer::OnStarted() is run when the worker is actually started.
+ void Start(int64 service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ const std::vector<int>& possible_process_ids,
+ const StatusCallback& callback);
// Stops the worker. It is invalid to call this when the worker is
// not in STARTING or RUNNING status.
@@ -105,6 +111,10 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
EmbeddedWorkerInstance(EmbeddedWorkerRegistry* registry,
int embedded_worker_id);
+ // Called back from EmbeddedWorkerRegistry after Start() passes control to the
+ // UI thread to acquire a reference to the process.
+ void RecordProcessId(int process_id, ServiceWorkerStatusCode status);
+
// Called back from Registry when the worker instance has ack'ed that
// its WorkerGlobalScope is actually started on |thread_id| in the
// child process.
@@ -135,9 +145,10 @@ class CONTENT_EXPORT EmbeddedWorkerInstance {
int line_number,
const GURL& source_url);
- // Chooses a process to start this worker and populate process_id_.
- // Returns false when no process is available.
- bool ChooseProcess();
+ // 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;
scoped_refptr<EmbeddedWorkerRegistry> registry_;
const int embedded_worker_id_;
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index f78ba81..244b5f9 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -9,6 +9,7 @@
#include "content/browser/service_worker/embedded_worker_registry.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_context_wrapper.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,30 +24,35 @@ class EmbeddedWorkerInstanceTest : public testing::Test {
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
- helper_.reset(new EmbeddedWorkerTestHelper(
- context_.get(), kRenderProcessId));
+ helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
}
virtual void TearDown() OVERRIDE {
helper_.reset();
- context_.reset();
}
+ ServiceWorkerContextCore* context() { return helper_->context(); }
+
EmbeddedWorkerRegistry* embedded_worker_registry() {
- DCHECK(context_);
- return context_->embedded_worker_registry();
+ DCHECK(context());
+ return context()->embedded_worker_registry();
}
IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
};
+static void SaveStatusAndCall(ServiceWorkerStatusCode* out,
+ const base::Closure& callback,
+ ServiceWorkerStatusCode status) {
+ *out = status;
+ callback.Run();
+}
+
TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
@@ -57,17 +63,20 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
const GURL scope("http://example.com/*");
const GURL url("http://example.com/worker.js");
- // This fails as we have no available process yet.
- EXPECT_EQ(SERVICE_WORKER_ERROR_PROCESS_NOT_FOUND,
- worker->Start(service_worker_version_id, scope, url));
- EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
-
// Simulate adding one process to the worker.
helper_->SimulateAddProcessToWorker(embedded_worker_id, kRenderProcessId);
// Start should succeed.
- EXPECT_EQ(SERVICE_WORKER_OK,
- worker->Start(service_worker_version_id, scope, url));
+ ServiceWorkerStatusCode status;
+ base::RunLoop run_loop;
+ worker->Start(
+ service_worker_version_id,
+ scope,
+ url,
+ std::vector<int>(),
+ base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ run_loop.Run();
+ EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
base::RunLoop().RunUntilIdle();
@@ -90,6 +99,36 @@ TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
EmbeddedWorkerMsg_StopWorker::ID));
}
+TEST_F(EmbeddedWorkerInstanceTest, InstanceDestroyedBeforeStartFinishes) {
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ const int64 service_worker_version_id = 55L;
+ const GURL scope("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);
+ worker->Start(
+ service_worker_version_id,
+ scope,
+ url,
+ available_process,
+ base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ // But destroy it before it gets a chance to complete.
+ worker.reset();
+ run_loop.Run();
+ EXPECT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
+
+ // Verify that we didn't send the message to start the worker.
+ ASSERT_FALSE(
+ ipc_sink()->GetUniqueMessageMatching(EmbeddedWorkerMsg_StartWorker::ID));
+}
+
TEST_F(EmbeddedWorkerInstanceTest, ChooseProcess) {
scoped_ptr<EmbeddedWorkerInstance> worker =
embedded_worker_registry()->CreateWorker();
@@ -106,10 +145,16 @@ TEST_F(EmbeddedWorkerInstanceTest, ChooseProcess) {
helper_->SimulateAddProcessToWorker(embedded_worker_id, 3);
// Process 3 has the biggest # of references and it should be chosen.
- EXPECT_EQ(SERVICE_WORKER_OK,
- worker->Start(1L,
- GURL("http://example.com/*"),
- GURL("http://example.com/worker.js")));
+ ServiceWorkerStatusCode status;
+ base::RunLoop run_loop;
+ worker->Start(
+ 1L,
+ GURL("http://example.com/*"),
+ GURL("http://example.com/worker.js"),
+ std::vector<int>(),
+ base::Bind(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+ run_loop.Run();
+ EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
EXPECT_EQ(3, worker->process_id());
diff --git a/content/browser/service_worker/embedded_worker_registry.cc b/content/browser/service_worker/embedded_worker_registry.cc
index 249eab0..d10f553 100644
--- a/content/browser/service_worker/embedded_worker_registry.cc
+++ b/content/browser/service_worker/embedded_worker_registry.cc
@@ -4,10 +4,13 @@
#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "base/bind_helpers.h"
#include "base/stl_util.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/common/service_worker/embedded_worker_messages.h"
+#include "content/public/browser/browser_thread.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_sender.h"
@@ -25,20 +28,34 @@ scoped_ptr<EmbeddedWorkerInstance> EmbeddedWorkerRegistry::CreateWorker() {
return worker.Pass();
}
-ServiceWorkerStatusCode EmbeddedWorkerRegistry::StartWorker(
- int process_id,
- int embedded_worker_id,
- int64 service_worker_version_id,
- const GURL& scope,
- const GURL& script_url) {
- return Send(
- process_id,
- new EmbeddedWorkerMsg_StartWorker(
- embedded_worker_id, service_worker_version_id, scope, script_url));
+void EmbeddedWorkerRegistry::StartWorker(const std::vector<int>& process_ids,
+ int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ const StatusCallback& callback) {
+ if (!context_) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ return;
+ }
+ context_->process_manager()->AllocateWorkerProcess(
+ process_ids,
+ script_url,
+ base::Bind(&EmbeddedWorkerRegistry::StartWorkerWithProcessId,
+ this,
+ embedded_worker_id,
+ base::Passed(make_scoped_ptr(new EmbeddedWorkerMsg_StartWorker(
+ embedded_worker_id,
+ service_worker_version_id,
+ scope,
+ script_url))),
+ callback));
}
ServiceWorkerStatusCode EmbeddedWorkerRegistry::StopWorker(
int process_id, int embedded_worker_id) {
+ if (context_)
+ context_->process_manager()->ReleaseWorkerProcess(process_id);
return Send(process_id,
new EmbeddedWorkerMsg_StopWorker(embedded_worker_id));
}
@@ -55,6 +72,14 @@ bool EmbeddedWorkerRegistry::OnMessageReceived(const IPC::Message& message) {
return found->second->OnMessageReceived(message);
}
+void EmbeddedWorkerRegistry::Shutdown() {
+ for (WorkerInstanceMap::iterator it = worker_map_.begin();
+ it != worker_map_.end();
+ ++it) {
+ it->second->Stop();
+ }
+}
+
void EmbeddedWorkerRegistry::OnWorkerStarted(
int process_id, int thread_id, int embedded_worker_id) {
DCHECK(!ContainsKey(worker_process_map_, process_id) ||
@@ -143,7 +168,38 @@ EmbeddedWorkerInstance* EmbeddedWorkerRegistry::GetWorker(
return found->second;
}
-EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {}
+EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {
+ Shutdown();
+}
+
+void EmbeddedWorkerRegistry::StartWorkerWithProcessId(
+ int embedded_worker_id,
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker> message,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status,
+ int process_id) {
+ WorkerInstanceMap::const_iterator worker =
+ worker_map_.find(embedded_worker_id);
+ if (worker == worker_map_.end()) {
+ // The Instance was destroyed before it could finish starting. Undo what
+ // we've done so far.
+ if (context_)
+ context_->process_manager()->ReleaseWorkerProcess(process_id);
+ callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ return;
+ }
+ worker->second->RecordProcessId(process_id, status);
+
+ if (status != SERVICE_WORKER_OK) {
+ callback.Run(status);
+ return;
+ }
+ // The ServiceWorkerDispatcherHost is supposed to be created when the process
+ // is created, and keep an entry in process_sender_map_ for its whole
+ // lifetime.
+ DCHECK(ContainsKey(process_sender_map_, process_id));
+ callback.Run(Send(process_id, message.release()));
+}
ServiceWorkerStatusCode EmbeddedWorkerRegistry::Send(
int process_id, IPC::Message* message) {
diff --git a/content/browser/service_worker/embedded_worker_registry.h b/content/browser/service_worker/embedded_worker_registry.h
index 8350f82..5c12111 100644
--- a/content/browser/service_worker/embedded_worker_registry.h
+++ b/content/browser/service_worker/embedded_worker_registry.h
@@ -7,6 +7,7 @@
#include <map>
#include <set>
+#include <vector>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
@@ -16,6 +17,7 @@
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
+class EmbeddedWorkerMsg_StartWorker;
class GURL;
namespace IPC {
@@ -36,6 +38,8 @@ class ServiceWorkerContextCore;
class CONTENT_EXPORT EmbeddedWorkerRegistry
: public NON_EXPORTED_BASE(base::RefCounted<EmbeddedWorkerRegistry>) {
public:
+ typedef base::Callback<void(ServiceWorkerStatusCode)> StatusCallback;
+
explicit EmbeddedWorkerRegistry(
base::WeakPtr<ServiceWorkerContextCore> context);
@@ -46,14 +50,18 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
scoped_ptr<EmbeddedWorkerInstance> CreateWorker();
// Called from EmbeddedWorkerInstance, relayed to the child process.
- ServiceWorkerStatusCode StartWorker(int process_id,
- int embedded_worker_id,
- int64 service_worker_version_id,
- const GURL& scope,
- const GURL& script_url);
+ void StartWorker(const std::vector<int>& process_ids,
+ int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& scope,
+ const GURL& script_url,
+ const StatusCallback& callback);
ServiceWorkerStatusCode StopWorker(int process_id,
int embedded_worker_id);
+ // Stop all active workers, even if they're handling events.
+ void Shutdown();
+
// Called back from EmbeddedWorker in the child process, relayed via
// ServiceWorkerDispatcherHost.
void OnWorkerStarted(int process_id, int thread_id, int embedded_worker_id);
@@ -85,6 +93,14 @@ class CONTENT_EXPORT EmbeddedWorkerRegistry
typedef std::map<int, IPC::Sender*> ProcessToSenderMap;
~EmbeddedWorkerRegistry();
+
+ void StartWorkerWithProcessId(
+ int embedded_worker_id,
+ scoped_ptr<EmbeddedWorkerMsg_StartWorker> message,
+ const StatusCallback& callback,
+ ServiceWorkerStatusCode status,
+ int process_id);
+
ServiceWorkerStatusCode Send(int process_id, IPC::Message* message);
// RemoveWorker is called when EmbeddedWorkerInstance is destructed.
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 67ca05a..7501f5a 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -8,22 +8,33 @@
#include "content/browser/service_worker/embedded_worker_instance.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_wrapper.h"
#include "content/common/service_worker/embedded_worker_messages.h"
#include "content/common/service_worker/service_worker_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
-EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(
- ServiceWorkerContextCore* context,
- int mock_render_process_id)
- : context_(context->AsWeakPtr()),
+static bool AlwaysTrue(int process_id) {
+ return true;
+}
+
+EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper(int mock_render_process_id)
+ : wrapper_(new ServiceWorkerContextWrapper(NULL)),
next_thread_id_(0),
weak_factory_(this) {
+ wrapper_->Init(base::FilePath(), NULL);
+ scoped_ptr<ServiceWorkerProcessManager> process_manager(
+ new ServiceWorkerProcessManager(wrapper_));
+ process_manager->SetProcessRefcountOpsForTest(base::Bind(AlwaysTrue),
+ base::Bind(AlwaysTrue));
+ wrapper_->context()->SetProcessManagerForTest(process_manager.Pass());
registry()->AddChildProcessSender(mock_render_process_id, this);
}
EmbeddedWorkerTestHelper::~EmbeddedWorkerTestHelper() {
+ if (wrapper_)
+ wrapper_->Shutdown();
}
void EmbeddedWorkerTestHelper::SimulateAddProcessToWorker(
@@ -58,6 +69,15 @@ bool EmbeddedWorkerTestHelper::OnMessageReceived(const IPC::Message& message) {
return handled;
}
+ServiceWorkerContextCore* EmbeddedWorkerTestHelper::context() {
+ return wrapper_->context();
+}
+
+void EmbeddedWorkerTestHelper::ShutdownContext() {
+ wrapper_->Shutdown();
+ wrapper_ = NULL;
+}
+
void EmbeddedWorkerTestHelper::OnStartWorker(
int embedded_worker_id,
int64 service_worker_version_id,
@@ -219,8 +239,8 @@ void EmbeddedWorkerTestHelper::OnFetchEventStub(
}
EmbeddedWorkerRegistry* EmbeddedWorkerTestHelper::registry() {
- DCHECK(context_);
- return context_->embedded_worker_registry();
+ DCHECK(context());
+ return context()->embedded_worker_registry();
}
} // namespace content
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index af95f675..27a0416 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -21,12 +21,14 @@ namespace content {
class EmbeddedWorkerRegistry;
class EmbeddedWorkerTestHelper;
class ServiceWorkerContextCore;
+class ServiceWorkerContextWrapper;
struct ServiceWorkerFetchRequest;
// In-Process EmbeddedWorker test helper.
//
-// Usage: create an instance of this class for a ServiceWorkerContextCore
-// to test browser-side embedded worker code without creating a child process.
+// Usage: create an instance of this class to test browser-side embedded worker
+// code without creating a child process. This class will create a
+// ServiceWorkerContextWrapper and ServiceWorkerContextCore for you.
//
// By default this class just notifies back WorkerStarted and WorkerStopped
// for StartWorker and StopWorker requests. The default implementation
@@ -42,8 +44,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
public:
// Initialize this helper for |context|, and enable this as an IPC
// sender for |mock_render_process_id|.
- EmbeddedWorkerTestHelper(ServiceWorkerContextCore* context,
- int mock_render_process_id);
+ EmbeddedWorkerTestHelper(int mock_render_process_id);
virtual ~EmbeddedWorkerTestHelper();
// Call this to simulate add/associate a process to a worker.
@@ -61,6 +62,10 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
// Inner IPC sink for script context messages sent via EmbeddedWorker.
IPC::TestSink* inner_ipc_sink() { return &inner_sink_; }
+ ServiceWorkerContextCore* context();
+ ServiceWorkerContextWrapper* context_wrapper() { return wrapper_.get(); }
+ void ShutdownContext();
+
protected:
// Called when StartWorker, StopWorker and SendMessageToWorker message
// is sent to the embedded worker. Override if necessary. By default
@@ -112,7 +117,7 @@ class EmbeddedWorkerTestHelper : public IPC::Sender,
void OnFetchEventStub(int request_id,
const ServiceWorkerFetchRequest& request);
- base::WeakPtr<ServiceWorkerContextCore> context_;
+ scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
IPC::TestSink sink_;
IPC::TestSink inner_sink_;
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 60a9849..6ab1e7d 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -164,9 +164,17 @@ class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
const GURL scope = embedded_test_server()->GetURL("/*");
const GURL script_url = embedded_test_server()->GetURL(
"/service_worker/worker.js");
- ServiceWorkerStatusCode status = worker_->Start(
- service_worker_version_id, scope, script_url);
-
+ std::vector<int> processes;
+ processes.push_back(
+ shell()->web_contents()->GetRenderProcessHost()->GetID());
+ worker_->Start(
+ service_worker_version_id,
+ scope,
+ script_url,
+ processes,
+ base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
+ }
+ void StartOnIOThread2(ServiceWorkerStatusCode status) {
last_worker_status_ = worker_->status();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
@@ -596,7 +604,6 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, Registration) {
public_context()->RegisterServiceWorker(
embedded_test_server()->GetURL("/*"),
embedded_test_server()->GetURL(kWorkerUrl),
- RenderProcessID(),
base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
true,
run_loop.QuitClosure()));
@@ -610,7 +617,6 @@ IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, Registration) {
public_context()->RegisterServiceWorker(
embedded_test_server()->GetURL("/*"),
embedded_test_server()->GetURL(kWorkerUrl),
- RenderProcessID(),
base::Bind(&ServiceWorkerBlackBoxBrowserTest::ExpectResultAndRun,
true,
run_loop.QuitClosure()));
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index 9b8a17a..910b33c 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -8,8 +8,10 @@
#include "base/strings/string_util.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_observer.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_info.h"
#include "content/browser/service_worker/service_worker_job_coordinator.h"
+#include "content/browser/service_worker/service_worker_process_manager.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_register_job.h"
#include "content/browser/service_worker/service_worker_registration.h"
@@ -76,13 +78,16 @@ void ServiceWorkerContextCore::ProviderHostIterator::Initialize() {
ServiceWorkerContextCore::ServiceWorkerContextCore(
const base::FilePath& path,
quota::QuotaManagerProxy* quota_manager_proxy,
- ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list)
- : storage_(new ServiceWorkerStorage(
- path, AsWeakPtr(), quota_manager_proxy)),
+ ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list,
+ scoped_ptr<ServiceWorkerProcessManager> process_manager)
+ : storage_(
+ new ServiceWorkerStorage(path, AsWeakPtr(), quota_manager_proxy)),
embedded_worker_registry_(new EmbeddedWorkerRegistry(AsWeakPtr())),
job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())),
+ process_manager_(process_manager.Pass()),
next_handle_id_(0),
- observer_list_(observer_list) {}
+ observer_list_(observer_list) {
+}
ServiceWorkerContextCore::~ServiceWorkerContextCore() {
for (VersionMap::iterator it = live_versions_.begin();
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h
index 2fae441..a8cdc41 100644
--- a/content/browser/service_worker/service_worker_context_core.h
+++ b/content/browser/service_worker/service_worker_context_core.h
@@ -15,6 +15,7 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list_threadsafe.h"
#include "content/browser/service_worker/service_worker_info.h"
+#include "content/browser/service_worker/service_worker_process_manager.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_storage.h"
@@ -86,7 +87,8 @@ class CONTENT_EXPORT ServiceWorkerContextCore
ServiceWorkerContextCore(
const base::FilePath& user_data_directory,
quota::QuotaManagerProxy* quota_manager_proxy,
- ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list);
+ ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list,
+ scoped_ptr<ServiceWorkerProcessManager> process_manager);
virtual ~ServiceWorkerContextCore();
// ServiceWorkerVersion::Listener overrides.
@@ -106,6 +108,9 @@ class CONTENT_EXPORT ServiceWorkerContextCore
const GURL& source_url) OVERRIDE;
ServiceWorkerStorage* storage() { return storage_.get(); }
+ ServiceWorkerProcessManager* process_manager() {
+ return process_manager_.get();
+ }
EmbeddedWorkerRegistry* embedded_worker_registry() {
return embedded_worker_registry_.get();
}
@@ -149,6 +154,12 @@ class CONTENT_EXPORT ServiceWorkerContextCore
// Returns new context-local unique ID for ServiceWorkerHandle.
int GetNewServiceWorkerHandleId();
+ // Allows tests to change how processes are created.
+ void SetProcessManagerForTest(
+ scoped_ptr<ServiceWorkerProcessManager> new_process_manager) {
+ process_manager_ = new_process_manager.Pass();
+ }
+
private:
typedef std::map<int64, ServiceWorkerRegistration*> RegistrationsMap;
typedef std::map<int64, ServiceWorkerVersion*> VersionMap;
@@ -167,6 +178,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore
scoped_ptr<ServiceWorkerStorage> storage_;
scoped_refptr<EmbeddedWorkerRegistry> embedded_worker_registry_;
scoped_ptr<ServiceWorkerJobCoordinator> job_coordinator_;
+ scoped_ptr<ServiceWorkerProcessManager> process_manager_;
std::map<int64, ServiceWorkerRegistration*> live_registrations_;
std::map<int64, ServiceWorkerVersion*> live_versions_;
int next_handle_id_;
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index 3c7d55f..00e9527 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -83,9 +83,8 @@ void ExpectRegisteredWorkers(
class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
public:
- RejectInstallTestHelper(ServiceWorkerContextCore* context,
- int mock_render_process_id)
- : EmbeddedWorkerTestHelper(context, mock_render_process_id) {}
+ RejectInstallTestHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(mock_render_process_id) {}
virtual void OnInstallEvent(int embedded_worker_id,
int request_id,
@@ -99,9 +98,8 @@ class RejectInstallTestHelper : public EmbeddedWorkerTestHelper {
class RejectActivateTestHelper : public EmbeddedWorkerTestHelper {
public:
- RejectActivateTestHelper(ServiceWorkerContextCore* context,
- int mock_render_process_id)
- : EmbeddedWorkerTestHelper(context, mock_render_process_id) {}
+ RejectActivateTestHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(mock_render_process_id) {}
virtual void OnActivateEvent(int embedded_worker_id,
int request_id) OVERRIDE {
@@ -121,19 +119,17 @@ class ServiceWorkerContextTest : public testing::Test {
render_process_id_(99) {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
- helper_.reset(new EmbeddedWorkerTestHelper(
- context_.get(), render_process_id_));
+ helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
}
virtual void TearDown() OVERRIDE {
helper_.reset();
- context_.reset();
}
+ ServiceWorkerContextCore* context() { return helper_->context(); }
+
protected:
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
const int render_process_id_;
};
@@ -143,7 +139,7 @@ TEST_F(ServiceWorkerContextTest, Register) {
int64 registration_id = kInvalidServiceWorkerRegistrationId;
int64 version_id = kInvalidServiceWorkerVersionId;
bool called = false;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
GURL("http://www.example.com/*"),
GURL("http://www.example.com/service_worker.js"),
render_process_id_,
@@ -162,7 +158,7 @@ TEST_F(ServiceWorkerContextTest, Register) {
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
- context_->storage()->FindRegistrationForId(
+ context()->storage()->FindRegistrationForId(
registration_id,
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_OK,
@@ -176,12 +172,12 @@ TEST_F(ServiceWorkerContextTest, Register) {
// registration callback should indicate success, but there should be no pending
// or active worker in the registration.
TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
- helper_.reset(
- new RejectInstallTestHelper(context_.get(), render_process_id_));
+ helper_.reset(); // Make sure the process lookups stay overridden.
+ helper_.reset(new RejectInstallTestHelper(render_process_id_));
int64 registration_id = kInvalidServiceWorkerRegistrationId;
int64 version_id = kInvalidServiceWorkerVersionId;
bool called = false;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
GURL("http://www.example.com/*"),
GURL("http://www.example.com/service_worker.js"),
render_process_id_,
@@ -200,7 +196,7 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
- context_->storage()->FindRegistrationForId(
+ context()->storage()->FindRegistrationForId(
registration_id,
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
@@ -214,12 +210,12 @@ TEST_F(ServiceWorkerContextTest, Register_RejectInstall) {
// registration callback should indicate success, but there should be no pending
// or active worker in the registration.
TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
- helper_.reset(
- new RejectActivateTestHelper(context_.get(), render_process_id_));
+ helper_.reset(); // Make sure the process lookups stay overridden.
+ helper_.reset(new RejectActivateTestHelper(render_process_id_));
int64 registration_id = kInvalidServiceWorkerRegistrationId;
int64 version_id = kInvalidServiceWorkerVersionId;
bool called = false;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
GURL("http://www.example.com/*"),
GURL("http://www.example.com/service_worker.js"),
render_process_id_,
@@ -238,7 +234,7 @@ TEST_F(ServiceWorkerContextTest, Register_RejectActivate) {
EXPECT_NE(kInvalidServiceWorkerRegistrationId, registration_id);
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
- context_->storage()->FindRegistrationForId(
+ context()->storage()->FindRegistrationForId(
registration_id,
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
@@ -255,7 +251,7 @@ TEST_F(ServiceWorkerContextTest, Unregister) {
bool called = false;
int64 registration_id = kInvalidServiceWorkerRegistrationId;
int64 version_id = kInvalidServiceWorkerVersionId;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
pattern,
GURL("http://www.example.com/service_worker.js"),
render_process_id_,
@@ -269,14 +265,14 @@ TEST_F(ServiceWorkerContextTest, Unregister) {
EXPECT_NE(kInvalidServiceWorkerVersionId, version_id);
called = false;
- context_->UnregisterServiceWorker(
+ context()->UnregisterServiceWorker(
pattern, render_process_id_, NULL, MakeUnregisteredCallback(&called));
ASSERT_FALSE(called);
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(called);
- context_->storage()->FindRegistrationForId(
+ context()->storage()->FindRegistrationForId(
registration_id,
base::Bind(&ExpectRegisteredWorkers,
SERVICE_WORKER_ERROR_NOT_FOUND,
@@ -294,7 +290,7 @@ TEST_F(ServiceWorkerContextTest, RegisterNewScript) {
bool called = false;
int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
int64 old_version_id = kInvalidServiceWorkerVersionId;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
pattern,
GURL("http://www.example.com/service_worker.js"),
render_process_id_,
@@ -310,7 +306,7 @@ TEST_F(ServiceWorkerContextTest, RegisterNewScript) {
called = false;
int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
int64 new_version_id = kInvalidServiceWorkerVersionId;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
pattern,
GURL("http://www.example.com/service_worker_new.js"),
render_process_id_,
@@ -338,7 +334,7 @@ TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) {
bool called = false;
int64 old_registration_id = kInvalidServiceWorkerRegistrationId;
int64 old_version_id = kInvalidServiceWorkerVersionId;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
pattern,
script_url,
render_process_id_,
@@ -354,7 +350,7 @@ TEST_F(ServiceWorkerContextTest, RegisterDuplicateScript) {
called = false;
int64 new_registration_id = kInvalidServiceWorkerRegistrationId;
int64 new_version_id = kInvalidServiceWorkerVersionId;
- context_->RegisterServiceWorker(
+ context()->RegisterServiceWorker(
pattern,
script_url,
render_process_id_,
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 2ccffa1..8f64134 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -7,14 +7,18 @@
#include "base/files/file_path.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_observer.h"
+#include "content/browser/service_worker/service_worker_process_manager.h"
#include "content/public/browser/browser_thread.h"
#include "webkit/browser/quota/quota_manager_proxy.h"
namespace content {
-ServiceWorkerContextWrapper::ServiceWorkerContextWrapper()
+ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
+ BrowserContext* browser_context)
: observer_list_(
- new ObserverListThreadSafe<ServiceWorkerContextObserver>()) {}
+ new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
+ browser_context_(browser_context) {
+}
ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
}
@@ -24,19 +28,26 @@ void ServiceWorkerContextWrapper::Init(
quota::QuotaManagerProxy* quota_manager_proxy) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&ServiceWorkerContextWrapper::Init, this,
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerContextWrapper::Init,
+ this,
user_data_directory,
make_scoped_refptr(quota_manager_proxy)));
return;
}
DCHECK(!context_core_);
context_core_.reset(new ServiceWorkerContextCore(
- user_data_directory, quota_manager_proxy, observer_list_));
+ user_data_directory,
+ quota_manager_proxy,
+ observer_list_,
+ make_scoped_ptr(new ServiceWorkerProcessManager(this))));
}
void ServiceWorkerContextWrapper::Shutdown() {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ browser_context_ = NULL;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ServiceWorkerContextWrapper::Shutdown, this));
@@ -65,7 +76,6 @@ static void FinishRegistrationOnIO(
void ServiceWorkerContextWrapper::RegisterServiceWorker(
const GURL& pattern,
const GURL& script_url,
- int source_process_id,
const ResultCallback& continuation) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
@@ -75,7 +85,6 @@ void ServiceWorkerContextWrapper::RegisterServiceWorker(
this,
pattern,
script_url,
- source_process_id,
continuation));
return;
}
@@ -83,7 +92,7 @@ void ServiceWorkerContextWrapper::RegisterServiceWorker(
context()->RegisterServiceWorker(
pattern,
script_url,
- source_process_id,
+ -1,
NULL /* provider_host */,
base::Bind(&FinishRegistrationOnIO, continuation));
}
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h
index cea9c06..bd83210 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.h
+++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_WRAPPER_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_CONTEXT_WRAPPER_H_
+#include <vector>
+
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -22,6 +24,8 @@ class QuotaManagerProxy;
namespace content {
+class BrowserContext;
+class ServiceWorkerContextCore;
class ServiceWorkerContextObserver;
// A refcounted wrapper class for our core object. Higher level content lib
@@ -32,7 +36,7 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
: NON_EXPORTED_BASE(public ServiceWorkerContext),
public base::RefCountedThreadSafe<ServiceWorkerContextWrapper> {
public:
- ServiceWorkerContextWrapper();
+ ServiceWorkerContextWrapper(BrowserContext* browser_context);
// Init and Shutdown are for use on the UI thread when the profile,
// storagepartition is being setup and torn down.
@@ -44,12 +48,10 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
ServiceWorkerContextCore* context();
// ServiceWorkerContext implementation:
- virtual void RegisterServiceWorker(const GURL& pattern,
- const GURL& script_url,
- int source_process_id,
- const ResultCallback& continuation)
- OVERRIDE;
-
+ virtual void RegisterServiceWorker(
+ const GURL& pattern,
+ const GURL& script_url,
+ const ResultCallback& continuation) OVERRIDE;
virtual void UnregisterServiceWorker(const GURL& pattern,
int source_process_id,
const ResultCallback& continuation)
@@ -60,11 +62,14 @@ class CONTENT_EXPORT ServiceWorkerContextWrapper
private:
friend class base::RefCountedThreadSafe<ServiceWorkerContextWrapper>;
+ friend class ServiceWorkerProcessManager;
virtual ~ServiceWorkerContextWrapper();
- scoped_ptr<ServiceWorkerContextCore> context_core_;
- scoped_refptr<ObserverListThreadSafe<ServiceWorkerContextObserver> >
+ const scoped_refptr<ObserverListThreadSafe<ServiceWorkerContextObserver> >
observer_list_;
+ // Cleared in Shutdown():
+ BrowserContext* browser_context_;
+ scoped_ptr<ServiceWorkerContextCore> context_core_;
};
} // namespace content
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 562fc95..ec6a839 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -44,7 +44,9 @@ ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
: BrowserMessageFilter(kFilteredMessageClasses,
arraysize(kFilteredMessageClasses)),
render_process_id_(render_process_id),
- message_port_message_filter_(message_port_message_filter) {}
+ message_port_message_filter_(message_port_message_filter),
+ channel_ready_(false) {
+}
ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
if (context_) {
@@ -68,6 +70,16 @@ void ServiceWorkerDispatcherHost::Init(
render_process_id_, this);
}
+void ServiceWorkerDispatcherHost::OnFilterAdded(IPC::Channel* channel) {
+ BrowserMessageFilter::OnFilterAdded(channel);
+ channel_ready_ = true;
+ std::vector<IPC::Message*> messages;
+ pending_messages_.release(&messages);
+ for (size_t i = 0; i < messages.size(); ++i) {
+ BrowserMessageFilter::Send(messages[i]);
+ }
+}
+
void ServiceWorkerDispatcherHost::OnDestruct() const {
BrowserThread::DeleteOnIOThread::Destruct(this);
}
@@ -116,6 +128,17 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived(
return handled;
}
+bool ServiceWorkerDispatcherHost::Send(IPC::Message* message) {
+ if (channel_ready_) {
+ BrowserMessageFilter::Send(message);
+ // Don't bother passing through Send()'s result: it's not reliable.
+ return true;
+ }
+
+ pending_messages_.push_back(message);
+ return true;
+}
+
void ServiceWorkerDispatcherHost::RegisterServiceWorkerHandle(
scoped_ptr<ServiceWorkerHandle> handle) {
int handle_id = handle->handle_id();
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index 473f239..97b50bd 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -31,11 +31,20 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
void Init(ServiceWorkerContextWrapper* context_wrapper);
- // BrowserIOMessageFilter implementation
+ // BrowserMessageFilter implementation
+ virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE;
virtual void OnDestruct() const OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE;
+ // IPC::Sender implementation
+
+ // Send() queues the message until the underlying channel is ready. This
+ // class assumes that Send() can only fail after that when the renderer
+ // process has terminated, at which point the whole instance will eventually
+ // be destroyed.
+ virtual bool Send(IPC::Message* message) OVERRIDE;
+
void RegisterServiceWorkerHandle(scoped_ptr<ServiceWorkerHandle> handle);
protected:
@@ -98,6 +107,9 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter {
IDMap<ServiceWorkerHandle, IDMapOwnPointer> handles_;
+ bool channel_ready_; // True after BrowserMessageFilter::channel_ != NULL.
+ ScopedVector<IPC::Message> pending_messages_;
+
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerDispatcherHost);
};
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 8a407ef..9c74777 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -29,23 +29,19 @@ class ServiceWorkerDispatcherHostTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
virtual void SetUp() {
- context_wrapper_ = new ServiceWorkerContextWrapper;
- context_wrapper_->Init(base::FilePath(), NULL);
- helper_.reset(new EmbeddedWorkerTestHelper(context(), kRenderProcessId));
+ helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
}
virtual void TearDown() {
helper_.reset();
- if (context_wrapper_) {
- context_wrapper_->Shutdown();
- context_wrapper_ = NULL;
- }
}
- ServiceWorkerContextCore* context() { return context_wrapper_->context(); }
+ ServiceWorkerContextCore* context() { return helper_->context(); }
+ ServiceWorkerContextWrapper* context_wrapper() {
+ return helper_->context_wrapper();
+ }
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
};
@@ -85,7 +81,7 @@ TEST_F(ServiceWorkerDispatcherHostTest, DisabledCausesError) {
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host =
new TestingServiceWorkerDispatcherHost(
- kRenderProcessId, context_wrapper_.get(), helper_.get());
+ kRenderProcessId, context_wrapper(), helper_.get());
bool handled;
dispatcher_host->OnMessageReceived(
@@ -112,7 +108,7 @@ TEST_F(ServiceWorkerDispatcherHostTest, DISABLED_Enabled) {
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host =
new TestingServiceWorkerDispatcherHost(
- kRenderProcessId, context_wrapper_.get(), helper_.get());
+ kRenderProcessId, context_wrapper(), helper_.get());
bool handled;
dispatcher_host->OnMessageReceived(
@@ -137,10 +133,9 @@ TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) {
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host =
new TestingServiceWorkerDispatcherHost(
- kRenderProcessId, context_wrapper_.get(), helper_.get());
+ kRenderProcessId, context_wrapper(), helper_.get());
- context_wrapper_->Shutdown();
- context_wrapper_ = NULL;
+ helper_->ShutdownContext();
bool handled;
dispatcher_host->OnMessageReceived(
@@ -157,7 +152,7 @@ TEST_F(ServiceWorkerDispatcherHostTest, EarlyContextDeletion) {
TEST_F(ServiceWorkerDispatcherHostTest, ProviderCreatedAndDestroyed) {
scoped_refptr<TestingServiceWorkerDispatcherHost> dispatcher_host =
new TestingServiceWorkerDispatcherHost(
- kRenderProcessId, context_wrapper_.get(), helper_.get());
+ kRenderProcessId, context_wrapper(), helper_.get());
const int kProviderId = 1001; // Test with a value != kRenderProcessId.
diff --git a/content/browser/service_worker/service_worker_handle_unittest.cc b/content/browser/service_worker/service_worker_handle_unittest.cc
index ebc3c745..70c4456 100644
--- a/content/browser/service_worker/service_worker_handle_unittest.cc
+++ b/content/browser/service_worker/service_worker_handle_unittest.cc
@@ -44,17 +44,15 @@ class ServiceWorkerHandleTest : public testing::Test {
: browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
- helper_.reset(new EmbeddedWorkerTestHelper(context_.get(),
- kRenderProcessId));
+ helper_.reset(new EmbeddedWorkerTestHelper(kRenderProcessId));
registration_ = new ServiceWorkerRegistration(
GURL("http://www.example.com/*"),
GURL("http://www.example.com/service_worker.js"),
- 1L, context_->AsWeakPtr());
+ 1L,
+ helper_->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_,
- 1L, context_->AsWeakPtr());
+ registration_, 1L, helper_->context()->AsWeakPtr());
// Simulate adding one process to the worker.
int embedded_worker_id = version_->embedded_worker()->embedded_worker_id();
@@ -65,13 +63,11 @@ class ServiceWorkerHandleTest : public testing::Test {
registration_ = NULL;
version_ = NULL;
helper_.reset();
- context_.reset();
}
IPC::TestSink* ipc_sink() { return helper_->ipc_sink(); }
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
@@ -79,8 +75,11 @@ class ServiceWorkerHandleTest : public testing::Test {
};
TEST_F(ServiceWorkerHandleTest, OnVersionStateChanged) {
- scoped_ptr<ServiceWorkerHandle> handle = ServiceWorkerHandle::Create(
- context_->AsWeakPtr(), helper_.get(), 1 /* thread_id */, version_);
+ scoped_ptr<ServiceWorkerHandle> handle =
+ ServiceWorkerHandle::Create(helper_->context()->AsWeakPtr(),
+ helper_.get(),
+ 1 /* thread_id */,
+ version_);
// Start the worker, and then...
ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index de5e612..35c368e 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -94,24 +94,22 @@ class ServiceWorkerJobTest : public testing::Test {
render_process_id_(88) {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
- helper_.reset(new EmbeddedWorkerTestHelper(context_.get(),
- render_process_id_));
+ helper_.reset(new EmbeddedWorkerTestHelper(render_process_id_));
}
virtual void TearDown() OVERRIDE {
helper_.reset();
- context_.reset();
}
+ ServiceWorkerContextCore* context() const { return helper_->context(); }
+
ServiceWorkerJobCoordinator* job_coordinator() const {
- return context_->job_coordinator();
+ return context()->job_coordinator();
}
- ServiceWorkerStorage* storage() const { return context_->storage(); }
+ ServiceWorkerStorage* storage() const { return context()->storage(); }
protected:
TestBrowserThreadBundle browser_thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
int render_process_id_;
@@ -398,9 +396,8 @@ TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
public:
- FailToStartWorkerTestHelper(ServiceWorkerContextCore* context,
- int mock_render_process_id)
- : EmbeddedWorkerTestHelper(context, mock_render_process_id) {}
+ FailToStartWorkerTestHelper(int mock_render_process_id)
+ : EmbeddedWorkerTestHelper(mock_render_process_id) {}
virtual void OnStartWorker(int embedded_worker_id,
int64 service_worker_version_id,
@@ -413,8 +410,7 @@ class FailToStartWorkerTestHelper : public EmbeddedWorkerTestHelper {
};
TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) {
- helper_.reset(
- new FailToStartWorkerTestHelper(context_.get(), render_process_id_));
+ helper_.reset(new FailToStartWorkerTestHelper(render_process_id_));
bool called = false;
scoped_refptr<ServiceWorkerRegistration> registration;
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc
new file mode 100644
index 0000000..b6a2891
--- /dev/null
+++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -0,0 +1,145 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/service_worker/service_worker_process_manager.h"
+
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/site_instance.h"
+#include "url/gurl.h"
+
+namespace content {
+
+ServiceWorkerProcessManager::ServiceWorkerProcessManager(
+ ServiceWorkerContextWrapper* context_wrapper)
+ : context_wrapper_(context_wrapper),
+ weak_this_factory_(this),
+ weak_this_(weak_this_factory_.GetWeakPtr()) {
+}
+
+ServiceWorkerProcessManager::~ServiceWorkerProcessManager() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void ServiceWorkerProcessManager::AllocateWorkerProcess(
+ const std::vector<int>& process_ids,
+ const GURL& script_url,
+ const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
+ callback) const {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess,
+ weak_this_,
+ process_ids,
+ script_url,
+ callback));
+ return;
+ }
+
+ for (std::vector<int>::const_iterator it = process_ids.begin();
+ it != process_ids.end();
+ ++it) {
+ if (IncrementWorkerRefcountByPid(*it)) {
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, *it));
+ return;
+ }
+ }
+
+ if (!context_wrapper_->browser_context_) {
+ // Shutdown has started.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
+ return;
+ }
+ // No existing processes available; start a new one.
+ scoped_refptr<SiteInstance> site_instance = SiteInstance::CreateForURL(
+ context_wrapper_->browser_context_, script_url);
+ RenderProcessHost* rph = site_instance->GetProcess();
+ // This Init() call posts a task to the IO thread that adds the RPH's
+ // ServiceWorkerDispatcherHost to the
+ // EmbeddedWorkerRegistry::process_sender_map_.
+ if (!rph->Init()) {
+ LOG(ERROR) << "Couldn't start a new process!";
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
+ return;
+ }
+
+ static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, rph->GetID()));
+}
+
+void ServiceWorkerProcessManager::ReleaseWorkerProcess(int process_id) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerProcessManager::ReleaseWorkerProcess,
+ weak_this_,
+ process_id));
+ return;
+ }
+ if (!DecrementWorkerRefcountByPid(process_id)) {
+ DCHECK(false) << "DecrementWorkerRef(" << process_id
+ << ") doesn't match a previous IncrementWorkerRef";
+ }
+}
+
+void ServiceWorkerProcessManager::SetProcessRefcountOpsForTest(
+ const base::Callback<bool(int)>& increment_for_test,
+ const base::Callback<bool(int)>& decrement_for_test) {
+ increment_for_test_ = increment_for_test;
+ decrement_for_test_ = decrement_for_test;
+}
+
+bool ServiceWorkerProcessManager::IncrementWorkerRefcountByPid(
+ int process_id) const {
+ if (!increment_for_test_.is_null())
+ return increment_for_test_.Run(process_id);
+
+ RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+ if (rph && !rph->FastShutdownStarted()) {
+ static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
+ return true;
+ }
+
+ return false;
+}
+
+bool ServiceWorkerProcessManager::DecrementWorkerRefcountByPid(
+ int process_id) const {
+ if (!decrement_for_test_.is_null())
+ return decrement_for_test_.Run(process_id);
+
+ RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+ if (rph)
+ static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount();
+
+ return rph != NULL;
+}
+
+} // namespace content
+
+namespace base {
+// Destroying ServiceWorkerProcessManagers only on the UI thread allows the
+// member WeakPtr to safely guard the object's lifetime when used on that
+// thread.
+void DefaultDeleter<content::ServiceWorkerProcessManager>::operator()(
+ content::ServiceWorkerProcessManager* ptr) const {
+ content::BrowserThread::DeleteSoon(
+ content::BrowserThread::UI, FROM_HERE, ptr);
+}
+} // namespace base
diff --git a/content/browser/service_worker/service_worker_process_manager.h b/content/browser/service_worker/service_worker_process_manager.h
new file mode 100644
index 0000000..c856a52
--- /dev/null
+++ b/content/browser/service_worker/service_worker_process_manager.h
@@ -0,0 +1,84 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROCESS_MANAGER_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROCESS_MANAGER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/service_worker/service_worker_status_code.h"
+
+class GURL;
+
+namespace content {
+
+class BrowserContext;
+class ServiceWorkerContextWrapper;
+
+// 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
+// ServiceWorkerContextCore is destroyed on the IO thread.
+class CONTENT_EXPORT ServiceWorkerProcessManager {
+ public:
+ // |*this| must be owned by |context_wrapper|->context().
+ explicit ServiceWorkerProcessManager(
+ ServiceWorkerContextWrapper* context_wrapper);
+
+ ~ServiceWorkerProcessManager();
+
+ // 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.
+ //
+ // Allocation can fail with SERVICE_WORKER_ERROR_START_WORKER_FAILED if
+ // RenderProcessHost::Init fails.
+ void AllocateWorkerProcess(
+ const std::vector<int>& process_ids,
+ const GURL& script_url,
+ const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
+ callback) const;
+
+ // Drops a reference to a process that was running a Service Worker. This
+ // must match a call to AllocateWorkerProcess.
+ void ReleaseWorkerProcess(int process_id);
+
+ // |increment_for_test| and |decrement_for_test| define how to look up a
+ // process by ID and increment or decrement its worker reference count. This
+ // must be called before any reference to this object escapes to another
+ // thread, and is considered part of construction.
+ void SetProcessRefcountOpsForTest(
+ const base::Callback<bool(int)>& increment_for_test,
+ const base::Callback<bool(int)>& decrement_for_test);
+
+ private:
+ bool IncrementWorkerRefcountByPid(int process_id) const;
+ bool DecrementWorkerRefcountByPid(int process_id) const;
+
+ // These fields are only accessed on the UI thread after construction.
+ scoped_refptr<ServiceWorkerContextWrapper> context_wrapper_;
+ base::Callback<bool(int)> increment_for_test_;
+ base::Callback<bool(int)> decrement_for_test_;
+
+ // Used to double-check that we don't access *this after it's destroyed.
+ base::WeakPtrFactory<ServiceWorkerProcessManager> weak_this_factory_;
+ base::WeakPtr<ServiceWorkerProcessManager> weak_this_;
+};
+
+} // namespace content
+
+namespace base {
+// Specialized to post the deletion to the UI thread.
+template <>
+struct CONTENT_EXPORT DefaultDeleter<content::ServiceWorkerProcessManager> {
+ void operator()(content::ServiceWorkerProcessManager* ptr) const;
+};
+} // namespace base
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_PROCESS_MANAGER_H_
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 5a60295..03c513a 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -23,7 +23,11 @@ class ServiceWorkerProviderHostTest : public testing::Test {
virtual ~ServiceWorkerProviderHostTest() {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
+ context_.reset(new ServiceWorkerContextCore(
+ base::FilePath(),
+ NULL,
+ NULL,
+ scoped_ptr<ServiceWorkerProcessManager>()));
scope_ = GURL("http://www.example.com/*");
script_url_ = GURL("http://www.example.com/service_worker.js");
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index 27b687eca..6819305 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -43,14 +43,10 @@ ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {
void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback,
int process_id) {
- DCHECK_NE(-1, process_id);
- if (phase_ >= UPDATE && pending_version())
- pending_version()->AddProcessToWorker(process_id);
- else
- pending_process_ids_.push_back(process_id);
-
if (!is_promise_resolved_) {
callbacks_.push_back(callback);
+ if (process_id != -1 && (phase_ < UPDATE || !pending_version()))
+ pending_process_ids_.push_back(process_id);
return;
}
RunSoon(base::Bind(
@@ -228,15 +224,11 @@ void ServiceWorkerRegisterJob::UpdateAndContinue(
// the worker.
set_pending_version(new ServiceWorkerVersion(
registration(), context_->storage()->NewVersionId(), context_));
- for (std::vector<int>::const_iterator it = pending_process_ids_.begin();
- it != pending_process_ids_.end();
- ++it) {
- pending_version()->AddProcessToWorker(*it);
- }
// TODO(michaeln): Start the worker into a paused state where the
// script resource is downloaded but not yet evaluated.
- pending_version()->StartWorker(
+ pending_version()->StartWorkerWithCandidateProcesses(
+ pending_process_ids_,
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 5b02039..0a0c198 100644
--- a/content/browser/service_worker/service_worker_register_job.h
+++ b/content/browser/service_worker/service_worker_register_job.h
@@ -45,9 +45,10 @@ 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. |process_id| is
- // added via AddProcessToWorker to the ServiceWorkerVersion created by the
- // registration job.
+ // 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);
// ServiceWorkerRegisterJobBase implementation:
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 23f190e..d1015b2 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -21,7 +21,11 @@ class ServiceWorkerRegistrationTest : public testing::Test {
: io_thread_(BrowserThread::IO, &message_loop_) {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
+ context_.reset(new ServiceWorkerContextCore(
+ base::FilePath(),
+ NULL,
+ NULL,
+ scoped_ptr<ServiceWorkerProcessManager>()));
context_ptr_ = context_->AsWeakPtr();
}
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index ed2268a..80ee8af 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -72,7 +72,11 @@ class ServiceWorkerStorageTest : public testing::Test {
}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
+ context_.reset(new ServiceWorkerContextCore(
+ base::FilePath(),
+ NULL,
+ NULL,
+ scoped_ptr<ServiceWorkerProcessManager>()));
context_ptr_ = context_->AsWeakPtr();
storage()->simulated_lazy_initted_ = true;
}
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 63e57d6..931cace 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -89,34 +89,32 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
virtual ~ServiceWorkerURLRequestJobTest() {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
- helper_.reset(new EmbeddedWorkerTestHelper(context_.get(), kProcessID));
+ helper_.reset(new EmbeddedWorkerTestHelper(kProcessID));
registration_ = new ServiceWorkerRegistration(
GURL("http://example.com/*"),
GURL("http://example.com/service_worker.js"),
- 1L, context_->AsWeakPtr());
+ 1L,
+ helper_->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_,
- 1L, context_->AsWeakPtr());
+ registration_, 1L, helper_->context()->AsWeakPtr());
scoped_ptr<ServiceWorkerProviderHost> provider_host(
- new ServiceWorkerProviderHost(kProcessID, kProviderID,
- context_->AsWeakPtr(), NULL));
+ new ServiceWorkerProviderHost(
+ kProcessID, kProviderID, helper_->context()->AsWeakPtr(), NULL));
provider_host->SetActiveVersion(version_.get());
url_request_job_factory_.SetProtocolHandler(
"http", new MockProtocolHandler(provider_host->AsWeakPtr()));
url_request_context_.set_job_factory(&url_request_job_factory_);
- context_->AddProviderHost(provider_host.Pass());
+ helper_->context()->AddProviderHost(provider_host.Pass());
}
virtual void TearDown() OVERRIDE {
version_ = NULL;
registration_ = NULL;
helper_.reset();
- context_.reset();
}
void TestRequest() {
@@ -137,7 +135,6 @@ class ServiceWorkerURLRequestJobTest : public testing::Test {
TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
scoped_ptr<EmbeddedWorkerTestHelper> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 8cb4d12..592f88b 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -139,24 +139,34 @@ ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
}
void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
+ StartWorkerWithCandidateProcesses(std::vector<int>(), callback);
+}
+
+void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
+ const std::vector<int>& possible_process_ids,
+ const StatusCallback& callback) {
DCHECK(embedded_worker_);
- if (running_status() == RUNNING) {
- RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
- return;
- }
- if (running_status() == STOPPING) {
- RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
- return;
- }
- if (start_callbacks_.empty()) {
- ServiceWorkerStatusCode status = embedded_worker_->Start(
- version_id_, scope_, script_url_);
- if (status != SERVICE_WORKER_OK) {
- RunSoon(base::Bind(callback, status));
+ switch (running_status()) {
+ case RUNNING:
+ RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
+ return;
+ case STOPPING:
+ RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
+ return;
+ case STOPPED:
+ case STARTING:
+ start_callbacks_.push_back(callback);
+ if (running_status() == STOPPED) {
+ embedded_worker_->Start(
+ version_id_,
+ scope_,
+ script_url_,
+ possible_process_ids,
+ base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError,
+ weak_factory_.GetWeakPtr()));
+ }
return;
- }
}
- start_callbacks_.push_back(callback);
}
void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
@@ -196,48 +206,39 @@ void ServiceWorkerVersion::DispatchInstallEvent(
int active_version_id,
const StatusCallback& callback) {
DCHECK_EQ(NEW, status()) << status();
+ SetStatus(INSTALLING);
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
- StartWorker(base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(), callback,
- base::Bind(&self::DispatchInstallEvent,
- weak_factory_.GetWeakPtr(),
- active_version_id, callback)));
- return;
- }
-
- SetStatus(INSTALLING);
- int request_id = install_callbacks_.Add(new StatusCallback(callback));
- ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
- ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
- if (status != SERVICE_WORKER_OK) {
- install_callbacks_.Remove(request_id);
- RunSoon(base::Bind(callback, status));
+ StartWorker(
+ base::Bind(&RunTaskAfterStartWorker,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ base::Bind(&self::DispatchInstallEventAfterStartWorker,
+ weak_factory_.GetWeakPtr(),
+ active_version_id,
+ callback)));
+ } else {
+ DispatchInstallEventAfterStartWorker(active_version_id, callback);
}
}
void ServiceWorkerVersion::DispatchActivateEvent(
const StatusCallback& callback) {
DCHECK_EQ(INSTALLED, status()) << status();
+ SetStatus(ACTIVATING);
if (running_status() != RUNNING) {
// Schedule calling this method after starting the worker.
- StartWorker(base::Bind(&RunTaskAfterStartWorker,
- weak_factory_.GetWeakPtr(), callback,
- base::Bind(&self::DispatchActivateEvent,
- weak_factory_.GetWeakPtr(),
- callback)));
- return;
- }
-
- SetStatus(ACTIVATING);
- int request_id = activate_callbacks_.Add(new StatusCallback(callback));
- ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
- ServiceWorkerMsg_ActivateEvent(request_id));
- if (status != SERVICE_WORKER_OK) {
- activate_callbacks_.Remove(request_id);
- RunSoon(base::Bind(callback, status));
+ StartWorker(
+ base::Bind(&RunTaskAfterStartWorker,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ base::Bind(&self::DispatchActivateEventAfterStartWorker,
+ weak_factory_.GetWeakPtr(),
+ callback)));
+ } else {
+ DispatchActivateEventAfterStartWorker(callback);
}
}
@@ -433,6 +434,39 @@ bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
return handled;
}
+void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
+ ServiceWorkerStatusCode status) {
+ if (status != SERVICE_WORKER_OK)
+ RunCallbacks(this, &start_callbacks_, status);
+}
+
+void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
+ int active_version_id,
+ const StatusCallback& callback) {
+ DCHECK_EQ(RUNNING, running_status())
+ << "Worker stopped too soon after it was started.";
+ int request_id = install_callbacks_.Add(new StatusCallback(callback));
+ ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
+ ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
+ if (status != SERVICE_WORKER_OK) {
+ install_callbacks_.Remove(request_id);
+ RunSoon(base::Bind(callback, status));
+ }
+}
+
+void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
+ const StatusCallback& callback) {
+ DCHECK_EQ(RUNNING, running_status())
+ << "Worker stopped too soon after it was started.";
+ int request_id = activate_callbacks_.Add(new StatusCallback(callback));
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
+ if (status != SERVICE_WORKER_OK) {
+ activate_callbacks_.Remove(request_id);
+ RunSoon(base::Bind(callback, status));
+ }
+}
+
void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
std::vector<int> client_ids;
ControlleeByIDMap::iterator it(&controllee_by_id_);
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index dcdf1b6..e0db0ff 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -118,6 +118,14 @@ 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.
+ // This returns OK (success) if the worker is already running.
+ void StartWorkerWithCandidateProcesses(
+ const std::vector<int>& potential_process_ids,
+ const StatusCallback& callback);
+
+ // Starts an embedded worker for this version.
// This returns OK (success) if the worker is already stopped.
void StopWorker(const StatusCallback& callback);
@@ -212,6 +220,12 @@ class CONTENT_EXPORT ServiceWorkerVersion
virtual ~ServiceWorkerVersion();
+ void RunStartWorkerCallbacksOnError(ServiceWorkerStatusCode status);
+
+ void DispatchInstallEventAfterStartWorker(int active_version_id,
+ const StatusCallback& callback);
+ void DispatchActivateEventAfterStartWorker(const StatusCallback& callback);
+
// Message handlers.
void OnGetClientDocuments(int request_id);
void OnActivateEventFinished(int request_id,
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 9cea769..6622e5a 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -33,8 +33,8 @@ static const int kRenderProcessId = 1;
class MessageReceiver : public EmbeddedWorkerTestHelper {
public:
- MessageReceiver(ServiceWorkerContextCore* context)
- : EmbeddedWorkerTestHelper(context, kRenderProcessId),
+ MessageReceiver()
+ : EmbeddedWorkerTestHelper(kRenderProcessId),
current_embedded_worker_id_(0) {}
virtual ~MessageReceiver() {}
@@ -117,16 +117,15 @@ class ServiceWorkerVersionTest : public testing::Test {
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
virtual void SetUp() OVERRIDE {
- context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL, NULL));
- helper_.reset(new MessageReceiver(context_.get()));
+ helper_.reset(new MessageReceiver());
registration_ = new ServiceWorkerRegistration(
GURL("http://www.example.com/*"),
GURL("http://www.example.com/service_worker.js"),
- 1L, context_->AsWeakPtr());
+ 1L,
+ helper_->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
- registration_,
- 1L, context_->AsWeakPtr());
+ registration_, 1L, helper_->context()->AsWeakPtr());
// Simulate adding one process to the worker.
int embedded_worker_id = version_->embedded_worker()->embedded_worker_id();
@@ -138,11 +137,9 @@ class ServiceWorkerVersionTest : public testing::Test {
version_ = 0;
registration_ = 0;
helper_.reset();
- context_.reset();
}
TestBrowserThreadBundle thread_bundle_;
- scoped_ptr<ServiceWorkerContextCore> context_;
scoped_ptr<MessageReceiver> helper_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;