1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/service_worker/service_worker_registration.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "content/browser/service_worker/embedded_worker_status.h"
13 #include "content/browser/service_worker/service_worker_container_host.h"
14 #include "content/browser/service_worker/service_worker_context_core.h"
15 #include "content/browser/service_worker/service_worker_context_wrapper.h"
16 #include "content/browser/service_worker/service_worker_info.h"
17 #include "content/browser/service_worker/service_worker_job_coordinator.h"
18 #include "content/browser/service_worker/service_worker_metrics.h"
19 #include "content/browser/service_worker/service_worker_register_job.h"
20 #include "content/browser/service_worker/service_worker_version.h"
21 #include "content/common/content_navigation_policy.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
24 
25 namespace content {
26 
27 namespace {
28 
29 // If an outgoing active worker has no controllees or the waiting worker called
30 // skipWaiting(), it is given |kMaxLameDuckTime| time to finish its requests
31 // before it is removed. If the waiting worker called skipWaiting() more than
32 // this time ago, or the outgoing worker has had no controllees for a continuous
33 // period of time exceeding this time, the outgoing worker will be removed even
34 // if it has ongoing requests.
35 constexpr base::TimeDelta kMaxLameDuckTime = base::TimeDelta::FromMinutes(5);
36 
GetVersionInfo(ServiceWorkerVersion * version)37 ServiceWorkerVersionInfo GetVersionInfo(ServiceWorkerVersion* version) {
38   if (!version)
39     return ServiceWorkerVersionInfo();
40   return version->GetInfo();
41 }
42 
43 }  // namespace
44 
ServiceWorkerRegistration(const blink::mojom::ServiceWorkerRegistrationOptions & options,int64_t registration_id,base::WeakPtr<ServiceWorkerContextCore> context)45 ServiceWorkerRegistration::ServiceWorkerRegistration(
46     const blink::mojom::ServiceWorkerRegistrationOptions& options,
47     int64_t registration_id,
48     base::WeakPtr<ServiceWorkerContextCore> context)
49     : scope_(options.scope),
50       // Safe to convert GURL to Origin because service workers are restricted
51       // to secure contexts.
52       origin_(url::Origin::Create(options.scope)),
53       update_via_cache_(options.update_via_cache),
54       registration_id_(registration_id),
55       status_(Status::kIntact),
56       store_state_(StoreState::kNotStored),
57       should_activate_when_ready_(false),
58       resources_total_size_bytes_(0),
59       context_(context),
60       task_runner_(base::ThreadTaskRunnerHandle::Get()) {
61   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
62   DCHECK_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, registration_id);
63   DCHECK(context_);
64   context_->AddLiveRegistration(this);
65 }
66 
~ServiceWorkerRegistration()67 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
68   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
69   DCHECK(!listeners_.might_have_observers());
70   if (context_)
71     context_->RemoveLiveRegistration(registration_id_);
72 }
73 
SetStatus(Status status)74 void ServiceWorkerRegistration::SetStatus(Status status) {
75   if (status_ == status)
76     return;
77 #if DCHECK_IS_ON()
78   switch (status_) {
79     case Status::kIntact:
80       DCHECK_EQ(status, Status::kUninstalling);
81       break;
82     case Status::kUninstalling:
83       // All transitions are allowed:
84       // - To kIntact: resurrected.
85       // - To kUninstalled: finished uninstalling.
86       break;
87     case Status::kUninstalled:
88       NOTREACHED();
89       break;
90   }
91 #endif  // DCHECK_IS_ON()
92 
93   status_ = status;
94 
95   if (active_version_)
96     active_version_->SetRegistrationStatus(status_);
97   if (waiting_version_)
98     waiting_version_->SetRegistrationStatus(status_);
99   if (installing_version_)
100     installing_version_->SetRegistrationStatus(status_);
101 }
102 
IsStored() const103 bool ServiceWorkerRegistration::IsStored() const {
104   return context_ && store_state_ == StoreState::kStored;
105 }
106 
SetStored()107 void ServiceWorkerRegistration::SetStored() {
108   store_state_ = StoreState::kStored;
109 }
110 
UnsetStored()111 void ServiceWorkerRegistration::UnsetStored() {
112   store_state_ = StoreState::kNotStored;
113 }
114 
GetNewestVersion() const115 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
116   if (installing_version())
117     return installing_version();
118   if (waiting_version())
119     return waiting_version();
120   return active_version();
121 }
122 
AddListener(Listener * listener)123 void ServiceWorkerRegistration::AddListener(Listener* listener) {
124   listeners_.AddObserver(listener);
125 }
126 
RemoveListener(Listener * listener)127 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
128   listeners_.RemoveObserver(listener);
129 }
130 
NotifyRegistrationFailed()131 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
132   for (auto& observer : listeners_)
133     observer.OnRegistrationFailed(this);
134   NotifyRegistrationFinished();
135 }
136 
NotifyUpdateFound()137 void ServiceWorkerRegistration::NotifyUpdateFound() {
138   for (auto& observer : listeners_)
139     observer.OnUpdateFound(this);
140 }
141 
NotifyVersionAttributesChanged(blink::mojom::ChangedServiceWorkerObjectsMaskPtr mask)142 void ServiceWorkerRegistration::NotifyVersionAttributesChanged(
143     blink::mojom::ChangedServiceWorkerObjectsMaskPtr mask) {
144   for (auto& observer : listeners_)
145     observer.OnVersionAttributesChanged(this, mask.Clone());
146   if (mask->active || mask->waiting)
147     NotifyRegistrationFinished();
148 }
149 
GetInfo()150 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
151   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
152   return ServiceWorkerRegistrationInfo(
153       scope(), update_via_cache(), registration_id_,
154       is_deleted() ? ServiceWorkerRegistrationInfo::IS_DELETED
155                    : ServiceWorkerRegistrationInfo::IS_NOT_DELETED,
156       GetVersionInfo(active_version_.get()),
157       GetVersionInfo(waiting_version_.get()),
158       GetVersionInfo(installing_version_.get()), resources_total_size_bytes_,
159       navigation_preload_state_.enabled,
160       navigation_preload_state_.header.length());
161 }
162 
SetActiveVersion(const scoped_refptr<ServiceWorkerVersion> & version)163 void ServiceWorkerRegistration::SetActiveVersion(
164     const scoped_refptr<ServiceWorkerVersion>& version) {
165   if (active_version_ == version)
166     return;
167 
168   should_activate_when_ready_ = false;
169 
170   auto mask =
171       blink::mojom::ChangedServiceWorkerObjectsMask::New(false, false, false);
172   if (version) {
173     UnsetVersionInternal(version.get(), mask.get());
174     version->SetRegistrationStatus(status_);
175   }
176   active_version_ = version;
177   if (active_version_)
178     active_version_->SetNavigationPreloadState(navigation_preload_state_);
179   mask->active = true;
180 
181   NotifyVersionAttributesChanged(std::move(mask));
182 }
183 
SetWaitingVersion(const scoped_refptr<ServiceWorkerVersion> & version)184 void ServiceWorkerRegistration::SetWaitingVersion(
185     const scoped_refptr<ServiceWorkerVersion>& version) {
186   if (waiting_version_ == version)
187     return;
188 
189   should_activate_when_ready_ = false;
190 
191   auto mask =
192       blink::mojom::ChangedServiceWorkerObjectsMask::New(false, false, false);
193   if (version) {
194     UnsetVersionInternal(version.get(), mask.get());
195     version->SetRegistrationStatus(status_);
196   }
197   waiting_version_ = version;
198   mask->waiting = true;
199 
200   NotifyVersionAttributesChanged(std::move(mask));
201 }
202 
SetInstallingVersion(const scoped_refptr<ServiceWorkerVersion> & version)203 void ServiceWorkerRegistration::SetInstallingVersion(
204     const scoped_refptr<ServiceWorkerVersion>& version) {
205   if (installing_version_ == version)
206     return;
207   auto mask =
208       blink::mojom::ChangedServiceWorkerObjectsMask::New(false, false, false);
209   if (version) {
210     UnsetVersionInternal(version.get(), mask.get());
211     version->SetRegistrationStatus(status_);
212   }
213   installing_version_ = version;
214   mask->installing = true;
215   NotifyVersionAttributesChanged(std::move(mask));
216 }
217 
UnsetVersion(ServiceWorkerVersion * version)218 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
219   if (!version)
220     return;
221   auto mask =
222       blink::mojom::ChangedServiceWorkerObjectsMask::New(false, false, false);
223   UnsetVersionInternal(version, mask.get());
224   if (mask->installing || mask->waiting || mask->active)
225     NotifyVersionAttributesChanged(std::move(mask));
226 }
227 
UnsetVersionInternal(ServiceWorkerVersion * version,blink::mojom::ChangedServiceWorkerObjectsMask * mask)228 void ServiceWorkerRegistration::UnsetVersionInternal(
229     ServiceWorkerVersion* version,
230     blink::mojom::ChangedServiceWorkerObjectsMask* mask) {
231   DCHECK(version);
232 
233   if (installing_version_.get() == version) {
234     installing_version_ = nullptr;
235     mask->installing = true;
236   } else if (waiting_version_.get() == version) {
237     waiting_version_ = nullptr;
238     should_activate_when_ready_ = false;
239     mask->waiting = true;
240   } else if (active_version_.get() == version) {
241     active_version_ = nullptr;
242     mask->active = true;
243   }
244 }
245 
SetUpdateViaCache(blink::mojom::ServiceWorkerUpdateViaCache update_via_cache)246 void ServiceWorkerRegistration::SetUpdateViaCache(
247     blink::mojom::ServiceWorkerUpdateViaCache update_via_cache) {
248   if (update_via_cache_ == update_via_cache)
249     return;
250   update_via_cache_ = update_via_cache;
251   for (auto& observer : listeners_)
252     observer.OnUpdateViaCacheChanged(this);
253 }
254 
ActivateWaitingVersionWhenReady()255 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
256   DCHECK(waiting_version());
257   should_activate_when_ready_ = true;
258   if (IsReadyToActivate()) {
259     ActivateWaitingVersion(false /* delay */);
260     return;
261   }
262 
263   if (IsLameDuckActiveVersion()) {
264     if (active_version()->running_status() == EmbeddedWorkerStatus::RUNNING) {
265       // If the waiting worker is ready and the active worker needs to be
266       // swapped out, ask the active worker to trigger idle timer as soon as
267       // possible.
268       active_version()->TriggerIdleTerminationAsap();
269     }
270     StartLameDuckTimer();
271   }
272 }
273 
ClaimClients()274 void ServiceWorkerRegistration::ClaimClients() {
275   DCHECK(context_);
276   DCHECK(active_version());
277 
278   // https://w3c.github.io/ServiceWorker/#clients-claim
279   //
280   // "For each service worker client client whose origin is the same as the
281   //  service worker's origin:
282   const bool include_reserved_clients = false;
283   // Include clients in BackForwardCache in order to evict them if needed.
284   const bool include_back_forward_cached_clients = true;
285   for (std::unique_ptr<ServiceWorkerContextCore::ContainerHostIterator> it =
286            context_->GetClientContainerHostIterator(
287                scope_.GetOrigin(), include_reserved_clients,
288                include_back_forward_cached_clients);
289        !it->IsAtEnd(); it->Advance()) {
290     ServiceWorkerContainerHost* container_host = it->GetContainerHost();
291     // "1. If client’s execution ready flag is unset or client’s discarded flag
292     //     is set, continue."
293     // |include_reserved_clients| ensures only execution ready clients are
294     // returned.
295     DCHECK(container_host->is_execution_ready());
296 
297     // This is part of step 5 but performed here as an optimization. Do nothing
298     // if this version is already the controller.
299     if (container_host->controller() == active_version())
300       continue;
301 
302     // "2. If client is not a secure context, continue."
303     if (!container_host->IsEligibleForServiceWorkerController())
304       continue;
305 
306     // "3. Let registration be the result of running Match Service Worker
307     //     Registration algorithm passing client’s creation URL as the argument.
308     //  4. If registration is not the service worker's containing service worker
309     //     registration, continue."
310     if (container_host->MatchRegistration() != this)
311       continue;
312 
313     // Evict the client in BackForwardCache.
314     if (container_host->IsInBackForwardCache())
315       container_host->EvictFromBackForwardCache(
316           BackForwardCacheMetrics::NotRestoredReason::kServiceWorkerClaim);
317 
318     // The remaining steps are performed here:
319     container_host->ClaimedByRegistration(this);
320   }
321 }
322 
DeleteAndClearWhenReady()323 void ServiceWorkerRegistration::DeleteAndClearWhenReady() {
324   DCHECK(context_);
325   if (is_deleted()) {
326     // We already deleted and are waiting to clear, or the registration is
327     // already cleared.
328     return;
329   }
330 
331   context_->registry()->DeleteRegistration(
332       this, scope().GetOrigin(),
333       AdaptCallbackForRepeating(
334           base::BindOnce(&ServiceWorkerRegistration::OnDeleteFinished, this)));
335 
336   if (!active_version() || !active_version()->HasControllee())
337     Clear();
338 }
339 
DeleteAndClearImmediately()340 void ServiceWorkerRegistration::DeleteAndClearImmediately() {
341   DCHECK(context_);
342   if (!is_deleted()) {
343     context_->registry()->DeleteRegistration(
344         this, scope().GetOrigin(),
345         AdaptCallbackForRepeating(base::BindOnce(
346             &ServiceWorkerRegistration::OnDeleteFinished, this)));
347   }
348 
349   if (is_uninstalling())
350     Clear();
351 }
352 
AbortPendingClear(StatusCallback callback)353 void ServiceWorkerRegistration::AbortPendingClear(StatusCallback callback) {
354   DCHECK(context_);
355 
356   switch (status_) {
357     case Status::kIntact:
358       std::move(callback).Run(blink::ServiceWorkerStatusCode::kOk);
359       return;
360     case Status::kUninstalling:
361       break;
362     case Status::kUninstalled:
363       NOTREACHED()
364           << "attempt to resurrect a completely uninstalled registration";
365       break;
366   }
367 
368   context_->registry()->NotifyDoneUninstallingRegistration(this,
369                                                            Status::kIntact);
370 
371   scoped_refptr<ServiceWorkerVersion> most_recent_version =
372       waiting_version() ? waiting_version() : active_version();
373   DCHECK(most_recent_version.get());
374   context_->registry()->NotifyInstallingRegistration(this);
375   context_->registry()->StoreRegistration(
376       this, most_recent_version.get(),
377       base::BindOnce(&ServiceWorkerRegistration::OnRestoreFinished, this,
378                      std::move(callback), most_recent_version));
379 }
380 
OnNoControllees(ServiceWorkerVersion * version)381 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
382   DCHECK(context_);
383   if (version != active_version())
384     return;
385 
386   if (is_uninstalling()) {
387     // TODO(falken): This can destroy the caller (ServiceWorkerVersion). Try to
388     // make this async.
389     Clear();
390     return;
391   }
392 
393   if (IsReadyToActivate()) {
394     ActivateWaitingVersion(true /* delay */);
395     return;
396   }
397 
398   if (IsLameDuckActiveVersion()) {
399     if (should_activate_when_ready_ &&
400         active_version()->running_status() == EmbeddedWorkerStatus::RUNNING) {
401       // If the waiting worker is ready and the active worker needs to be
402       // swapped out, ask the active worker to trigger idle timer as soon as
403       // possible.
404       active_version()->TriggerIdleTerminationAsap();
405     }
406     StartLameDuckTimer();
407   }
408 }
409 
OnNoWork(ServiceWorkerVersion * version)410 void ServiceWorkerRegistration::OnNoWork(ServiceWorkerVersion* version) {
411   DCHECK(context_);
412 
413   if (version == active_version() && IsReadyToActivate())
414     ActivateWaitingVersion(true /* delay */);
415 }
416 
IsReadyToActivate() const417 bool ServiceWorkerRegistration::IsReadyToActivate() const {
418   if (!should_activate_when_ready_)
419     return false;
420 
421   DCHECK(waiting_version());
422   const ServiceWorkerVersion* waiting = waiting_version();
423   const ServiceWorkerVersion* active = active_version();
424   if (!active) {
425     return true;
426   }
427   if (IsLameDuckActiveVersion()) {
428     return active->HasNoWork() ||
429            waiting->TimeSinceSkipWaiting() > kMaxLameDuckTime ||
430            active->TimeSinceNoControllees() > kMaxLameDuckTime;
431   }
432   return false;
433 }
434 
IsLameDuckActiveVersion() const435 bool ServiceWorkerRegistration::IsLameDuckActiveVersion() const {
436   if (!waiting_version() || !active_version())
437     return false;
438   return waiting_version()->skip_waiting() ||
439          !active_version()->HasControllee();
440 }
441 
StartLameDuckTimer()442 void ServiceWorkerRegistration::StartLameDuckTimer() {
443   DCHECK(IsLameDuckActiveVersion());
444   if (lame_duck_timer_.IsRunning())
445     return;
446 
447   lame_duck_timer_.Start(
448       FROM_HERE, kMaxLameDuckTime,
449       base::BindRepeating(
450           &ServiceWorkerRegistration::RemoveLameDuckIfNeeded,
451           Unretained(this) /* OK because |this| owns the timer */));
452 }
453 
RemoveLameDuckIfNeeded()454 void ServiceWorkerRegistration::RemoveLameDuckIfNeeded() {
455   if (!should_activate_when_ready_) {
456     lame_duck_timer_.Stop();
457     return;
458   }
459 
460   if (IsReadyToActivate()) {
461     ActivateWaitingVersion(false /* delay */);
462     return;
463   }
464 
465   if (!IsLameDuckActiveVersion()) {
466     lame_duck_timer_.Stop();
467   }
468 }
469 
ActivateWaitingVersion(bool delay)470 void ServiceWorkerRegistration::ActivateWaitingVersion(bool delay) {
471   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
472   DCHECK(context_);
473   DCHECK(IsReadyToActivate());
474   should_activate_when_ready_ = false;
475   lame_duck_timer_.Stop();
476 
477   scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
478   scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
479 
480   if (activating_version->is_redundant())
481     return;  // Activation is no longer relevant.
482 
483   // "5. If exitingWorker is not null,
484   if (exiting_version.get()) {
485     // Whenever activation happens, evict bfcached controllees.
486     if (IsBackForwardCacheEnabled()) {
487       exiting_version->EvictBackForwardCachedControllees(
488           BackForwardCacheMetrics::NotRestoredReason::
489               kServiceWorkerVersionActivation);
490     }
491 
492     // TODO(falken): Update the quoted spec comments once
493     // https://github.com/slightlyoff/ServiceWorker/issues/916 is codified in
494     // the spec.
495     // "1. Wait for exitingWorker to finish handling any in-progress requests."
496     // This is already handled by IsReadyToActivate().
497     // "2. Terminate exitingWorker."
498     exiting_version->StopWorker(base::DoNothing());
499     // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
500     // "redundant" as the arguments."
501     exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
502   }
503 
504   // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
505   // "7. Set serviceWorkerRegistration.waitingWorker to null."
506   SetActiveVersion(activating_version);
507 
508   // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
509   // "activating" as arguments."
510   activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
511   // "9. Fire a simple event named controllerchange..."
512   if (activating_version->skip_waiting()) {
513     for (auto& observer : listeners_)
514       observer.OnSkippedWaiting(this);
515   }
516 
517   // "10. Queue a task to fire an event named activate..."
518   // The browser could be shutting down. To avoid spurious start worker
519   // failures, wait a bit before continuing.
520   if (delay) {
521     task_runner_->PostDelayedTask(
522         FROM_HERE,
523         base::BindOnce(&ServiceWorkerRegistration::ContinueActivation, this,
524                        activating_version),
525         base::TimeDelta::FromSeconds(1));
526   } else {
527     ContinueActivation(std::move(activating_version));
528   }
529 }
530 
ContinueActivation(scoped_refptr<ServiceWorkerVersion> activating_version)531 void ServiceWorkerRegistration::ContinueActivation(
532     scoped_refptr<ServiceWorkerVersion> activating_version) {
533   if (!context_)
534     return;
535   if (active_version() != activating_version.get())
536     return;
537   DCHECK_EQ(ServiceWorkerVersion::ACTIVATING, activating_version->status());
538   activating_version->RunAfterStartWorker(
539       ServiceWorkerMetrics::EventType::ACTIVATE,
540       base::BindOnce(&ServiceWorkerRegistration::DispatchActivateEvent, this,
541                      activating_version));
542 }
543 
ForceDelete()544 void ServiceWorkerRegistration::ForceDelete() {
545   DCHECK(context_);
546   DCHECK(!is_uninstalled()) << "attempt to delete registration twice";
547 
548   // Protect the registration since version->Doom() can stop |version|, which
549   // destroys start worker callbacks, which might be the only things holding a
550   // reference to |this|.
551   scoped_refptr<ServiceWorkerRegistration> protect(this);
552 
553   // Abort any queued or running jobs for this registration.
554   context_->job_coordinator()->Abort(scope());
555 
556   // The rest of this function is similar to Clear() but is slightly different
557   // because this emergency deletion isn't part of the spec and happens
558   // outside of the normal job coordinator.
559   // TODO(falken): Consider merging the two.
560   should_activate_when_ready_ = false;
561 
562   // Doom versions. This sets the versions to redundant and tells the
563   // controllees that they are gone.
564   //
565   // There can't be an installing version since we aborted any register job.
566   DCHECK(!installing_version_);
567   auto mask =
568       blink::mojom::ChangedServiceWorkerObjectsMask::New(false, false, false);
569   // Unset the version first so we stop listening to the version as it might
570   // invoke listener methods during Doom().
571   if (scoped_refptr<ServiceWorkerVersion> waiting_version = waiting_version_) {
572     UnsetVersionInternal(waiting_version.get(), mask.get());
573     waiting_version->Doom();
574   }
575   if (scoped_refptr<ServiceWorkerVersion> active_version = active_version_) {
576     UnsetVersionInternal(active_version.get(), mask.get());
577     active_version->Doom();
578   }
579 
580   // Delete the registration and its state from storage.
581   if (status() == Status::kIntact) {
582     context_->registry()->DeleteRegistration(
583         this, scope().GetOrigin(),
584         base::BindOnce(&ServiceWorkerRegistration::OnDeleteFinished, protect));
585   }
586   DCHECK(is_uninstalling());
587   context_->registry()->NotifyDoneUninstallingRegistration(
588       this, Status::kUninstalled);
589 
590   // Tell observers that this registration is gone.
591   NotifyRegistrationFailed();
592 }
593 
NotifyRegistrationFinished()594 void ServiceWorkerRegistration::NotifyRegistrationFinished() {
595   std::vector<base::OnceClosure> callbacks;
596   callbacks.swap(registration_finished_callbacks_);
597   for (auto& callback : callbacks)
598     std::move(callback).Run();
599 }
600 
SetTaskRunnerForTest(scoped_refptr<base::SingleThreadTaskRunner> task_runner)601 void ServiceWorkerRegistration::SetTaskRunnerForTest(
602     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
603   task_runner_ = task_runner;
604 }
605 
EnableNavigationPreload(bool enable)606 void ServiceWorkerRegistration::EnableNavigationPreload(bool enable) {
607   navigation_preload_state_.enabled = enable;
608   if (active_version_)
609     active_version_->SetNavigationPreloadState(navigation_preload_state_);
610 }
611 
SetNavigationPreloadHeader(const std::string & header)612 void ServiceWorkerRegistration::SetNavigationPreloadHeader(
613     const std::string& header) {
614   navigation_preload_state_.header = header;
615   if (active_version_)
616     active_version_->SetNavigationPreloadState(navigation_preload_state_);
617 }
618 
RegisterRegistrationFinishedCallback(base::OnceClosure callback)619 void ServiceWorkerRegistration::RegisterRegistrationFinishedCallback(
620     base::OnceClosure callback) {
621   // This should only be called if the registration is in progress.
622   DCHECK(!active_version() && !waiting_version() && !is_uninstalled() &&
623          !is_uninstalling());
624   registration_finished_callbacks_.push_back(std::move(callback));
625 }
626 
DispatchActivateEvent(scoped_refptr<ServiceWorkerVersion> activating_version,blink::ServiceWorkerStatusCode start_worker_status)627 void ServiceWorkerRegistration::DispatchActivateEvent(
628     scoped_refptr<ServiceWorkerVersion> activating_version,
629     blink::ServiceWorkerStatusCode start_worker_status) {
630   if (start_worker_status != blink::ServiceWorkerStatusCode::kOk) {
631     OnActivateEventFinished(activating_version, start_worker_status);
632     return;
633   }
634   if (activating_version != active_version()) {
635     OnActivateEventFinished(activating_version,
636                             blink::ServiceWorkerStatusCode::kErrorFailed);
637     return;
638   }
639 
640   DCHECK_EQ(ServiceWorkerVersion::ACTIVATING, activating_version->status());
641   DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, activating_version->running_status())
642       << "Worker stopped too soon after it was started.";
643   int request_id = activating_version->StartRequest(
644       ServiceWorkerMetrics::EventType::ACTIVATE,
645       base::BindOnce(&ServiceWorkerRegistration::OnActivateEventFinished, this,
646                      activating_version));
647   activating_version->endpoint()->DispatchActivateEvent(
648       activating_version->CreateSimpleEventCallback(request_id));
649 }
650 
OnActivateEventFinished(scoped_refptr<ServiceWorkerVersion> activating_version,blink::ServiceWorkerStatusCode status)651 void ServiceWorkerRegistration::OnActivateEventFinished(
652     scoped_refptr<ServiceWorkerVersion> activating_version,
653     blink::ServiceWorkerStatusCode status) {
654   // Activate is prone to failing due to shutdown, because it's triggered when
655   // tabs close.
656   bool is_shutdown =
657       !context_ || context_->wrapper()->process_manager()->IsShutdown();
658   ServiceWorkerMetrics::RecordActivateEventStatus(status, is_shutdown);
659 
660   if (!context_ || activating_version != active_version() ||
661       activating_version->status() != ServiceWorkerVersion::ACTIVATING) {
662     return;
663   }
664 
665   // Normally, the worker is committed to become activated once we get here, per
666   // spec. E.g., if the script rejected waitUntil or had an unhandled exception,
667   // it should still be activated. However, if the failure occurred during
668   // shutdown, ignore it to give the worker another chance the next time the
669   // browser starts up.
670   if (is_shutdown && status != blink::ServiceWorkerStatusCode::kOk)
671     return;
672 
673   // "Run the Update State algorithm passing registration's active worker and
674   // 'activated' as the arguments."
675   activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
676   context_->registry()->UpdateToActiveState(id(), scope().GetOrigin(),
677                                             base::DoNothing());
678 }
679 
OnDeleteFinished(blink::ServiceWorkerStatusCode status)680 void ServiceWorkerRegistration::OnDeleteFinished(
681     blink::ServiceWorkerStatusCode status) {
682   for (auto& listener : listeners_)
683     listener.OnRegistrationDeleted(this);
684 }
685 
Clear()686 void ServiceWorkerRegistration::Clear() {
687   DCHECK(is_uninstalling());
688   SetStatus(Status::kUninstalled);
689   should_activate_when_ready_ = false;
690 
691   // Some callbacks, at least OnRegistrationFinishedUninstalling and
692   // NotifyDoneUninstallingRegistration, may drop their references to
693   // |this|, so protect it first.
694   // TODO(falken): Clean this up, can we call the observers from a task
695   // or make the observers more polite?
696   auto protect = base::WrapRefCounted(this);
697 
698   if (context_) {
699     context_->registry()->NotifyDoneUninstallingRegistration(
700         this, Status::kUninstalled);
701   }
702 
703   std::vector<scoped_refptr<ServiceWorkerVersion>> versions_to_doom;
704   auto mask =
705       blink::mojom::ChangedServiceWorkerObjectsMask::New(false, false, false);
706   if (installing_version_.get()) {
707     versions_to_doom.push_back(installing_version_);
708     installing_version_ = nullptr;
709     mask->installing = true;
710   }
711   if (waiting_version_.get()) {
712     versions_to_doom.push_back(waiting_version_);
713     waiting_version_ = nullptr;
714     mask->waiting = true;
715   }
716   if (active_version_.get()) {
717     versions_to_doom.push_back(active_version_);
718     active_version_ = nullptr;
719     mask->active = true;
720   }
721 
722   if (mask->installing || mask->waiting || mask->active) {
723     NotifyVersionAttributesChanged(std::move(mask));
724 
725     // Doom only after notifying attributes changed, because the spec requires
726     // the attributes to be cleared by the time the statechange event is
727     // dispatched.
728     for (const auto& version : versions_to_doom)
729       version->Doom();
730   }
731 
732   for (auto& observer : listeners_)
733     observer.OnRegistrationFinishedUninstalling(this);
734 }
735 
OnRestoreFinished(StatusCallback callback,scoped_refptr<ServiceWorkerVersion> version,blink::ServiceWorkerStatusCode status)736 void ServiceWorkerRegistration::OnRestoreFinished(
737     StatusCallback callback,
738     scoped_refptr<ServiceWorkerVersion> version,
739     blink::ServiceWorkerStatusCode status) {
740   if (!context_) {
741     std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort);
742     return;
743   }
744   context_->registry()->NotifyDoneInstallingRegistration(this, version.get(),
745                                                          status);
746   std::move(callback).Run(status);
747 }
748 
749 }  // namespace content
750