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_version.h"
6 
7 #include <stddef.h>
8 
9 #include <limits>
10 #include <map>
11 #include <string>
12 
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/debug/dump_without_crashing.h"
17 #include "base/guid.h"
18 #include "base/location.h"
19 #include "base/memory/ref_counted.h"
20 #include "base/metrics/field_trial_params.h"
21 #include "base/metrics/histogram_macros.h"
22 #include "base/single_thread_task_runner.h"
23 #include "base/stl_util.h"
24 #include "base/strings/string16.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/task/post_task.h"
27 #include "base/threading/thread_task_runner_handle.h"
28 #include "base/time/default_clock.h"
29 #include "base/time/default_tick_clock.h"
30 #include "content/browser/bad_message.h"
31 #include "content/browser/child_process_security_policy_impl.h"
32 #include "content/browser/frame_host/back_forward_cache_can_store_document_result.h"
33 #include "content/browser/service_worker/payment_handler_support.h"
34 #include "content/browser/service_worker/service_worker_consts.h"
35 #include "content/browser/service_worker/service_worker_container_host.h"
36 #include "content/browser/service_worker/service_worker_context_core.h"
37 #include "content/browser/service_worker/service_worker_context_wrapper.h"
38 #include "content/browser/service_worker/service_worker_installed_scripts_sender.h"
39 #include "content/browser/service_worker/service_worker_provider_host.h"
40 #include "content/browser/service_worker/service_worker_registration.h"
41 #include "content/common/content_navigation_policy.h"
42 #include "content/common/service_worker/service_worker_utils.h"
43 #include "content/public/browser/browser_thread.h"
44 #include "content/public/browser/content_browser_client.h"
45 #include "content/public/browser/page_navigator.h"
46 #include "content/public/browser/service_worker_external_request_result.h"
47 #include "content/public/common/content_client.h"
48 #include "content/public/common/content_features.h"
49 #include "content/public/common/result_codes.h"
50 #include "net/base/net_errors.h"
51 #include "net/http/http_response_headers.h"
52 #include "net/http/http_response_info.h"
53 #include "third_party/blink/public/common/features.h"
54 #include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
55 #include "third_party/blink/public/common/service_worker/service_worker_type_converters.h"
56 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
57 
58 namespace content {
59 namespace {
60 
61 // Timeout for an installed worker to start.
62 constexpr base::TimeDelta kStartInstalledWorkerTimeout =
63     base::TimeDelta::FromSeconds(60);
64 
65 // Timeout for a request to be handled.
66 constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromMinutes(5);
67 
68 const base::FeatureParam<int> kUpdateDelayParam{
69     &blink::features::kServiceWorkerUpdateDelay, "update_delay_in_ms", 1000};
70 
71 // The default value is set to max since it's not used when the feature is
72 // disabled. In that case, the service worker will be terminated by the idle
73 // timeout.
74 const base::FeatureParam<int> kTerminationDelayParam{
75     &features::kServiceWorkerTerminationOnNoControllee,
76     "termination_delay_in_ms", std::numeric_limits<int>::max()};
77 
78 const char kClaimClientsStateErrorMesage[] =
79     "Only the active worker can claim clients.";
80 
81 const char kClaimClientsShutdownErrorMesage[] =
82     "Failed to claim clients due to Service Worker system shutdown.";
83 
84 const char kNotRespondingErrorMesage[] = "Service Worker is not responding.";
85 const char kForceUpdateInfoMessage[] =
86     "Service Worker was updated because \"Update on reload\" was "
87     "checked in the DevTools Application panel.";
88 
RunSoon(base::OnceClosure callback)89 void RunSoon(base::OnceClosure callback) {
90   if (!callback.is_null())
91     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
92                                                   std::move(callback));
93 }
94 
95 template <typename CallbackArray, typename Arg>
RunCallbacks(ServiceWorkerVersion * version,CallbackArray * callbacks_ptr,const Arg & arg)96 void RunCallbacks(ServiceWorkerVersion* version,
97                   CallbackArray* callbacks_ptr,
98                   const Arg& arg) {
99   CallbackArray callbacks;
100   callbacks.swap(*callbacks_ptr);
101   for (auto& callback : callbacks)
102     std::move(callback).Run(arg);
103 }
104 
105 // An adapter to run a |callback| after StartWorker.
RunCallbackAfterStartWorker(base::WeakPtr<ServiceWorkerVersion> version,ServiceWorkerVersion::StatusCallback callback,blink::ServiceWorkerStatusCode status)106 void RunCallbackAfterStartWorker(base::WeakPtr<ServiceWorkerVersion> version,
107                                  ServiceWorkerVersion::StatusCallback callback,
108                                  blink::ServiceWorkerStatusCode status) {
109   if (status == blink::ServiceWorkerStatusCode::kOk &&
110       version->running_status() != EmbeddedWorkerStatus::RUNNING) {
111     // We've tried to start the worker (and it has succeeded), but
112     // it looks it's not running yet.
113     NOTREACHED() << "The worker's not running after successful StartWorker";
114     std::move(callback).Run(
115         blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed);
116     return;
117   }
118   std::move(callback).Run(status);
119 }
120 
ClearTick(base::TimeTicks * time)121 void ClearTick(base::TimeTicks* time) {
122   *time = base::TimeTicks();
123 }
124 
125 const int kInvalidTraceId = -1;
126 
NextTraceId()127 int NextTraceId() {
128   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
129   static int trace_id = 0;
130   if (trace_id == std::numeric_limits<int>::max())
131     trace_id = 0;
132   else
133     ++trace_id;
134   DCHECK_NE(kInvalidTraceId, trace_id);
135   return trace_id;
136 }
137 
OnConnectionError(base::WeakPtr<EmbeddedWorkerInstance> embedded_worker)138 void OnConnectionError(base::WeakPtr<EmbeddedWorkerInstance> embedded_worker) {
139   if (!embedded_worker)
140     return;
141 
142   switch (embedded_worker->status()) {
143     case EmbeddedWorkerStatus::STARTING:
144     case EmbeddedWorkerStatus::RUNNING:
145       // In this case the disconnection might be happening because of sudden
146       // renderer shutdown like crash.
147       embedded_worker->Detach();
148       break;
149     case EmbeddedWorkerStatus::STOPPING:
150     case EmbeddedWorkerStatus::STOPPED:
151       // Do nothing
152       break;
153   }
154 }
155 
OnOpenWindowFinished(blink::mojom::ServiceWorkerHost::OpenNewTabCallback callback,blink::ServiceWorkerStatusCode status,blink::mojom::ServiceWorkerClientInfoPtr client_info)156 void OnOpenWindowFinished(
157     blink::mojom::ServiceWorkerHost::OpenNewTabCallback callback,
158     blink::ServiceWorkerStatusCode status,
159     blink::mojom::ServiceWorkerClientInfoPtr client_info) {
160   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
161   const bool success = (status == blink::ServiceWorkerStatusCode::kOk);
162   base::Optional<std::string> error_msg;
163   if (!success) {
164     DCHECK(!client_info);
165     error_msg.emplace("Something went wrong while trying to open the window.");
166   }
167   std::move(callback).Run(success, std::move(client_info), error_msg);
168 }
169 
DidShowPaymentHandlerWindow(const GURL & url,const base::WeakPtr<ServiceWorkerContextCore> & context,blink::mojom::ServiceWorkerHost::OpenPaymentHandlerWindowCallback callback,bool success,int render_process_id,int render_frame_id)170 void DidShowPaymentHandlerWindow(
171     const GURL& url,
172     const base::WeakPtr<ServiceWorkerContextCore>& context,
173     blink::mojom::ServiceWorkerHost::OpenPaymentHandlerWindowCallback callback,
174     bool success,
175     int render_process_id,
176     int render_frame_id) {
177   if (success) {
178     service_worker_client_utils::DidNavigate(
179         context, url.GetOrigin(),
180         base::BindOnce(&OnOpenWindowFinished, std::move(callback)),
181         render_process_id, render_frame_id);
182   } else {
183     OnOpenWindowFinished(std::move(callback),
184                          blink::ServiceWorkerStatusCode::kErrorFailed,
185                          nullptr /* client_info */);
186   }
187 }
188 
DidNavigateClient(blink::mojom::ServiceWorkerHost::NavigateClientCallback callback,const GURL & url,blink::ServiceWorkerStatusCode status,blink::mojom::ServiceWorkerClientInfoPtr client)189 void DidNavigateClient(
190     blink::mojom::ServiceWorkerHost::NavigateClientCallback callback,
191     const GURL& url,
192     blink::ServiceWorkerStatusCode status,
193     blink::mojom::ServiceWorkerClientInfoPtr client) {
194   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
195   const bool success = (status == blink::ServiceWorkerStatusCode::kOk);
196   base::Optional<std::string> error_msg;
197   if (!success) {
198     DCHECK(!client);
199     error_msg.emplace("Cannot navigate to URL: " + url.spec());
200   }
201   std::move(callback).Run(success, std::move(client), error_msg);
202 }
203 
GetUpdateDelay()204 base::TimeDelta GetUpdateDelay() {
205   return base::TimeDelta::FromMilliseconds(kUpdateDelayParam.Get());
206 }
207 
208 }  // namespace
209 
210 constexpr base::TimeDelta ServiceWorkerVersion::kTimeoutTimerDelay;
211 constexpr base::TimeDelta ServiceWorkerVersion::kStartNewWorkerTimeout;
212 constexpr base::TimeDelta ServiceWorkerVersion::kStopWorkerTimeout;
213 
MainScriptResponse(const net::HttpResponseInfo & http_info)214 ServiceWorkerVersion::MainScriptResponse::MainScriptResponse(
215     const net::HttpResponseInfo& http_info) {
216   response_time = http_info.response_time;
217   if (http_info.headers)
218     http_info.headers->GetLastModifiedValue(&last_modified);
219   headers = http_info.headers;
220   ssl_info = http_info.ssl_info;
221 }
222 
MainScriptResponse(const network::mojom::URLResponseHead & response_head)223 ServiceWorkerVersion::MainScriptResponse::MainScriptResponse(
224     const network::mojom::URLResponseHead& response_head) {
225   response_time = response_head.response_time;
226   if (response_head.headers)
227     response_head.headers->GetLastModifiedValue(&last_modified);
228   headers = response_head.headers;
229   if (response_head.ssl_info.has_value())
230     ssl_info = response_head.ssl_info.value();
231 }
232 
233 ServiceWorkerVersion::MainScriptResponse::~MainScriptResponse() = default;
234 
RestartTick(base::TimeTicks * time) const235 void ServiceWorkerVersion::RestartTick(base::TimeTicks* time) const {
236   *time = tick_clock_->NowTicks();
237 }
238 
RequestExpired(const base::TimeTicks & expiration) const239 bool ServiceWorkerVersion::RequestExpired(
240     const base::TimeTicks& expiration) const {
241   if (expiration.is_null())
242     return false;
243   return tick_clock_->NowTicks() >= expiration;
244 }
245 
GetTickDuration(const base::TimeTicks & time) const246 base::TimeDelta ServiceWorkerVersion::GetTickDuration(
247     const base::TimeTicks& time) const {
248   if (time.is_null())
249     return base::TimeDelta();
250   return tick_clock_->NowTicks() - time;
251 }
252 
ServiceWorkerVersion(ServiceWorkerRegistration * registration,const GURL & script_url,blink::mojom::ScriptType script_type,int64_t version_id,base::WeakPtr<ServiceWorkerContextCore> context)253 ServiceWorkerVersion::ServiceWorkerVersion(
254     ServiceWorkerRegistration* registration,
255     const GURL& script_url,
256     blink::mojom::ScriptType script_type,
257     int64_t version_id,
258     base::WeakPtr<ServiceWorkerContextCore> context)
259     : version_id_(version_id),
260       registration_id_(registration->id()),
261       script_url_(script_url),
262       // Safe to convert GURL to Origin because service workers are restricted
263       // to secure contexts.
264       script_origin_(url::Origin::Create(script_url_)),
265       scope_(registration->scope()),
266       script_type_(script_type),
267       fetch_handler_existence_(FetchHandlerExistence::UNKNOWN),
268       site_for_uma_(ServiceWorkerMetrics::SiteFromURL(scope_)),
269       context_(context),
270       script_cache_map_(this, context),
271       tick_clock_(base::DefaultTickClock::GetInstance()),
272       clock_(base::DefaultClock::GetInstance()),
273       ping_controller_(this),
274       validator_(std::make_unique<blink::TrialTokenValidator>()) {
275   DCHECK_NE(blink::mojom::kInvalidServiceWorkerVersionId, version_id);
276   DCHECK(context_);
277   DCHECK(registration);
278   DCHECK(script_url_.is_valid());
279   embedded_worker_ = std::make_unique<EmbeddedWorkerInstance>(this);
280   embedded_worker_->AddObserver(this);
281   context_->AddLiveVersion(this);
282 }
283 
~ServiceWorkerVersion()284 ServiceWorkerVersion::~ServiceWorkerVersion() {
285   // TODO(falken): Investigate whether this can be removed. The destructor used
286   // to be more complicated and could result in various methods being called.
287   in_dtor_ = true;
288 
289   // Record UMA if the worker was trying to start. One way we get here is if the
290   // user closed the tab before the SW could start up.
291   if (!start_callbacks_.empty()) {
292     // RecordStartWorkerResult must be the first element of start_callbacks_.
293     StatusCallback record_start_worker_result = std::move(start_callbacks_[0]);
294     start_callbacks_.clear();
295     std::move(record_start_worker_result)
296         .Run(blink::ServiceWorkerStatusCode::kErrorAbort);
297   }
298 
299   if (context_)
300     context_->RemoveLiveVersion(version_id_);
301 
302   embedded_worker_->RemoveObserver(this);
303 }
304 
SetNavigationPreloadState(const blink::mojom::NavigationPreloadState & state)305 void ServiceWorkerVersion::SetNavigationPreloadState(
306     const blink::mojom::NavigationPreloadState& state) {
307   navigation_preload_state_ = state;
308 }
309 
SetStatus(Status status)310 void ServiceWorkerVersion::SetStatus(Status status) {
311   if (status_ == status)
312     return;
313 
314   TRACE_EVENT2("ServiceWorker", "ServiceWorkerVersion::SetStatus", "Script URL",
315                script_url_.spec(), "New Status", VersionStatusToString(status));
316 
317   // |fetch_handler_existence_| must be set before setting the status to
318   // INSTALLED,
319   // ACTIVATING or ACTIVATED.
320   DCHECK(fetch_handler_existence_ != FetchHandlerExistence::UNKNOWN ||
321          !(status == INSTALLED || status == ACTIVATING || status == ACTIVATED));
322 
323   status_ = status;
324   if (skip_waiting_) {
325     switch (status_) {
326       case NEW:
327         // |skip_waiting_| should not be set before the version is NEW.
328         NOTREACHED();
329         return;
330       case INSTALLING:
331         // Do nothing until INSTALLED time.
332         break;
333       case INSTALLED:
334         // Start recording the time when the version is trying to skip waiting.
335         RestartTick(&skip_waiting_time_);
336         break;
337       case ACTIVATING:
338         // Do nothing until ACTIVATED time.
339         break;
340       case ACTIVATED:
341         // Resolve skip waiting promises.
342         ClearTick(&skip_waiting_time_);
343         for (SkipWaitingCallback& callback : pending_skip_waiting_requests_) {
344           std::move(callback).Run(true);
345         }
346         pending_skip_waiting_requests_.clear();
347         break;
348       case REDUNDANT:
349         // Fail any pending skip waiting requests since this version is dead.
350         for (SkipWaitingCallback& callback : pending_skip_waiting_requests_) {
351           std::move(callback).Run(false);
352         }
353         pending_skip_waiting_requests_.clear();
354         break;
355     }
356   }
357 
358   // OnVersionStateChanged() invokes updates of the status using state
359   // change IPC at ServiceWorkerObjectHost (for JS-land on renderer process) and
360   // ServiceWorkerContextCore (for devtools and serviceworker-internals).
361   // This should be done before using the new status by
362   // |status_change_callbacks_| which sends the IPC for resolving the .ready
363   // property.
364   // TODO(shimazu): Clarify the dependency of OnVersionStateChanged and
365   // |status_change_callbacks_|
366   for (auto& observer : observers_)
367     observer.OnVersionStateChanged(this);
368 
369   std::vector<base::OnceClosure> callbacks;
370   callbacks.swap(status_change_callbacks_);
371   for (auto& callback : callbacks)
372     std::move(callback).Run();
373 
374   if (status == INSTALLED) {
375     embedded_worker_->OnWorkerVersionInstalled();
376   } else if (status == REDUNDANT) {
377     embedded_worker_->OnWorkerVersionDoomed();
378 
379     // TODO(crbug.com/951571): Remove this once we figured out the cause of
380     // invalid controller status.
381     redundant_state_callstack_ = base::debug::StackTrace();
382 
383     // Tell the storage system that this worker's script resources can now be
384     // deleted.
385     std::vector<storage::mojom::ServiceWorkerResourceRecordPtr> resources;
386     script_cache_map_.GetResources(&resources);
387     context_->storage()->PurgeResources(resources);
388   }
389 }
390 
RegisterStatusChangeCallback(base::OnceClosure callback)391 void ServiceWorkerVersion::RegisterStatusChangeCallback(
392     base::OnceClosure callback) {
393   status_change_callbacks_.push_back(std::move(callback));
394 }
395 
GetInfo()396 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
397   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
398   ServiceWorkerVersionInfo info(
399       running_status(), status(), fetch_handler_existence(), script_url(),
400       script_origin(), registration_id(), version_id(),
401       embedded_worker()->process_id(), embedded_worker()->thread_id(),
402       embedded_worker()->worker_devtools_agent_route_id());
403   for (const auto& controllee : controllee_map_) {
404     ServiceWorkerContainerHost* container_host = controllee.second;
405     info.clients.insert(std::make_pair(
406         container_host->client_uuid(),
407         ServiceWorkerClientInfo(
408             container_host->process_id(), container_host->frame_id(),
409             container_host->web_contents_getter(), container_host->type())));
410   }
411 
412   info.script_response_time = script_response_time_for_devtools_;
413   if (!main_script_response_)
414     return info;
415 
416   // If the service worker hasn't started, then |main_script_response_| is not
417   // set, so we use |script_response_time_for_devtools_| to populate |info|. If
418   // the worker has started, this value should match with the timestamp stored
419   // in |main_script_response_|.
420   DCHECK_EQ(info.script_response_time, main_script_response_->response_time);
421   info.script_last_modified = main_script_response_->last_modified;
422 
423   return info;
424 }
425 
set_fetch_handler_existence(FetchHandlerExistence existence)426 void ServiceWorkerVersion::set_fetch_handler_existence(
427     FetchHandlerExistence existence) {
428   DCHECK_EQ(fetch_handler_existence_, FetchHandlerExistence::UNKNOWN);
429   DCHECK_NE(existence, FetchHandlerExistence::UNKNOWN);
430   fetch_handler_existence_ = existence;
431   if (site_for_uma_ != ServiceWorkerMetrics::Site::OTHER)
432     return;
433   if (existence == FetchHandlerExistence::EXISTS)
434     site_for_uma_ = ServiceWorkerMetrics::Site::WITH_FETCH_HANDLER;
435   else
436     site_for_uma_ = ServiceWorkerMetrics::Site::WITHOUT_FETCH_HANDLER;
437 }
438 
StartWorker(ServiceWorkerMetrics::EventType purpose,StatusCallback callback)439 void ServiceWorkerVersion::StartWorker(ServiceWorkerMetrics::EventType purpose,
440                                        StatusCallback callback) {
441   TRACE_EVENT_INSTANT2(
442       "ServiceWorker", "ServiceWorkerVersion::StartWorker (instant)",
443       TRACE_EVENT_SCOPE_THREAD, "Script", script_url_.spec(), "Purpose",
444       ServiceWorkerMetrics::EventTypeToString(purpose));
445 
446   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
447   const bool is_browser_startup_complete =
448       GetContentClient()->browser()->IsBrowserStartupComplete();
449   if (!context_) {
450     RecordStartWorkerResult(purpose, status_, kInvalidTraceId,
451                             is_browser_startup_complete,
452                             blink::ServiceWorkerStatusCode::kErrorAbort);
453     RunSoon(base::BindOnce(std::move(callback),
454                            blink::ServiceWorkerStatusCode::kErrorAbort));
455     return;
456   }
457   if (is_redundant()) {
458     RecordStartWorkerResult(purpose, status_, kInvalidTraceId,
459                             is_browser_startup_complete,
460                             blink::ServiceWorkerStatusCode::kErrorRedundant);
461     RunSoon(base::BindOnce(std::move(callback),
462                            blink::ServiceWorkerStatusCode::kErrorRedundant));
463     return;
464   }
465   if (!IsStartWorkerAllowed()) {
466     RecordStartWorkerResult(purpose, status_, kInvalidTraceId,
467                             is_browser_startup_complete,
468                             blink::ServiceWorkerStatusCode::kErrorDisallowed);
469     RunSoon(base::BindOnce(std::move(callback),
470                            blink::ServiceWorkerStatusCode::kErrorDisallowed));
471     return;
472   }
473 
474   // Ensure the live registration during starting worker so that the worker can
475   // get associated with it in
476   // ServiceWorkerProviderHost::CompleteStartWorkerPreparation.
477   context_->registry()->FindRegistrationForId(
478       registration_id_, scope_.GetOrigin(),
479       base::BindOnce(
480           &ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker,
481           weak_factory_.GetWeakPtr(), purpose, status_,
482           is_browser_startup_complete, std::move(callback)));
483 }
484 
StopWorker(base::OnceClosure callback)485 void ServiceWorkerVersion::StopWorker(base::OnceClosure callback) {
486   TRACE_EVENT_INSTANT2("ServiceWorker",
487                        "ServiceWorkerVersion::StopWorker (instant)",
488                        TRACE_EVENT_SCOPE_THREAD, "Script", script_url_.spec(),
489                        "Status", VersionStatusToString(status_));
490 
491   switch (running_status()) {
492     case EmbeddedWorkerStatus::STARTING:
493     case EmbeddedWorkerStatus::RUNNING: {
494       // EmbeddedWorkerInstance::Stop() may synchronously call
495       // ServiceWorkerVersion::OnStopped() and destroy |this|. This protection
496       // avoids it.
497       scoped_refptr<ServiceWorkerVersion> protect = this;
498       embedded_worker_->Stop();
499       if (running_status() == EmbeddedWorkerStatus::STOPPED) {
500         RunSoon(std::move(callback));
501         return;
502       }
503       stop_callbacks_.push_back(std::move(callback));
504 
505       // Protect |this| until Stop() correctly finished. Otherwise the
506       // |stop_callbacks_| might not be called. The destruction of |this| could
507       // happen before the message OnStopped() when the final
508       // ServiceWorkerObjectHost is destructed because of the termination.
509       // Note that this isn't necessary to be the final element of
510       // |stop_callbacks_| because there's another logic to protect |this| when
511       // calling |stop_callbacks_|.
512       stop_callbacks_.push_back(base::BindOnce(
513           [](scoped_refptr<content::ServiceWorkerVersion>) {}, protect));
514       return;
515     }
516     case EmbeddedWorkerStatus::STOPPING:
517       stop_callbacks_.push_back(std::move(callback));
518       return;
519     case EmbeddedWorkerStatus::STOPPED:
520       RunSoon(std::move(callback));
521       return;
522   }
523   NOTREACHED();
524 }
525 
TriggerIdleTerminationAsap()526 void ServiceWorkerVersion::TriggerIdleTerminationAsap() {
527   needs_to_be_terminated_asap_ = true;
528   endpoint()->SetIdleDelay(base::TimeDelta::FromSeconds(0));
529 }
530 
OnRequestTermination()531 bool ServiceWorkerVersion::OnRequestTermination() {
532   if (running_status() == EmbeddedWorkerStatus::STOPPING)
533     return true;
534   DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, running_status());
535 
536   worker_is_idle_on_renderer_ = true;
537 
538   // Determine if the worker can be terminated.
539   bool will_be_terminated = HasNoWork();
540   if (embedded_worker_->devtools_attached()) {
541     // Basically the service worker won't be terminated if DevTools is attached.
542     // But when activation is happening and this worker needs to be terminated
543     // asap, it'll be terminated.
544     will_be_terminated = needs_to_be_terminated_asap_;
545   }
546 
547   if (will_be_terminated) {
548     embedded_worker_->Stop();
549   } else {
550     // The worker needs to run more. The worker should start handling queued
551     // events dispatched to the worker directly (e.g. FetchEvent for
552     // subresources).
553     worker_is_idle_on_renderer_ = false;
554   }
555 
556   return will_be_terminated;
557 }
558 
ScheduleUpdate()559 void ServiceWorkerVersion::ScheduleUpdate() {
560   if (!context_)
561     return;
562   if (update_timer_.IsRunning()) {
563     update_timer_.Reset();
564     return;
565   }
566   if (is_update_scheduled_)
567     return;
568   is_update_scheduled_ = true;
569 
570   // Protect |this| until the timer fires, since we may be stopping
571   // and soon no one might hold a reference to us.
572   context_->ProtectVersion(base::WrapRefCounted(this));
573 
574   update_timer_.Start(FROM_HERE, GetUpdateDelay(),
575                       base::BindOnce(&ServiceWorkerVersion::StartUpdate,
576                                      weak_factory_.GetWeakPtr()));
577 }
578 
StartUpdate()579 void ServiceWorkerVersion::StartUpdate() {
580   if (!context_)
581     return;
582   context_->registry()->FindRegistrationForId(
583       registration_id_, scope_.GetOrigin(),
584       base::BindOnce(&ServiceWorkerVersion::FoundRegistrationForUpdate,
585                      weak_factory_.GetWeakPtr()));
586 }
587 
StartRequest(ServiceWorkerMetrics::EventType event_type,StatusCallback error_callback)588 int ServiceWorkerVersion::StartRequest(
589     ServiceWorkerMetrics::EventType event_type,
590     StatusCallback error_callback) {
591   return StartRequestWithCustomTimeout(event_type, std::move(error_callback),
592                                        kRequestTimeout, KILL_ON_TIMEOUT);
593 }
594 
StartRequestWithCustomTimeout(ServiceWorkerMetrics::EventType event_type,StatusCallback error_callback,const base::TimeDelta & timeout,TimeoutBehavior timeout_behavior)595 int ServiceWorkerVersion::StartRequestWithCustomTimeout(
596     ServiceWorkerMetrics::EventType event_type,
597     StatusCallback error_callback,
598     const base::TimeDelta& timeout,
599     TimeoutBehavior timeout_behavior) {
600   DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, running_status())
601       << "Can only start a request with a running worker.";
602   DCHECK(event_type == ServiceWorkerMetrics::EventType::INSTALL ||
603          event_type == ServiceWorkerMetrics::EventType::ACTIVATE ||
604          event_type == ServiceWorkerMetrics::EventType::MESSAGE ||
605          event_type == ServiceWorkerMetrics::EventType::EXTERNAL_REQUEST ||
606          status() == ACTIVATED)
607       << "Event of type " << static_cast<int>(event_type)
608       << " can only be dispatched to an active worker: " << status();
609 
610   // |context_| is needed for some bookkeeping. If there's no context, the
611   // request will be aborted soon, so don't bother aborting the request directly
612   // here, and just skip this bookkeeping.
613   if (context_) {
614     if (event_type != ServiceWorkerMetrics::EventType::INSTALL &&
615         event_type != ServiceWorkerMetrics::EventType::ACTIVATE &&
616         event_type != ServiceWorkerMetrics::EventType::MESSAGE) {
617       // Reset the self-update delay iff this is not an event that can triggered
618       // by a service worker itself. Otherwise, service workers can use update()
619       // to keep running forever via install and activate events, or
620       // postMessage() between themselves to reset the delay via message event.
621       // postMessage() resets the delay in ServiceWorkerObjectHost, iff it
622       // didn't come from a service worker.
623       ServiceWorkerRegistration* registration =
624           context_->GetLiveRegistration(registration_id_);
625       DCHECK(registration) << "running workers should have a live registration";
626       registration->set_self_update_delay(base::TimeDelta());
627     }
628   }
629 
630   auto request = std::make_unique<InflightRequest>(
631       std::move(error_callback), clock_->Now(), tick_clock_->NowTicks(),
632       event_type);
633   InflightRequest* request_rawptr = request.get();
634   int request_id = inflight_requests_.Add(std::move(request));
635   TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerVersion::Request",
636                            request_rawptr, "Request id", request_id,
637                            "Event type",
638                            ServiceWorkerMetrics::EventTypeToString(event_type));
639 
640   base::TimeTicks expiration_time = tick_clock_->NowTicks() + timeout;
641   bool is_inserted = false;
642   std::set<InflightRequestTimeoutInfo>::iterator iter;
643   std::tie(iter, is_inserted) = request_timeouts_.emplace(
644       request_id, event_type, expiration_time, timeout_behavior);
645   DCHECK(is_inserted);
646   request_rawptr->timeout_iter = iter;
647   if (expiration_time > max_request_expiration_time_)
648     max_request_expiration_time_ = expiration_time;
649 
650   // Even if the worker is in the idle state, the new event which is about to
651   // be dispatched will reset the idle status. That means the worker can receive
652   // events directly from any client, so we cannot trigger OnNoWork after this
653   // point.
654   worker_is_idle_on_renderer_ = false;
655   return request_id;
656 }
657 
StartExternalRequest(const std::string & request_uuid)658 ServiceWorkerExternalRequestResult ServiceWorkerVersion::StartExternalRequest(
659     const std::string& request_uuid) {
660   if (running_status() == EmbeddedWorkerStatus::STARTING) {
661     return pending_external_requests_.insert(request_uuid).second
662                ? ServiceWorkerExternalRequestResult::kOk
663                : ServiceWorkerExternalRequestResult::kBadRequestId;
664   }
665 
666   if (running_status() == EmbeddedWorkerStatus::STOPPING ||
667       running_status() == EmbeddedWorkerStatus::STOPPED) {
668     return ServiceWorkerExternalRequestResult::kWorkerNotRunning;
669   }
670 
671   if (external_request_uuid_to_request_id_.count(request_uuid) > 0u)
672     return ServiceWorkerExternalRequestResult::kBadRequestId;
673 
674   int request_id =
675       StartRequest(ServiceWorkerMetrics::EventType::EXTERNAL_REQUEST,
676                    base::BindOnce(&ServiceWorkerVersion::CleanUpExternalRequest,
677                                   this, request_uuid));
678   external_request_uuid_to_request_id_[request_uuid] = request_id;
679   return ServiceWorkerExternalRequestResult::kOk;
680 }
681 
FinishRequest(int request_id,bool was_handled)682 bool ServiceWorkerVersion::FinishRequest(int request_id, bool was_handled) {
683   InflightRequest* request = inflight_requests_.Lookup(request_id);
684   if (!request)
685     return false;
686   ServiceWorkerMetrics::RecordEventDuration(
687       request->event_type, tick_clock_->NowTicks() - request->start_time_ticks,
688       was_handled);
689 
690   TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
691                          request, "Handled", was_handled);
692   request_timeouts_.erase(request->timeout_iter);
693   inflight_requests_.Remove(request_id);
694 
695   if (!HasWorkInBrowser())
696     OnNoWorkInBrowser();
697   return true;
698 }
699 
FinishExternalRequest(const std::string & request_uuid)700 ServiceWorkerExternalRequestResult ServiceWorkerVersion::FinishExternalRequest(
701     const std::string& request_uuid) {
702   if (running_status() == EmbeddedWorkerStatus::STARTING)
703     return pending_external_requests_.erase(request_uuid) > 0u
704                ? ServiceWorkerExternalRequestResult::kOk
705                : ServiceWorkerExternalRequestResult::kBadRequestId;
706 
707   // If it's STOPPED, there is no request to finish. We could just consider this
708   // a success, but the caller may want to know about it. (If it's STOPPING,
709   // proceed with finishing the request as normal.)
710   if (running_status() == EmbeddedWorkerStatus::STOPPED)
711     return ServiceWorkerExternalRequestResult::kWorkerNotRunning;
712 
713   auto iter = external_request_uuid_to_request_id_.find(request_uuid);
714   if (iter != external_request_uuid_to_request_id_.end()) {
715     int request_id = iter->second;
716     external_request_uuid_to_request_id_.erase(iter);
717     return FinishRequest(request_id, true)
718                ? ServiceWorkerExternalRequestResult::kOk
719                : ServiceWorkerExternalRequestResult::kBadRequestId;
720   }
721 
722   // It is possible that the request was cancelled or timed out before and we
723   // won't find it in |external_request_uuid_to_request_id_|. Just return
724   // kOk.
725   // TODO(falken): Consider keeping track of these so we can return
726   // kBadRequestId for invalid requests ids.
727   return ServiceWorkerExternalRequestResult::kOk;
728 }
729 
730 ServiceWorkerVersion::SimpleEventCallback
CreateSimpleEventCallback(int request_id)731 ServiceWorkerVersion::CreateSimpleEventCallback(int request_id) {
732   // The weak reference to |this| is safe because storage of the callbacks, the
733   // inflight responses of blink::mojom::ServiceWorker messages, is owned by
734   // |this|.
735   return base::BindOnce(&ServiceWorkerVersion::OnSimpleEventFinished,
736                         base::Unretained(this), request_id);
737 }
738 
RunAfterStartWorker(ServiceWorkerMetrics::EventType purpose,StatusCallback callback)739 void ServiceWorkerVersion::RunAfterStartWorker(
740     ServiceWorkerMetrics::EventType purpose,
741     StatusCallback callback) {
742   if (running_status() == EmbeddedWorkerStatus::RUNNING) {
743     DCHECK(start_callbacks_.empty());
744     std::move(callback).Run(blink::ServiceWorkerStatusCode::kOk);
745     return;
746   }
747   StartWorker(purpose,
748               base::BindOnce(&RunCallbackAfterStartWorker,
749                              weak_factory_.GetWeakPtr(), std::move(callback)));
750 }
751 
AddControllee(ServiceWorkerContainerHost * container_host)752 void ServiceWorkerVersion::AddControllee(
753     ServiceWorkerContainerHost* container_host) {
754   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
755   // TODO(crbug.com/1021718): Remove this CHECK once we figure out the cause of
756   // crash.
757   CHECK(container_host);
758   const std::string& uuid = container_host->client_uuid();
759   CHECK(!container_host->client_uuid().empty());
760   // TODO(crbug.com/1021718): Change to DCHECK once we figure out the cause of
761   // crash.
762   CHECK(!base::Contains(controllee_map_, uuid));
763 
764   // TODO(yuzus, crbug.com/951571): Remove these CHECKs once we figure out the
765   // cause of crash.
766   CHECK_NE(status_, NEW);
767   CHECK_NE(status_, INSTALLING);
768   CHECK_NE(status_, INSTALLED);
769   CHECK_NE(status_, REDUNDANT);
770 
771   if (base::FeatureList::IsEnabled(
772           features::kServiceWorkerTerminationOnNoControllee) &&
773       !HasControllee()) {
774     // If the service worker starts to control a new client and the service
775     // worker needs to work, let's extend the idle timeout to the default value.
776     UpdateIdleDelayIfNeeded(base::TimeDelta::FromSeconds(
777         blink::mojom::kServiceWorkerDefaultIdleDelayInSeconds));
778   }
779 
780   controllee_map_[uuid] = container_host;
781   embedded_worker_->UpdateForegroundPriority();
782   ClearTick(&no_controllees_time_);
783 
784   ServiceWorkerRegistration* registration =
785       context_->GetLiveRegistration(registration_id_);
786   if (registration) {
787     registration->set_self_update_delay(base::TimeDelta());
788   }
789 
790   // Notify observers asynchronously for consistency with RemoveControllee.
791   base::ThreadTaskRunnerHandle::Get()->PostTask(
792       FROM_HERE,
793       base::BindOnce(
794           &ServiceWorkerVersion::NotifyControlleeAdded,
795           weak_factory_.GetWeakPtr(), uuid,
796           ServiceWorkerClientInfo(
797               container_host->process_id(), container_host->frame_id(),
798               container_host->web_contents_getter(), container_host->type())));
799 }
800 
RemoveControllee(const std::string & client_uuid)801 void ServiceWorkerVersion::RemoveControllee(const std::string& client_uuid) {
802   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
803   DCHECK(base::Contains(controllee_map_, client_uuid));
804   controllee_map_.erase(client_uuid);
805 
806   embedded_worker_->UpdateForegroundPriority();
807 
808   // Notify observers asynchronously since this gets called during
809   // ServiceWorkerProviderHost's destructor, and we don't want observers to do
810   // work during that.
811   base::ThreadTaskRunnerHandle::Get()->PostTask(
812       FROM_HERE, base::BindOnce(&ServiceWorkerVersion::NotifyControlleeRemoved,
813                                 weak_factory_.GetWeakPtr(), client_uuid));
814 
815   if (base::FeatureList::IsEnabled(
816           features::kServiceWorkerTerminationOnNoControllee) &&
817       !HasControllee()) {
818     // Terminate the worker after all controllees are gone with a delay set by
819     // |kTerminationDelayParam|, which is provided by the field trial.
820     // When a new controllee checks in before the delay passes, the idle delay
821     // is set to the default in AddControllee().
822     UpdateIdleDelayIfNeeded(
823         base::TimeDelta::FromMilliseconds(kTerminationDelayParam.Get()));
824   }
825 }
826 
MoveControlleeToBackForwardCacheMap(const std::string & client_uuid)827 void ServiceWorkerVersion::MoveControlleeToBackForwardCacheMap(
828     const std::string& client_uuid) {
829   DCHECK(IsBackForwardCacheEnabled());
830   DCHECK(base::Contains(controllee_map_, client_uuid));
831   DCHECK(!base::Contains(bfcached_controllee_map_, client_uuid));
832   bfcached_controllee_map_[client_uuid] = controllee_map_[client_uuid];
833   RemoveControllee(client_uuid);
834 }
835 
RestoreControlleeFromBackForwardCacheMap(const std::string & client_uuid)836 void ServiceWorkerVersion::RestoreControlleeFromBackForwardCacheMap(
837     const std::string& client_uuid) {
838   // TODO(crbug.com/1021718): Change these to DCHECK once we figure out the
839   // cause of crash.
840   CHECK(IsBackForwardCacheEnabled());
841   CHECK(!base::Contains(controllee_map_, client_uuid));
842   if (!base::Contains(bfcached_controllee_map_, client_uuid)) {
843     // We are navigating to the page using BackForwardCache, which is being
844     // evicted due to activation, postMessage or claim. In this case, we reload
845     // the page without using BackForwardCache, so we can assume that
846     // ContainerHost will be deleted soon.
847     // TODO(crbug.com/1021718): Remove this CHECK once we fix the crash.
848     CHECK(base::Contains(controllees_to_be_evicted_, client_uuid));
849     // TODO(crbug.com/1021718): Remove DumpWithoutCrashing once we confirm the
850     // cause of the crash.
851     static auto* no_controllee_reason = base::debug::AllocateCrashKeyString(
852         "no_controllee_reason", base::debug::CrashKeySize::Size32);
853     BackForwardCacheCanStoreDocumentResult can_store;
854     can_store.No(controllees_to_be_evicted_.at(client_uuid));
855     base::debug::ScopedCrashKeyString scoped_no_controllee_reason(
856         no_controllee_reason, can_store.ToString());
857     base::debug::DumpWithoutCrashing();
858     return;
859   }
860   AddControllee(bfcached_controllee_map_.at(client_uuid));
861   bfcached_controllee_map_.erase(client_uuid);
862 }
863 
RemoveControlleeFromBackForwardCacheMap(const std::string & client_uuid)864 void ServiceWorkerVersion::RemoveControlleeFromBackForwardCacheMap(
865     const std::string& client_uuid) {
866   DCHECK(IsBackForwardCacheEnabled());
867   DCHECK(base::Contains(bfcached_controllee_map_, client_uuid));
868   bfcached_controllee_map_.erase(client_uuid);
869 }
870 
OnControlleeDestroyed(const std::string & client_uuid)871 void ServiceWorkerVersion::OnControlleeDestroyed(
872     const std::string& client_uuid) {
873   if (!IsBackForwardCacheEnabled()) {
874     RemoveControllee(client_uuid);
875   } else {
876     if (base::Contains(controllee_map_, client_uuid)) {
877       RemoveControllee(client_uuid);
878     } else if (base::Contains(bfcached_controllee_map_, client_uuid)) {
879       RemoveControlleeFromBackForwardCacheMap(client_uuid);
880     } else {
881       // It is possible that the controllee belongs to neither |controllee_map_|
882       // or |bfcached_controllee_map_|. This happens when a BackForwardCached
883       // controllee is deleted after eviction, which has already removed it from
884       // |bfcached_controllee_map_|.
885       // In this case, |controllees_to_be_evicted_| should contain the
886       // controllee.
887       // TODO(crbug.com/1021718): Remove this CHECK once we fix the crash.
888       CHECK(base::Contains(controllees_to_be_evicted_, client_uuid));
889       controllees_to_be_evicted_.erase(client_uuid);
890     }
891   }
892 }
893 
EvictBackForwardCachedControllees(BackForwardCacheMetrics::NotRestoredReason reason)894 void ServiceWorkerVersion::EvictBackForwardCachedControllees(
895     BackForwardCacheMetrics::NotRestoredReason reason) {
896   DCHECK(IsBackForwardCacheEnabled());
897   while (!bfcached_controllee_map_.empty()) {
898     auto controllee = bfcached_controllee_map_.begin();
899     EvictBackForwardCachedControllee(controllee->second, reason);
900   }
901 }
902 
EvictBackForwardCachedControllee(ServiceWorkerContainerHost * controllee,BackForwardCacheMetrics::NotRestoredReason reason)903 void ServiceWorkerVersion::EvictBackForwardCachedControllee(
904     ServiceWorkerContainerHost* controllee,
905     BackForwardCacheMetrics::NotRestoredReason reason) {
906   controllee->EvictFromBackForwardCache(reason);
907   controllees_to_be_evicted_[controllee->client_uuid()] = reason;
908   RemoveControlleeFromBackForwardCacheMap(controllee->client_uuid());
909 }
910 
AddObserver(Observer * observer)911 void ServiceWorkerVersion::AddObserver(Observer* observer) {
912   observers_.AddObserver(observer);
913 }
914 
RemoveObserver(Observer * observer)915 void ServiceWorkerVersion::RemoveObserver(Observer* observer) {
916   observers_.RemoveObserver(observer);
917 }
918 
ReportError(blink::ServiceWorkerStatusCode status,const std::string & status_message)919 void ServiceWorkerVersion::ReportError(blink::ServiceWorkerStatusCode status,
920                                        const std::string& status_message) {
921   if (status_message.empty()) {
922     OnReportException(
923         base::UTF8ToUTF16(blink::ServiceWorkerStatusToString(status)), -1, -1,
924         GURL());
925   } else {
926     OnReportException(base::UTF8ToUTF16(status_message), -1, -1, GURL());
927   }
928 }
929 
ReportForceUpdateToDevTools()930 void ServiceWorkerVersion::ReportForceUpdateToDevTools() {
931   AddMessageToConsole(blink::mojom::ConsoleMessageLevel::kWarning,
932                       kForceUpdateInfoMessage);
933 }
934 
SetStartWorkerStatusCode(blink::ServiceWorkerStatusCode status)935 void ServiceWorkerVersion::SetStartWorkerStatusCode(
936     blink::ServiceWorkerStatusCode status) {
937   start_worker_status_ = status;
938 }
939 
Doom()940 void ServiceWorkerVersion::Doom() {
941   // Protect |this| because NotifyControllerLost() and Stop() callees
942   // may drop references to |this|.
943   scoped_refptr<ServiceWorkerVersion> protect(this);
944 
945   // Tell controllees that this version is dead. Each controllee will call
946   // ServiceWorkerVersion::RemoveControllee(), so be careful with iterators.
947   auto iter = controllee_map_.begin();
948   while (iter != controllee_map_.end()) {
949     ServiceWorkerContainerHost* container_host = iter->second;
950     ++iter;
951     container_host->NotifyControllerLost();
952   }
953   // Any controllee this version had should have removed itself.
954   DCHECK(!HasControllee());
955 
956   SetStatus(REDUNDANT);
957   if (running_status() == EmbeddedWorkerStatus::STARTING ||
958       running_status() == EmbeddedWorkerStatus::RUNNING) {
959     // |start_worker_status_| == kErrorExists means that this version was
960     // created for update but the script was identical to the incumbent version.
961     // In this case we should stop the worker immediately even when DevTools is
962     // attached. Otherwise the redundant worker stays as a selectable context
963     // in DevTools' console.
964     // TODO(bashi): Remove this workaround when byte-for-byte update check is
965     // shipped.
966     bool stop_immediately =
967         start_worker_status_ == blink::ServiceWorkerStatusCode::kErrorExists;
968     if (stop_immediately || !embedded_worker()->devtools_attached()) {
969       embedded_worker_->Stop();
970     } else {
971       stop_when_devtools_detached_ = true;
972     }
973   }
974 }
975 
OnMainScriptLoaded()976 void ServiceWorkerVersion::OnMainScriptLoaded() {
977   if (!initialize_global_scope_after_main_script_loaded_)
978     return;
979   initialize_global_scope_after_main_script_loaded_ = false;
980 
981   int net_error = script_cache_map()->main_script_net_error();
982   if (net_error != net::OK)
983     return;
984 
985   // The subresource loaders need to be updated. Get the factories with the
986   // correct COEP value and pass it to the service worker.
987   //
988   // TODO(https://crbug.com/1039613): Update the loader factories passed to the
989   // script loader factory too.
990   DCHECK_EQ(NEW, status());
991   embedded_worker_->CreateFactoryBundles(
992       base::BindOnce(&ServiceWorkerVersion::InitializeGlobalScope,
993                      weak_factory_.GetWeakPtr()));
994 }
995 
InitializeGlobalScope(std::unique_ptr<blink::PendingURLLoaderFactoryBundle> script_loader_factories,std::unique_ptr<blink::PendingURLLoaderFactoryBundle> subresource_loader_factories)996 void ServiceWorkerVersion::InitializeGlobalScope(
997     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
998         script_loader_factories,
999     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
1000         subresource_loader_factories) {
1001   DCHECK(service_worker_host_);
1002   scoped_refptr<ServiceWorkerRegistration> registration =
1003       base::WrapRefCounted(context_->GetLiveRegistration(registration_id_));
1004   // The registration must exist since we keep a reference to it during
1005   // service worker startup.
1006   DCHECK(registration);
1007 
1008   if (subresource_loader_factories) {
1009     // |subresource_loader_factories| is valid only when the service worker is
1010     // a new worker.
1011     DCHECK_EQ(NEW, status());
1012 
1013     // |script_loader_factories| should be updated too.
1014     DCHECK(script_loader_factories);
1015     embedded_worker_->UpdateLoaderFactories(
1016         std::move(script_loader_factories),
1017         /*subresource_loader_factories=*/nullptr);
1018   }
1019 
1020   DCHECK(provider_host_);
1021   service_worker_remote_->InitializeGlobalScope(
1022       std::move(service_worker_host_),
1023       provider_host_->container_host()
1024           ->CreateServiceWorkerRegistrationObjectInfo(std::move(registration)),
1025       provider_host_->container_host()->CreateServiceWorkerObjectInfoToSend(
1026           this),
1027       fetch_handler_existence_, std::move(subresource_loader_factories));
1028 }
1029 
SetValidOriginTrialTokens(const blink::TrialTokenValidator::FeatureToTokensMap & tokens)1030 void ServiceWorkerVersion::SetValidOriginTrialTokens(
1031     const blink::TrialTokenValidator::FeatureToTokensMap& tokens) {
1032   origin_trial_tokens_ = validator_->GetValidTokens(
1033       url::Origin::Create(scope()), tokens, clock_->Now());
1034 }
1035 
SetDevToolsAttached(bool attached)1036 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
1037   embedded_worker()->SetDevToolsAttached(attached);
1038 
1039   if (stop_when_devtools_detached_ && !attached) {
1040     DCHECK_EQ(REDUNDANT, status());
1041     if (running_status() == EmbeddedWorkerStatus::STARTING ||
1042         running_status() == EmbeddedWorkerStatus::RUNNING) {
1043       embedded_worker_->Stop();
1044     }
1045     return;
1046   }
1047   if (attached) {
1048     // TODO(falken): Canceling the timeouts when debugging could cause
1049     // heisenbugs; we should instead run them as normal show an educational
1050     // message in DevTools when they occur. crbug.com/470419
1051 
1052     // Don't record the startup time metric once DevTools is attached.
1053     ClearTick(&start_time_);
1054     skip_recording_startup_time_ = true;
1055 
1056     // Cancel request timeouts.
1057     SetAllRequestExpirations(base::TimeTicks());
1058     return;
1059   }
1060   if (!start_callbacks_.empty()) {
1061     // Reactivate the timer for start timeout.
1062     DCHECK(timeout_timer_.IsRunning());
1063     DCHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
1064            running_status() == EmbeddedWorkerStatus::STOPPING)
1065         << static_cast<int>(running_status());
1066     RestartTick(&start_time_);
1067   }
1068 
1069   // Reactivate request timeouts, setting them all to the same expiration time.
1070   SetAllRequestExpirations(tick_clock_->NowTicks() + kRequestTimeout);
1071 }
1072 
SetMainScriptResponse(std::unique_ptr<MainScriptResponse> response)1073 void ServiceWorkerVersion::SetMainScriptResponse(
1074     std::unique_ptr<MainScriptResponse> response) {
1075   script_response_time_for_devtools_ = response->response_time;
1076   main_script_response_ = std::move(response);
1077 
1078   // Updates |origin_trial_tokens_| if it is not set yet. This happens when:
1079   //  1) The worker is a new one.
1080   //  OR
1081   //  2) The worker is an existing one but the entry in ServiceWorkerDatabase
1082   //     was written by old version Chrome (< M56), so |origin_trial_tokens|
1083   //     wasn't set in the entry.
1084   if (!origin_trial_tokens_) {
1085     origin_trial_tokens_ = validator_->GetValidTokensFromHeaders(
1086         url::Origin::Create(scope()), main_script_response_->headers.get(),
1087         clock_->Now());
1088   }
1089 
1090   if (context_) {
1091     context_->OnMainScriptResponseSet(version_id(), *main_script_response_);
1092   }
1093 }
1094 
SimulatePingTimeoutForTesting()1095 void ServiceWorkerVersion::SimulatePingTimeoutForTesting() {
1096   ping_controller_.SimulateTimeoutForTesting();
1097 }
1098 
SetTickClockForTesting(const base::TickClock * tick_clock)1099 void ServiceWorkerVersion::SetTickClockForTesting(
1100     const base::TickClock* tick_clock) {
1101   tick_clock_ = tick_clock;
1102 }
1103 
SetClockForTesting(base::Clock * clock)1104 void ServiceWorkerVersion::SetClockForTesting(base::Clock* clock) {
1105   clock_ = clock;
1106 }
1107 
HasNoWork() const1108 bool ServiceWorkerVersion::HasNoWork() const {
1109   return !HasWorkInBrowser() && worker_is_idle_on_renderer_;
1110 }
1111 
1112 const ServiceWorkerVersion::MainScriptResponse*
GetMainScriptResponse()1113 ServiceWorkerVersion::GetMainScriptResponse() {
1114   return main_script_response_.get();
1115 }
1116 
InflightRequestTimeoutInfo(int id,ServiceWorkerMetrics::EventType event_type,const base::TimeTicks & expiration,TimeoutBehavior timeout_behavior)1117 ServiceWorkerVersion::InflightRequestTimeoutInfo::InflightRequestTimeoutInfo(
1118     int id,
1119     ServiceWorkerMetrics::EventType event_type,
1120     const base::TimeTicks& expiration,
1121     TimeoutBehavior timeout_behavior)
1122     : id(id),
1123       event_type(event_type),
1124       expiration(expiration),
1125       timeout_behavior(timeout_behavior) {}
1126 
1127 ServiceWorkerVersion::InflightRequestTimeoutInfo::
~InflightRequestTimeoutInfo()1128     ~InflightRequestTimeoutInfo() {}
1129 
operator <(const InflightRequestTimeoutInfo & other) const1130 bool ServiceWorkerVersion::InflightRequestTimeoutInfo::operator<(
1131     const InflightRequestTimeoutInfo& other) const {
1132   if (expiration == other.expiration)
1133     return id < other.id;
1134   return expiration < other.expiration;
1135 }
1136 
InflightRequest(StatusCallback callback,base::Time time,const base::TimeTicks & time_ticks,ServiceWorkerMetrics::EventType event_type)1137 ServiceWorkerVersion::InflightRequest::InflightRequest(
1138     StatusCallback callback,
1139     base::Time time,
1140     const base::TimeTicks& time_ticks,
1141     ServiceWorkerMetrics::EventType event_type)
1142     : error_callback(std::move(callback)),
1143       start_time(time),
1144       start_time_ticks(time_ticks),
1145       event_type(event_type) {}
1146 
~InflightRequest()1147 ServiceWorkerVersion::InflightRequest::~InflightRequest() {}
1148 
OnScriptEvaluationStart()1149 void ServiceWorkerVersion::OnScriptEvaluationStart() {
1150   DCHECK_EQ(EmbeddedWorkerStatus::STARTING, running_status());
1151   // Activate ping/pong now that JavaScript execution will start.
1152   ping_controller_.Activate();
1153 }
1154 
OnStarting()1155 void ServiceWorkerVersion::OnStarting() {
1156   for (auto& observer : observers_)
1157     observer.OnRunningStateChanged(this);
1158 }
1159 
OnStarted(blink::mojom::ServiceWorkerStartStatus start_status,bool has_fetch_handler)1160 void ServiceWorkerVersion::OnStarted(
1161     blink::mojom::ServiceWorkerStartStatus start_status,
1162     bool has_fetch_handler) {
1163   DCHECK_EQ(EmbeddedWorkerStatus::RUNNING, running_status());
1164 
1165   // TODO(falken): This maps kAbruptCompletion to kErrorScriptEvaluated, which
1166   // most start callbacks will consider to be a failure. But the worker thread
1167   // is running, and the spec considers it a success, so the callbacks should
1168   // change to treat kErrorScriptEvaluated as success, or use
1169   // ServiceWorkerStartStatus directly.
1170   blink::ServiceWorkerStatusCode status =
1171       mojo::ConvertTo<blink::ServiceWorkerStatusCode>(start_status);
1172 
1173   if (status == blink::ServiceWorkerStatusCode::kOk &&
1174       fetch_handler_existence_ == FetchHandlerExistence::UNKNOWN)
1175     set_fetch_handler_existence(has_fetch_handler
1176                                     ? FetchHandlerExistence::EXISTS
1177                                     : FetchHandlerExistence::DOES_NOT_EXIST);
1178 
1179   // Fire all start callbacks.
1180   scoped_refptr<ServiceWorkerVersion> protect(this);
1181   FinishStartWorker(status);
1182   for (auto& observer : observers_)
1183     observer.OnRunningStateChanged(this);
1184 
1185   if (!pending_external_requests_.empty()) {
1186     std::set<std::string> pending_external_requests;
1187     std::swap(pending_external_requests_, pending_external_requests);
1188     for (const std::string& request_uuid : pending_external_requests)
1189       StartExternalRequest(request_uuid);
1190   }
1191 }
1192 
OnStopping()1193 void ServiceWorkerVersion::OnStopping() {
1194   DCHECK(stop_time_.is_null());
1195   RestartTick(&stop_time_);
1196   TRACE_EVENT_ASYNC_BEGIN2("ServiceWorker", "ServiceWorkerVersion::StopWorker",
1197                            stop_time_.since_origin().InMicroseconds(), "Script",
1198                            script_url_.spec(), "Version Status",
1199                            VersionStatusToString(status_));
1200 
1201   // Shorten the interval so stalling in stopped can be fixed quickly. Once the
1202   // worker stops, the timer is disabled. The interval will be reset to normal
1203   // when the worker starts up again.
1204   SetTimeoutTimerInterval(kStopWorkerTimeout);
1205   for (auto& observer : observers_)
1206     observer.OnRunningStateChanged(this);
1207 }
1208 
OnStopped(EmbeddedWorkerStatus old_status)1209 void ServiceWorkerVersion::OnStopped(EmbeddedWorkerStatus old_status) {
1210   if (IsInstalled(status())) {
1211     ServiceWorkerMetrics::RecordWorkerStopped(
1212         ServiceWorkerMetrics::StopStatus::NORMAL);
1213   }
1214   if (!stop_time_.is_null())
1215     ServiceWorkerMetrics::RecordStopWorkerTime(GetTickDuration(stop_time_));
1216 
1217   OnStoppedInternal(old_status);
1218 }
1219 
OnDetached(EmbeddedWorkerStatus old_status)1220 void ServiceWorkerVersion::OnDetached(EmbeddedWorkerStatus old_status) {
1221   if (IsInstalled(status())) {
1222     ServiceWorkerMetrics::RecordWorkerStopped(
1223         ServiceWorkerMetrics::StopStatus::DETACH_BY_REGISTRY);
1224   }
1225   OnStoppedInternal(old_status);
1226 }
1227 
OnRegisteredToDevToolsManager()1228 void ServiceWorkerVersion::OnRegisteredToDevToolsManager() {
1229   for (auto& observer : observers_)
1230     observer.OnDevToolsRoutingIdChanged(this);
1231 }
1232 
OnReportException(const base::string16 & error_message,int line_number,int column_number,const GURL & source_url)1233 void ServiceWorkerVersion::OnReportException(
1234     const base::string16& error_message,
1235     int line_number,
1236     int column_number,
1237     const GURL& source_url) {
1238   for (auto& observer : observers_) {
1239     observer.OnErrorReported(this, error_message, line_number, column_number,
1240                              source_url);
1241   }
1242 }
1243 
OnReportConsoleMessage(blink::mojom::ConsoleMessageSource source,blink::mojom::ConsoleMessageLevel message_level,const base::string16 & message,int line_number,const GURL & source_url)1244 void ServiceWorkerVersion::OnReportConsoleMessage(
1245     blink::mojom::ConsoleMessageSource source,
1246     blink::mojom::ConsoleMessageLevel message_level,
1247     const base::string16& message,
1248     int line_number,
1249     const GURL& source_url) {
1250   for (auto& observer : observers_) {
1251     observer.OnReportConsoleMessage(this, source, message_level, message,
1252                                     line_number, source_url);
1253   }
1254 }
1255 
OnStartSent(blink::ServiceWorkerStatusCode status)1256 void ServiceWorkerVersion::OnStartSent(blink::ServiceWorkerStatusCode status) {
1257   if (status != blink::ServiceWorkerStatusCode::kOk) {
1258     scoped_refptr<ServiceWorkerVersion> protect(this);
1259     FinishStartWorker(DeduceStartWorkerFailureReason(status));
1260   }
1261 }
1262 
SetCachedMetadata(const GURL & url,base::span<const uint8_t> data)1263 void ServiceWorkerVersion::SetCachedMetadata(const GURL& url,
1264                                              base::span<const uint8_t> data) {
1265   int64_t callback_id =
1266       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds();
1267   TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1268                            "ServiceWorkerVersion::SetCachedMetadata",
1269                            callback_id, "URL", url.spec());
1270   script_cache_map_.WriteMetadata(
1271       url, data,
1272       base::BindOnce(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
1273                      weak_factory_.GetWeakPtr(), callback_id, data.size()));
1274 }
1275 
ClearCachedMetadata(const GURL & url)1276 void ServiceWorkerVersion::ClearCachedMetadata(const GURL& url) {
1277   int64_t callback_id =
1278       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds();
1279   TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1280                            "ServiceWorkerVersion::ClearCachedMetadata",
1281                            callback_id, "URL", url.spec());
1282   script_cache_map_.ClearMetadata(
1283       url, base::BindOnce(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
1284                           weak_factory_.GetWeakPtr(), callback_id));
1285 }
1286 
ClaimClients(ClaimClientsCallback callback)1287 void ServiceWorkerVersion::ClaimClients(ClaimClientsCallback callback) {
1288   if (status_ != ACTIVATING && status_ != ACTIVATED) {
1289     std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kState,
1290                             std::string(kClaimClientsStateErrorMesage));
1291     return;
1292   }
1293   if (!context_) {
1294     std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kAbort,
1295                             std::string(kClaimClientsShutdownErrorMesage));
1296     return;
1297   }
1298 
1299   ServiceWorkerRegistration* registration =
1300       context_->GetLiveRegistration(registration_id_);
1301   // Registration must be kept alive by ServiceWorkerGlobalScope#registration.
1302   if (!registration) {
1303     mojo::ReportBadMessage("ClaimClients: No live registration");
1304     // ReportBadMessage() will kill the renderer process, but Mojo complains if
1305     // the callback is not run. Just run it with nonsense arguments.
1306     std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kUnknown,
1307                             std::string());
1308     return;
1309   }
1310 
1311   registration->ClaimClients();
1312   std::move(callback).Run(blink::mojom::ServiceWorkerErrorType::kNone,
1313                           base::nullopt);
1314 }
1315 
GetClients(blink::mojom::ServiceWorkerClientQueryOptionsPtr options,GetClientsCallback callback)1316 void ServiceWorkerVersion::GetClients(
1317     blink::mojom::ServiceWorkerClientQueryOptionsPtr options,
1318     GetClientsCallback callback) {
1319   service_worker_client_utils::GetClients(
1320       weak_factory_.GetWeakPtr(), std::move(options), std::move(callback));
1321 }
1322 
GetClient(const std::string & client_uuid,GetClientCallback callback)1323 void ServiceWorkerVersion::GetClient(const std::string& client_uuid,
1324                                      GetClientCallback callback) {
1325   if (!context_) {
1326     // The promise will be resolved to 'undefined'.
1327     std::move(callback).Run(nullptr);
1328     return;
1329   }
1330   ServiceWorkerContainerHost* container_host =
1331       context_->GetContainerHostByClientID(client_uuid);
1332   if (!container_host ||
1333       container_host->url().GetOrigin() != script_url_.GetOrigin()) {
1334     // The promise will be resolved to 'undefined'.
1335     // Note that we don't BadMessage here since Clients#get() can be passed an
1336     // arbitrary UUID. The BadMessages for the origin mismatches below are
1337     // appropriate because the UUID is taken directly from a Client object so we
1338     // expect it to be valid.
1339     std::move(callback).Run(nullptr);
1340     return;
1341   }
1342   if (!container_host->is_execution_ready()) {
1343     container_host->AddExecutionReadyCallback(
1344         base::BindOnce(&ServiceWorkerVersion::GetClientInternal, this,
1345                        client_uuid, std::move(callback)));
1346     return;
1347   }
1348   service_worker_client_utils::GetClient(container_host, std::move(callback));
1349 }
1350 
GetClientInternal(const std::string & client_uuid,GetClientCallback callback)1351 void ServiceWorkerVersion::GetClientInternal(const std::string& client_uuid,
1352                                              GetClientCallback callback) {
1353   ServiceWorkerContainerHost* container_host =
1354       context_->GetContainerHostByClientID(client_uuid);
1355   if (!container_host || !container_host->is_execution_ready()) {
1356     std::move(callback).Run(nullptr);
1357     return;
1358   }
1359   service_worker_client_utils::GetClient(container_host, std::move(callback));
1360 }
1361 
OpenNewTab(const GURL & url,OpenNewTabCallback callback)1362 void ServiceWorkerVersion::OpenNewTab(const GURL& url,
1363                                       OpenNewTabCallback callback) {
1364   OpenWindow(url, service_worker_client_utils::WindowType::NEW_TAB_WINDOW,
1365              std::move(callback));
1366 }
1367 
OpenPaymentHandlerWindow(const GURL & url,OpenPaymentHandlerWindowCallback callback)1368 void ServiceWorkerVersion::OpenPaymentHandlerWindow(
1369     const GURL& url,
1370     OpenPaymentHandlerWindowCallback callback) {
1371   // Just respond failure if we are shutting down.
1372   if (!context_) {
1373     std::move(callback).Run(
1374         false /* success */, nullptr /* client */,
1375         std::string("The service worker system is shutting down."));
1376     return;
1377   }
1378 
1379   if (!url.is_valid() ||
1380       !url::Origin::Create(url).IsSameOriginWith(script_origin_)) {
1381     mojo::ReportBadMessage(
1382         "Received PaymentRequestEvent#openWindow() request for a cross-origin "
1383         "URL.");
1384     receiver_.reset();
1385     return;
1386   }
1387 
1388   PaymentHandlerSupport::ShowPaymentHandlerWindow(
1389       url, context_.get(),
1390       base::BindOnce(&DidShowPaymentHandlerWindow, url, context_),
1391       base::BindOnce(
1392           &ServiceWorkerVersion::OpenWindow, weak_factory_.GetWeakPtr(), url,
1393           service_worker_client_utils::WindowType::PAYMENT_HANDLER_WINDOW),
1394       std::move(callback));
1395 }
1396 
PostMessageToClient(const std::string & client_uuid,blink::TransferableMessage message)1397 void ServiceWorkerVersion::PostMessageToClient(
1398     const std::string& client_uuid,
1399     blink::TransferableMessage message) {
1400   if (!context_)
1401     return;
1402   ServiceWorkerContainerHost* container_host =
1403       context_->GetContainerHostByClientID(client_uuid);
1404   if (!container_host) {
1405     // The client may already have been closed, just ignore.
1406     return;
1407   }
1408 
1409   if (IsBackForwardCacheEnabled()) {
1410     // When |PostMessageToClient| is called on a client that is in bfcache,
1411     // evict the bfcache entry.
1412     if (container_host->IsInBackForwardCache()) {
1413       EvictBackForwardCachedControllee(
1414           container_host, BackForwardCacheMetrics::NotRestoredReason::
1415                               kServiceWorkerPostMessage);
1416       return;
1417     }
1418   }
1419 
1420   if (container_host->url().GetOrigin() != script_url_.GetOrigin()) {
1421     mojo::ReportBadMessage(
1422         "Received Client#postMessage() request for a cross-origin client.");
1423     receiver_.reset();
1424     return;
1425   }
1426   if (!container_host->is_execution_ready()) {
1427     // It's subtle why this ReportBadMessage is correct. Consider the
1428     // sequence:
1429     // 1. Page does ServiceWorker.postMessage().
1430     // 2. Service worker does onmessage = (evt) => {evt.source.postMessage()};.
1431     //
1432     // The IPC sequence is:
1433     // 1. Page sends NotifyExecutionReady() to its ServiceWorkerContainerHost
1434     //    once created.
1435     // 2. Page sends PostMessageToServiceWorker() to the object's
1436     //    ServiceWorkerObjectHost.
1437     // 3. Service worker sends PostMessageToClient() to its ServiceWorkerHost.
1438     //
1439     // It's guaranteed that 1. arrives before 2., since the
1440     // ServiceWorkerObjectHost must have been sent over
1441     // ServiceWorkerContainerHost (using Register, GetRegistrationForReady), so
1442     // they are associated. After that 3. occurs and we get here and are
1443     // guaranteed execution ready the above ordering.
1444     //
1445     // The above reasoning would break if there is a way for a page to get a
1446     // ServiceWorkerObjectHost not associated with its
1447     // ServiceWorkerContainerHost. If that world should occur, we should queue
1448     // the message instead of crashing.
1449     mojo::ReportBadMessage(
1450         "Received Client#postMessage() request for a reserved client.");
1451     receiver_.reset();
1452     return;
1453   }
1454   container_host->PostMessageToClient(this, std::move(message));
1455 }
1456 
FocusClient(const std::string & client_uuid,FocusClientCallback callback)1457 void ServiceWorkerVersion::FocusClient(const std::string& client_uuid,
1458                                        FocusClientCallback callback) {
1459   if (!context_) {
1460     std::move(callback).Run(nullptr /* client */);
1461     return;
1462   }
1463   ServiceWorkerContainerHost* container_host =
1464       context_->GetContainerHostByClientID(client_uuid);
1465   if (!container_host) {
1466     // The client may already have been closed, just fail.
1467     std::move(callback).Run(nullptr /* client */);
1468     return;
1469   }
1470   if (container_host->url().GetOrigin() != script_url_.GetOrigin()) {
1471     mojo::ReportBadMessage(
1472         "Received WindowClient#focus() request for a cross-origin client.");
1473     receiver_.reset();
1474     return;
1475   }
1476   if (container_host->client_type() !=
1477       blink::mojom::ServiceWorkerClientType::kWindow) {
1478     // focus() should be called only for WindowClient.
1479     mojo::ReportBadMessage(
1480         "Received WindowClient#focus() request for a non-window client.");
1481     receiver_.reset();
1482     return;
1483   }
1484 
1485   service_worker_client_utils::FocusWindowClient(container_host,
1486                                                  std::move(callback));
1487 }
1488 
NavigateClient(const std::string & client_uuid,const GURL & url,NavigateClientCallback callback)1489 void ServiceWorkerVersion::NavigateClient(const std::string& client_uuid,
1490                                           const GURL& url,
1491                                           NavigateClientCallback callback) {
1492   if (!context_) {
1493     std::move(callback).Run(
1494         false /* success */, nullptr /* client */,
1495         std::string("The service worker system is shutting down."));
1496     return;
1497   }
1498 
1499   if (!url.is_valid() || !base::IsValidGUID(client_uuid)) {
1500     mojo::ReportBadMessage(
1501         "Received unexpected invalid URL/UUID from renderer process.");
1502     receiver_.reset();
1503     return;
1504   }
1505 
1506   // Reject requests for URLs that the process is not allowed to access. It's
1507   // possible to receive such requests since the renderer-side checks are
1508   // slightly different. For example, the view-source scheme will not be
1509   // filtered out by Blink.
1510   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1511           embedded_worker_->process_id(), url)) {
1512     std::move(callback).Run(
1513         false /* success */, nullptr /* client */,
1514         "The service worker is not allowed to access URL: " + url.spec());
1515     return;
1516   }
1517 
1518   ServiceWorkerContainerHost* container_host =
1519       context_->GetContainerHostByClientID(client_uuid);
1520   if (!container_host) {
1521     std::move(callback).Run(false /* success */, nullptr /* client */,
1522                             std::string("The client was not found."));
1523     return;
1524   }
1525   if (container_host->url().GetOrigin() != script_url_.GetOrigin()) {
1526     mojo::ReportBadMessage(
1527         "Received WindowClient#navigate() request for a cross-origin client.");
1528     receiver_.reset();
1529     return;
1530   }
1531   if (container_host->client_type() !=
1532       blink::mojom::ServiceWorkerClientType::kWindow) {
1533     // navigate() should be called only for WindowClient.
1534     mojo::ReportBadMessage(
1535         "Received WindowClient#navigate() request for a non-window client.");
1536     receiver_.reset();
1537     return;
1538   }
1539   if (container_host->controller() != this) {
1540     std::move(callback).Run(
1541         false /* success */, nullptr /* client */,
1542         std::string(
1543             "This service worker is not the client's active service worker."));
1544     return;
1545   }
1546 
1547   service_worker_client_utils::NavigateClient(
1548       url, script_url_, container_host->process_id(),
1549       container_host->frame_id(), context_,
1550       base::BindOnce(&DidNavigateClient, std::move(callback), url));
1551 }
1552 
SkipWaiting(SkipWaitingCallback callback)1553 void ServiceWorkerVersion::SkipWaiting(SkipWaitingCallback callback) {
1554   skip_waiting_ = true;
1555 
1556   // Per spec, resolve the skip waiting promise now if activation won't be
1557   // triggered here. The ActivateWaitingVersionWhenReady() call below only
1558   // triggers it if we're in INSTALLED state. So if we're not in INSTALLED
1559   // state, resolve the promise now. Even if we're in INSTALLED state, there are
1560   // still cases where ActivateWaitingVersionWhenReady() won't trigger the
1561   // activation. In that case, it's a slight spec violation to not resolve now,
1562   // but we'll eventually resolve the promise in SetStatus().
1563   if (status_ != INSTALLED) {
1564     std::move(callback).Run(true);
1565     return;
1566   }
1567 
1568   if (!context_) {
1569     std::move(callback).Run(false);
1570     return;
1571   }
1572   ServiceWorkerRegistration* registration =
1573       context_->GetLiveRegistration(registration_id_);
1574   // TODO(leonhsl): Here we should be guaranteed a registration since
1575   // ServiceWorkerGlobalScope#registration should be keeping the registration
1576   // alive currently. So we need to confirm and remove this nullable check
1577   // later.
1578   if (!registration) {
1579     std::move(callback).Run(false);
1580     return;
1581   }
1582   if (skip_waiting_time_.is_null())
1583     RestartTick(&skip_waiting_time_);
1584   pending_skip_waiting_requests_.push_back(std::move(callback));
1585   if (pending_skip_waiting_requests_.size() == 1)
1586     registration->ActivateWaitingVersionWhenReady();
1587 }
1588 
OnSetCachedMetadataFinished(int64_t callback_id,size_t size,int result)1589 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64_t callback_id,
1590                                                        size_t size,
1591                                                        int result) {
1592   TRACE_EVENT_ASYNC_END1("ServiceWorker",
1593                          "ServiceWorkerVersion::SetCachedMetadata", callback_id,
1594                          "result", result);
1595   for (auto& observer : observers_)
1596     observer.OnCachedMetadataUpdated(this, size);
1597 }
1598 
OnClearCachedMetadataFinished(int64_t callback_id,int result)1599 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64_t callback_id,
1600                                                          int result) {
1601   TRACE_EVENT_ASYNC_END1("ServiceWorker",
1602                          "ServiceWorkerVersion::ClearCachedMetadata",
1603                          callback_id, "result", result);
1604   for (auto& observer : observers_)
1605     observer.OnCachedMetadataUpdated(this, 0);
1606 }
1607 
OpenWindow(GURL url,service_worker_client_utils::WindowType type,OpenNewTabCallback callback)1608 void ServiceWorkerVersion::OpenWindow(
1609     GURL url,
1610     service_worker_client_utils::WindowType type,
1611     OpenNewTabCallback callback) {
1612   // Just respond failure if we are shutting down.
1613   if (!context_) {
1614     std::move(callback).Run(
1615         false /* success */, nullptr /* client */,
1616         std::string("The service worker system is shutting down."));
1617     return;
1618   }
1619 
1620   if (!url.is_valid()) {
1621     mojo::ReportBadMessage(
1622         "Received unexpected invalid URL from renderer process.");
1623     receiver_.reset();
1624     return;
1625   }
1626 
1627   // The renderer treats all URLs in the about: scheme as being about:blank.
1628   // Canonicalize about: URLs to about:blank.
1629   if (url.SchemeIs(url::kAboutScheme))
1630     url = GURL(url::kAboutBlankURL);
1631 
1632   // Reject requests for URLs that the process is not allowed to access. It's
1633   // possible to receive such requests since the renderer-side checks are
1634   // slightly different. For example, the view-source scheme will not be
1635   // filtered out by Blink.
1636   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1637           embedded_worker_->process_id(), url)) {
1638     std::move(callback).Run(false /* success */, nullptr /* client */,
1639                             url.spec() + " cannot be opened.");
1640     return;
1641   }
1642 
1643   service_worker_client_utils::OpenWindow(
1644       url, script_url_, embedded_worker_->embedded_worker_id(),
1645       embedded_worker_->process_id(), context_, type,
1646       base::BindOnce(&OnOpenWindowFinished, std::move(callback)));
1647 }
1648 
HasWorkInBrowser() const1649 bool ServiceWorkerVersion::HasWorkInBrowser() const {
1650   return !inflight_requests_.IsEmpty() || !start_callbacks_.empty();
1651 }
1652 
OnSimpleEventFinished(int request_id,blink::mojom::ServiceWorkerEventStatus status)1653 void ServiceWorkerVersion::OnSimpleEventFinished(
1654     int request_id,
1655     blink::mojom::ServiceWorkerEventStatus status) {
1656   InflightRequest* request = inflight_requests_.Lookup(request_id);
1657   // |request| will be null when the request has been timed out.
1658   if (!request)
1659     return;
1660   // Copy error callback before calling FinishRequest.
1661   StatusCallback callback = std::move(request->error_callback);
1662 
1663   FinishRequest(request_id,
1664                 status == blink::mojom::ServiceWorkerEventStatus::COMPLETED);
1665 
1666   std::move(callback).Run(
1667       mojo::ConvertTo<blink::ServiceWorkerStatusCode>(status));
1668 }
1669 
CountFeature(blink::mojom::WebFeature feature)1670 void ServiceWorkerVersion::CountFeature(blink::mojom::WebFeature feature) {
1671   if (!used_features_.insert(feature).second)
1672     return;
1673   for (auto container_host_by_uuid : controllee_map_)
1674     container_host_by_uuid.second->CountFeature(feature);
1675 }
1676 
set_cross_origin_embedder_policy(network::CrossOriginEmbedderPolicy cross_origin_embedder_policy)1677 void ServiceWorkerVersion::set_cross_origin_embedder_policy(
1678     network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) {
1679   // Once it is set, the CrossOriginEmbedderPolicy is immutable.
1680   DCHECK(!cross_origin_embedder_policy_ ||
1681          cross_origin_embedder_policy_ == cross_origin_embedder_policy);
1682   cross_origin_embedder_policy_ = std::move(cross_origin_embedder_policy);
1683 }
1684 
1685 // static
IsInstalled(ServiceWorkerVersion::Status status)1686 bool ServiceWorkerVersion::IsInstalled(ServiceWorkerVersion::Status status) {
1687   switch (status) {
1688     case ServiceWorkerVersion::NEW:
1689     case ServiceWorkerVersion::INSTALLING:
1690     case ServiceWorkerVersion::REDUNDANT:
1691       return false;
1692     case ServiceWorkerVersion::INSTALLED:
1693     case ServiceWorkerVersion::ACTIVATING:
1694     case ServiceWorkerVersion::ACTIVATED:
1695       return true;
1696   }
1697   NOTREACHED() << "Unexpected status: " << status;
1698   return false;
1699 }
1700 
1701 // static
VersionStatusToString(ServiceWorkerVersion::Status status)1702 std::string ServiceWorkerVersion::VersionStatusToString(
1703     ServiceWorkerVersion::Status status) {
1704   switch (status) {
1705     case ServiceWorkerVersion::NEW:
1706       return "new";
1707     case ServiceWorkerVersion::INSTALLING:
1708       return "installing";
1709     case ServiceWorkerVersion::INSTALLED:
1710       return "installed";
1711     case ServiceWorkerVersion::ACTIVATING:
1712       return "activating";
1713     case ServiceWorkerVersion::ACTIVATED:
1714       return "activated";
1715     case ServiceWorkerVersion::REDUNDANT:
1716       return "redundant";
1717   }
1718   NOTREACHED() << status;
1719   return std::string();
1720 }
1721 
IncrementPendingUpdateHintCount()1722 void ServiceWorkerVersion::IncrementPendingUpdateHintCount() {
1723   pending_update_hint_count_++;
1724 }
1725 
DecrementPendingUpdateHintCount()1726 void ServiceWorkerVersion::DecrementPendingUpdateHintCount() {
1727   DCHECK_GT(pending_update_hint_count_, 0);
1728   pending_update_hint_count_--;
1729   if (pending_update_hint_count_ == 0)
1730     ScheduleUpdate();
1731 }
1732 
OnPongFromWorker()1733 void ServiceWorkerVersion::OnPongFromWorker() {
1734   ping_controller_.OnPongReceived();
1735 }
1736 
DidEnsureLiveRegistrationForStartWorker(ServiceWorkerMetrics::EventType purpose,Status prestart_status,bool is_browser_startup_complete,StatusCallback callback,blink::ServiceWorkerStatusCode status,scoped_refptr<ServiceWorkerRegistration> registration)1737 void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
1738     ServiceWorkerMetrics::EventType purpose,
1739     Status prestart_status,
1740     bool is_browser_startup_complete,
1741     StatusCallback callback,
1742     blink::ServiceWorkerStatusCode status,
1743     scoped_refptr<ServiceWorkerRegistration> registration) {
1744   scoped_refptr<ServiceWorkerRegistration> protect = registration;
1745   if (status == blink::ServiceWorkerStatusCode::kErrorNotFound) {
1746     // When the registration has already been deleted from the storage but its
1747     // active worker is still controlling clients, the event should be
1748     // dispatched on the worker. However, the storage cannot find the
1749     // registration. To handle the case, check the live registrations here.
1750     protect = context_->GetLiveRegistration(registration_id_);
1751     if (protect) {
1752       DCHECK(protect->is_uninstalling());
1753       status = blink::ServiceWorkerStatusCode::kOk;
1754     }
1755   }
1756   if (status != blink::ServiceWorkerStatusCode::kOk) {
1757     RecordStartWorkerResult(purpose, prestart_status, kInvalidTraceId,
1758                             is_browser_startup_complete, status);
1759     RunSoon(base::BindOnce(
1760         std::move(callback),
1761         blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed));
1762     return;
1763   }
1764   if (is_redundant()) {
1765     RecordStartWorkerResult(purpose, prestart_status, kInvalidTraceId,
1766                             is_browser_startup_complete,
1767                             blink::ServiceWorkerStatusCode::kErrorRedundant);
1768     RunSoon(base::BindOnce(std::move(callback),
1769                            blink::ServiceWorkerStatusCode::kErrorRedundant));
1770     return;
1771   }
1772 
1773   MarkIfStale();
1774 
1775   switch (running_status()) {
1776     case EmbeddedWorkerStatus::RUNNING:
1777       RunSoon(base::BindOnce(std::move(callback),
1778                              blink::ServiceWorkerStatusCode::kOk));
1779       return;
1780     case EmbeddedWorkerStatus::STARTING:
1781       DCHECK(!start_callbacks_.empty());
1782       break;
1783     case EmbeddedWorkerStatus::STOPPING:
1784     case EmbeddedWorkerStatus::STOPPED:
1785       if (start_callbacks_.empty()) {
1786         int trace_id = NextTraceId();
1787         TRACE_EVENT_ASYNC_BEGIN2(
1788             "ServiceWorker", "ServiceWorkerVersion::StartWorker", trace_id,
1789             "Script", script_url_.spec(), "Purpose",
1790             ServiceWorkerMetrics::EventTypeToString(purpose));
1791         start_callbacks_.push_back(
1792             base::BindOnce(&ServiceWorkerVersion::RecordStartWorkerResult,
1793                            weak_factory_.GetWeakPtr(), purpose, prestart_status,
1794                            trace_id, is_browser_startup_complete));
1795       }
1796       break;
1797   }
1798 
1799   // Keep the live registration while starting the worker.
1800   start_callbacks_.push_back(base::BindOnce(
1801       [](StatusCallback callback,
1802          scoped_refptr<ServiceWorkerRegistration> protect,
1803          blink::ServiceWorkerStatusCode status) {
1804         std::move(callback).Run(status);
1805       },
1806       std::move(callback), protect));
1807 
1808   if (running_status() == EmbeddedWorkerStatus::STOPPED)
1809     StartWorkerInternal();
1810   DCHECK(timeout_timer_.IsRunning());
1811 }
1812 
StartWorkerInternal()1813 void ServiceWorkerVersion::StartWorkerInternal() {
1814   DCHECK(context_);
1815   DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, running_status());
1816   DCHECK(inflight_requests_.IsEmpty());
1817   DCHECK(request_timeouts_.empty());
1818 
1819   StartTimeoutTimer();
1820 
1821   // Set expiration time in advance so that the service worker can
1822   // call postMessage() to itself immediately after it starts.
1823   max_request_expiration_time_ = tick_clock_->NowTicks() + kRequestTimeout;
1824 
1825   worker_is_idle_on_renderer_ = false;
1826   needs_to_be_terminated_asap_ = false;
1827 
1828   auto provider_info =
1829       blink::mojom::ServiceWorkerProviderInfoForStartWorker::New();
1830   DCHECK(!provider_host_);
1831   provider_host_ = std::make_unique<ServiceWorkerProviderHost>(
1832       provider_info->host_remote.InitWithNewEndpointAndPassReceiver(), this,
1833       context());
1834 
1835   auto params = blink::mojom::EmbeddedWorkerStartParams::New();
1836   params->service_worker_version_id = version_id_;
1837   params->scope = scope_;
1838   params->script_url = script_url_;
1839   params->script_type = script_type_;
1840   // Need to clone this object because StartWorkerInternal() can/ be called
1841   // more than once.
1842   params->outside_fetch_client_settings_object =
1843       outside_fetch_client_settings_object_.Clone();
1844   params->user_agent = GetContentClient()->browser()->GetUserAgent();
1845   params->ua_metadata = GetContentClient()->browser()->GetUserAgentMetadata();
1846   params->is_installed = IsInstalled(status_);
1847   params->script_url_to_skip_throttling = updated_script_url_;
1848 
1849   if (IsInstalled(status())) {
1850     DCHECK(!installed_scripts_sender_);
1851     installed_scripts_sender_ =
1852         std::make_unique<ServiceWorkerInstalledScriptsSender>(this);
1853     params->installed_scripts_info =
1854         installed_scripts_sender_->CreateInfoAndBind();
1855     installed_scripts_sender_->Start();
1856   }
1857 
1858   params->service_worker_receiver =
1859       service_worker_remote_.BindNewPipeAndPassReceiver();
1860   // TODO(horo): These CHECKs are for debugging crbug.com/759938.
1861   CHECK(service_worker_remote_.is_bound());
1862   CHECK(params->service_worker_receiver.is_valid());
1863   service_worker_remote_.set_disconnect_handler(
1864       base::BindOnce(&OnConnectionError, embedded_worker_->AsWeakPtr()));
1865   receiver_.reset();
1866   receiver_.Bind(service_worker_host_.InitWithNewEndpointAndPassReceiver());
1867   // Initialize the global scope now if the worker won't be paused. Otherwise,
1868   // delay initialization until the main script is loaded.
1869   if (!initialize_global_scope_after_main_script_loaded_)
1870     InitializeGlobalScope(/*script_loader_factories=*/nullptr,
1871                           /*subresource_loader_factories=*/nullptr);
1872 
1873   if (!controller_receiver_.is_valid()) {
1874     controller_receiver_ = remote_controller_.BindNewPipeAndPassReceiver();
1875   }
1876   params->controller_receiver = std::move(controller_receiver_);
1877 
1878   params->provider_info = std::move(provider_info);
1879 
1880   embedded_worker_->Start(std::move(params),
1881                           base::BindOnce(&ServiceWorkerVersion::OnStartSent,
1882                                          weak_factory_.GetWeakPtr()));
1883 }
1884 
StartTimeoutTimer()1885 void ServiceWorkerVersion::StartTimeoutTimer() {
1886   DCHECK(!timeout_timer_.IsRunning());
1887 
1888   if (embedded_worker_->devtools_attached()) {
1889     // Don't record the startup time metric once DevTools is attached.
1890     ClearTick(&start_time_);
1891     skip_recording_startup_time_ = true;
1892   } else {
1893     RestartTick(&start_time_);
1894     skip_recording_startup_time_ = false;
1895   }
1896 
1897   // Ping will be activated in OnScriptEvaluationStart.
1898   ping_controller_.Deactivate();
1899 
1900   timeout_timer_.Start(FROM_HERE, kTimeoutTimerDelay, this,
1901                        &ServiceWorkerVersion::OnTimeoutTimer);
1902 }
1903 
StopTimeoutTimer()1904 void ServiceWorkerVersion::StopTimeoutTimer() {
1905   timeout_timer_.Stop();
1906 
1907   // Trigger update if worker is stale.
1908   if (!in_dtor_ && !stale_time_.is_null()) {
1909     ClearTick(&stale_time_);
1910     if (!update_timer_.IsRunning())
1911       ScheduleUpdate();
1912   }
1913 }
1914 
SetTimeoutTimerInterval(base::TimeDelta interval)1915 void ServiceWorkerVersion::SetTimeoutTimerInterval(base::TimeDelta interval) {
1916   DCHECK(timeout_timer_.IsRunning());
1917   if (timeout_timer_.GetCurrentDelay() != interval) {
1918     timeout_timer_.Stop();
1919     timeout_timer_.Start(FROM_HERE, interval, this,
1920                          &ServiceWorkerVersion::OnTimeoutTimer);
1921   }
1922 }
1923 
OnTimeoutTimer()1924 void ServiceWorkerVersion::OnTimeoutTimer() {
1925   // TODO(horo): This CHECK is for debugging crbug.com/759938.
1926   CHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
1927         running_status() == EmbeddedWorkerStatus::RUNNING ||
1928         running_status() == EmbeddedWorkerStatus::STOPPING)
1929       << static_cast<int>(running_status());
1930 
1931   if (!context_)
1932     return;
1933 
1934   MarkIfStale();
1935 
1936   // Stopping the worker hasn't finished within a certain period.
1937   if (GetTickDuration(stop_time_) > kStopWorkerTimeout) {
1938     DCHECK_EQ(EmbeddedWorkerStatus::STOPPING, running_status());
1939     if (IsInstalled(status())) {
1940       ServiceWorkerMetrics::RecordWorkerStopped(
1941           ServiceWorkerMetrics::StopStatus::TIMEOUT);
1942     }
1943     ReportError(blink::ServiceWorkerStatusCode::kErrorTimeout,
1944                 "DETACH_STALLED_IN_STOPPING");
1945 
1946     // Detach the worker. Remove |this| as a listener first; otherwise
1947     // OnStoppedInternal might try to restart before the new worker
1948     // is created. Also, protect |this|, since swapping out the
1949     // EmbeddedWorkerInstance could destroy our ServiceWorkerProviderHost
1950     // which could in turn destroy |this|.
1951     scoped_refptr<ServiceWorkerVersion> protect_this(this);
1952     embedded_worker_->RemoveObserver(this);
1953     embedded_worker_->Detach();
1954     embedded_worker_ = std::make_unique<EmbeddedWorkerInstance>(this);
1955     embedded_worker_->AddObserver(this);
1956 
1957     // Call OnStoppedInternal to fail callbacks and possibly restart.
1958     OnStoppedInternal(EmbeddedWorkerStatus::STOPPING);
1959     return;
1960   }
1961 
1962   // Trigger update if worker is stale and we waited long enough for it to go
1963   // idle.
1964   if (GetTickDuration(stale_time_) > kRequestTimeout) {
1965     ClearTick(&stale_time_);
1966     if (!update_timer_.IsRunning())
1967       ScheduleUpdate();
1968   }
1969 
1970   // Starting a worker hasn't finished within a certain period.
1971   const base::TimeDelta start_limit = IsInstalled(status())
1972                                           ? kStartInstalledWorkerTimeout
1973                                           : kStartNewWorkerTimeout;
1974   if (GetTickDuration(start_time_) > start_limit) {
1975     DCHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
1976            running_status() == EmbeddedWorkerStatus::STOPPING)
1977         << static_cast<int>(running_status());
1978     scoped_refptr<ServiceWorkerVersion> protect(this);
1979     FinishStartWorker(blink::ServiceWorkerStatusCode::kErrorTimeout);
1980     if (running_status() == EmbeddedWorkerStatus::STARTING)
1981       embedded_worker_->Stop();
1982     return;
1983   }
1984 
1985   // Requests have not finished before their expiration.
1986   bool stop_for_timeout = false;
1987   auto timeout_iter = request_timeouts_.begin();
1988   while (timeout_iter != request_timeouts_.end()) {
1989     const InflightRequestTimeoutInfo& info = *timeout_iter;
1990     if (!RequestExpired(info.expiration))
1991       break;
1992     if (MaybeTimeoutRequest(info)) {
1993       stop_for_timeout =
1994           stop_for_timeout || info.timeout_behavior == KILL_ON_TIMEOUT;
1995     }
1996     timeout_iter = request_timeouts_.erase(timeout_iter);
1997   }
1998   if (stop_for_timeout && running_status() != EmbeddedWorkerStatus::STOPPING)
1999     embedded_worker_->Stop();
2000 
2001   // For the timeouts below, there are no callbacks to timeout so there is
2002   // nothing more to do if the worker is already stopping.
2003   if (running_status() == EmbeddedWorkerStatus::STOPPING)
2004     return;
2005 
2006   // Check ping status.
2007   ping_controller_.CheckPingStatus();
2008 }
2009 
PingWorker()2010 void ServiceWorkerVersion::PingWorker() {
2011   // TODO(horo): This CHECK is for debugging crbug.com/759938.
2012   CHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
2013         running_status() == EmbeddedWorkerStatus::RUNNING);
2014   // base::Unretained here is safe because endpoint() is owned by
2015   // |this|.
2016   endpoint()->Ping(base::BindOnce(&ServiceWorkerVersion::OnPongFromWorker,
2017                                   base::Unretained(this)));
2018 }
2019 
OnPingTimeout()2020 void ServiceWorkerVersion::OnPingTimeout() {
2021   DCHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
2022          running_status() == EmbeddedWorkerStatus::RUNNING);
2023   MaybeReportConsoleMessageToInternals(
2024       blink::mojom::ConsoleMessageLevel::kVerbose, kNotRespondingErrorMesage);
2025   embedded_worker_->StopIfNotAttachedToDevTools();
2026 }
2027 
RecordStartWorkerResult(ServiceWorkerMetrics::EventType purpose,Status prestart_status,int trace_id,bool is_browser_startup_complete,blink::ServiceWorkerStatusCode status)2028 void ServiceWorkerVersion::RecordStartWorkerResult(
2029     ServiceWorkerMetrics::EventType purpose,
2030     Status prestart_status,
2031     int trace_id,
2032     bool is_browser_startup_complete,
2033     blink::ServiceWorkerStatusCode status) {
2034   if (trace_id != kInvalidTraceId) {
2035     TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::StartWorker",
2036                            trace_id, "Status",
2037                            blink::ServiceWorkerStatusToString(status));
2038   }
2039   base::TimeTicks start_time = start_time_;
2040   ClearTick(&start_time_);
2041 
2042   if (context_ && IsInstalled(prestart_status))
2043     context_->UpdateVersionFailureCount(version_id_, status);
2044 
2045   if (IsInstalled(prestart_status))
2046     ServiceWorkerMetrics::RecordStartInstalledWorkerStatus(status, purpose);
2047 
2048   if (status == blink::ServiceWorkerStatusCode::kOk && !start_time.is_null() &&
2049       !skip_recording_startup_time_) {
2050     ServiceWorkerMetrics::RecordStartWorkerTime(
2051         GetTickDuration(start_time), IsInstalled(prestart_status),
2052         embedded_worker_->start_situation(), purpose);
2053   }
2054 
2055   if (status != blink::ServiceWorkerStatusCode::kErrorTimeout)
2056     return;
2057   EmbeddedWorkerInstance::StartingPhase phase =
2058       EmbeddedWorkerInstance::NOT_STARTING;
2059   EmbeddedWorkerStatus running_status = embedded_worker_->status();
2060   // Build an artifical JavaScript exception to show in the ServiceWorker
2061   // log for developers; it's not user-facing so it's not a localized resource.
2062   std::string message = "ServiceWorker startup timed out. ";
2063   if (running_status != EmbeddedWorkerStatus::STARTING) {
2064     message.append("The worker had unexpected status: ");
2065     message.append(EmbeddedWorkerInstance::StatusToString(running_status));
2066   } else {
2067     phase = embedded_worker_->starting_phase();
2068     message.append("The worker was in startup phase: ");
2069     message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
2070   }
2071   message.append(".");
2072   OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
2073   DVLOG(1) << message;
2074   UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase", phase,
2075                             EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
2076 }
2077 
MaybeTimeoutRequest(const InflightRequestTimeoutInfo & info)2078 bool ServiceWorkerVersion::MaybeTimeoutRequest(
2079     const InflightRequestTimeoutInfo& info) {
2080   InflightRequest* request = inflight_requests_.Lookup(info.id);
2081   if (!request)
2082     return false;
2083 
2084   TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
2085                          request, "Error", "Timeout");
2086   std::move(request->error_callback)
2087       .Run(blink::ServiceWorkerStatusCode::kErrorTimeout);
2088   inflight_requests_.Remove(info.id);
2089   return true;
2090 }
2091 
SetAllRequestExpirations(const base::TimeTicks & expiration)2092 void ServiceWorkerVersion::SetAllRequestExpirations(
2093     const base::TimeTicks& expiration) {
2094   std::set<InflightRequestTimeoutInfo> new_timeouts;
2095   for (const auto& info : request_timeouts_) {
2096     bool is_inserted = false;
2097     std::set<InflightRequestTimeoutInfo>::iterator iter;
2098     std::tie(iter, is_inserted) = new_timeouts.emplace(
2099         info.id, info.event_type, expiration, info.timeout_behavior);
2100     DCHECK(is_inserted);
2101     InflightRequest* request = inflight_requests_.Lookup(info.id);
2102     DCHECK(request);
2103     request->timeout_iter = iter;
2104   }
2105   request_timeouts_.swap(new_timeouts);
2106 }
2107 
2108 blink::ServiceWorkerStatusCode
DeduceStartWorkerFailureReason(blink::ServiceWorkerStatusCode default_code)2109 ServiceWorkerVersion::DeduceStartWorkerFailureReason(
2110     blink::ServiceWorkerStatusCode default_code) {
2111   if (ping_controller_.IsTimedOut())
2112     return blink::ServiceWorkerStatusCode::kErrorTimeout;
2113 
2114   if (start_worker_status_ != blink::ServiceWorkerStatusCode::kOk)
2115     return start_worker_status_;
2116 
2117   int main_script_net_error = script_cache_map()->main_script_net_error();
2118   if (main_script_net_error != net::OK) {
2119     if (net::IsCertificateError(main_script_net_error))
2120       return blink::ServiceWorkerStatusCode::kErrorSecurity;
2121     switch (main_script_net_error) {
2122       case net::ERR_INSECURE_RESPONSE:
2123       case net::ERR_UNSAFE_REDIRECT:
2124         return blink::ServiceWorkerStatusCode::kErrorSecurity;
2125       case net::ERR_ABORTED:
2126         return blink::ServiceWorkerStatusCode::kErrorAbort;
2127       default:
2128         return blink::ServiceWorkerStatusCode::kErrorNetwork;
2129     }
2130   }
2131 
2132   return default_code;
2133 }
2134 
MarkIfStale()2135 void ServiceWorkerVersion::MarkIfStale() {
2136   if (!context_)
2137     return;
2138   if (update_timer_.IsRunning() || !stale_time_.is_null())
2139     return;
2140   ServiceWorkerRegistration* registration =
2141       context_->GetLiveRegistration(registration_id_);
2142   if (!registration || registration->active_version() != this)
2143     return;
2144   base::TimeDelta time_since_last_check =
2145       clock_->Now() - registration->last_update_check();
2146   if (time_since_last_check >
2147       ServiceWorkerConsts::kServiceWorkerScriptMaxCacheAge)
2148     RestartTick(&stale_time_);
2149 }
2150 
FoundRegistrationForUpdate(blink::ServiceWorkerStatusCode status,scoped_refptr<ServiceWorkerRegistration> registration)2151 void ServiceWorkerVersion::FoundRegistrationForUpdate(
2152     blink::ServiceWorkerStatusCode status,
2153     scoped_refptr<ServiceWorkerRegistration> registration) {
2154   if (!context_)
2155     return;
2156 
2157   const scoped_refptr<ServiceWorkerVersion> protect = this;
2158   if (is_update_scheduled_) {
2159     context_->UnprotectVersion(version_id_);
2160     is_update_scheduled_ = false;
2161   }
2162 
2163   if (status != blink::ServiceWorkerStatusCode::kOk ||
2164       registration->active_version() != this)
2165     return;
2166   context_->UpdateServiceWorker(registration.get(),
2167                                 false /* force_bypass_cache */);
2168 }
2169 
OnStoppedInternal(EmbeddedWorkerStatus old_status)2170 void ServiceWorkerVersion::OnStoppedInternal(EmbeddedWorkerStatus old_status) {
2171   DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, running_status());
2172   scoped_refptr<ServiceWorkerVersion> protect;
2173   if (!in_dtor_)
2174     protect = this;
2175 
2176   // |start_callbacks_| can be non-empty if a start worker request arrived while
2177   // the worker was stopping. The worker must be restarted to fulfill the
2178   // request.
2179   bool should_restart = !start_callbacks_.empty();
2180   if (is_redundant() || in_dtor_) {
2181     // This worker will be destroyed soon.
2182     should_restart = false;
2183   } else if (ping_controller_.IsTimedOut()) {
2184     // This worker exhausted its time to run, don't let it restart.
2185     should_restart = false;
2186   } else if (old_status == EmbeddedWorkerStatus::STARTING) {
2187     // This worker unexpectedly stopped because start failed.  Attempting to
2188     // restart on start failure could cause an endless loop of start attempts,
2189     // so don't try to restart now.
2190     should_restart = false;
2191   }
2192 
2193   if (!stop_time_.is_null()) {
2194     TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::StopWorker",
2195                            stop_time_.since_origin().InMicroseconds(),
2196                            "Restart", should_restart);
2197     ClearTick(&stop_time_);
2198   }
2199   StopTimeoutTimer();
2200 
2201   // Fire all stop callbacks.
2202   std::vector<base::OnceClosure> callbacks;
2203   callbacks.swap(stop_callbacks_);
2204   for (auto& callback : callbacks)
2205     std::move(callback).Run();
2206 
2207   if (!should_restart) {
2208     // Let all start callbacks fail.
2209     FinishStartWorker(DeduceStartWorkerFailureReason(
2210         blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed));
2211   }
2212 
2213   // Let all message callbacks fail (this will also fire and clear all
2214   // callbacks for events).
2215   // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
2216   base::IDMap<std::unique_ptr<InflightRequest>>::iterator iter(
2217       &inflight_requests_);
2218   while (!iter.IsAtEnd()) {
2219     TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
2220                            iter.GetCurrentValue(), "Error", "Worker Stopped");
2221     std::move(iter.GetCurrentValue()->error_callback)
2222         .Run(blink::ServiceWorkerStatusCode::kErrorFailed);
2223     iter.Advance();
2224   }
2225   inflight_requests_.Clear();
2226   request_timeouts_.clear();
2227   external_request_uuid_to_request_id_.clear();
2228   service_worker_remote_.reset();
2229   remote_controller_.reset();
2230   DCHECK(!controller_receiver_.is_valid());
2231   installed_scripts_sender_.reset();
2232   receiver_.reset();
2233   pending_external_requests_.clear();
2234   worker_is_idle_on_renderer_ = true;
2235   provider_host_.reset();
2236 
2237   for (auto& observer : observers_)
2238     observer.OnRunningStateChanged(this);
2239   if (should_restart) {
2240     StartWorkerInternal();
2241   } else if (!HasWorkInBrowser()) {
2242     OnNoWorkInBrowser();
2243   }
2244 }
2245 
FinishStartWorker(blink::ServiceWorkerStatusCode status)2246 void ServiceWorkerVersion::FinishStartWorker(
2247     blink::ServiceWorkerStatusCode status) {
2248   RunCallbacks(this, &start_callbacks_, status);
2249 }
2250 
CleanUpExternalRequest(const std::string & request_uuid,blink::ServiceWorkerStatusCode status)2251 void ServiceWorkerVersion::CleanUpExternalRequest(
2252     const std::string& request_uuid,
2253     blink::ServiceWorkerStatusCode status) {
2254   if (status == blink::ServiceWorkerStatusCode::kOk)
2255     return;
2256   external_request_uuid_to_request_id_.erase(request_uuid);
2257 }
2258 
OnNoWorkInBrowser()2259 void ServiceWorkerVersion::OnNoWorkInBrowser() {
2260   DCHECK(!HasWorkInBrowser());
2261   if (worker_is_idle_on_renderer_) {
2262     for (auto& observer : observers_)
2263       observer.OnNoWork(this);
2264   }
2265 }
2266 
IsStartWorkerAllowed() const2267 bool ServiceWorkerVersion::IsStartWorkerAllowed() const {
2268   // Check that the worker is allowed on this origin. It's possible a
2269   // worker was previously allowed and installed, but later the embedder's
2270   // policy or binary changed to disallow this origin.
2271   if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(
2272           {script_url_})) {
2273     return false;
2274   }
2275 
2276   // Check that the worker is allowed on the given scope. It's possible a worker
2277   // was previously allowed and installed, but later content settings changed to
2278   // disallow this scope. Since this worker might not be used for a specific
2279   // tab, pass a null callback as WebContents getter.
2280   if (ServiceWorkerContext::IsServiceWorkerOnUIEnabled()) {
2281     if (!GetContentClient()->browser()->AllowServiceWorkerOnUI(
2282             scope_, scope_, url::Origin::Create(scope_), script_url_,
2283             context_->wrapper()->browser_context(), base::NullCallback())) {
2284       return false;
2285     }
2286   } else {
2287     // resource_context() can return null in unit tests.
2288     if ((context_->wrapper()->resource_context() &&
2289          !GetContentClient()->browser()->AllowServiceWorkerOnIO(
2290              scope_, scope_, url::Origin::Create(scope_), script_url_,
2291              context_->wrapper()->resource_context(), base::NullCallback()))) {
2292       return false;
2293     }
2294   }
2295 
2296   return true;
2297 }
2298 
NotifyControlleeAdded(const std::string & uuid,const ServiceWorkerClientInfo & info)2299 void ServiceWorkerVersion::NotifyControlleeAdded(
2300     const std::string& uuid,
2301     const ServiceWorkerClientInfo& info) {
2302   for (auto& observer : observers_)
2303     observer.OnControlleeAdded(this, uuid, info);
2304 }
2305 
NotifyControlleeRemoved(const std::string & uuid)2306 void ServiceWorkerVersion::NotifyControlleeRemoved(const std::string& uuid) {
2307   // The observers can destroy |this|, so protect it first.
2308   // TODO(falken): Make OnNoControllees an explicit call to our registration
2309   // instead of an observer callback, if it has dangerous side-effects like
2310   // destroying the caller.
2311   auto protect = base::WrapRefCounted(this);
2312   for (auto& observer : observers_)
2313     observer.OnControlleeRemoved(this, uuid);
2314   if (!HasControllee()) {
2315     RestartTick(&no_controllees_time_);
2316     for (auto& observer : observers_)
2317       observer.OnNoControllees(this);
2318   }
2319 }
2320 
PrepareForUpdate(std::map<GURL,ServiceWorkerUpdateChecker::ComparedScriptInfo> compared_script_info_map,const GURL & updated_script_url,network::CrossOriginEmbedderPolicy cross_origin_embedder_policy)2321 void ServiceWorkerVersion::PrepareForUpdate(
2322     std::map<GURL, ServiceWorkerUpdateChecker::ComparedScriptInfo>
2323         compared_script_info_map,
2324     const GURL& updated_script_url,
2325     network::CrossOriginEmbedderPolicy cross_origin_embedder_policy) {
2326   compared_script_info_map_ = std::move(compared_script_info_map);
2327   updated_script_url_ = updated_script_url;
2328   set_cross_origin_embedder_policy(cross_origin_embedder_policy);
2329 }
2330 
2331 const std::map<GURL, ServiceWorkerUpdateChecker::ComparedScriptInfo>&
compared_script_info_map() const2332 ServiceWorkerVersion::compared_script_info_map() const {
2333   return compared_script_info_map_;
2334 }
2335 
2336 ServiceWorkerUpdateChecker::ComparedScriptInfo
TakeComparedScriptInfo(const GURL & script_url)2337 ServiceWorkerVersion::TakeComparedScriptInfo(const GURL& script_url) {
2338   auto it = compared_script_info_map_.find(script_url);
2339   DCHECK(it != compared_script_info_map_.end());
2340   ServiceWorkerUpdateChecker::ComparedScriptInfo info = std::move(it->second);
2341   compared_script_info_map_.erase(it);
2342   return info;
2343 }
2344 
ShouldRequireForegroundPriority(int worker_process_id) const2345 bool ServiceWorkerVersion::ShouldRequireForegroundPriority(
2346     int worker_process_id) const {
2347   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
2348 
2349   // Currently FetchEvents are the only type of event we need to really process
2350   // at foreground priority.  If the service worker does not have a FetchEvent
2351   // handler then we can always allow it to go to the background.
2352   if (fetch_handler_existence_ != FetchHandlerExistence::EXISTS)
2353     return false;
2354 
2355   // Keep the service worker at foreground priority if its controlling clients
2356   // from a different process.  In this situation we are likely to need to
2357   // quickly service FetchEvents when the worker's process does not have any
2358   // visible windows and would have otherwise been moved to the background.
2359   //
2360   // Ideally we would check the visibility of all clients as well, but that
2361   // would also require triggering additional checks on every visibility
2362   // change of all clients.  That would add a lot of complexity and its
2363   // unclear we need to pay that cost yet.  This may get easier once the
2364   // service worker code runs on the UI thread directly. (crbug.com/824858)
2365   //
2366   // For now the requirement for cross-process clients should filter out most
2367   // service workers.  The impact of foreground service workers is further
2368   // limited by the automatic shutdown mechanism.
2369   for (const auto& controllee : controllee_map_) {
2370     ServiceWorkerContainerHost* container_host = controllee.second;
2371     if (container_host->process_id() != worker_process_id)
2372       return true;
2373   }
2374   return false;
2375 }
2376 
UpdateForegroundPriority()2377 void ServiceWorkerVersion::UpdateForegroundPriority() {
2378   embedded_worker_->UpdateForegroundPriority();
2379 }
2380 
AddMessageToConsole(blink::mojom::ConsoleMessageLevel message_level,const std::string & message)2381 void ServiceWorkerVersion::AddMessageToConsole(
2382     blink::mojom::ConsoleMessageLevel message_level,
2383     const std::string& message) {
2384   if (running_status() == EmbeddedWorkerStatus::STARTING ||
2385       running_status() == EmbeddedWorkerStatus::RUNNING) {
2386     endpoint()->AddMessageToConsole(message_level, message);
2387   }
2388 }
2389 
MaybeReportConsoleMessageToInternals(blink::mojom::ConsoleMessageLevel message_level,const std::string & message)2390 void ServiceWorkerVersion::MaybeReportConsoleMessageToInternals(
2391     blink::mojom::ConsoleMessageLevel message_level,
2392     const std::string& message) {
2393   // When the internals UI page is opened, the page listens to
2394   // OnReportConsoleMessage().
2395   OnReportConsoleMessage(blink::mojom::ConsoleMessageSource::kOther,
2396                          message_level, base::UTF8ToUTF16(message), -1,
2397                          script_url_);
2398 }
2399 
UpdateIdleDelayIfNeeded(base::TimeDelta delay)2400 void ServiceWorkerVersion::UpdateIdleDelayIfNeeded(base::TimeDelta delay) {
2401   // The idle delay can be updated only when the worker is still running.
2402   bool update_idle_delay = running_status() == EmbeddedWorkerStatus::STARTING ||
2403                            running_status() == EmbeddedWorkerStatus::RUNNING;
2404 
2405   // The idle delay should not be updated when the worker needs to be
2406   // terminated ASAP so that the new worker can be activated soon.
2407   update_idle_delay = update_idle_delay && !needs_to_be_terminated_asap_;
2408 
2409   if (update_idle_delay) {
2410     endpoint()->SetIdleDelay(delay);
2411   }
2412 }
2413 
2414 }  // namespace content
2415