Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(731)

Unified Diff: content/browser/service_worker/service_worker_register_job.cc

Issue 380093002: Update installed ServiceWorkers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/service_worker/service_worker_register_job.cc
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index 67793c6004cc4baca63b83b4a2b8af526918e784..dd96b604b3c19393659c30f33e7d5f79bc0b4c3b 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -21,7 +21,38 @@ void RunSoon(const base::Closure& closure) {
base::MessageLoop::current()->PostTask(FROM_HERE, closure);
}
-}
+// Helper class for the [[Update]] algo.
+class DeferredActivationHelper : public ServiceWorkerVersion::Listener {
+ public:
+ explicit DeferredActivationHelper(ServiceWorkerRegistration* registration)
+ : registration_(registration),
+ active_version_(registration->active_version()),
+ waiting_version_(registration->waiting_version()) {
+ active_version_->AddListener(this);
+ }
+
+ virtual ~DeferredActivationHelper() {}
+
+ private:
+ virtual void OnNoControllees(ServiceWorkerVersion* version) OVERRIDE {
+ DCHECK_EQ(active_version_, version);
+ scoped_ptr<DeferredActivationHelper> self_deletor(this);
+ active_version_->RemoveListener(this);
+ if (registration_->active_version() != active_version_ ||
+ registration_->waiting_version() != waiting_version_) {
+ return; // Something has changed making activation n/a.
+ }
+ registration_->ActivateWaitingVersion(
+ base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
+ }
+
+ scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_refptr<ServiceWorkerVersion> active_version_;
+ scoped_refptr<ServiceWorkerVersion> waiting_version_;
+ DISALLOW_COPY_AND_ASSIGN(DeferredActivationHelper);
+};
+
+} // namespace
typedef ServiceWorkerRegisterJobBase::RegistrationJobType RegistrationJobType;
@@ -30,6 +61,7 @@ ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
const GURL& pattern,
const GURL& script_url)
: context_(context),
+ job_type_(REGISTRATION_JOB),
pattern_(pattern),
script_url_(script_url),
phase_(INITIAL),
@@ -37,6 +69,20 @@ ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
promise_resolved_status_(SERVICE_WORKER_OK),
weak_factory_(this) {}
+ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
+ base::WeakPtr<ServiceWorkerContextCore> context,
+ ServiceWorkerRegistration* registration)
+ : context_(context),
+ job_type_(UPDATE_JOB),
+ pattern_(registration->pattern()),
+ script_url_(registration->script_url()),
+ phase_(INITIAL),
+ is_promise_resolved_(false),
+ promise_resolved_status_(SERVICE_WORKER_OK),
+ weak_factory_(this) {
+ internal_.registration = registration;
+}
+
ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {
DCHECK(!context_ ||
phase_ == INITIAL || phase_ == COMPLETE || phase_ == ABORT)
@@ -58,11 +104,17 @@ void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback,
void ServiceWorkerRegisterJob::Start() {
SetPhase(START);
- context_->storage()->FindRegistrationForPattern(
- pattern_,
- base::Bind(
- &ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue,
- weak_factory_.GetWeakPtr()));
+ ServiceWorkerStorage::FindRegistrationCallback next_step;
+ if (job_type_ == REGISTRATION_JOB) {
+ next_step = base::Bind(
+ &ServiceWorkerRegisterJob::ContinueWithRegistration,
+ weak_factory_.GetWeakPtr());
+ } else {
+ next_step = base::Bind(
+ &ServiceWorkerRegisterJob::ContinueWithUpdate,
+ weak_factory_.GetWeakPtr());
+ }
+ context_->storage()->FindRegistrationForPattern(pattern_, next_step);
}
void ServiceWorkerRegisterJob::Abort() {
@@ -82,7 +134,7 @@ bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
}
RegistrationJobType ServiceWorkerRegisterJob::GetType() {
- return REGISTRATION;
+ return job_type_;
}
ServiceWorkerRegisterJob::Internal::Internal() {}
@@ -97,7 +149,7 @@ void ServiceWorkerRegisterJob::set_registration(
}
ServiceWorkerRegistration* ServiceWorkerRegisterJob::registration() {
- DCHECK(phase_ >= REGISTER) << phase_;
+ DCHECK(phase_ >= REGISTER || job_type_ == UPDATE_JOB) << phase_;
return internal_.registration;
}
@@ -149,9 +201,10 @@ void ServiceWorkerRegisterJob::SetPhase(Phase phase) {
// "Let serviceWorkerRegistration be _GetRegistration(scope)"
// |existing_registration| corresponds to serviceWorkerRegistration.
// Throughout this file, comments in quotes are excerpts from the spec.
-void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue(
+void ServiceWorkerRegisterJob::ContinueWithRegistration(
ServiceWorkerStatusCode status,
const scoped_refptr<ServiceWorkerRegistration>& existing_registration) {
+ DCHECK_EQ(REGISTRATION_JOB, job_type_);
// On unexpected error, abort this registration job.
if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) {
Complete(status);
@@ -168,7 +221,7 @@ void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue(
// but seems reasonable, and without SoftUpdate implemented we can never
// Update otherwise).
if (!existing_registration->active_version()) {
- UpdateAndContinue(status);
+ UpdateAndContinue();
return;
}
ResolvePromise(
@@ -198,6 +251,23 @@ void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue(
weak_factory_.GetWeakPtr()));
}
+void ServiceWorkerRegisterJob::ContinueWithUpdate(
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& existing_registration) {
+ DCHECK_EQ(UPDATE_JOB, job_type_);
+ if (status != SERVICE_WORKER_OK) {
+ Complete(status);
+ return;
+ }
+
+ if (existing_registration != registration()) {
+ Complete(SERVICE_WORKER_ERROR_NOT_FOUND);
+ return;
+ }
+
+ UpdateAndContinue();
+}
+
// Creates a new ServiceWorkerRegistration.
void ServiceWorkerRegisterJob::RegisterAndContinue(
ServiceWorkerStatusCode status) {
@@ -211,19 +281,13 @@ void ServiceWorkerRegisterJob::RegisterAndContinue(
set_registration(new ServiceWorkerRegistration(
pattern_, script_url_, context_->storage()->NewRegistrationId(),
context_));
- context_->storage()->NotifyInstallingRegistration(registration());
- UpdateAndContinue(SERVICE_WORKER_OK);
+ UpdateAndContinue();
}
-// This function corresponds to the spec's _Update algorithm.
-void ServiceWorkerRegisterJob::UpdateAndContinue(
- ServiceWorkerStatusCode status) {
+// This function corresponds to the spec's [[Update]] algorithm.
+void ServiceWorkerRegisterJob::UpdateAndContinue() {
SetPhase(UPDATE);
- if (status != SERVICE_WORKER_OK) {
- // Abort this registration job.
- Complete(status);
- return;
- }
+ context_->storage()->NotifyInstallingRegistration(registration());
// TODO(falken): "If serviceWorkerRegistration.installingWorker is not null.."
// then terminate the installing worker. It doesn't make sense to implement
@@ -235,8 +299,7 @@ void ServiceWorkerRegisterJob::UpdateAndContinue(
set_new_version(new ServiceWorkerVersion(
registration(), context_->storage()->NewVersionId(), context_));
- // TODO(michaeln): Pause after downloading when performing an update.
- bool pause_after_download = false;
+ bool pause_after_download = job_type_ == UPDATE_JOB;
if (pause_after_download)
new_version()->embedded_worker()->AddListener(this);
new_version()->StartWorkerWithCandidateProcesses(
@@ -307,7 +370,13 @@ void ServiceWorkerRegisterJob::OnStoreRegistrationComplete(
return;
}
- // TODO(nhiroki): "9. If registration.waitingWorker is not null, then:..."
+ // "9. If registration.waitingWorker is not null, then:..."
+ if (registration()->waiting_version()) {
+ // "1. Run the [[UpdateState]] algorithm passing registration.waitingWorker
+ // and "redundant" as the arguments."
+ registration()->waiting_version()->SetStatus(
+ ServiceWorkerVersion::REDUNDANT);
+ }
// "10. Set registration.waitingWorker to registration.installingWorker."
// "11. Set registration.installingWorker to null."
@@ -318,67 +387,27 @@ void ServiceWorkerRegisterJob::OnStoreRegistrationComplete(
// "12. Run the [[UpdateState]] algorithm passing registration.waitingWorker
// and "installed" as the arguments."
new_version()->SetStatus(ServiceWorkerVersion::INSTALLED);
- ActivateAndContinue();
-}
-// This function corresponds to the spec's _Activate algorithm.
-void ServiceWorkerRegisterJob::ActivateAndContinue() {
- SetPhase(ACTIVATE);
+ // TODO(michaeln): "13. If activateImmediate is true, then..."
- // "4. If existingWorker is not null, then: wait for exitingWorker to finish
- // handling any in-progress requests."
- // See if we already have an active_version for the scope and it has
- // controllee documents (if so activating the new version should wait
- // until we have no documents controlled by the version).
+ // "14. Wait until no document is using registration as their
+ // Service Worker registration."
if (registration()->active_version() &&
registration()->active_version()->HasControllee()) {
- // TODO(kinuko,falken): Currently we immediately return if the existing
- // registration already has an active version, so we shouldn't come
- // this way.
- NOTREACHED();
- // TODO(falken): Register an continuation task to wait for NoControllees
- // notification so that we can resume activation later.
+ scoped_ptr<DeferredActivationHelper> deferred_activation(
+ new DeferredActivationHelper(registration()));
+ // It will delete itself when done.
+ ignore_result(deferred_activation.release());
Complete(SERVICE_WORKER_OK);
return;
}
- // "5. Set serviceWorkerRegistration.activeWorker to activatingWorker."
- // "6. Set serviceWorkerRegistration.waitingWorker to null."
- DisassociateVersionFromDocuments(context_, new_version());
- registration()->SetActiveVersion(new_version());
- AssociateActiveVersionToDocuments(context_, new_version());
-
- // "7. Run the [[UpdateState]] algorithm passing registration.activeWorker and
- // "activating" as arguments."
- new_version()->SetStatus(ServiceWorkerVersion::ACTIVATING);
-
- // TODO(nhiroki): "8. Fire a simple event named controllerchange..."
-
- // "9. Fire an event named activate..."
- new_version()->DispatchActivateEvent(
- base::Bind(&ServiceWorkerRegisterJob::OnActivateFinished,
+ SetPhase(ACTIVATE);
+ registration()->ActivateWaitingVersion(
+ base::Bind(&ServiceWorkerRegisterJob::Complete,
weak_factory_.GetWeakPtr()));
}
-void ServiceWorkerRegisterJob::OnActivateFinished(
- ServiceWorkerStatusCode status) {
- // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
- // unexpectedly terminated) we may want to retry sending the event again.
- if (status != SERVICE_WORKER_OK) {
- // "11. If activateFailed is true, then:..."
- Complete(status);
- return;
- }
-
- // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
- // and "activated" as the arguments."
- new_version()->SetStatus(ServiceWorkerVersion::ACTIVATED);
- context_->storage()->UpdateToActiveState(
- registration(),
- base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
- Complete(SERVICE_WORKER_OK);
-}
-
void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) {
CompleteInternal(status);
context_->job_coordinator()->FinishJob(pattern_, this);
@@ -431,19 +460,44 @@ void ServiceWorkerRegisterJob::ResolvePromise(
}
void ServiceWorkerRegisterJob::OnPausedAfterDownload() {
- // TODO(michaeln): Compare the old and new script.
- // If different unpause the worker and continue with
- // the job. If the same ResolvePromise with the current
- // version and complete the job, throwing away the new version
- // since there's nothing new.
- new_version()->embedded_worker()->RemoveListener(this);
- new_version()->embedded_worker()->ResumeAfterDownload();
+ // This happens prior to OnStartWorkerFinished time.
+ scoped_refptr<ServiceWorkerVersion> current_version =
+ registration()->active_version();
+ DCHECK(current_version);
+ int64 current_script_id =
+ current_version->script_cache_map()->Lookup(script_url_);
+ int64 new_script_id =
+ new_version()->script_cache_map()->Lookup(script_url_);
+
+ // TODO(michaeln): It would be better to compare as the new resource
+ // is being downloaded and to avoid writing it to disk until we know
+ // its needed.
+ context_->storage()->CompareScriptResources(
+ current_script_id, new_script_id,
+ base::Bind(&ServiceWorkerRegisterJob::OnCompareScriptResourcesComplete,
+ weak_factory_.GetWeakPtr(),
+ current_version));
}
bool ServiceWorkerRegisterJob::OnMessageReceived(const IPC::Message& message) {
return false;
}
+void ServiceWorkerRegisterJob::OnCompareScriptResourcesComplete(
+ ServiceWorkerVersion* current_version,
+ ServiceWorkerStatusCode status,
+ bool are_equal) {
+ if (are_equal) {
+ ResolvePromise(SERVICE_WORKER_OK, registration(), current_version);
+ Complete(SERVICE_WORKER_ERROR_EXISTS);
+ return;
+ }
+
+ // Proceed with really starting the worker.
+ new_version()->embedded_worker()->ResumeAfterDownload();
+ new_version()->embedded_worker()->RemoveListener(this);
+}
+
// static
void ServiceWorkerRegisterJob::AssociateInstallingVersionToDocuments(
base::WeakPtr<ServiceWorkerContextCore> context,

Powered by Google App Engine
This is Rietveld 408576698