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.
5 #include "content/browser/service_worker/service_worker_version.h"
11 #include "base/command_line.h"
12 #include "base/guid.h"
13 #include "base/location.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string16.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/thread_task_runner_handle.h"
21 #include "base/time/time.h"
22 #include "content/browser/bad_message.h"
23 #include "content/browser/child_process_security_policy_impl.h"
24 #include "content/browser/message_port_message_filter.h"
25 #include "content/browser/message_port_service.h"
26 #include "content/browser/service_worker/embedded_worker_instance.h"
27 #include "content/browser/service_worker/embedded_worker_registry.h"
28 #include "content/browser/service_worker/service_worker_context_core.h"
29 #include "content/browser/service_worker/service_worker_context_wrapper.h"
30 #include "content/browser/service_worker/service_worker_metrics.h"
31 #include "content/browser/service_worker/service_worker_registration.h"
32 #include "content/browser/storage_partition_impl.h"
33 #include "content/common/service_worker/service_worker_messages.h"
34 #include "content/common/service_worker/service_worker_type_converters.h"
35 #include "content/common/service_worker/service_worker_utils.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "content/public/browser/content_browser_client.h"
38 #include "content/public/browser/page_navigator.h"
39 #include "content/public/browser/render_frame_host.h"
40 #include "content/public/browser/render_process_host.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/browser/web_contents_observer.h"
43 #include "content/public/common/background_sync.mojom.h"
44 #include "content/public/common/child_process_host.h"
45 #include "content/public/common/content_client.h"
46 #include "content/public/common/content_switches.h"
47 #include "content/public/common/result_codes.h"
48 #include "content/public/common/service_registry.h"
49 #include "mojo/common/common_type_converters.h"
50 #include "mojo/common/url_type_converters.h"
51 #include "net/http/http_response_headers.h"
52 #include "net/http/http_response_info.h"
56 using StatusCallback
= ServiceWorkerVersion::StatusCallback
;
57 using ServiceWorkerClients
= std::vector
<ServiceWorkerClientInfo
>;
58 using GetClientsCallback
=
59 base::Callback
<void(scoped_ptr
<ServiceWorkerClients
>)>;
63 // Delay between the timeout timer firing.
64 const int kTimeoutTimerDelaySeconds
= 30;
66 // Time to wait until stopping an idle worker.
67 const int kIdleWorkerTimeoutSeconds
= 30;
69 // Time until a stopping worker is considered stalled.
70 const int kStopWorkerTimeoutSeconds
= 30;
72 // Default delay for scheduled update.
73 const int kUpdateDelaySeconds
= 1;
75 // Timeout for waiting for a response to a ping.
76 const int kPingTimeoutSeconds
= 30;
78 // If the SW was destructed while starting up, how many seconds it
79 // had to start up for this to be considered a timeout occurrence.
80 const int kDestructedStartingWorkerTimeoutThresholdSeconds
= 5;
82 const char kClaimClientsStateErrorMesage
[] =
83 "Only the active worker can claim clients.";
85 const char kClaimClientsShutdownErrorMesage
[] =
86 "Failed to claim clients due to Service Worker system shutdown.";
88 void RunSoon(const base::Closure
& callback
) {
89 if (!callback
.is_null())
90 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback
);
93 template <typename CallbackArray
, typename Arg
>
94 void RunCallbacks(ServiceWorkerVersion
* version
,
95 CallbackArray
* callbacks_ptr
,
97 CallbackArray callbacks
;
98 callbacks
.swap(*callbacks_ptr
);
99 for (const auto& callback
: callbacks
)
103 template <typename IDMAP
, typename
... Params
>
104 void RunIDMapCallbacks(IDMAP
* requests
, const Params
&... params
) {
105 typename
IDMAP::iterator
iter(requests
);
106 while (!iter
.IsAtEnd()) {
107 iter
.GetCurrentValue()->callback
.Run(params
...);
113 template <typename CallbackType
, typename
... Params
>
114 bool RunIDMapCallback(IDMap
<CallbackType
, IDMapOwnPointer
>* requests
,
116 const Params
&... params
) {
117 CallbackType
* request
= requests
->Lookup(request_id
);
121 request
->callback
.Run(params
...);
122 requests
->Remove(request_id
);
126 void RunStartWorkerCallback(
127 const StatusCallback
& callback
,
128 scoped_refptr
<ServiceWorkerRegistration
> protect
,
129 ServiceWorkerStatusCode status
) {
130 callback
.Run(status
);
133 // A callback adapter to start a |task| after StartWorker.
134 void RunTaskAfterStartWorker(
135 base::WeakPtr
<ServiceWorkerVersion
> version
,
136 const StatusCallback
& error_callback
,
137 const base::Closure
& task
,
138 ServiceWorkerStatusCode status
) {
139 if (status
!= SERVICE_WORKER_OK
) {
140 if (!error_callback
.is_null())
141 error_callback
.Run(status
);
144 if (version
->running_status() != ServiceWorkerVersion::RUNNING
) {
145 // We've tried to start the worker (and it has succeeded), but
146 // it looks it's not running yet.
147 NOTREACHED() << "The worker's not running after successful StartWorker";
148 if (!error_callback
.is_null())
149 error_callback
.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
155 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback
& callback
,
156 ServiceWorkerStatusCode status
) {
158 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
159 ServiceWorkerResponse());
162 void RunErrorMessageCallback(
163 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
164 const ServiceWorkerVersion::StatusCallback
& callback
,
165 ServiceWorkerStatusCode status
) {
166 // Transfering the message ports failed, so destroy the ports.
167 for (const TransferredMessagePort
& port
: sent_message_ports
) {
168 MessagePortService::GetInstance()->ClosePort(port
.id
);
170 callback
.Run(status
);
173 void RunErrorServicePortConnectCallback(
174 const ServiceWorkerVersion::ServicePortConnectCallback
& callback
,
175 ServiceWorkerStatusCode status
) {
176 callback
.Run(status
, false /* accept_connection */, base::string16(),
180 using OpenURLCallback
= base::Callback
<void(int, int)>;
182 // The OpenURLObserver class is a WebContentsObserver that will wait for a
183 // WebContents to be initialized, run the |callback| passed to its constructor
184 // then self destroy.
185 // The callback will receive the process and frame ids. If something went wrong
186 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
187 // The callback will be called in the IO thread.
188 class OpenURLObserver
: public WebContentsObserver
{
190 OpenURLObserver(WebContents
* web_contents
, const OpenURLCallback
& callback
)
191 : WebContentsObserver(web_contents
), callback_(callback
) {}
193 void DidCommitProvisionalLoadForFrame(
194 RenderFrameHost
* render_frame_host
,
195 const GURL
& validated_url
,
196 ui::PageTransition transition_type
) override
{
197 DCHECK(web_contents());
199 if (render_frame_host
!= web_contents()->GetMainFrame())
202 RunCallback(render_frame_host
->GetProcess()->GetID(),
203 render_frame_host
->GetRoutingID());
206 void RenderProcessGone(base::TerminationStatus status
) override
{
207 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
210 void WebContentsDestroyed() override
{
211 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
215 void RunCallback(int render_process_id
, int render_frame_id
) {
216 // After running the callback, |this| will stop observing, thus
217 // web_contents() should return nullptr and |RunCallback| should no longer
218 // be called. Then, |this| will self destroy.
219 DCHECK(web_contents());
221 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
222 base::Bind(callback_
,
226 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
229 const OpenURLCallback callback_
;
231 DISALLOW_COPY_AND_ASSIGN(OpenURLObserver
);
234 void DidOpenURL(const OpenURLCallback
& callback
, WebContents
* web_contents
) {
235 DCHECK(web_contents
);
237 new OpenURLObserver(web_contents
, callback
);
240 void NavigateClientOnUI(const GURL
& url
,
241 const GURL
& script_url
,
244 const OpenURLCallback
& callback
) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
247 RenderFrameHost
* render_frame_host
=
248 RenderFrameHost::FromID(process_id
, frame_id
);
249 WebContents
* web_contents
=
250 WebContents::FromRenderFrameHost(render_frame_host
);
252 if (!render_frame_host
|| !web_contents
) {
253 BrowserThread::PostTask(
254 BrowserThread::IO
, FROM_HERE
,
255 base::Bind(callback
, ChildProcessHost::kInvalidUniqueID
,
260 OpenURLParams
params(
261 url
, Referrer::SanitizeForRequest(
262 url
, Referrer(script_url
, blink::WebReferrerPolicyDefault
)),
263 CURRENT_TAB
, ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
264 true /* is_renderer_initiated */);
265 web_contents
->OpenURL(params
);
266 DidOpenURL(callback
, web_contents
);
271 const GURL
& script_url
,
273 const scoped_refptr
<ServiceWorkerContextWrapper
>& context_wrapper
,
274 const OpenURLCallback
& callback
) {
275 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
277 BrowserContext
* browser_context
= context_wrapper
->storage_partition()
278 ? context_wrapper
->storage_partition()->browser_context()
280 // We are shutting down.
281 if (!browser_context
)
284 RenderProcessHost
* render_process_host
=
285 RenderProcessHost::FromID(process_id
);
286 if (render_process_host
->IsForGuestsOnly()) {
287 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
289 ChildProcessHost::kInvalidUniqueID
,
294 OpenURLParams
params(
295 url
, Referrer::SanitizeForRequest(
296 url
, Referrer(script_url
, blink::WebReferrerPolicyDefault
)),
297 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
298 true /* is_renderer_initiated */);
300 GetContentClient()->browser()->OpenURL(
301 browser_context
, params
,
302 base::Bind(&DidOpenURL
, callback
));
305 void KillEmbeddedWorkerProcess(int process_id
, ResultCode code
) {
306 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
307 RenderProcessHost
* render_process_host
=
308 RenderProcessHost::FromID(process_id
);
309 if (render_process_host
->GetHandle() != base::kNullProcessHandle
) {
310 bad_message::ReceivedBadMessage(render_process_host
,
311 bad_message::SERVICE_WORKER_BAD_URL
);
315 void ClearTick(base::TimeTicks
* time
) {
316 *time
= base::TimeTicks();
319 void RestartTick(base::TimeTicks
* time
) {
320 *time
= base::TimeTicks().Now();
323 base::TimeDelta
GetTickDuration(const base::TimeTicks
& time
) {
325 return base::TimeDelta();
326 return base::TimeTicks().Now() - time
;
329 void OnGetWindowClientsFromUI(
330 // The tuple contains process_id, frame_id, client_uuid.
331 const std::vector
<base::Tuple
<int, int, std::string
>>& clients_info
,
332 const GURL
& script_url
,
333 const GetClientsCallback
& callback
) {
334 scoped_ptr
<ServiceWorkerClients
> clients(new ServiceWorkerClients
);
336 for (const auto& it
: clients_info
) {
337 ServiceWorkerClientInfo info
=
338 ServiceWorkerProviderHost::GetWindowClientInfoOnUI(base::get
<0>(it
),
341 // If the request to the provider_host returned an empty
342 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
343 // it with a valid RenderFrameHost. It might be because the frame was killed
344 // or navigated in between.
348 // We can get info for a frame that was navigating end ended up with a
349 // different URL than expected. In such case, we should make sure to not
350 // expose cross-origin WindowClient.
351 if (info
.url
.GetOrigin() != script_url
.GetOrigin())
354 info
.client_uuid
= base::get
<2>(it
);
355 clients
->push_back(info
);
358 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
359 base::Bind(callback
, base::Passed(&clients
)));
362 void AddWindowClient(
363 ServiceWorkerProviderHost
* host
,
364 std::vector
<base::Tuple
<int, int, std::string
>>* client_info
) {
365 if (host
->client_type() != blink::WebServiceWorkerClientTypeWindow
)
367 client_info
->push_back(base::MakeTuple(host
->process_id(), host
->frame_id(),
368 host
->client_uuid()));
371 void AddNonWindowClient(ServiceWorkerProviderHost
* host
,
372 const ServiceWorkerClientQueryOptions
& options
,
373 ServiceWorkerClients
* clients
) {
374 blink::WebServiceWorkerClientType host_client_type
= host
->client_type();
375 if (host_client_type
== blink::WebServiceWorkerClientTypeWindow
)
377 if (options
.client_type
!= blink::WebServiceWorkerClientTypeAll
&&
378 options
.client_type
!= host_client_type
)
381 ServiceWorkerClientInfo
client_info(blink::WebPageVisibilityStateHidden
,
383 host
->document_url(),
384 REQUEST_CONTEXT_FRAME_TYPE_NONE
,
385 base::TimeTicks(), host_client_type
);
386 client_info
.client_uuid
= host
->client_uuid();
387 clients
->push_back(client_info
);
390 bool IsInstalled(ServiceWorkerVersion::Status status
) {
392 case ServiceWorkerVersion::NEW
:
393 case ServiceWorkerVersion::INSTALLING
:
394 case ServiceWorkerVersion::REDUNDANT
:
396 case ServiceWorkerVersion::INSTALLED
:
397 case ServiceWorkerVersion::ACTIVATING
:
398 case ServiceWorkerVersion::ACTIVATED
:
401 NOTREACHED() << "Unexpected status: " << status
;
405 struct ServiceWorkerClientInfoSortMRU
{
406 bool operator()(const ServiceWorkerClientInfo
& a
,
407 const ServiceWorkerClientInfo
& b
) const {
408 return a
.last_focus_time
> b
.last_focus_time
;
414 const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes
= 5;
415 const int ServiceWorkerVersion::kRequestTimeoutMinutes
= 5;
417 class ServiceWorkerVersion::Metrics
{
419 using EventType
= ServiceWorkerMetrics::EventType
;
420 explicit Metrics(ServiceWorkerVersion
* owner
) : owner_(owner
) {}
422 if (owner_
->should_exclude_from_uma_
)
424 for (const auto& ev
: event_stats_
) {
425 ServiceWorkerMetrics::RecordEventHandledRatio(
426 ev
.first
, ev
.second
.handled_events
, ev
.second
.fired_events
);
430 void RecordEventHandledStatus(EventType event
, bool handled
) {
431 event_stats_
[event
].fired_events
++;
433 event_stats_
[event
].handled_events
++;
436 void NotifyStopping() {
437 stop_status_
= ServiceWorkerMetrics::STOP_STATUS_STOPPING
;
440 void NotifyStopped() {
441 switch (stop_status_
) {
442 case ServiceWorkerMetrics::STOP_STATUS_STOPPED
:
443 case ServiceWorkerMetrics::STOP_STATUS_STALLED_THEN_STOPPED
:
445 case ServiceWorkerMetrics::STOP_STATUS_STOPPING
:
446 stop_status_
= ServiceWorkerMetrics::STOP_STATUS_STOPPED
;
448 case ServiceWorkerMetrics::STOP_STATUS_STALLED
:
449 stop_status_
= ServiceWorkerMetrics::STOP_STATUS_STALLED_THEN_STOPPED
;
451 case ServiceWorkerMetrics::NUM_STOP_STATUS_TYPES
:
455 if (IsInstalled(owner_
->status()))
456 ServiceWorkerMetrics::RecordStopWorkerStatus(stop_status_
);
459 void NotifyStalledInStopping() {
460 if (stop_status_
!= ServiceWorkerMetrics::STOP_STATUS_STOPPING
)
462 stop_status_
= ServiceWorkerMetrics::STOP_STATUS_STALLED
;
463 if (IsInstalled(owner_
->status()))
464 ServiceWorkerMetrics::RecordStopWorkerStatus(stop_status_
);
469 size_t fired_events
= 0;
470 size_t handled_events
= 0;
473 ServiceWorkerVersion
* owner_
;
474 std::map
<EventType
, EventStat
> event_stats_
;
475 ServiceWorkerMetrics::StopWorkerStatus stop_status_
=
476 ServiceWorkerMetrics::STOP_STATUS_STOPPING
;
478 DISALLOW_COPY_AND_ASSIGN(Metrics
);
481 // A controller for periodically sending a ping to the worker to see
482 // if the worker is not stalling.
483 class ServiceWorkerVersion::PingController
{
485 explicit PingController(ServiceWorkerVersion
* version
) : version_(version
) {}
488 void Activate() { ping_state_
= PINGING
; }
491 ClearTick(&ping_time_
);
492 ping_state_
= NOT_PINGING
;
495 void OnPongReceived() { ClearTick(&ping_time_
); }
497 bool IsTimedOut() { return ping_state_
== PING_TIMED_OUT
; }
499 // Checks ping status. This is supposed to be called periodically.
501 // - OnPingTimeout() if the worker hasn't reponded within a certain period.
502 // - PingWorker() if we're running ping timer and can send next ping.
503 void CheckPingStatus() {
504 if (GetTickDuration(ping_time_
) >
505 base::TimeDelta::FromSeconds(kPingTimeoutSeconds
)) {
506 ping_state_
= PING_TIMED_OUT
;
507 version_
->OnPingTimeout();
511 // Check if we want to send a next ping.
512 if (ping_state_
!= PINGING
|| !ping_time_
.is_null())
515 if (version_
->PingWorker() != SERVICE_WORKER_OK
) {
516 // TODO(falken): Maybe try resending Ping a few times first?
517 ping_state_
= PING_TIMED_OUT
;
518 version_
->OnPingTimeout();
521 RestartTick(&ping_time_
);
524 void SimulateTimeoutForTesting() {
525 version_
->PingWorker();
526 ping_state_
= PING_TIMED_OUT
;
527 version_
->OnPingTimeout();
531 enum PingState
{ NOT_PINGING
, PINGING
, PING_TIMED_OUT
};
532 ServiceWorkerVersion
* version_
; // Not owned.
533 base::TimeTicks ping_time_
;
534 PingState ping_state_
= NOT_PINGING
;
535 DISALLOW_COPY_AND_ASSIGN(PingController
);
538 ServiceWorkerVersion::ServiceWorkerVersion(
539 ServiceWorkerRegistration
* registration
,
540 const GURL
& script_url
,
542 base::WeakPtr
<ServiceWorkerContextCore
> context
)
543 : version_id_(version_id
),
544 registration_id_(registration
->id()),
545 script_url_(script_url
),
546 scope_(registration
->pattern()),
548 script_cache_map_(this, context
),
549 ping_controller_(new PingController(this)),
550 should_exclude_from_uma_(
551 ServiceWorkerMetrics::ShouldExcludeURLFromHistogram(scope_
)),
552 weak_factory_(this) {
554 DCHECK(registration
);
555 context_
->AddLiveVersion(this);
556 embedded_worker_
= context_
->embedded_worker_registry()->CreateWorker();
557 embedded_worker_
->AddListener(this);
560 ServiceWorkerVersion::~ServiceWorkerVersion() {
563 // The user may have closed the tab waiting for SW to start up.
564 if (GetTickDuration(start_time_
) >
565 base::TimeDelta::FromSeconds(
566 kDestructedStartingWorkerTimeoutThresholdSeconds
)) {
567 DCHECK(timeout_timer_
.IsRunning());
568 DCHECK(!embedded_worker_
->devtools_attached());
569 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT
);
572 // Same with stopping.
573 if (GetTickDuration(stop_time_
) >
574 base::TimeDelta::FromSeconds(kStopWorkerTimeoutSeconds
)) {
575 metrics_
->NotifyStalledInStopping();
579 context_
->RemoveLiveVersion(version_id_
);
581 if (running_status() == STARTING
|| running_status() == RUNNING
)
582 embedded_worker_
->Stop();
583 embedded_worker_
->RemoveListener(this);
586 void ServiceWorkerVersion::SetStatus(Status status
) {
587 if (status_
== status
)
592 if (skip_waiting_
&& status_
== ACTIVATED
) {
593 for (int request_id
: pending_skip_waiting_requests_
)
594 DidSkipWaiting(request_id
);
595 pending_skip_waiting_requests_
.clear();
598 std::vector
<base::Closure
> callbacks
;
599 callbacks
.swap(status_change_callbacks_
);
600 for (const auto& callback
: callbacks
)
603 FOR_EACH_OBSERVER(Listener
, listeners_
, OnVersionStateChanged(this));
606 void ServiceWorkerVersion::RegisterStatusChangeCallback(
607 const base::Closure
& callback
) {
608 status_change_callbacks_
.push_back(callback
);
611 ServiceWorkerVersionInfo
ServiceWorkerVersion::GetInfo() {
612 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
613 ServiceWorkerVersionInfo
info(
614 running_status(), status(), script_url(), registration_id(), version_id(),
615 embedded_worker()->process_id(), embedded_worker()->thread_id(),
616 embedded_worker()->worker_devtools_agent_route_id());
617 for (const auto& controllee
: controllee_map_
) {
618 const ServiceWorkerProviderHost
* host
= controllee
.second
;
619 info
.clients
.insert(std::make_pair(
621 ServiceWorkerVersionInfo::ClientInfo(
622 host
->process_id(), host
->route_id(), host
->provider_type())));
624 if (!main_script_http_info_
)
626 info
.script_response_time
= main_script_http_info_
->response_time
;
627 if (main_script_http_info_
->headers
)
628 main_script_http_info_
->headers
->GetLastModifiedValue(
629 &info
.script_last_modified
);
633 void ServiceWorkerVersion::StartWorker(const StatusCallback
& callback
) {
635 RecordStartWorkerResult(SERVICE_WORKER_ERROR_ABORT
);
636 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_ABORT
));
639 if (is_redundant()) {
640 RecordStartWorkerResult(SERVICE_WORKER_ERROR_REDUNDANT
);
641 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_REDUNDANT
));
644 prestart_status_
= status_
;
646 // Ensure the live registration during starting worker so that the worker can
647 // get associated with it in SWDispatcherHost::OnSetHostedVersionId().
648 context_
->storage()->FindRegistrationForId(
651 base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker
,
652 weak_factory_
.GetWeakPtr(),
656 void ServiceWorkerVersion::StopWorker(const StatusCallback
& callback
) {
657 if (running_status() == STOPPED
) {
658 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
661 if (stop_callbacks_
.empty()) {
662 ServiceWorkerStatusCode status
= embedded_worker_
->Stop();
663 if (status
!= SERVICE_WORKER_OK
) {
664 RunSoon(base::Bind(callback
, status
));
668 stop_callbacks_
.push_back(callback
);
671 void ServiceWorkerVersion::ScheduleUpdate() {
674 if (update_timer_
.IsRunning()) {
675 update_timer_
.Reset();
678 if (is_update_scheduled_
)
680 is_update_scheduled_
= true;
682 // Protect |this| until the timer fires, since we may be stopping
683 // and soon no one might hold a reference to us.
684 context_
->ProtectVersion(make_scoped_refptr(this));
685 update_timer_
.Start(FROM_HERE
,
686 base::TimeDelta::FromSeconds(kUpdateDelaySeconds
),
687 base::Bind(&ServiceWorkerVersion::StartUpdate
,
688 weak_factory_
.GetWeakPtr()));
691 void ServiceWorkerVersion::StartUpdate() {
694 context_
->storage()->FindRegistrationForId(
695 registration_id_
, scope_
.GetOrigin(),
696 base::Bind(&ServiceWorkerVersion::FoundRegistrationForUpdate
,
697 weak_factory_
.GetWeakPtr()));
700 void ServiceWorkerVersion::DeferScheduledUpdate() {
701 if (update_timer_
.IsRunning())
702 update_timer_
.Reset();
705 void ServiceWorkerVersion::DispatchMessageEvent(
706 const base::string16
& message
,
707 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
708 const StatusCallback
& callback
) {
709 for (const TransferredMessagePort
& port
: sent_message_ports
) {
710 MessagePortService::GetInstance()->HoldMessages(port
.id
);
713 DispatchMessageEventInternal(message
, sent_message_ports
, callback
);
716 void ServiceWorkerVersion::DispatchMessageEventInternal(
717 const base::string16
& message
,
718 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
719 const StatusCallback
& callback
) {
721 if (running_status() != RUNNING
) {
722 // Schedule calling this method after starting the worker.
723 StartWorker(base::Bind(
724 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
725 base::Bind(&RunErrorMessageCallback
, sent_message_ports
, callback
),
726 base::Bind(&self::DispatchMessageEventInternal
,
727 weak_factory_
.GetWeakPtr(), message
, sent_message_ports
,
732 // TODO(kinuko): Cleanup this (and corresponding unit test) when message
733 // event becomes extendable, round-trip event. (crbug.com/498596)
734 RestartTick(&idle_time_
);
736 MessagePortMessageFilter
* filter
=
737 embedded_worker_
->message_port_message_filter();
738 std::vector
<int> new_routing_ids
;
739 filter
->UpdateMessagePortsWithNewRoutes(sent_message_ports
, &new_routing_ids
);
740 ServiceWorkerStatusCode status
=
741 embedded_worker_
->SendMessage(ServiceWorkerMsg_MessageToWorker(
742 message
, sent_message_ports
, new_routing_ids
));
743 RunSoon(base::Bind(callback
, status
));
746 void ServiceWorkerVersion::DispatchInstallEvent(
747 const StatusCallback
& callback
) {
749 DCHECK_EQ(INSTALLING
, status()) << status();
751 if (running_status() != RUNNING
) {
752 // Schedule calling this method after starting the worker.
754 base::Bind(&RunTaskAfterStartWorker
,
755 weak_factory_
.GetWeakPtr(),
757 base::Bind(&self::DispatchInstallEventAfterStartWorker
,
758 weak_factory_
.GetWeakPtr(),
761 DispatchInstallEventAfterStartWorker(callback
);
765 void ServiceWorkerVersion::DispatchActivateEvent(
766 const StatusCallback
& callback
) {
768 DCHECK_EQ(ACTIVATING
, status()) << status();
770 if (running_status() != RUNNING
) {
771 // Schedule calling this method after starting the worker.
773 base::Bind(&RunTaskAfterStartWorker
,
774 weak_factory_
.GetWeakPtr(),
776 base::Bind(&self::DispatchActivateEventAfterStartWorker
,
777 weak_factory_
.GetWeakPtr(),
780 DispatchActivateEventAfterStartWorker(callback
);
784 void ServiceWorkerVersion::DispatchFetchEvent(
785 const ServiceWorkerFetchRequest
& request
,
786 const base::Closure
& prepare_callback
,
787 const FetchCallback
& fetch_callback
) {
789 DCHECK_EQ(ACTIVATED
, status()) << status();
791 if (running_status() != RUNNING
) {
792 // Schedule calling this method after starting the worker.
793 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
794 weak_factory_
.GetWeakPtr(),
795 base::Bind(&RunErrorFetchCallback
, fetch_callback
),
796 base::Bind(&self::DispatchFetchEvent
,
797 weak_factory_
.GetWeakPtr(),
804 prepare_callback
.Run();
806 int request_id
= AddRequest(fetch_callback
, &fetch_requests_
, REQUEST_FETCH
);
807 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
808 ServiceWorkerMsg_FetchEvent(request_id
, request
));
809 if (status
!= SERVICE_WORKER_OK
) {
810 fetch_requests_
.Remove(request_id
);
811 RunSoon(base::Bind(&RunErrorFetchCallback
,
813 SERVICE_WORKER_ERROR_FAILED
));
817 void ServiceWorkerVersion::DispatchSyncEvent(SyncRegistrationPtr registration
,
818 const StatusCallback
& callback
) {
820 DCHECK_EQ(ACTIVATED
, status()) << status();
821 if (running_status() != RUNNING
) {
822 // Schedule calling this method after starting the worker.
823 StartWorker(base::Bind(
824 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(), callback
,
825 base::Bind(&self::DispatchSyncEvent
, weak_factory_
.GetWeakPtr(),
826 base::Passed(registration
.Pass()), callback
)));
830 int request_id
= AddRequest(callback
, &sync_requests_
, REQUEST_SYNC
);
831 if (!background_sync_dispatcher_
) {
832 embedded_worker_
->GetServiceRegistry()->ConnectToRemoteService(
833 mojo::GetProxy(&background_sync_dispatcher_
));
834 background_sync_dispatcher_
.set_connection_error_handler(base::Bind(
835 &ServiceWorkerVersion::OnBackgroundSyncDispatcherConnectionError
,
836 weak_factory_
.GetWeakPtr()));
839 background_sync_dispatcher_
->Sync(
840 registration
.Pass(), base::Bind(&self::OnSyncEventFinished
,
841 weak_factory_
.GetWeakPtr(), request_id
));
844 void ServiceWorkerVersion::DispatchNotificationClickEvent(
845 const StatusCallback
& callback
,
846 int64_t persistent_notification_id
,
847 const PlatformNotificationData
& notification_data
,
850 DCHECK_EQ(ACTIVATED
, status()) << status();
851 if (running_status() != RUNNING
) {
852 // Schedule calling this method after starting the worker.
853 StartWorker(base::Bind(
854 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(), callback
,
855 base::Bind(&self::DispatchNotificationClickEvent
,
856 weak_factory_
.GetWeakPtr(), callback
,
857 persistent_notification_id
, notification_data
,
862 int request_id
= AddRequest(callback
, ¬ification_click_requests_
,
863 REQUEST_NOTIFICATION_CLICK
);
864 ServiceWorkerStatusCode status
=
865 embedded_worker_
->SendMessage(ServiceWorkerMsg_NotificationClickEvent(
866 request_id
, persistent_notification_id
, notification_data
,
868 if (status
!= SERVICE_WORKER_OK
) {
869 notification_click_requests_
.Remove(request_id
);
870 RunSoon(base::Bind(callback
, status
));
874 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback
& callback
,
875 const std::string
& data
) {
877 DCHECK_EQ(ACTIVATED
, status()) << status();
878 if (running_status() != RUNNING
) {
879 // Schedule calling this method after starting the worker.
880 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
881 weak_factory_
.GetWeakPtr(), callback
,
882 base::Bind(&self::DispatchPushEvent
,
883 weak_factory_
.GetWeakPtr(),
888 int request_id
= AddRequest(callback
, &push_requests_
, REQUEST_PUSH
);
889 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
890 ServiceWorkerMsg_PushEvent(request_id
, data
));
891 if (status
!= SERVICE_WORKER_OK
) {
892 push_requests_
.Remove(request_id
);
893 RunSoon(base::Bind(callback
, status
));
897 void ServiceWorkerVersion::DispatchGeofencingEvent(
898 const StatusCallback
& callback
,
899 blink::WebGeofencingEventType event_type
,
900 const std::string
& region_id
,
901 const blink::WebCircularGeofencingRegion
& region
) {
903 DCHECK_EQ(ACTIVATED
, status()) << status();
905 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
906 switches::kEnableExperimentalWebPlatformFeatures
)) {
907 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
911 if (running_status() != RUNNING
) {
912 // Schedule calling this method after starting the worker.
913 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
914 weak_factory_
.GetWeakPtr(),
916 base::Bind(&self::DispatchGeofencingEvent
,
917 weak_factory_
.GetWeakPtr(),
926 AddRequest(callback
, &geofencing_requests_
, REQUEST_GEOFENCING
);
927 ServiceWorkerStatusCode status
=
928 embedded_worker_
->SendMessage(ServiceWorkerMsg_GeofencingEvent(
929 request_id
, event_type
, region_id
, region
));
930 if (status
!= SERVICE_WORKER_OK
) {
931 geofencing_requests_
.Remove(request_id
);
932 RunSoon(base::Bind(callback
, status
));
936 void ServiceWorkerVersion::DispatchServicePortConnectEvent(
937 const ServicePortConnectCallback
& callback
,
938 const GURL
& target_url
,
942 DCHECK_EQ(ACTIVATED
, status()) << status();
944 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
945 switches::kEnableExperimentalWebPlatformFeatures
)) {
946 callback
.Run(SERVICE_WORKER_ERROR_ABORT
, false, base::string16(),
951 if (running_status() != RUNNING
) {
952 // Schedule calling this method after starting the worker.
954 base::Bind(&RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
955 base::Bind(&RunErrorServicePortConnectCallback
, callback
),
956 base::Bind(&self::DispatchServicePortConnectEvent
,
957 weak_factory_
.GetWeakPtr(), callback
, target_url
,
962 int request_id
= AddRequest(callback
, &service_port_connect_requests_
,
963 REQUEST_SERVICE_PORT_CONNECT
);
964 if (!service_port_dispatcher_
) {
965 embedded_worker_
->GetServiceRegistry()->ConnectToRemoteService(
966 mojo::GetProxy(&service_port_dispatcher_
));
967 service_port_dispatcher_
.set_connection_error_handler(base::Bind(
968 &ServiceWorkerVersion::OnServicePortDispatcherConnectionError
,
969 weak_factory_
.GetWeakPtr()));
971 service_port_dispatcher_
->Connect(
972 mojo::String::From(target_url
), mojo::String::From(origin
), port_id
,
973 base::Bind(&ServiceWorkerVersion::OnServicePortConnectEventFinished
,
974 weak_factory_
.GetWeakPtr(), request_id
));
977 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
978 const NavigatorConnectClient
& client
,
979 const base::string16
& message
,
980 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
981 const StatusCallback
& callback
) {
983 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
984 // have already put all the sent message ports on hold. So no need to do that
987 if (running_status() != RUNNING
) {
988 // Schedule calling this method after starting the worker.
989 StartWorker(base::Bind(
990 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
991 base::Bind(&RunErrorMessageCallback
, sent_message_ports
, callback
),
992 base::Bind(&self::DispatchCrossOriginMessageEvent
,
993 weak_factory_
.GetWeakPtr(), client
, message
,
994 sent_message_ports
, callback
)));
998 MessagePortMessageFilter
* filter
=
999 embedded_worker_
->message_port_message_filter();
1000 std::vector
<int> new_routing_ids
;
1001 filter
->UpdateMessagePortsWithNewRoutes(sent_message_ports
, &new_routing_ids
);
1002 ServiceWorkerStatusCode status
=
1003 embedded_worker_
->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
1004 client
, message
, sent_message_ports
, new_routing_ids
));
1005 RunSoon(base::Bind(callback
, status
));
1008 void ServiceWorkerVersion::AddControllee(
1009 ServiceWorkerProviderHost
* provider_host
) {
1010 const std::string
& uuid
= provider_host
->client_uuid();
1011 CHECK(!provider_host
->client_uuid().empty());
1012 DCHECK(!ContainsKey(controllee_map_
, uuid
));
1013 controllee_map_
[uuid
] = provider_host
;
1014 // Keep the worker alive a bit longer right after a new controllee is added.
1015 RestartTick(&idle_time_
);
1016 FOR_EACH_OBSERVER(Listener
, listeners_
,
1017 OnControlleeAdded(this, provider_host
));
1020 void ServiceWorkerVersion::RemoveControllee(
1021 ServiceWorkerProviderHost
* provider_host
) {
1022 const std::string
& uuid
= provider_host
->client_uuid();
1023 DCHECK(ContainsKey(controllee_map_
, uuid
));
1024 controllee_map_
.erase(uuid
);
1025 FOR_EACH_OBSERVER(Listener
, listeners_
,
1026 OnControlleeRemoved(this, provider_host
));
1027 if (HasControllee())
1029 FOR_EACH_OBSERVER(Listener
, listeners_
, OnNoControllees(this));
1032 bool ServiceWorkerVersion::HasWindowClients() {
1033 return !GetWindowClientsInternal(false /* include_uncontrolled */).empty();
1036 void ServiceWorkerVersion::AddStreamingURLRequestJob(
1037 const ServiceWorkerURLRequestJob
* request_job
) {
1038 DCHECK(streaming_url_request_jobs_
.find(request_job
) ==
1039 streaming_url_request_jobs_
.end());
1040 streaming_url_request_jobs_
.insert(request_job
);
1043 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
1044 const ServiceWorkerURLRequestJob
* request_job
) {
1045 streaming_url_request_jobs_
.erase(request_job
);
1050 void ServiceWorkerVersion::AddListener(Listener
* listener
) {
1051 listeners_
.AddObserver(listener
);
1054 void ServiceWorkerVersion::RemoveListener(Listener
* listener
) {
1055 listeners_
.RemoveObserver(listener
);
1058 void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status
,
1059 const std::string
& status_message
) {
1060 if (status_message
.empty()) {
1061 OnReportException(base::UTF8ToUTF16(ServiceWorkerStatusToString(status
)),
1064 OnReportException(base::UTF8ToUTF16(status_message
), -1, -1, GURL());
1068 void ServiceWorkerVersion::SetStartWorkerStatusCode(
1069 ServiceWorkerStatusCode status
) {
1070 start_worker_status_
= status
;
1073 void ServiceWorkerVersion::Doom() {
1074 DCHECK(!HasControllee());
1075 SetStatus(REDUNDANT
);
1076 if (running_status() == STARTING
|| running_status() == RUNNING
)
1077 embedded_worker_
->Stop();
1080 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
1081 script_cache_map_
.GetResources(&resources
);
1082 context_
->storage()->PurgeResources(resources
);
1085 void ServiceWorkerVersion::SetDevToolsAttached(bool attached
) {
1086 embedded_worker()->set_devtools_attached(attached
);
1088 // TODO(falken): Canceling the timeouts when debugging could cause
1089 // heisenbugs; we should instead run them as normal show an educational
1090 // message in DevTools when they occur. crbug.com/470419
1092 // Don't record the startup time metric once DevTools is attached.
1093 ClearTick(&start_time_
);
1094 skip_recording_startup_time_
= true;
1096 // Cancel request timeouts.
1097 SetAllRequestTimes(base::TimeTicks());
1100 if (!start_callbacks_
.empty()) {
1101 // Reactivate the timer for start timeout.
1102 DCHECK(timeout_timer_
.IsRunning());
1103 DCHECK(running_status() == STARTING
|| running_status() == STOPPING
)
1104 << running_status();
1105 RestartTick(&start_time_
);
1108 // Reactivate request timeouts.
1109 SetAllRequestTimes(base::TimeTicks::Now());
1112 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
1113 const net::HttpResponseInfo
& http_info
) {
1114 main_script_http_info_
.reset(new net::HttpResponseInfo(http_info
));
1115 FOR_EACH_OBSERVER(Listener
, listeners_
,
1116 OnMainScriptHttpResponseInfoSet(this));
1119 void ServiceWorkerVersion::SimulatePingTimeoutForTesting() {
1120 ping_controller_
->SimulateTimeoutForTesting();
1123 const net::HttpResponseInfo
*
1124 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
1125 return main_script_http_info_
.get();
1128 ServiceWorkerVersion::RequestInfo::RequestInfo(int id
,
1130 const base::TimeTicks
& now
)
1131 : id(id
), type(type
), time(now
) {
1134 ServiceWorkerVersion::RequestInfo::~RequestInfo() {
1137 template <typename CallbackType
>
1138 ServiceWorkerVersion::PendingRequest
<CallbackType
>::PendingRequest(
1139 const CallbackType
& callback
,
1140 const base::TimeTicks
& time
)
1141 : callback(callback
), start_time(time
) {
1144 template <typename CallbackType
>
1145 ServiceWorkerVersion::PendingRequest
<CallbackType
>::~PendingRequest() {
1148 void ServiceWorkerVersion::OnScriptLoaded() {
1149 if (running_status() == STOPPING
)
1151 DCHECK_EQ(STARTING
, running_status());
1152 // Activate ping/pong now that JavaScript execution will start.
1153 ping_controller_
->Activate();
1156 void ServiceWorkerVersion::OnStarting() {
1157 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
1160 void ServiceWorkerVersion::OnStarted() {
1161 DCHECK_EQ(RUNNING
, running_status());
1162 RestartTick(&idle_time_
);
1164 // Fire all start callbacks.
1165 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1166 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_OK
);
1167 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
1170 void ServiceWorkerVersion::OnStopping() {
1171 metrics_
->NotifyStopping();
1172 RestartTick(&stop_time_
);
1173 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
1176 void ServiceWorkerVersion::OnStopped(
1177 EmbeddedWorkerInstance::Status old_status
) {
1178 metrics_
->NotifyStopped();
1179 if (!stop_time_
.is_null())
1180 ServiceWorkerMetrics::RecordStopWorkerTime(GetTickDuration(stop_time_
));
1182 OnStoppedInternal(old_status
);
1185 void ServiceWorkerVersion::OnDetached(
1186 EmbeddedWorkerInstance::Status old_status
) {
1187 OnStoppedInternal(old_status
);
1190 void ServiceWorkerVersion::OnReportException(
1191 const base::string16
& error_message
,
1194 const GURL
& source_url
) {
1199 this, error_message
, line_number
, column_number
, source_url
));
1202 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier
,
1204 const base::string16
& message
,
1206 const GURL
& source_url
) {
1207 FOR_EACH_OBSERVER(Listener
,
1209 OnReportConsoleMessage(this,
1217 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message
& message
) {
1218 bool handled
= true;
1219 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion
, message
)
1220 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients
,
1222 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished
,
1223 OnActivateEventFinished
)
1224 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished
,
1225 OnInstallEventFinished
)
1226 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished
,
1227 OnFetchEventFinished
)
1228 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished
,
1229 OnNotificationClickEventFinished
)
1230 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished
,
1231 OnPushEventFinished
)
1232 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished
,
1233 OnGeofencingEventFinished
)
1234 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow
,
1236 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata
,
1237 OnSetCachedMetadata
)
1238 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata
,
1239 OnClearCachedMetadata
)
1240 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient
,
1241 OnPostMessageToClient
)
1242 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient
,
1244 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NavigateClient
, OnNavigateClient
)
1245 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting
,
1247 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients
,
1249 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong
, OnPongFromWorker
)
1250 IPC_MESSAGE_UNHANDLED(handled
= false)
1251 IPC_END_MESSAGE_MAP()
1255 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
1256 ServiceWorkerStatusCode status
) {
1257 if (status
!= SERVICE_WORKER_OK
) {
1258 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1259 RunCallbacks(this, &start_callbacks_
,
1260 DeduceStartWorkerFailureReason(status
));
1264 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
1265 const StatusCallback
& callback
) {
1266 DCHECK_EQ(RUNNING
, running_status())
1267 << "Worker stopped too soon after it was started.";
1269 int request_id
= AddRequest(callback
, &install_requests_
, REQUEST_INSTALL
);
1270 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
1271 ServiceWorkerMsg_InstallEvent(request_id
));
1272 if (status
!= SERVICE_WORKER_OK
) {
1273 install_requests_
.Remove(request_id
);
1274 RunSoon(base::Bind(callback
, status
));
1278 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
1279 const StatusCallback
& callback
) {
1280 DCHECK_EQ(RUNNING
, running_status())
1281 << "Worker stopped too soon after it was started.";
1283 int request_id
= AddRequest(callback
, &activate_requests_
, REQUEST_ACTIVATE
);
1284 ServiceWorkerStatusCode status
=
1285 embedded_worker_
->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id
));
1286 if (status
!= SERVICE_WORKER_OK
) {
1287 activate_requests_
.Remove(request_id
);
1288 RunSoon(base::Bind(callback
, status
));
1292 void ServiceWorkerVersion::OnGetClients(
1294 const ServiceWorkerClientQueryOptions
& options
) {
1295 TRACE_EVENT_ASYNC_BEGIN2(
1296 "ServiceWorker", "ServiceWorkerVersion::OnGetClients", request_id
,
1297 "client_type", options
.client_type
, "include_uncontrolled",
1298 options
.include_uncontrolled
);
1300 ServiceWorkerClients clients
;
1301 if (controllee_map_
.empty() && !options
.include_uncontrolled
) {
1302 OnGetClientsFinished(request_id
, &clients
);
1306 // For Window clients we want to query the info on the UI thread first.
1307 if (options
.client_type
== blink::WebServiceWorkerClientTypeWindow
||
1308 options
.client_type
== blink::WebServiceWorkerClientTypeAll
) {
1309 GetWindowClients(request_id
, options
);
1313 GetNonWindowClients(request_id
, options
, &clients
);
1314 OnGetClientsFinished(request_id
, &clients
);
1317 void ServiceWorkerVersion::OnGetClientsFinished(int request_id
,
1318 ServiceWorkerClients
* clients
) {
1319 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1320 TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::OnGetClients",
1321 request_id
, "The number of clients", clients
->size());
1323 if (running_status() != RUNNING
)
1325 // Sort clients so that the most recently active tab is in the front.
1326 std::sort(clients
->begin(), clients
->end(), ServiceWorkerClientInfoSortMRU());
1327 embedded_worker_
->SendMessage(
1328 ServiceWorkerMsg_DidGetClients(request_id
, *clients
));
1331 void ServiceWorkerVersion::OnActivateEventFinished(
1333 blink::WebServiceWorkerEventResult result
) {
1334 DCHECK(ACTIVATING
== status() ||
1335 REDUNDANT
== status()) << status();
1336 TRACE_EVENT0("ServiceWorker",
1337 "ServiceWorkerVersion::OnActivateEventFinished");
1339 PendingRequest
<StatusCallback
>* request
=
1340 activate_requests_
.Lookup(request_id
);
1342 NOTREACHED() << "Got unexpected message: " << request_id
;
1345 ServiceWorkerStatusCode rv
= SERVICE_WORKER_OK
;
1346 if (result
== blink::WebServiceWorkerEventResultRejected
)
1347 rv
= SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
;
1349 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.ActivateEvent.Time",
1350 base::TimeTicks::Now() - request
->start_time
);
1352 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1353 request
->callback
.Run(rv
);
1354 RemoveCallbackAndStopIfRedundant(&activate_requests_
, request_id
);
1357 void ServiceWorkerVersion::OnInstallEventFinished(
1359 blink::WebServiceWorkerEventResult result
) {
1360 // Status is REDUNDANT if the worker was doomed while handling the install
1361 // event, and finished handling before being terminated.
1362 DCHECK(status() == INSTALLING
|| status() == REDUNDANT
) << status();
1363 TRACE_EVENT0("ServiceWorker",
1364 "ServiceWorkerVersion::OnInstallEventFinished");
1366 PendingRequest
<StatusCallback
>* request
=
1367 install_requests_
.Lookup(request_id
);
1369 NOTREACHED() << "Got unexpected message: " << request_id
;
1372 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1373 if (result
== blink::WebServiceWorkerEventResultRejected
)
1374 status
= SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
;
1376 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.InstallEvent.Time",
1377 base::TimeTicks::Now() - request
->start_time
);
1379 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1380 request
->callback
.Run(status
);
1381 RemoveCallbackAndStopIfRedundant(&install_requests_
, request_id
);
1384 void ServiceWorkerVersion::OnFetchEventFinished(
1386 ServiceWorkerFetchEventResult result
,
1387 const ServiceWorkerResponse
& response
) {
1388 TRACE_EVENT1("ServiceWorker",
1389 "ServiceWorkerVersion::OnFetchEventFinished",
1390 "Request id", request_id
);
1391 PendingRequest
<FetchCallback
>* request
= fetch_requests_
.Lookup(request_id
);
1393 NOTREACHED() << "Got unexpected message: " << request_id
;
1397 // TODO(kinuko): Record other event statuses too.
1398 const bool handled
= (result
== SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE
);
1399 metrics_
->RecordEventHandledStatus(ServiceWorkerMetrics::EVENT_TYPE_FETCH
,
1402 ServiceWorkerMetrics::RecordFetchEventTime(
1403 result
, base::TimeTicks::Now() - request
->start_time
);
1405 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1406 request
->callback
.Run(SERVICE_WORKER_OK
, result
, response
);
1407 RemoveCallbackAndStopIfRedundant(&fetch_requests_
, request_id
);
1410 void ServiceWorkerVersion::OnSyncEventFinished(
1412 ServiceWorkerEventStatus status
) {
1413 TRACE_EVENT1("ServiceWorker",
1414 "ServiceWorkerVersion::OnSyncEventFinished",
1415 "Request id", request_id
);
1416 PendingRequest
<StatusCallback
>* request
= sync_requests_
.Lookup(request_id
);
1418 NOTREACHED() << "Got unexpected message: " << request_id
;
1422 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1423 request
->callback
.Run(mojo::ConvertTo
<ServiceWorkerStatusCode
>(status
));
1424 RemoveCallbackAndStopIfRedundant(&sync_requests_
, request_id
);
1427 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1429 TRACE_EVENT1("ServiceWorker",
1430 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1431 "Request id", request_id
);
1432 PendingRequest
<StatusCallback
>* request
=
1433 notification_click_requests_
.Lookup(request_id
);
1435 NOTREACHED() << "Got unexpected message: " << request_id
;
1439 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.NotificationClickEvent.Time",
1440 base::TimeTicks::Now() - request
->start_time
);
1442 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1443 request
->callback
.Run(SERVICE_WORKER_OK
);
1444 RemoveCallbackAndStopIfRedundant(¬ification_click_requests_
, request_id
);
1447 void ServiceWorkerVersion::OnPushEventFinished(
1449 blink::WebServiceWorkerEventResult result
) {
1450 TRACE_EVENT1("ServiceWorker",
1451 "ServiceWorkerVersion::OnPushEventFinished",
1452 "Request id", request_id
);
1453 PendingRequest
<StatusCallback
>* request
= push_requests_
.Lookup(request_id
);
1455 NOTREACHED() << "Got unexpected message: " << request_id
;
1458 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1459 if (result
== blink::WebServiceWorkerEventResultRejected
)
1460 status
= SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED
;
1462 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.PushEvent.Time",
1463 base::TimeTicks::Now() - request
->start_time
);
1465 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1466 request
->callback
.Run(status
);
1467 RemoveCallbackAndStopIfRedundant(&push_requests_
, request_id
);
1470 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id
) {
1471 TRACE_EVENT1("ServiceWorker",
1472 "ServiceWorkerVersion::OnGeofencingEventFinished",
1475 PendingRequest
<StatusCallback
>* request
=
1476 geofencing_requests_
.Lookup(request_id
);
1478 NOTREACHED() << "Got unexpected message: " << request_id
;
1482 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1483 request
->callback
.Run(SERVICE_WORKER_OK
);
1484 RemoveCallbackAndStopIfRedundant(&geofencing_requests_
, request_id
);
1487 void ServiceWorkerVersion::OnServicePortConnectEventFinished(
1489 ServicePortConnectResult result
,
1490 const mojo::String
& name
,
1491 const mojo::String
& data
) {
1492 TRACE_EVENT1("ServiceWorker",
1493 "ServiceWorkerVersion::OnServicePortConnectEventFinished",
1494 "Request id", request_id
);
1495 PendingRequest
<ServicePortConnectCallback
>* request
=
1496 service_port_connect_requests_
.Lookup(request_id
);
1498 NOTREACHED() << "Got unexpected message: " << request_id
;
1502 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1503 request
->callback
.Run(SERVICE_WORKER_OK
,
1504 result
== SERVICE_PORT_CONNECT_RESULT_ACCEPT
,
1505 name
.To
<base::string16
>(), data
.To
<base::string16
>());
1506 RemoveCallbackAndStopIfRedundant(&service_port_connect_requests_
, request_id
);
1509 void ServiceWorkerVersion::OnOpenWindow(int request_id
, GURL url
) {
1510 // Just abort if we are shutting down.
1514 if (!url
.is_valid()) {
1515 DVLOG(1) << "Received unexpected invalid URL from renderer process.";
1516 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
1517 base::Bind(&KillEmbeddedWorkerProcess
,
1518 embedded_worker_
->process_id(),
1519 RESULT_CODE_KILLED_BAD_MESSAGE
));
1523 // The renderer treats all URLs in the about: scheme as being about:blank.
1524 // Canonicalize about: URLs to about:blank.
1525 if (url
.SchemeIs(url::kAboutScheme
))
1526 url
= GURL(url::kAboutBlankURL
);
1528 // Reject requests for URLs that the process is not allowed to access. It's
1529 // possible to receive such requests since the renderer-side checks are
1530 // slightly different. For example, the view-source scheme will not be
1531 // filtered out by Blink.
1532 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1533 embedded_worker_
->process_id(), url
)) {
1534 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowError(
1535 request_id
, url
.spec() + " cannot be opened."));
1539 BrowserThread::PostTask(
1540 BrowserThread::UI
, FROM_HERE
,
1541 base::Bind(&OpenWindowOnUI
,
1544 embedded_worker_
->process_id(),
1545 make_scoped_refptr(context_
->wrapper()),
1546 base::Bind(&ServiceWorkerVersion::DidOpenWindow
,
1547 weak_factory_
.GetWeakPtr(),
1551 void ServiceWorkerVersion::DidOpenWindow(int request_id
,
1552 int render_process_id
,
1553 int render_frame_id
) {
1554 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1556 if (running_status() != RUNNING
)
1559 if (render_process_id
== ChildProcessHost::kInvalidUniqueID
&&
1560 render_frame_id
== MSG_ROUTING_NONE
) {
1561 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowError(
1562 request_id
, "Something went wrong while trying to open the window."));
1567 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1568 !it
->IsAtEnd(); it
->Advance()) {
1569 ServiceWorkerProviderHost
* provider_host
= it
->GetProviderHost();
1570 if (provider_host
->process_id() != render_process_id
||
1571 provider_host
->frame_id() != render_frame_id
) {
1574 provider_host
->GetWindowClientInfo(base::Bind(
1575 &ServiceWorkerVersion::OnOpenWindowFinished
, weak_factory_
.GetWeakPtr(),
1576 request_id
, provider_host
->client_uuid()));
1580 // If here, it means that no provider_host was found, in which case, the
1581 // renderer should still be informed that the window was opened.
1582 OnOpenWindowFinished(request_id
, std::string(), ServiceWorkerClientInfo());
1585 void ServiceWorkerVersion::OnOpenWindowFinished(
1587 const std::string
& client_uuid
,
1588 const ServiceWorkerClientInfo
& client_info
) {
1589 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1591 if (running_status() != RUNNING
)
1594 ServiceWorkerClientInfo
client(client_info
);
1596 // If the |client_info| is empty, it means that the opened window wasn't
1597 // controlled but the action still succeeded. The renderer process is
1598 // expecting an empty client in such case.
1599 if (!client
.IsEmpty())
1600 client
.client_uuid
= client_uuid
;
1602 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1603 request_id
, client
));
1606 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL
& url
,
1607 const std::vector
<char>& data
) {
1608 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
1609 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1610 "ServiceWorkerVersion::OnSetCachedMetadata",
1611 callback_id
, "URL", url
.spec());
1612 script_cache_map_
.WriteMetadata(
1613 url
, data
, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished
,
1614 weak_factory_
.GetWeakPtr(), callback_id
));
1617 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id
,
1619 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1620 "ServiceWorkerVersion::OnSetCachedMetadata",
1621 callback_id
, "result", result
);
1622 FOR_EACH_OBSERVER(Listener
, listeners_
, OnCachedMetadataUpdated(this));
1625 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL
& url
) {
1626 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
1627 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1628 "ServiceWorkerVersion::OnClearCachedMetadata",
1629 callback_id
, "URL", url
.spec());
1630 script_cache_map_
.ClearMetadata(
1631 url
, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished
,
1632 weak_factory_
.GetWeakPtr(), callback_id
));
1635 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id
,
1637 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1638 "ServiceWorkerVersion::OnClearCachedMetadata",
1639 callback_id
, "result", result
);
1640 FOR_EACH_OBSERVER(Listener
, listeners_
, OnCachedMetadataUpdated(this));
1643 void ServiceWorkerVersion::OnPostMessageToClient(
1644 const std::string
& client_uuid
,
1645 const base::string16
& message
,
1646 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
1649 TRACE_EVENT1("ServiceWorker",
1650 "ServiceWorkerVersion::OnPostMessageToDocument",
1651 "Client id", client_uuid
);
1652 ServiceWorkerProviderHost
* provider_host
=
1653 context_
->GetProviderHostByClientID(client_uuid
);
1654 if (!provider_host
) {
1655 // The client may already have been closed, just ignore.
1658 if (provider_host
->document_url().GetOrigin() != script_url_
.GetOrigin()) {
1659 // The client does not belong to the same origin as this ServiceWorker,
1660 // possibly due to timing issue or bad message.
1663 provider_host
->PostMessage(this, message
, sent_message_ports
);
1666 void ServiceWorkerVersion::OnFocusClient(int request_id
,
1667 const std::string
& client_uuid
) {
1670 TRACE_EVENT2("ServiceWorker",
1671 "ServiceWorkerVersion::OnFocusClient",
1672 "Request id", request_id
,
1673 "Client id", client_uuid
);
1674 ServiceWorkerProviderHost
* provider_host
=
1675 context_
->GetProviderHostByClientID(client_uuid
);
1676 if (!provider_host
) {
1677 // The client may already have been closed, just ignore.
1680 if (provider_host
->document_url().GetOrigin() != script_url_
.GetOrigin()) {
1681 // The client does not belong to the same origin as this ServiceWorker,
1682 // possibly due to timing issue or bad message.
1685 provider_host
->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished
,
1686 weak_factory_
.GetWeakPtr(), request_id
,
1690 void ServiceWorkerVersion::OnFocusClientFinished(
1692 const std::string
& client_uuid
,
1693 const ServiceWorkerClientInfo
& client
) {
1694 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1696 if (running_status() != RUNNING
)
1699 ServiceWorkerClientInfo
client_info(client
);
1700 client_info
.client_uuid
= client_uuid
;
1702 embedded_worker_
->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1703 request_id
, client_info
));
1706 void ServiceWorkerVersion::OnNavigateClient(int request_id
,
1707 const std::string
& client_uuid
,
1712 TRACE_EVENT2("ServiceWorker", "ServiceWorkerVersion::OnNavigateClient",
1713 "Request id", request_id
, "Client id", client_uuid
);
1715 if (!url
.is_valid() || !base::IsValidGUID(client_uuid
)) {
1716 DVLOG(1) << "Received unexpected invalid URL/UUID from renderer process.";
1717 BrowserThread::PostTask(
1718 BrowserThread::UI
, FROM_HERE
,
1719 base::Bind(&KillEmbeddedWorkerProcess
, embedded_worker_
->process_id(),
1720 RESULT_CODE_KILLED_BAD_MESSAGE
));
1724 // Reject requests for URLs that the process is not allowed to access. It's
1725 // possible to receive such requests since the renderer-side checks are
1726 // slightly different. For example, the view-source scheme will not be
1727 // filtered out by Blink.
1728 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1729 embedded_worker_
->process_id(), url
)) {
1730 embedded_worker_
->SendMessage(
1731 ServiceWorkerMsg_NavigateClientError(request_id
, url
));
1735 ServiceWorkerProviderHost
* provider_host
=
1736 context_
->GetProviderHostByClientID(client_uuid
);
1737 if (!provider_host
|| provider_host
->active_version() != this) {
1738 embedded_worker_
->SendMessage(
1739 ServiceWorkerMsg_NavigateClientError(request_id
, url
));
1743 BrowserThread::PostTask(
1744 BrowserThread::UI
, FROM_HERE
,
1745 base::Bind(&NavigateClientOnUI
, url
, script_url_
,
1746 provider_host
->process_id(), provider_host
->frame_id(),
1747 base::Bind(&ServiceWorkerVersion::DidNavigateClient
,
1748 weak_factory_
.GetWeakPtr(), request_id
)));
1751 void ServiceWorkerVersion::DidNavigateClient(int request_id
,
1752 int render_process_id
,
1753 int render_frame_id
) {
1754 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1756 if (running_status() != RUNNING
)
1759 if (render_process_id
== ChildProcessHost::kInvalidUniqueID
&&
1760 render_frame_id
== MSG_ROUTING_NONE
) {
1761 embedded_worker_
->SendMessage(
1762 ServiceWorkerMsg_NavigateClientError(request_id
, GURL()));
1767 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1768 !it
->IsAtEnd(); it
->Advance()) {
1769 ServiceWorkerProviderHost
* provider_host
= it
->GetProviderHost();
1770 if (provider_host
->process_id() != render_process_id
||
1771 provider_host
->frame_id() != render_frame_id
) {
1774 provider_host
->GetWindowClientInfo(base::Bind(
1775 &ServiceWorkerVersion::OnNavigateClientFinished
,
1776 weak_factory_
.GetWeakPtr(), request_id
, provider_host
->client_uuid()));
1780 OnNavigateClientFinished(request_id
, std::string(),
1781 ServiceWorkerClientInfo());
1784 void ServiceWorkerVersion::OnNavigateClientFinished(
1786 const std::string
& client_uuid
,
1787 const ServiceWorkerClientInfo
& client_info
) {
1788 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1790 if (running_status() != RUNNING
)
1793 ServiceWorkerClientInfo
client(client_info
);
1795 // If the |client_info| is empty, it means that the navigated client wasn't
1796 // controlled but the action still succeeded. The renderer process is
1797 // expecting an empty client in such case.
1798 if (!client
.IsEmpty())
1799 client
.client_uuid
= client_uuid
;
1801 embedded_worker_
->SendMessage(
1802 ServiceWorkerMsg_NavigateClientResponse(request_id
, client
));
1805 void ServiceWorkerVersion::OnSkipWaiting(int request_id
) {
1806 skip_waiting_
= true;
1807 if (status_
!= INSTALLED
)
1808 return DidSkipWaiting(request_id
);
1812 ServiceWorkerRegistration
* registration
=
1813 context_
->GetLiveRegistration(registration_id_
);
1816 pending_skip_waiting_requests_
.push_back(request_id
);
1817 if (pending_skip_waiting_requests_
.size() == 1)
1818 registration
->ActivateWaitingVersionWhenReady();
1821 void ServiceWorkerVersion::DidSkipWaiting(int request_id
) {
1822 if (running_status() == STARTING
|| running_status() == RUNNING
)
1823 embedded_worker_
->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id
));
1826 void ServiceWorkerVersion::OnClaimClients(int request_id
) {
1827 if (status_
!= ACTIVATING
&& status_
!= ACTIVATED
) {
1828 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1829 request_id
, blink::WebServiceWorkerError::ErrorTypeState
,
1830 base::ASCIIToUTF16(kClaimClientsStateErrorMesage
)));
1834 if (ServiceWorkerRegistration
* registration
=
1835 context_
->GetLiveRegistration(registration_id_
)) {
1836 registration
->ClaimClients();
1837 embedded_worker_
->SendMessage(
1838 ServiceWorkerMsg_DidClaimClients(request_id
));
1843 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1844 request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
1845 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage
)));
1848 void ServiceWorkerVersion::OnPongFromWorker() {
1849 ping_controller_
->OnPongReceived();
1852 void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
1853 const StatusCallback
& callback
,
1854 ServiceWorkerStatusCode status
,
1855 const scoped_refptr
<ServiceWorkerRegistration
>& protect
) {
1856 if (status
!= SERVICE_WORKER_OK
) {
1857 RecordStartWorkerResult(status
);
1858 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
1861 if (is_redundant()) {
1862 RecordStartWorkerResult(SERVICE_WORKER_ERROR_REDUNDANT
);
1863 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_REDUNDANT
));
1869 switch (running_status()) {
1871 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
1876 if (start_callbacks_
.empty()) {
1877 start_callbacks_
.push_back(
1878 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult
,
1879 weak_factory_
.GetWeakPtr()));
1881 // Keep the live registration while starting the worker.
1882 start_callbacks_
.push_back(
1883 base::Bind(&RunStartWorkerCallback
, callback
, protect
));
1884 StartWorkerInternal();
1889 void ServiceWorkerVersion::StartWorkerInternal() {
1891 metrics_
.reset(new Metrics(this));
1893 if (!timeout_timer_
.IsRunning())
1894 StartTimeoutTimer();
1895 if (running_status() == STOPPED
) {
1896 embedded_worker_
->Start(
1897 version_id_
, scope_
, script_url_
,
1898 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated
,
1899 weak_factory_
.GetWeakPtr()));
1903 void ServiceWorkerVersion::GetWindowClients(
1905 const ServiceWorkerClientQueryOptions
& options
) {
1906 DCHECK(options
.client_type
== blink::WebServiceWorkerClientTypeWindow
||
1907 options
.client_type
== blink::WebServiceWorkerClientTypeAll
);
1908 const std::vector
<base::Tuple
<int, int, std::string
>>& clients_info
=
1909 GetWindowClientsInternal(options
.include_uncontrolled
);
1911 if (clients_info
.empty()) {
1912 DidGetWindowClients(request_id
, options
,
1913 make_scoped_ptr(new ServiceWorkerClients
));
1917 BrowserThread::PostTask(
1918 BrowserThread::UI
, FROM_HERE
,
1919 base::Bind(&OnGetWindowClientsFromUI
, clients_info
, script_url_
,
1920 base::Bind(&ServiceWorkerVersion::DidGetWindowClients
,
1921 weak_factory_
.GetWeakPtr(), request_id
, options
)));
1924 const std::vector
<base::Tuple
<int, int, std::string
>>
1925 ServiceWorkerVersion::GetWindowClientsInternal(bool include_uncontrolled
) {
1926 std::vector
<base::Tuple
<int, int, std::string
>> clients_info
;
1927 if (!include_uncontrolled
) {
1928 for (auto& controllee
: controllee_map_
)
1929 AddWindowClient(controllee
.second
, &clients_info
);
1932 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1933 !it
->IsAtEnd(); it
->Advance()) {
1934 AddWindowClient(it
->GetProviderHost(), &clients_info
);
1937 return clients_info
;
1940 void ServiceWorkerVersion::DidGetWindowClients(
1942 const ServiceWorkerClientQueryOptions
& options
,
1943 scoped_ptr
<ServiceWorkerClients
> clients
) {
1944 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1945 if (options
.client_type
== blink::WebServiceWorkerClientTypeAll
)
1946 GetNonWindowClients(request_id
, options
, clients
.get());
1947 OnGetClientsFinished(request_id
, clients
.get());
1950 void ServiceWorkerVersion::GetNonWindowClients(
1952 const ServiceWorkerClientQueryOptions
& options
,
1953 ServiceWorkerClients
* clients
) {
1954 if (!options
.include_uncontrolled
) {
1955 for (auto& controllee
: controllee_map_
) {
1956 AddNonWindowClient(controllee
.second
, options
, clients
);
1960 context_
->GetClientProviderHostIterator(script_url_
.GetOrigin());
1961 !it
->IsAtEnd(); it
->Advance()) {
1962 AddNonWindowClient(it
->GetProviderHost(), options
, clients
);
1967 void ServiceWorkerVersion::StartTimeoutTimer() {
1968 DCHECK(!timeout_timer_
.IsRunning());
1970 if (embedded_worker_
->devtools_attached()) {
1971 // Don't record the startup time metric once DevTools is attached.
1972 ClearTick(&start_time_
);
1973 skip_recording_startup_time_
= true;
1975 RestartTick(&start_time_
);
1976 skip_recording_startup_time_
= false;
1979 // The worker is starting up and not yet idle.
1980 ClearTick(&idle_time_
);
1982 // Ping will be activated in OnScriptLoaded.
1983 ping_controller_
->Deactivate();
1985 timeout_timer_
.Start(FROM_HERE
,
1986 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds
),
1987 this, &ServiceWorkerVersion::OnTimeoutTimer
);
1990 void ServiceWorkerVersion::StopTimeoutTimer() {
1991 timeout_timer_
.Stop();
1992 ClearTick(&idle_time_
);
1994 // Trigger update if worker is stale.
1995 if (!in_dtor_
&& !stale_time_
.is_null()) {
1996 ClearTick(&stale_time_
);
1997 if (!update_timer_
.IsRunning())
2002 void ServiceWorkerVersion::OnTimeoutTimer() {
2003 DCHECK(running_status() == STARTING
|| running_status() == RUNNING
||
2004 running_status() == STOPPING
)
2005 << running_status();
2009 if (GetTickDuration(stop_time_
) >
2010 base::TimeDelta::FromSeconds(kStopWorkerTimeoutSeconds
)) {
2011 metrics_
->NotifyStalledInStopping();
2014 // Trigger update if worker is stale and we waited long enough for it to go
2016 if (GetTickDuration(stale_time_
) >
2017 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes
)) {
2018 ClearTick(&stale_time_
);
2019 if (!update_timer_
.IsRunning())
2023 // Starting a worker hasn't finished within a certain period.
2024 if (GetTickDuration(start_time_
) >
2025 base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes
)) {
2026 DCHECK(running_status() == STARTING
|| running_status() == STOPPING
)
2027 << running_status();
2028 scoped_refptr
<ServiceWorkerVersion
> protect(this);
2029 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_ERROR_TIMEOUT
);
2030 if (running_status() == STARTING
)
2031 embedded_worker_
->Stop();
2035 // Requests have not finished within a certain period.
2036 bool request_timed_out
= false;
2037 while (!requests_
.empty()) {
2038 RequestInfo info
= requests_
.front();
2039 if (GetTickDuration(info
.time
) <
2040 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes
))
2042 if (MaybeTimeOutRequest(info
)) {
2043 request_timed_out
= true;
2044 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RequestTimeouts.Count",
2045 info
.type
, NUM_REQUEST_TYPES
);
2049 if (request_timed_out
&& running_status() != STOPPING
)
2050 embedded_worker_
->Stop();
2052 // For the timeouts below, there are no callbacks to timeout so there is
2053 // nothing more to do if the worker is already stopping.
2054 if (running_status() == STOPPING
)
2057 // The worker has been idle for longer than a certain period.
2058 if (GetTickDuration(idle_time_
) >
2059 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds
)) {
2064 // Check ping status.
2065 ping_controller_
->CheckPingStatus();
2068 ServiceWorkerStatusCode
ServiceWorkerVersion::PingWorker() {
2069 DCHECK(running_status() == STARTING
|| running_status() == RUNNING
);
2070 return embedded_worker_
->SendMessage(ServiceWorkerMsg_Ping());
2073 void ServiceWorkerVersion::OnPingTimeout() {
2074 DCHECK(running_status() == STARTING
|| running_status() == RUNNING
);
2075 // TODO(falken): Show a message to the developer that the SW was stopped due
2076 // to timeout (crbug.com/457968). Also, change the error code to
2077 // SERVICE_WORKER_ERROR_TIMEOUT.
2081 void ServiceWorkerVersion::StopWorkerIfIdle() {
2082 if (HasInflightRequests() && !ping_controller_
->IsTimedOut())
2084 if (running_status() == STOPPED
|| running_status() == STOPPING
||
2085 !stop_callbacks_
.empty()) {
2089 // TODO(falken): We may need to handle StopIfIdle failure and
2090 // forcibly fail pending callbacks so no one is stuck waiting
2092 embedded_worker_
->StopIfIdle();
2095 bool ServiceWorkerVersion::HasInflightRequests() const {
2096 return !activate_requests_
.IsEmpty() || !install_requests_
.IsEmpty() ||
2097 !fetch_requests_
.IsEmpty() || !sync_requests_
.IsEmpty() ||
2098 !notification_click_requests_
.IsEmpty() || !push_requests_
.IsEmpty() ||
2099 !geofencing_requests_
.IsEmpty() ||
2100 !service_port_connect_requests_
.IsEmpty() ||
2101 !streaming_url_request_jobs_
.empty();
2104 void ServiceWorkerVersion::RecordStartWorkerResult(
2105 ServiceWorkerStatusCode status
) {
2106 base::TimeTicks start_time
= start_time_
;
2107 ClearTick(&start_time_
);
2109 ServiceWorkerMetrics::RecordStartWorkerStatus(status
,
2110 IsInstalled(prestart_status_
));
2112 if (status
== SERVICE_WORKER_OK
&& !start_time
.is_null() &&
2113 !skip_recording_startup_time_
) {
2114 ServiceWorkerMetrics::RecordStartWorkerTime(GetTickDuration(start_time
),
2115 IsInstalled(prestart_status_
));
2118 if (status
!= SERVICE_WORKER_ERROR_TIMEOUT
)
2120 EmbeddedWorkerInstance::StartingPhase phase
=
2121 EmbeddedWorkerInstance::NOT_STARTING
;
2122 EmbeddedWorkerInstance::Status running_status
= embedded_worker_
->status();
2123 // Build an artifical JavaScript exception to show in the ServiceWorker
2124 // log for developers; it's not user-facing so it's not a localized resource.
2125 std::string message
= "ServiceWorker startup timed out. ";
2126 if (running_status
!= EmbeddedWorkerInstance::STARTING
) {
2127 message
.append("The worker had unexpected status: ");
2128 message
.append(EmbeddedWorkerInstance::StatusToString(running_status
));
2130 phase
= embedded_worker_
->starting_phase();
2131 message
.append("The worker was in startup phase: ");
2132 message
.append(EmbeddedWorkerInstance::StartingPhaseToString(phase
));
2134 message
.append(".");
2135 OnReportException(base::UTF8ToUTF16(message
), -1, -1, GURL());
2136 DVLOG(1) << message
;
2137 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase",
2139 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE
);
2142 template <typename IDMAP
>
2143 void ServiceWorkerVersion::RemoveCallbackAndStopIfRedundant(IDMAP
* callbacks
,
2145 RestartTick(&idle_time_
);
2146 callbacks
->Remove(request_id
);
2147 if (is_redundant()) {
2148 // The stop should be already scheduled, but try to stop immediately, in
2149 // order to release worker resources soon.
2154 template <typename CallbackType
>
2155 int ServiceWorkerVersion::AddRequest(
2156 const CallbackType
& callback
,
2157 IDMap
<PendingRequest
<CallbackType
>, IDMapOwnPointer
>* callback_map
,
2158 RequestType request_type
) {
2159 base::TimeTicks now
= base::TimeTicks::Now();
2161 callback_map
->Add(new PendingRequest
<CallbackType
>(callback
, now
));
2162 requests_
.push(RequestInfo(request_id
, request_type
, now
));
2166 bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo
& info
) {
2167 switch (info
.type
) {
2168 case REQUEST_ACTIVATE
:
2169 return RunIDMapCallback(&activate_requests_
, info
.id
,
2170 SERVICE_WORKER_ERROR_TIMEOUT
);
2171 case REQUEST_INSTALL
:
2172 return RunIDMapCallback(&install_requests_
, info
.id
,
2173 SERVICE_WORKER_ERROR_TIMEOUT
);
2175 return RunIDMapCallback(
2176 &fetch_requests_
, info
.id
, SERVICE_WORKER_ERROR_TIMEOUT
,
2177 /* The other args are ignored for non-OK status. */
2178 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
, ServiceWorkerResponse());
2180 return RunIDMapCallback(&sync_requests_
, info
.id
,
2181 SERVICE_WORKER_ERROR_TIMEOUT
);
2182 case REQUEST_NOTIFICATION_CLICK
:
2183 return RunIDMapCallback(¬ification_click_requests_
, info
.id
,
2184 SERVICE_WORKER_ERROR_TIMEOUT
);
2186 return RunIDMapCallback(&push_requests_
, info
.id
,
2187 SERVICE_WORKER_ERROR_TIMEOUT
);
2188 case REQUEST_GEOFENCING
:
2189 return RunIDMapCallback(&geofencing_requests_
, info
.id
,
2190 SERVICE_WORKER_ERROR_TIMEOUT
);
2191 case REQUEST_SERVICE_PORT_CONNECT
:
2192 return RunIDMapCallback(&service_port_connect_requests_
, info
.id
,
2193 SERVICE_WORKER_ERROR_TIMEOUT
,
2194 false /* accept_connection */, base::string16(),
2196 case NUM_REQUEST_TYPES
:
2199 NOTREACHED() << "Got unexpected request type: " << info
.type
;
2203 void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks
& ticks
) {
2204 std::queue
<RequestInfo
> new_requests
;
2205 while (!requests_
.empty()) {
2206 RequestInfo info
= requests_
.front();
2208 new_requests
.push(info
);
2211 requests_
= new_requests
;
2214 ServiceWorkerStatusCode
ServiceWorkerVersion::DeduceStartWorkerFailureReason(
2215 ServiceWorkerStatusCode default_code
) {
2216 if (ping_controller_
->IsTimedOut())
2217 return SERVICE_WORKER_ERROR_TIMEOUT
;
2219 if (start_worker_status_
!= SERVICE_WORKER_OK
)
2220 return start_worker_status_
;
2222 const net::URLRequestStatus
& main_script_status
=
2223 script_cache_map()->main_script_status();
2224 if (main_script_status
.status() != net::URLRequestStatus::SUCCESS
) {
2225 switch (main_script_status
.error()) {
2226 case net::ERR_INSECURE_RESPONSE
:
2227 case net::ERR_UNSAFE_REDIRECT
:
2228 return SERVICE_WORKER_ERROR_SECURITY
;
2229 case net::ERR_ABORTED
:
2230 return SERVICE_WORKER_ERROR_ABORT
;
2232 return SERVICE_WORKER_ERROR_NETWORK
;
2236 return default_code
;
2239 void ServiceWorkerVersion::MarkIfStale() {
2242 if (update_timer_
.IsRunning() || !stale_time_
.is_null())
2244 ServiceWorkerRegistration
* registration
=
2245 context_
->GetLiveRegistration(registration_id_
);
2246 if (!registration
|| registration
->active_version() != this)
2248 base::TimeDelta time_since_last_check
=
2249 base::Time::Now() - registration
->last_update_check();
2250 if (time_since_last_check
>
2251 base::TimeDelta::FromHours(kServiceWorkerScriptMaxCacheAgeInHours
))
2252 RestartTick(&stale_time_
);
2255 void ServiceWorkerVersion::FoundRegistrationForUpdate(
2256 ServiceWorkerStatusCode status
,
2257 const scoped_refptr
<ServiceWorkerRegistration
>& registration
) {
2261 const scoped_refptr
<ServiceWorkerVersion
> protect
= this;
2262 if (is_update_scheduled_
) {
2263 context_
->UnprotectVersion(version_id_
);
2264 is_update_scheduled_
= false;
2267 if (status
!= SERVICE_WORKER_OK
|| registration
->active_version() != this)
2269 context_
->UpdateServiceWorker(registration
.get(),
2270 false /* force_bypass_cache */);
2273 void ServiceWorkerVersion::OnStoppedInternal(
2274 EmbeddedWorkerInstance::Status old_status
) {
2275 DCHECK_EQ(STOPPED
, running_status());
2276 scoped_refptr
<ServiceWorkerVersion
> protect
;
2283 bool should_restart
= !is_redundant() && !start_callbacks_
.empty() &&
2284 (old_status
!= EmbeddedWorkerInstance::STARTING
) &&
2285 !in_dtor_
&& !ping_controller_
->IsTimedOut();
2287 ClearTick(&stop_time_
);
2290 // Fire all stop callbacks.
2291 RunCallbacks(this, &stop_callbacks_
, SERVICE_WORKER_OK
);
2293 if (!should_restart
) {
2294 // Let all start callbacks fail.
2295 RunCallbacks(this, &start_callbacks_
,
2296 DeduceStartWorkerFailureReason(
2297 SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
2300 // Let all message callbacks fail (this will also fire and clear all
2301 // callbacks for events).
2302 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
2303 RunIDMapCallbacks(&activate_requests_
,
2304 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
2305 RunIDMapCallbacks(&install_requests_
,
2306 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
2307 RunIDMapCallbacks(&fetch_requests_
, SERVICE_WORKER_ERROR_FAILED
,
2308 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
2309 ServiceWorkerResponse());
2310 RunIDMapCallbacks(&sync_requests_
, SERVICE_WORKER_ERROR_FAILED
);
2311 RunIDMapCallbacks(¬ification_click_requests_
, SERVICE_WORKER_ERROR_FAILED
);
2312 RunIDMapCallbacks(&push_requests_
, SERVICE_WORKER_ERROR_FAILED
);
2313 RunIDMapCallbacks(&geofencing_requests_
, SERVICE_WORKER_ERROR_FAILED
);
2315 // Close all mojo services. This will also fire and clear all callbacks
2316 // for messages that are still outstanding for those services.
2317 OnServicePortDispatcherConnectionError();
2319 OnBackgroundSyncDispatcherConnectionError();
2321 streaming_url_request_jobs_
.clear();
2323 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRunningStateChanged(this));
2326 StartWorkerInternal();
2329 void ServiceWorkerVersion::OnServicePortDispatcherConnectionError() {
2330 RunIDMapCallbacks(&service_port_connect_requests_
,
2331 SERVICE_WORKER_ERROR_FAILED
, false, base::string16(),
2333 service_port_dispatcher_
.reset();
2336 void ServiceWorkerVersion::OnBackgroundSyncDispatcherConnectionError() {
2337 RunIDMapCallbacks(&sync_requests_
, SERVICE_WORKER_ERROR_FAILED
);
2338 background_sync_dispatcher_
.reset();
2341 void ServiceWorkerVersion::OnBeginEvent() {
2342 if (should_exclude_from_uma_
|| running_status() != RUNNING
||
2343 idle_time_
.is_null()) {
2346 ServiceWorkerMetrics::RecordTimeBetweenEvents(base::TimeTicks::Now() -
2350 } // namespace content