diff options
22 files changed, 447 insertions, 138 deletions
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc index ded0fb7..0ddaaf1 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.cc +++ b/content/browser/service_worker/service_worker_dispatcher_host.cc @@ -98,10 +98,6 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived( OnProviderCreated) IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ProviderDestroyed, OnProviderDestroyed) - IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_AddScriptClient, - OnAddScriptClient) - IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_RemoveScriptClient, - OnRemoveScriptClient) IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetVersionId, OnSetHostedVersionId) IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessage, @@ -118,8 +114,10 @@ bool ServiceWorkerDispatcherHost::OnMessageReceived( OnReportException) IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage, OnReportConsoleMessage) - IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ServiceWorkerObjectDestroyed, - OnServiceWorkerObjectDestroyed) + IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount, + OnIncrementServiceWorkerRefCount) + IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount, + OnDecrementServiceWorkerRefCount) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -276,28 +274,6 @@ void ServiceWorkerDispatcherHost::OnProviderDestroyed(int provider_id) { context_->RemoveProviderHost(render_process_id_, provider_id); } -void ServiceWorkerDispatcherHost::OnAddScriptClient( - int thread_id, int provider_id) { - if (!context_) - return; - ServiceWorkerProviderHost* provider_host = - context_->GetProviderHost(render_process_id_, provider_id); - if (!provider_host) - return; - provider_host->AddScriptClient(thread_id); -} - -void ServiceWorkerDispatcherHost::OnRemoveScriptClient( - int thread_id, int provider_id) { - if (!context_) - return; - ServiceWorkerProviderHost* provider_host = - context_->GetProviderHost(render_process_id_, provider_id); - if (!provider_host) - return; - provider_host->RemoveScriptClient(thread_id); -} - void ServiceWorkerDispatcherHost::OnSetHostedVersionId( int provider_id, int64 version_id) { if (!context_) @@ -393,9 +369,26 @@ void ServiceWorkerDispatcherHost::OnReportConsoleMessage( params.source_url); } -void ServiceWorkerDispatcherHost::OnServiceWorkerObjectDestroyed( +void ServiceWorkerDispatcherHost::OnIncrementServiceWorkerRefCount( int handle_id) { - handles_.Remove(handle_id); + ServiceWorkerHandle* handle = handles_.Lookup(handle_id); + if (!handle) { + BadMessageReceived(); + return; + } + handle->IncrementRefCount(); +} + +void ServiceWorkerDispatcherHost::OnDecrementServiceWorkerRefCount( + int handle_id) { + ServiceWorkerHandle* handle = handles_.Lookup(handle_id); + if (!handle) { + BadMessageReceived(); + return; + } + handle->DecrementRefCount(); + if (handle->HasNoRefCount()) + handles_.Remove(handle_id); } void ServiceWorkerDispatcherHost::UnregistrationComplete( diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h index cc0eeae..952bfe0 100644 --- a/content/browser/service_worker/service_worker_dispatcher_host.h +++ b/content/browser/service_worker/service_worker_dispatcher_host.h @@ -67,8 +67,6 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter { const GURL& pattern); void OnProviderCreated(int provider_id); void OnProviderDestroyed(int provider_id); - void OnAddScriptClient(int thread_id, int provider_id); - void OnRemoveScriptClient(int thread_id, int provider_id); void OnSetHostedVersionId(int provider_id, int64 version_id); void OnWorkerScriptLoaded(int embedded_worker_id); void OnWorkerScriptLoadFailed(int embedded_worker_id); @@ -86,7 +84,8 @@ class CONTENT_EXPORT ServiceWorkerDispatcherHost : public BrowserMessageFilter { void OnPostMessage(int handle_id, const base::string16& message, const std::vector<int>& sent_message_port_ids); - void OnServiceWorkerObjectDestroyed(int handle_id); + void OnIncrementServiceWorkerRefCount(int handle_id); + void OnDecrementServiceWorkerRefCount(int handle_id); // Callbacks from ServiceWorkerContextCore void RegistrationComplete(int thread_id, diff --git a/content/browser/service_worker/service_worker_handle.cc b/content/browser/service_worker/service_worker_handle.cc index cc57b6f..a07ab9e 100644 --- a/content/browser/service_worker/service_worker_handle.cc +++ b/content/browser/service_worker/service_worker_handle.cc @@ -63,6 +63,7 @@ ServiceWorkerHandle::ServiceWorkerHandle( sender_(sender), thread_id_(thread_id), handle_id_(context.get() ? context->GetNewServiceWorkerHandleId() : -1), + ref_count_(1), registration_(registration), version_(version) { version_->AddListener(this); @@ -112,4 +113,14 @@ ServiceWorkerObjectInfo ServiceWorkerHandle::GetObjectInfo() { return info; } +void ServiceWorkerHandle::IncrementRefCount() { + DCHECK_GT(ref_count_, 0); + ++ref_count_; +} + +void ServiceWorkerHandle::DecrementRefCount() { + DCHECK_GE(ref_count_, 0); + --ref_count_; +} + } // namespace content diff --git a/content/browser/service_worker/service_worker_handle.h b/content/browser/service_worker/service_worker_handle.h index 2aa7cc0..81d5b35 100644 --- a/content/browser/service_worker/service_worker_handle.h +++ b/content/browser/service_worker/service_worker_handle.h @@ -71,11 +71,16 @@ class CONTENT_EXPORT ServiceWorkerHandle ServiceWorkerVersion* version() { return version_.get(); } int handle_id() const { return handle_id_; } + bool HasNoRefCount() const { return ref_count_ <= 0; } + void IncrementRefCount(); + void DecrementRefCount(); + private: base::WeakPtr<ServiceWorkerContextCore> context_; IPC::Sender* sender_; // Not owned, it should always outlive this. const int thread_id_; const int handle_id_; + int ref_count_; // Created with 1. scoped_refptr<ServiceWorkerRegistration> registration_; scoped_refptr<ServiceWorkerVersion> version_; diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index aa874ae..a2f3cd3 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc @@ -16,6 +16,8 @@ namespace content { +static const int kDocumentMainThreadId = 0; + ServiceWorkerProviderHost::ServiceWorkerProviderHost( int process_id, int provider_id, base::WeakPtr<ServiceWorkerContextCore> context, @@ -33,16 +35,6 @@ ServiceWorkerProviderHost::~ServiceWorkerProviderHost() { pending_version_->RemovePendingControllee(this); } -void ServiceWorkerProviderHost::AddScriptClient(int thread_id) { - DCHECK(!ContainsKey(script_client_thread_ids_, thread_id)); - script_client_thread_ids_.insert(thread_id); -} - -void ServiceWorkerProviderHost::RemoveScriptClient(int thread_id) { - DCHECK(ContainsKey(script_client_thread_ids_, thread_id)); - script_client_thread_ids_.erase(thread_id); -} - void ServiceWorkerProviderHost::SetActiveVersion( ServiceWorkerVersion* version) { if (version == active_version_) @@ -57,19 +49,17 @@ void ServiceWorkerProviderHost::SetActiveVersion( if (!dispatcher_host_) return; // Could be NULL in some tests. - for (std::set<int>::iterator it = script_client_thread_ids_.begin(); - it != script_client_thread_ids_.end(); - ++it) { - ServiceWorkerObjectInfo info; - if (context_ && version) { - scoped_ptr<ServiceWorkerHandle> handle = - ServiceWorkerHandle::Create(context_, dispatcher_host_, *it, version); - info = handle->GetObjectInfo(); - dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass()); - } - dispatcher_host_->Send( - new ServiceWorkerMsg_SetCurrentServiceWorker(*it, provider_id(), info)); + ServiceWorkerObjectInfo info; + if (context_ && version) { + scoped_ptr<ServiceWorkerHandle> handle = + ServiceWorkerHandle::Create(context_, dispatcher_host_, + kDocumentMainThreadId, version); + info = handle->GetObjectInfo(); + dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass()); } + dispatcher_host_->Send( + new ServiceWorkerMsg_SetCurrentServiceWorker( + kDocumentMainThreadId, provider_id(), info)); } void ServiceWorkerProviderHost::SetPendingVersion( @@ -86,11 +76,7 @@ void ServiceWorkerProviderHost::SetPendingVersion( if (!dispatcher_host_) return; // Could be NULL in some tests. - for (std::set<int>::iterator it = script_client_thread_ids_.begin(); - it != script_client_thread_ids_.end(); - ++it) { - // TODO(kinuko): dispatch pendingchange event to the script clients. - } + // TODO(kinuko): dispatch pendingchange event to the document. } bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id) { diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 65a8807..d0adae3 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h @@ -42,9 +42,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost int process_id() const { return process_id_; } int provider_id() const { return provider_id_; } - const std::set<int>& script_client_thread_ids() const { - return script_client_thread_ids_; - } bool IsHostToRunningServiceWorker() { return running_hosted_version_ != NULL; @@ -71,12 +68,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost void set_document_url(const GURL& url) { document_url_ = url; } const GURL& document_url() const { return document_url_; } - // Adds and removes script client thread ID, who is listening events - // dispatched from ServiceWorker to the document (and any of its dedicated - // workers) corresponding to this provider. - void AddScriptClient(int thread_id); - void RemoveScriptClient(int thread_id); - // Associate |version| to this provider as its '.active' or '.pending' // version. // Giving NULL to this method will unset the corresponding field. @@ -96,7 +87,6 @@ class CONTENT_EXPORT ServiceWorkerProviderHost const int process_id_; const int provider_id_; GURL document_url_; - std::set<int> script_client_thread_ids_; scoped_refptr<ServiceWorkerVersion> active_version_; scoped_refptr<ServiceWorkerVersion> pending_version_; scoped_refptr<ServiceWorkerVersion> running_hosted_version_; diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc index d8ac46e..994acd7 100644 --- a/content/child/service_worker/service_worker_dispatcher.cc +++ b/content/child/service_worker/service_worker_dispatcher.cc @@ -7,9 +7,12 @@ #include "base/lazy_instance.h" #include "base/stl_util.h" #include "base/threading/thread_local.h" +#include "content/child/service_worker/service_worker_handle_reference.h" +#include "content/child/service_worker/service_worker_provider_context.h" #include "content/child/service_worker/web_service_worker_impl.h" #include "content/child/thread_safe_sender.h" #include "content/common/service_worker/service_worker_messages.h" +#include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h" #include "third_party/WebKit/public/web/WebSecurityOrigin.h" using blink::WebServiceWorkerError; @@ -39,13 +42,6 @@ ServiceWorkerDispatcher::ServiceWorkerDispatcher( } ServiceWorkerDispatcher::~ServiceWorkerDispatcher() { - for (ScriptClientMap::iterator it = script_clients_.begin(); - it != script_clients_.end(); - ++it) { - Send(new ServiceWorkerHostMsg_RemoveScriptClient( - CurrentWorkerId(), it->first)); - } - g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted); } @@ -91,23 +87,34 @@ void ServiceWorkerDispatcher::UnregisterServiceWorker( CurrentWorkerId(), request_id, provider_id, pattern)); } +void ServiceWorkerDispatcher::AddProviderContext( + ServiceWorkerProviderContext* provider_context) { + DCHECK(provider_context); + int provider_id = provider_context->provider_id(); + DCHECK(!ContainsKey(provider_contexts_, provider_id)); + provider_contexts_[provider_id] = provider_context; +} + +void ServiceWorkerDispatcher::RemoveProviderContext( + ServiceWorkerProviderContext* provider_context) { + DCHECK(provider_context); + DCHECK(ContainsKey(provider_contexts_, provider_context->provider_id())); + provider_contexts_.erase(provider_context->provider_id()); + worker_to_provider_.erase(provider_context->current_handle_id()); +} + void ServiceWorkerDispatcher::AddScriptClient( int provider_id, blink::WebServiceWorkerProviderClient* client) { DCHECK(client); DCHECK(!ContainsKey(script_clients_, provider_id)); script_clients_[provider_id] = client; - thread_safe_sender_->Send(new ServiceWorkerHostMsg_AddScriptClient( - CurrentWorkerId(), provider_id)); } void ServiceWorkerDispatcher::RemoveScriptClient(int provider_id) { // This could be possibly called multiple times to ensure termination. - if (ContainsKey(script_clients_, provider_id)) { + if (ContainsKey(script_clients_, provider_id)) script_clients_.erase(provider_id); - thread_safe_sender_->Send(new ServiceWorkerHostMsg_RemoveScriptClient( - CurrentWorkerId(), provider_id)); - } } ServiceWorkerDispatcher* @@ -195,27 +202,33 @@ void ServiceWorkerDispatcher::OnServiceWorkerStateChanged( int thread_id, int handle_id, blink::WebServiceWorkerState state) { - ServiceWorkerMap::iterator found = service_workers_.find(handle_id); - if (found == service_workers_.end()) - return; - found->second->OnStateChanged(state); + WorkerObjectMap::iterator worker = service_workers_.find(handle_id); + if (worker != service_workers_.end()) + worker->second->OnStateChanged(state); + + WorkerToProviderMap::iterator provider = worker_to_provider_.find(handle_id); + if (provider != worker_to_provider_.end()) + provider->second->OnServiceWorkerStateChanged(handle_id, state); } void ServiceWorkerDispatcher::OnSetCurrentServiceWorker( int thread_id, int provider_id, const ServiceWorkerObjectInfo& info) { - scoped_ptr<WebServiceWorkerImpl> worker( - new WebServiceWorkerImpl(info, thread_safe_sender_)); + ProviderContextMap::iterator provider = provider_contexts_.find(provider_id); + if (provider != provider_contexts_.end()) { + provider->second->OnSetCurrentServiceWorker(provider_id, info); + worker_to_provider_[info.handle_id] = provider->second; + } + ScriptClientMap::iterator found = script_clients_.find(provider_id); - if (found == script_clients_.end()) { - // Note that |worker|'s destructor sends a ServiceWorkerObjectDestroyed - // message so the browser-side can clean up the ServiceWorkerHandle it - // created when sending us this message. - return; + if (found != script_clients_.end()) { + // Populate the .current field with the new worker object. + scoped_ptr<ServiceWorkerHandleReference> handle_ref( + ServiceWorkerHandleReference::Create(info, thread_safe_sender_)); + found->second->setCurrentServiceWorker( + new WebServiceWorkerImpl(handle_ref.Pass(), thread_safe_sender_)); } - // TODO(falken): Call client->setCurrentServiceWorker(worker) when the Blink - // change to add that function rolls in. } void ServiceWorkerDispatcher::AddServiceWorker( diff --git a/content/child/service_worker/service_worker_dispatcher.h b/content/child/service_worker/service_worker_dispatcher.h index c1d8a75..2c6ca3a 100644 --- a/content/child/service_worker/service_worker_dispatcher.h +++ b/content/child/service_worker/service_worker_dispatcher.h @@ -29,6 +29,7 @@ namespace content { class ServiceWorkerMessageFilter; struct ServiceWorkerObjectInfo; +class ServiceWorkerProviderContext; class ThreadSafeSender; class WebServiceWorkerImpl; @@ -55,6 +56,13 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer { const GURL& pattern, blink::WebServiceWorkerProvider::WebServiceWorkerCallbacks* callbacks); + // Called when a new provider context for a document is created. Usually + // this happens when a new document is being loaded, and is called much + // earlier than AddScriptClient. + // (This is attached only to the document thread's ServiceWorkerDispatcher) + void AddProviderContext(ServiceWorkerProviderContext* provider_context); + void RemoveProviderContext(ServiceWorkerProviderContext* provider_context); + // Called when navigator.serviceWorker is instantiated or detached // for a document whose provider can be identified by |provider_id|. void AddScriptClient(int provider_id, @@ -74,7 +82,9 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer { typedef IDMap<blink::WebServiceWorkerProvider::WebServiceWorkerCallbacks, IDMapOwnPointer> CallbackMap; typedef std::map<int, blink::WebServiceWorkerProviderClient*> ScriptClientMap; - typedef std::map<int, WebServiceWorkerImpl*> ServiceWorkerMap; + typedef std::map<int, ServiceWorkerProviderContext*> ProviderContextMap; + typedef std::map<int, WebServiceWorkerImpl*> WorkerObjectMap; + typedef std::map<int, ServiceWorkerProviderContext*> WorkerToProviderMap; friend class WebServiceWorkerImpl; @@ -103,7 +113,12 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer { CallbackMap pending_callbacks_; ScriptClientMap script_clients_; - ServiceWorkerMap service_workers_; + ProviderContextMap provider_contexts_; + WorkerObjectMap service_workers_; + + // A map for ServiceWorkers that are associated to a particular document + // (e.g. as .current). + WorkerToProviderMap worker_to_provider_; scoped_refptr<ThreadSafeSender> thread_safe_sender_; diff --git a/content/child/service_worker/service_worker_handle_reference.cc b/content/child/service_worker/service_worker_handle_reference.cc new file mode 100644 index 0000000..1053cfb --- /dev/null +++ b/content/child/service_worker/service_worker_handle_reference.cc @@ -0,0 +1,50 @@ +// 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/child/service_worker/service_worker_handle_reference.h" + +#include "content/child/thread_safe_sender.h" +#include "content/common/service_worker/service_worker_messages.h" + +namespace content { + +scoped_ptr<ServiceWorkerHandleReference> +ServiceWorkerHandleReference::Create( + const ServiceWorkerObjectInfo& info, + ThreadSafeSender* sender) { + DCHECK(sender); + return make_scoped_ptr(new ServiceWorkerHandleReference(info, sender, true)); +} + +scoped_ptr<ServiceWorkerHandleReference> +ServiceWorkerHandleReference::CreateForDeleter( + const ServiceWorkerObjectInfo& info, + ThreadSafeSender* sender) { + DCHECK(sender); + return make_scoped_ptr(new ServiceWorkerHandleReference(info, sender, false)); +} + +ServiceWorkerHandleReference::ServiceWorkerHandleReference( + const ServiceWorkerObjectInfo& info, + ThreadSafeSender* sender, + bool increment_ref_in_ctor) + : info_(info), + sender_(sender) { + if (increment_ref_in_ctor && + info_.handle_id != kInvalidServiceWorkerHandleId) { + sender_->Send( + new ServiceWorkerHostMsg_IncrementServiceWorkerRefCount( + info_.handle_id)); + } +} + +ServiceWorkerHandleReference::~ServiceWorkerHandleReference() { + if (info_.handle_id != kInvalidServiceWorkerHandleId) { + sender_->Send( + new ServiceWorkerHostMsg_DecrementServiceWorkerRefCount( + info_.handle_id)); + } +} + +} // namespace content diff --git a/content/child/service_worker/service_worker_handle_reference.h b/content/child/service_worker/service_worker_handle_reference.h new file mode 100644 index 0000000..48f969f --- /dev/null +++ b/content/child/service_worker/service_worker_handle_reference.h @@ -0,0 +1,49 @@ +// 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_CHILD_SERVICE_WORKER_SERVICE_WORKER_HANDLE_REFERENCE_H_ +#define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_HANDLE_REFERENCE_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "content/common/service_worker/service_worker_types.h" + +namespace content { + +class ThreadSafeSender; + +// Automatically increments and decrements ServiceWorkerHandle's ref-count +// (in the browser side) in ctor and dtor. +class ServiceWorkerHandleReference { + public: + // Creates a new ServiceWorkerHandleReference (and increments ref-count). + static scoped_ptr<ServiceWorkerHandleReference> Create( + const ServiceWorkerObjectInfo& info, + ThreadSafeSender* sender); + // This doesn't increment ref-count in ctor. + static scoped_ptr<ServiceWorkerHandleReference> CreateForDeleter( + const ServiceWorkerObjectInfo& info, + ThreadSafeSender* sender); + + ~ServiceWorkerHandleReference(); + + const ServiceWorkerObjectInfo& info() const { return info_; } + int handle_id() const { return info_.handle_id; } + const GURL& scope() const { return info_.scope; } + const GURL& url() const { return info_.url; } + blink::WebServiceWorkerState state() const { return info_.state; } + void set_state(blink::WebServiceWorkerState state) { info_.state = state; } + + private: + ServiceWorkerHandleReference(const ServiceWorkerObjectInfo& info, + ThreadSafeSender* sender, + bool increment_ref_in_ctor); + ServiceWorkerObjectInfo info_; + scoped_refptr<ThreadSafeSender> sender_; + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerHandleReference); +}; + +} // namespace content + +#endif // CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_HANDLE_REFERENCE_H_ diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc index 8ba89df..ad3f4fb 100644 --- a/content/child/service_worker/service_worker_message_filter.cc +++ b/content/child/service_worker/service_worker_message_filter.cc @@ -23,7 +23,7 @@ void SendServiceWorkerObjectDestroyed( if (handle_id == kInvalidServiceWorkerHandleId) return; sender->Send( - new ServiceWorkerHostMsg_ServiceWorkerObjectDestroyed(handle_id)); + new ServiceWorkerHostMsg_DecrementServiceWorkerRefCount(handle_id)); } } // namespace diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc index 8a0eb6a..2f2ede6 100644 --- a/content/child/service_worker/service_worker_network_provider.cc +++ b/content/child/service_worker/service_worker_network_provider.cc @@ -6,6 +6,7 @@ #include "base/atomic_sequence_num.h" #include "content/child/child_thread.h" +#include "content/child/service_worker/service_worker_provider_context.h" #include "content/common/service_worker/service_worker_messages.h" namespace content { @@ -35,7 +36,8 @@ ServiceWorkerNetworkProvider* ServiceWorkerNetworkProvider::FromDocumentState( } ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider() - : provider_id_(GetNextProviderId()) { + : provider_id_(GetNextProviderId()), + context_(new ServiceWorkerProviderContext(provider_id_)) { if (!ChildThread::current()) return; // May be null in some tests. ChildThread::current()->Send( diff --git a/content/child/service_worker/service_worker_network_provider.h b/content/child/service_worker/service_worker_network_provider.h index 400918f..0d6f494 100644 --- a/content/child/service_worker/service_worker_network_provider.h +++ b/content/child/service_worker/service_worker_network_provider.h @@ -6,12 +6,15 @@ #define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_NETWORK_PROVIDER_IMPL_H_ #include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/supports_user_data.h" #include "content/common/content_export.h" namespace content { +class ServiceWorkerProviderContext; + // A unique provider_id is generated for each instance. // Instantiated prior to the main resource load being started and remains // allocated until after the last subresource load has occurred. @@ -37,6 +40,7 @@ class CONTENT_EXPORT ServiceWorkerNetworkProvider virtual ~ServiceWorkerNetworkProvider(); int provider_id() const { return provider_id_; } + ServiceWorkerProviderContext* context() { return context_.get(); } // This method is called for a provider that's associated with a // running service worker script. The version_id indicates which @@ -45,6 +49,7 @@ class CONTENT_EXPORT ServiceWorkerNetworkProvider private: const int provider_id_; + scoped_refptr<ServiceWorkerProviderContext> context_; DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNetworkProvider); }; diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc new file mode 100644 index 0000000..9426881 --- /dev/null +++ b/content/child/service_worker/service_worker_provider_context.cc @@ -0,0 +1,78 @@ +// 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/child/service_worker/service_worker_provider_context.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/stl_util.h" +#include "content/child/child_thread.h" +#include "content/child/service_worker/service_worker_dispatcher.h" +#include "content/child/service_worker/service_worker_handle_reference.h" +#include "content/child/thread_safe_sender.h" +#include "content/child/worker_task_runner.h" +#include "content/common/service_worker/service_worker_messages.h" + +namespace content { + +ServiceWorkerProviderContext::ServiceWorkerProviderContext(int provider_id) + : provider_id_(provider_id), + main_thread_loop_proxy_(base::MessageLoopProxy::current()) { + if (!ChildThread::current()) + return; // May be null in some tests. + thread_safe_sender_ = ChildThread::current()->thread_safe_sender(); + ServiceWorkerDispatcher* dispatcher = + ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance( + thread_safe_sender_); + DCHECK(dispatcher); + dispatcher->AddProviderContext(this); +} + +ServiceWorkerProviderContext::~ServiceWorkerProviderContext() { + if (ServiceWorkerDispatcher* dispatcher = + ServiceWorkerDispatcher::GetThreadSpecificInstance()) { + dispatcher->RemoveProviderContext(this); + } +} + +scoped_ptr<ServiceWorkerHandleReference> +ServiceWorkerProviderContext::GetCurrentServiceWorkerHandle() { + DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); + if (!current_) + return scoped_ptr<ServiceWorkerHandleReference>(); + return ServiceWorkerHandleReference::Create( + current_->info(), thread_safe_sender_); +} + +void ServiceWorkerProviderContext::OnServiceWorkerStateChanged( + int handle_id, + blink::WebServiceWorkerState state) { + // Currently .current is the only ServiceWorker associated to this provider. + DCHECK_EQ(current_handle_id(), handle_id); + current_->set_state(state); + + // TODO(kinuko): We can forward the message to other threads here + // when we support navigator.serviceWorker in dedicated workers. +} + +void ServiceWorkerProviderContext::OnSetCurrentServiceWorker( + int provider_id, + const ServiceWorkerObjectInfo& info) { + DCHECK_EQ(provider_id_, provider_id); + + // This context is is the primary owner of this handle, keeps the + // initial reference until it goes away. + current_ = ServiceWorkerHandleReference::CreateForDeleter( + info, thread_safe_sender_); + + // TODO(kinuko): We can forward the message to other threads here + // when we support navigator.serviceWorker in dedicated workers. +} + +int ServiceWorkerProviderContext::current_handle_id() const { + DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); + return current_ ? current_->info().handle_id : kInvalidServiceWorkerHandleId; +} + +} // namespace content diff --git a/content/child/service_worker/service_worker_provider_context.h b/content/child/service_worker/service_worker_provider_context.h new file mode 100644 index 0000000..23b1114 --- /dev/null +++ b/content/child/service_worker/service_worker_provider_context.h @@ -0,0 +1,66 @@ +// 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_CHILD_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_CONTEXT_H_ +#define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_CONTEXT_H_ + +#include <set> +#include <vector> + +#include "base/memory/ref_counted.h" +#include "base/sequenced_task_runner_helpers.h" +#include "base/synchronization/lock.h" +#include "content/common/service_worker/service_worker_types.h" + +namespace base { +class MessageLoopProxy; +} + +namespace IPC { +class Message; +} + +namespace content { + +class ServiceWorkerHandleReference; +struct ServiceWorkerProviderContextDeleter; +class ThreadSafeSender; + +// An instance of this class holds document-related information (e.g. +// .current). Created and destructed on the main thread. +// TODO(kinuko): To support navigator.serviceWorker in dedicated workers +// this needs to be RefCountedThreadSafe and .current info needs to be +// handled in a thread-safe manner (e.g. by a lock etc). +class ServiceWorkerProviderContext + : public base::RefCounted<ServiceWorkerProviderContext> { + public: + explicit ServiceWorkerProviderContext(int provider_id); + + // Returns a new handle reference for .current. + scoped_ptr<ServiceWorkerHandleReference> GetCurrentServiceWorkerHandle(); + + // Called from ServiceWorkerDispatcher. + void OnServiceWorkerStateChanged(int handle_id, + blink::WebServiceWorkerState state); + void OnSetCurrentServiceWorker(int provider_id, + const ServiceWorkerObjectInfo& info); + + int provider_id() const { return provider_id_; } + int current_handle_id() const; + + private: + friend class base::RefCounted<ServiceWorkerProviderContext>; + ~ServiceWorkerProviderContext(); + + const int provider_id_; + scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_; + scoped_refptr<ThreadSafeSender> thread_safe_sender_; + scoped_ptr<ServiceWorkerHandleReference> current_; + + DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderContext); +}; + +} // namespace content + +#endif // CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_PROVIDER_CONTEXT_H_ diff --git a/content/child/service_worker/web_service_worker_impl.cc b/content/child/service_worker/web_service_worker_impl.cc index 02f8779..683cf74 100644 --- a/content/child/service_worker/web_service_worker_impl.cc +++ b/content/child/service_worker/web_service_worker_impl.cc @@ -5,6 +5,7 @@ #include "content/child/service_worker/web_service_worker_impl.h" #include "content/child/service_worker/service_worker_dispatcher.h" +#include "content/child/service_worker/service_worker_handle_reference.h" #include "content/child/thread_safe_sender.h" #include "content/child/webmessageportchannel_impl.h" #include "content/common/service_worker/service_worker_messages.h" @@ -21,27 +22,38 @@ namespace content { WebServiceWorkerImpl::WebServiceWorkerImpl( const ServiceWorkerObjectInfo& info, ThreadSafeSender* thread_safe_sender) - : handle_id_(info.handle_id), - scope_(info.scope), - url_(info.url), - state_(info.state), + : handle_ref_( + ServiceWorkerHandleReference::CreateForDeleter(info, + thread_safe_sender)), + state_(handle_ref_->state()), thread_safe_sender_(thread_safe_sender), proxy_(NULL) { ServiceWorkerDispatcher* dispatcher = ServiceWorkerDispatcher::GetThreadSpecificInstance(); DCHECK(dispatcher); - dispatcher->AddServiceWorker(handle_id_, this); + dispatcher->AddServiceWorker(handle_ref_->handle_id(), this); +} + +WebServiceWorkerImpl::WebServiceWorkerImpl( + scoped_ptr<ServiceWorkerHandleReference> handle_ref, + ThreadSafeSender* thread_safe_sender) + : handle_ref_(handle_ref.Pass()), + state_(handle_ref_->state()), + thread_safe_sender_(thread_safe_sender), + proxy_(NULL) { + ServiceWorkerDispatcher* dispatcher = + ServiceWorkerDispatcher::GetThreadSpecificInstance(); + DCHECK(dispatcher); + dispatcher->AddServiceWorker(handle_ref_->handle_id(), this); } WebServiceWorkerImpl::~WebServiceWorkerImpl() { - if (handle_id_ == kInvalidServiceWorkerHandleId) + if (handle_ref_->handle_id() == kInvalidServiceWorkerHandleId) return; - thread_safe_sender_->Send( - new ServiceWorkerHostMsg_ServiceWorkerObjectDestroyed(handle_id_)); ServiceWorkerDispatcher* dispatcher = ServiceWorkerDispatcher::GetThreadSpecificInstance(); if (dispatcher) - dispatcher->RemoveServiceWorker(handle_id_); + dispatcher->RemoveServiceWorker(handle_ref_->handle_id()); } void WebServiceWorkerImpl::OnStateChanged( @@ -70,11 +82,11 @@ void WebServiceWorkerImpl::proxyReadyChanged() { } blink::WebURL WebServiceWorkerImpl::scope() const { - return scope_; + return handle_ref_->scope(); } blink::WebURL WebServiceWorkerImpl::url() const { - return url_; + return handle_ref_->url(); } blink::WebServiceWorkerState WebServiceWorkerImpl::state() const { @@ -84,7 +96,7 @@ blink::WebServiceWorkerState WebServiceWorkerImpl::state() const { void WebServiceWorkerImpl::postMessage(const WebString& message, WebMessagePortChannelArray* channels) { thread_safe_sender_->Send(new ServiceWorkerHostMsg_PostMessage( - handle_id_, + handle_ref_->handle_id(), message, WebMessagePortChannelImpl::ExtractMessagePortIDs(channels))); } diff --git a/content/child/service_worker/web_service_worker_impl.h b/content/child/service_worker/web_service_worker_impl.h index cf9728e..0558b23 100644 --- a/content/child/service_worker/web_service_worker_impl.h +++ b/content/child/service_worker/web_service_worker_impl.h @@ -20,14 +20,25 @@ class WebServiceWorkerProxy; namespace content { -class ThreadSafeSender; +class ServiceWorkerHandleReference; struct ServiceWorkerObjectInfo; +class ThreadSafeSender; +// Each instance corresponds to one ServiceWorker object in JS context, and +// is held by ServiceWorker object in blink's c++ layer, e.g. created one +// per navigator.serviceWorker.current or per successful +// navigator.serviceWorker.register call. +// +// Each instance holds one ServiceWorkerHandleReference so that +// corresponding ServiceWorkerHandle doesn't go away in the browser process +// while the ServiceWorker object is alive. class WebServiceWorkerImpl : NON_EXPORTED_BASE(public blink::WebServiceWorker) { public: WebServiceWorkerImpl(const ServiceWorkerObjectInfo& info, ThreadSafeSender* thread_safe_sender); + WebServiceWorkerImpl(scoped_ptr<ServiceWorkerHandleReference> handle_ref, + ThreadSafeSender* thread_safe_sender); virtual ~WebServiceWorkerImpl(); // Notifies that the service worker's state changed. This function may queue @@ -47,9 +58,7 @@ class WebServiceWorkerImpl // Commits the new state internally and notifies the proxy of the change. void ChangeState(blink::WebServiceWorkerState new_state); - const int handle_id_; - const GURL scope_; - const GURL url_; + scoped_ptr<ServiceWorkerHandleReference> handle_ref_; blink::WebServiceWorkerState state_; scoped_refptr<ThreadSafeSender> thread_safe_sender_; blink::WebServiceWorkerProxy* proxy_; diff --git a/content/child/service_worker/web_service_worker_provider_impl.cc b/content/child/service_worker/web_service_worker_provider_impl.cc index 99f9738..407552d 100644 --- a/content/child/service_worker/web_service_worker_provider_impl.cc +++ b/content/child/service_worker/web_service_worker_provider_impl.cc @@ -8,7 +8,12 @@ #include "base/logging.h" #include "content/child/child_thread.h" #include "content/child/service_worker/service_worker_dispatcher.h" +#include "content/child/service_worker/service_worker_handle_reference.h" +#include "content/child/service_worker/service_worker_provider_context.h" +#include "content/child/service_worker/web_service_worker_impl.h" #include "content/child/thread_safe_sender.h" +#include "content/common/service_worker/service_worker_messages.h" +#include "third_party/WebKit/public/platform/WebServiceWorkerProviderClient.h" #include "third_party/WebKit/public/platform/WebURL.h" using blink::WebURL; @@ -17,9 +22,10 @@ namespace content { WebServiceWorkerProviderImpl::WebServiceWorkerProviderImpl( ThreadSafeSender* thread_safe_sender, - int provider_id) + ServiceWorkerProviderContext* context) : thread_safe_sender_(thread_safe_sender), - provider_id_(provider_id) { + context_(context), + provider_id_(context->provider_id()) { } WebServiceWorkerProviderImpl::~WebServiceWorkerProviderImpl() { @@ -29,10 +35,28 @@ WebServiceWorkerProviderImpl::~WebServiceWorkerProviderImpl() { void WebServiceWorkerProviderImpl::setClient( blink::WebServiceWorkerProviderClient* client) { - if (client) - GetDispatcher()->AddScriptClient(provider_id_, client); - else + if (!client) { RemoveScriptClient(); + return; + } + + // TODO(kinuko): Here we could also register the current thread ID + // on the provider context so that multiple WebServiceWorkerProviderImpl + // (e.g. on document and on dedicated workers) can properly share + // the single provider context across threads. (http://crbug.com/366538 + // for more context) + scoped_ptr<ServiceWorkerHandleReference> current = + context_->GetCurrentServiceWorkerHandle(); + GetDispatcher()->AddScriptClient(provider_id_, client); + if (!current) + return; + + int handle_id = current->info().handle_id; + if (handle_id != kInvalidServiceWorkerHandleId) { + scoped_ptr<WebServiceWorkerImpl> worker( + new WebServiceWorkerImpl(current.Pass(), thread_safe_sender_)); + client->setCurrentServiceWorker(worker.release()); + } } void WebServiceWorkerProviderImpl::registerServiceWorker( diff --git a/content/child/service_worker/web_service_worker_provider_impl.h b/content/child/service_worker/web_service_worker_provider_impl.h index 69aeed6..912d2f4 100644 --- a/content/child/service_worker/web_service_worker_provider_impl.h +++ b/content/child/service_worker/web_service_worker_provider_impl.h @@ -18,13 +18,16 @@ class WebServiceWorkerProviderClient; namespace content { class ServiceWorkerDispatcher; +class ServiceWorkerProviderContext; class ThreadSafeSender; +// This class corresponds to one ServiceWorkerContainer interface in +// JS context (i.e. navigator.serviceWorker). class WebServiceWorkerProviderImpl : NON_EXPORTED_BASE(public blink::WebServiceWorkerProvider) { public: WebServiceWorkerProviderImpl(ThreadSafeSender* thread_safe_sender, - int provider_id); + ServiceWorkerProviderContext* context); virtual ~WebServiceWorkerProviderImpl(); virtual void setClient(blink::WebServiceWorkerProviderClient* client); @@ -36,11 +39,14 @@ class WebServiceWorkerProviderImpl virtual void unregisterServiceWorker(const blink::WebURL& pattern, WebServiceWorkerCallbacks*); + ServiceWorkerProviderContext* context() { return context_.get(); } + private: void RemoveScriptClient(); ServiceWorkerDispatcher* GetDispatcher(); scoped_refptr<ThreadSafeSender> thread_safe_sender_; + scoped_refptr<ServiceWorkerProviderContext> context_; const int provider_id_; DISALLOW_COPY_AND_ASSIGN(WebServiceWorkerProviderImpl); diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h index 8af1825..5337c6b 100644 --- a/content/common/service_worker/service_worker_messages.h +++ b/content/common/service_worker/service_worker_messages.h @@ -81,8 +81,12 @@ IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_ProviderCreated, IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_ProviderDestroyed, int /* provider_id */) -// Informs the browser of a ServiceWorker object being destroyed. -IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_ServiceWorkerObjectDestroyed, +// Increments and decrements the ServiceWorker object's reference +// counting in the browser side. The ServiceWorker object is created +// with ref-count==1 initially. +IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount, + int /* handle_id */) +IPC_MESSAGE_CONTROL1(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount, int /* handle_id */) // Informs the browser that |provider_id| is associated @@ -92,16 +96,6 @@ IPC_MESSAGE_CONTROL2(ServiceWorkerHostMsg_SetVersionId, int /* provider_id */, int64 /* version_id */) -// Informs the browser of a new scriptable API client in the child process. -IPC_MESSAGE_CONTROL2(ServiceWorkerHostMsg_AddScriptClient, - int /* thread_id */, - int /* provider_id */) - -// Informs the browser that the scriptable API client is unregistered. -IPC_MESSAGE_CONTROL2(ServiceWorkerHostMsg_RemoveScriptClient, - int /* thread_id */, - int /* provider_id */) - // Informs the browser that event handling has finished. // Routed to the target ServiceWorkerVersion. IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_InstallEventFinished, diff --git a/content/content_child.gypi b/content/content_child.gypi index c46451c..e695981 100644 --- a/content/content_child.gypi +++ b/content/content_child.gypi @@ -146,12 +146,16 @@ 'child/runtime_features.h', 'child/scoped_child_process_reference.cc', 'child/scoped_child_process_reference.h', + 'child/service_worker/service_worker_handle_reference.cc', + 'child/service_worker/service_worker_handle_reference.h', 'child/service_worker/service_worker_dispatcher.cc', 'child/service_worker/service_worker_dispatcher.h', 'child/service_worker/service_worker_message_filter.cc', 'child/service_worker/service_worker_message_filter.h', 'child/service_worker/service_worker_network_provider.cc', 'child/service_worker/service_worker_network_provider.h', + 'child/service_worker/service_worker_provider_context.cc', + 'child/service_worker/service_worker_provider_context.h', 'child/service_worker/web_service_worker_impl.cc', 'child/service_worker/web_service_worker_impl.h', 'child/service_worker/web_service_worker_provider_impl.cc', diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index f19a24a..37caed9 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -1383,11 +1383,9 @@ blink::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider( ServiceWorkerNetworkProvider* provider = ServiceWorkerNetworkProvider::FromDocumentState( DocumentState::FromDataSource(frame->dataSource())); - int provider_id = provider ? - provider->provider_id() : - kInvalidServiceWorkerProviderId; return new WebServiceWorkerProviderImpl( - ChildThread::current()->thread_safe_sender(), provider_id); + ChildThread::current()->thread_safe_sender(), + provider ? provider->context() : NULL); } void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame* frame) { |