Commit 71840871 authored by nhiroki's avatar nhiroki Committed by Commit bot

ServiceWorker: Make '.ready' return a promise to be resolved with ServiceWorkerRegistration (2/3)

Potential controllees need to observe version change events to make a ready
registration, but, before this patch, those events are sent not to potential
controllees but to pages that have the corresponding registration object
(to be more precise, pages that have the reference to the registration).

After this patch, ServiceWorkerProviderHost sends an IPC message to the
corresponding ServiceWorkerProviderContext when the host gets associated with
a registration and the provider context retains a reference of the registration
so that the potential controllee can observe the version change events.

1) Blink: https://codereview.chromium.org/476043002/
2) Chromium: THIS PATCH
3) Blink: https://codereview.chromium.org/532653002/

BUG=399533
TEST=content_unittests --gtest_filter=ServiceWorker*
TEST=run_webkit_tests.py --debug http/tests/serviceworker/ (with the patch (3))

Review URL: https://codereview.chromium.org/477593007

Cr-Commit-Position: refs/heads/master@{#294147}
parent abd0e10a
......@@ -114,7 +114,7 @@ void ServiceWorkerControlleeRequestHandler::PrepareForMainResource(
"URL", url.spec());
// The corresponding provider_host may already have associated a registration
// in redirect case, unassociate it now.
provider_host_->UnassociateRegistration();
provider_host_->DisassociateRegistration();
GURL stripped_url = net::SimplifyUrlForRequest(url);
provider_host_->SetDocumentUrl(stripped_url);
......
......@@ -60,7 +60,7 @@ void ServiceWorkerProviderHost::OnVersionAttributesChanged(
void ServiceWorkerProviderHost::OnRegistrationFailed(
ServiceWorkerRegistration* registration) {
DCHECK_EQ(associated_registration_.get(), registration);
UnassociateRegistration();
DisassociateRegistration();
}
void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
......@@ -116,15 +116,32 @@ void ServiceWorkerProviderHost::AssociateRegistration(
DecreaseProcessReference(associated_registration_->pattern());
IncreaseProcessReference(registration->pattern());
if (dispatcher_host_) {
ServiceWorkerRegistrationHandle* handle =
dispatcher_host_->GetOrCreateRegistrationHandle(
provider_id(), registration);
ServiceWorkerVersionAttributes attrs;
attrs.installing = handle->CreateServiceWorkerHandleAndPass(
registration->installing_version());
attrs.waiting = handle->CreateServiceWorkerHandleAndPass(
registration->waiting_version());
attrs.active = handle->CreateServiceWorkerHandleAndPass(
registration->active_version());
dispatcher_host_->Send(new ServiceWorkerMsg_AssociateRegistration(
kDocumentMainThreadId, provider_id(), handle->GetObjectInfo(), attrs));
}
associated_registration_ = registration;
registration->AddListener(this);
associated_registration_->AddListener(this);
installing_version_ = registration->installing_version();
waiting_version_ = registration->waiting_version();
active_version_ = registration->active_version();
SetControllerVersionAttribute(registration->active_version());
}
void ServiceWorkerProviderHost::UnassociateRegistration() {
void ServiceWorkerProviderHost::DisassociateRegistration() {
if (!associated_registration_.get())
return;
DecreaseProcessReference(associated_registration_->pattern());
......@@ -134,6 +151,11 @@ void ServiceWorkerProviderHost::UnassociateRegistration() {
waiting_version_ = NULL;
active_version_ = NULL;
SetControllerVersionAttribute(NULL);
if (dispatcher_host_) {
dispatcher_host_->Send(new ServiceWorkerMsg_DisassociateRegistration(
kDocumentMainThreadId, provider_id()));
}
}
scoped_ptr<ServiceWorkerRequestHandler>
......
......@@ -83,7 +83,7 @@ class CONTENT_EXPORT ServiceWorkerProviderHost
void AssociateRegistration(ServiceWorkerRegistration* registration);
// Clears the associated registration and stop listening to it.
void UnassociateRegistration();
void DisassociateRegistration();
// Returns false if the version is not in the expected STARTING in our
// process state. That would be indicative of a bad IPC message.
......
......@@ -97,7 +97,7 @@ TEST_F(ServiceWorkerProviderHostTest, SetActiveVersion_ProcessStatus) {
// Resetting the provider_host's active version should remove process refs
// from the version.
provider_host1_->UnassociateRegistration();
provider_host1_->DisassociateRegistration();
ASSERT_FALSE(HasProcessToRun());
}
......@@ -113,11 +113,11 @@ TEST_F(ServiceWorkerProviderHostTest,
// Disassociating one provider_host shouldn't remove all process refs
// from the version yet.
provider_host1_->UnassociateRegistration();
provider_host1_->DisassociateRegistration();
ASSERT_TRUE(HasProcessToRun());
// Disassociating the other provider_host will remove all process refs.
provider_host2_->UnassociateRegistration();
provider_host2_->DisassociateRegistration();
ASSERT_FALSE(HasProcessToRun());
}
......@@ -136,7 +136,7 @@ TEST_F(ServiceWorkerProviderHostTest, SetWaitingVersion_ProcessStatus) {
// Resetting the provider_host's waiting version should remove process refs
// from the version.
provider_host1_->UnassociateRegistration();
provider_host1_->DisassociateRegistration();
ASSERT_FALSE(HasProcessToRun());
}
......@@ -152,11 +152,11 @@ TEST_F(ServiceWorkerProviderHostTest,
// Disassociating one provider_host shouldn't remove all process refs
// from the version yet.
provider_host1_->UnassociateRegistration();
provider_host1_->DisassociateRegistration();
ASSERT_TRUE(HasProcessToRun());
// Disassociating the other provider_host will remove all process refs.
provider_host2_->UnassociateRegistration();
provider_host2_->DisassociateRegistration();
ASSERT_FALSE(HasProcessToRun());
}
......@@ -176,7 +176,7 @@ TEST_F(ServiceWorkerProviderHostTest,
VerifyVersionAttributes(provider_host2_, NULL, version_.get(), NULL);
// Disassociating the registration should clear all version attributes.
provider_host2_->UnassociateRegistration();
provider_host2_->DisassociateRegistration();
VerifyVersionAttributes(provider_host1_, NULL, version_.get(), NULL);
VerifyVersionAttributes(provider_host2_, NULL, NULL, NULL);
......@@ -213,7 +213,7 @@ TEST_F(ServiceWorkerProviderHostTest,
provider_host2_, version2.get(), version1.get(), NULL);
// Disassociating the registration should clear all version attributes.
provider_host2_->UnassociateRegistration();
provider_host2_->DisassociateRegistration();
VerifyVersionAttributes(
provider_host1_, version2.get(), version1.get(), NULL);
VerifyVersionAttributes(provider_host2_, NULL, NULL, NULL);
......
......@@ -96,12 +96,19 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
const ServiceWorkerObjectInfo& info,
bool adopt_handle);
// If an existing WebServiceWorkerRegistrationImpl exists for the
// registration, it is returned; otherwise a WebServiceWorkerRegistrationImpl
// is created and its ownership is transferred to the caller. If
// |adopt_handle| is true, a ServiceWorkerRegistrationHandleReference will be
// adopted for the specified registration.
WebServiceWorkerRegistrationImpl* GetServiceWorkerRegistration(
// Finds a WebServiceWorkerRegistrationImpl for the specified registration.
// If it's not found, returns NULL. If |adopt_handle| is true,
// a ServiceWorkerRegistrationHandleReference will be adopted for the
// registration.
WebServiceWorkerRegistrationImpl* FindServiceWorkerRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
bool adopt_handle);
// Creates a WebServiceWorkerRegistrationImpl for the specified registration
// and transfers its ownership to the caller. If |adopt_handle| is true, a
// ServiceWorkerRegistrationHandleReference will be adopted for the
// registration.
WebServiceWorkerRegistrationImpl* CreateServiceWorkerRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
bool adopt_handle);
......@@ -132,6 +139,12 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
// WorkerTaskRunner::Observer implementation.
virtual void OnWorkerRunLoopStopped() OVERRIDE;
void OnAssociateRegistration(int thread_id,
int provider_id,
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs);
void OnDisassociateRegistration(int thread_id,
int provider_id);
void OnRegistered(int thread_id,
int request_id,
const ServiceWorkerRegistrationObjectInfo& info,
......@@ -178,6 +191,9 @@ class ServiceWorkerDispatcher : public WorkerTaskRunner::Observer {
int provider_id,
int registration_handle_id,
const ServiceWorkerObjectInfo& info);
void SetReadyRegistration(
int provider_id,
int registration_handle_id);
// Keeps map from handle_id to ServiceWorker object.
void AddServiceWorker(int handle_id, WebServiceWorkerImpl* worker);
......
......@@ -10,6 +10,7 @@
#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_registration_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"
......@@ -56,6 +57,47 @@ ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() {
return controller_.get();
}
ServiceWorkerRegistrationHandleReference*
ServiceWorkerProviderContext::registration() {
DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
return registration_.get();
}
ServiceWorkerVersionAttributes
ServiceWorkerProviderContext::GetVersionAttributes() {
ServiceWorkerVersionAttributes attrs;
if (installing())
attrs.installing = installing()->info();
if (waiting())
attrs.waiting = waiting()->info();
if (active())
attrs.active = active()->info();
return attrs;
}
void ServiceWorkerProviderContext::OnAssociateRegistration(
const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs) {
DCHECK(!registration_);
DCHECK_NE(kInvalidServiceWorkerRegistrationHandleId, info.handle_id);
registration_ = ServiceWorkerRegistrationHandleReference::Adopt(
info, thread_safe_sender_.get());
installing_ = ServiceWorkerHandleReference::Adopt(
attrs.installing, thread_safe_sender_.get());
waiting_ = ServiceWorkerHandleReference::Adopt(
attrs.waiting, thread_safe_sender_.get());
active_ = ServiceWorkerHandleReference::Adopt(
attrs.active, thread_safe_sender_.get());
}
void ServiceWorkerProviderContext::OnDisassociateRegistration() {
controller_.reset();
active_.reset();
waiting_.reset();
installing_.reset();
registration_.reset();
}
void ServiceWorkerProviderContext::OnServiceWorkerStateChanged(
int handle_id,
blink::WebServiceWorkerState state) {
......@@ -80,33 +122,33 @@ void ServiceWorkerProviderContext::OnServiceWorkerStateChanged(
}
void ServiceWorkerProviderContext::OnSetInstallingServiceWorker(
int provider_id,
int registration_handle_id,
const ServiceWorkerObjectInfo& info) {
DCHECK_EQ(provider_id_, provider_id);
DCHECK(IsAssociatedWithRegistration(registration_handle_id));
installing_ =
ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
}
void ServiceWorkerProviderContext::OnSetWaitingServiceWorker(
int provider_id,
int registration_handle_id,
const ServiceWorkerObjectInfo& info) {
DCHECK_EQ(provider_id_, provider_id);
DCHECK(IsAssociatedWithRegistration(registration_handle_id));
waiting_ =
ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
}
void ServiceWorkerProviderContext::OnSetActiveServiceWorker(
int provider_id,
int registration_handle_id,
const ServiceWorkerObjectInfo& info) {
DCHECK_EQ(provider_id_, provider_id);
DCHECK(IsAssociatedWithRegistration(registration_handle_id));
active_ =
ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get());
}
void ServiceWorkerProviderContext::OnSetControllerServiceWorker(
int provider_id,
int registration_handle_id,
const ServiceWorkerObjectInfo& info) {
DCHECK_EQ(provider_id_, provider_id);
DCHECK(IsAssociatedWithRegistration(registration_handle_id));
// This context is is the primary owner of this handle, keeps the
// initial reference until it goes away.
......@@ -141,4 +183,19 @@ int ServiceWorkerProviderContext::controller_handle_id() const {
: kInvalidServiceWorkerHandleId;
}
int ServiceWorkerProviderContext::registration_handle_id() const {
DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread());
return registration_ ? registration_->info().handle_id
: kInvalidServiceWorkerRegistrationHandleId;
}
bool ServiceWorkerProviderContext::IsAssociatedWithRegistration(
int registration_handle_id) const {
if (!registration_)
return false;
if (registration_handle_id == kInvalidServiceWorkerRegistrationHandleId)
return false;
return registration_->info().handle_id == registration_handle_id;
}
} // namespace content
......@@ -24,6 +24,7 @@ class Message;
namespace content {
class ServiceWorkerHandleReference;
class ServiceWorkerRegistrationHandleReference;
struct ServiceWorkerProviderContextDeleter;
class ThreadSafeSender;
......@@ -38,15 +39,18 @@ class ServiceWorkerProviderContext
explicit ServiceWorkerProviderContext(int provider_id);
// Called from ServiceWorkerDispatcher.
void OnAssociateRegistration(const ServiceWorkerRegistrationObjectInfo& info,
const ServiceWorkerVersionAttributes& attrs);
void OnDisassociateRegistration();
void OnServiceWorkerStateChanged(int handle_id,
blink::WebServiceWorkerState state);
void OnSetInstallingServiceWorker(int provider_id,
void OnSetInstallingServiceWorker(int registration_handle_id,
const ServiceWorkerObjectInfo& info);
void OnSetWaitingServiceWorker(int provider_id,
void OnSetWaitingServiceWorker(int registration_handle_id,
const ServiceWorkerObjectInfo& info);
void OnSetActiveServiceWorker(int provider_id,
void OnSetActiveServiceWorker(int registration_handle_id,
const ServiceWorkerObjectInfo& info);
void OnSetControllerServiceWorker(int provider_id,
void OnSetControllerServiceWorker(int registration_handle_id,
const ServiceWorkerObjectInfo& info);
int provider_id() const { return provider_id_; }
......@@ -55,6 +59,9 @@ class ServiceWorkerProviderContext
ServiceWorkerHandleReference* waiting();
ServiceWorkerHandleReference* active();
ServiceWorkerHandleReference* controller();
ServiceWorkerRegistrationHandleReference* registration();
ServiceWorkerVersionAttributes GetVersionAttributes();
// Gets the handle ID of the installing Service Worker, or
// kInvalidServiceWorkerHandleId if the provider does not have a
......@@ -76,10 +83,17 @@ class ServiceWorkerProviderContext
// by a Service Worker.
int controller_handle_id() const;
// Gets the handle ID of the associated registration, or
// kInvalidRegistrationHandleId if the provider is not associated with any
// registration.
int registration_handle_id() const;
private:
friend class base::RefCounted<ServiceWorkerProviderContext>;
~ServiceWorkerProviderContext();
bool IsAssociatedWithRegistration(int registration_handle_id) const;
const int provider_id_;
scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
......@@ -87,6 +101,7 @@ class ServiceWorkerProviderContext
scoped_ptr<ServiceWorkerHandleReference> waiting_;
scoped_ptr<ServiceWorkerHandleReference> active_;
scoped_ptr<ServiceWorkerHandleReference> controller_;
scoped_ptr<ServiceWorkerRegistrationHandleReference> registration_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderContext);
};
......
......@@ -30,6 +30,7 @@ class ServiceWorkerRegistrationHandleReference {
~ServiceWorkerRegistrationHandleReference();
const ServiceWorkerRegistrationObjectInfo& info() const { return info_; }
int handle_id() const { return info_.handle_id; }
GURL scope() const { return info_.scope; }
......
......@@ -10,7 +10,9 @@
#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/service_worker_registration_handle_reference.h"
#include "content/child/service_worker/web_service_worker_impl.h"
#include "content/child/service_worker/web_service_worker_registration_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"
......@@ -47,6 +49,30 @@ void WebServiceWorkerProviderImpl::setClient(
// for more context)
GetDispatcher()->AddScriptClient(provider_id_, client);
if (!context_->registration()) {
// This provider is not associated with any registration.
return;
}
// Set .ready if the associated registration has the active service worker.
if (context_->active_handle_id() != kInvalidServiceWorkerHandleId) {
WebServiceWorkerRegistrationImpl* registration =
GetDispatcher()->FindServiceWorkerRegistration(
context_->registration()->info(), false);
if (!registration) {
registration = GetDispatcher()->CreateServiceWorkerRegistration(
context_->registration()->info(), false);
ServiceWorkerVersionAttributes attrs = context_->GetVersionAttributes();
registration->SetInstalling(
GetDispatcher()->GetServiceWorker(attrs.installing, false));
registration->SetWaiting(
GetDispatcher()->GetServiceWorker(attrs.waiting, false));
registration->SetActive(
GetDispatcher()->GetServiceWorker(attrs.active, false));
}
client->setReadyRegistration(registration);
}
if (context_->controller_handle_id() != kInvalidServiceWorkerHandleId) {
client->setController(GetDispatcher()->GetServiceWorker(
context_->controller()->info(), false));
......
......@@ -184,6 +184,17 @@ IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_CacheStorageKeys,
// extract it and dispatch the message to the correct ServiceWorkerDispatcher
// on the correct thread.
// Informs the child process that the given provider gets associated or
// disassociated with the registration.
IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_AssociateRegistration,
int /* thread_id */,
int /* provider_id */,
content::ServiceWorkerRegistrationObjectInfo,
content::ServiceWorkerVersionAttributes)
IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DisassociateRegistration,
int /* thread_id */,
int /* provider_id */)
// Response to ServiceWorkerMsg_RegisterServiceWorker.
IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_ServiceWorkerRegistered,
int /* thread_id */,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment