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"
7 #include "base/command_line.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "content/browser/message_port_message_filter.h"
14 #include "content/browser/message_port_service.h"
15 #include "content/browser/service_worker/embedded_worker_instance.h"
16 #include "content/browser/service_worker/embedded_worker_registry.h"
17 #include "content/browser/service_worker/service_worker_context_core.h"
18 #include "content/browser/service_worker/service_worker_context_wrapper.h"
19 #include "content/browser/service_worker/service_worker_registration.h"
20 #include "content/browser/service_worker/service_worker_utils.h"
21 #include "content/browser/storage_partition_impl.h"
22 #include "content/common/service_worker/service_worker_messages.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/content_browser_client.h"
25 #include "content/public/browser/page_navigator.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/browser/web_contents_observer.h"
30 #include "content/public/common/child_process_host.h"
31 #include "content/public/common/content_client.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/result_codes.h"
34 #include "net/http/http_response_info.h"
38 typedef ServiceWorkerVersion::StatusCallback StatusCallback
;
39 typedef ServiceWorkerVersion::MessageCallback MessageCallback
;
41 class ServiceWorkerVersion::GetClientDocumentsCallback
42 : public base::RefCounted
<GetClientDocumentsCallback
> {
44 GetClientDocumentsCallback(int request_id
,
45 ServiceWorkerVersion
* version
)
46 : request_id_(request_id
),
51 void AddClientInfo(int client_id
, const ServiceWorkerClientInfo
& info
) {
52 clients_
.push_back(info
);
53 clients_
.back().client_id
= client_id
;
57 friend class base::RefCounted
<GetClientDocumentsCallback
>;
59 virtual ~GetClientDocumentsCallback() {
60 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
62 if (version_
->running_status() == RUNNING
) {
63 version_
->embedded_worker_
->SendMessage(
64 ServiceWorkerMsg_DidGetClientDocuments(request_id_
, clients_
));
68 std::vector
<ServiceWorkerClientInfo
> clients_
;
70 scoped_refptr
<ServiceWorkerVersion
> version_
;
72 DISALLOW_COPY_AND_ASSIGN(GetClientDocumentsCallback
);
77 // Default delay for scheduled stop.
78 // (Note that if all references to the version is dropped the worker
79 // is also stopped without delay)
80 const int64 kStopWorkerDelay
= 30; // 30 secs.
82 // Delay for attempting to stop a doomed worker with in-flight requests.
83 const int64 kStopDoomedWorkerDelay
= 5; // 5 secs.
85 // Default delay for scheduled update.
86 const int kUpdateDelaySeconds
= 1;
88 // Delay between sending pings to the worker.
89 const int kPingIntervalTime
= 10; // 10 secs.
91 // Timeout for waiting for a response to a ping.
92 const int kPingTimeoutTime
= 30; // 30 secs.
94 const char kClaimClientsStateErrorMesage
[] =
95 "Only the active worker can claim clients.";
97 const char kClaimClientsShutdownErrorMesage
[] =
98 "Failed to claim clients due to Service Worker system shutdown.";
100 void RunSoon(const base::Closure
& callback
) {
101 if (!callback
.is_null())
102 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
105 template <typename CallbackArray
, typename Arg
>
106 void RunCallbacks(ServiceWorkerVersion
* version
,
107 CallbackArray
* callbacks_ptr
,
109 CallbackArray callbacks
;
110 callbacks
.swap(*callbacks_ptr
);
111 scoped_refptr
<ServiceWorkerVersion
> protect(version
);
112 for (const auto& callback
: callbacks
)
116 template <typename IDMAP
, typename
... Params
>
117 void RunIDMapCallbacks(IDMAP
* callbacks
, const Params
&... params
) {
118 typename
IDMAP::iterator
iter(callbacks
);
119 while (!iter
.IsAtEnd()) {
120 iter
.GetCurrentValue()->Run(params
...);
126 // A callback adapter to start a |task| after StartWorker.
127 void RunTaskAfterStartWorker(
128 base::WeakPtr
<ServiceWorkerVersion
> version
,
129 const StatusCallback
& error_callback
,
130 const base::Closure
& task
,
131 ServiceWorkerStatusCode status
) {
132 if (status
!= SERVICE_WORKER_OK
) {
133 if (!error_callback
.is_null())
134 error_callback
.Run(status
);
137 if (version
->running_status() != ServiceWorkerVersion::RUNNING
) {
138 // We've tried to start the worker (and it has succeeded), but
139 // it looks it's not running yet.
140 NOTREACHED() << "The worker's not running after successful StartWorker";
141 if (!error_callback
.is_null())
142 error_callback
.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
148 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback
& callback
,
149 ServiceWorkerStatusCode status
) {
151 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
152 ServiceWorkerResponse());
155 void RunErrorMessageCallback(
156 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
157 const ServiceWorkerVersion::StatusCallback
& callback
,
158 ServiceWorkerStatusCode status
) {
159 // Transfering the message ports failed, so destroy the ports.
160 for (const TransferredMessagePort
& port
: sent_message_ports
) {
161 MessagePortService::GetInstance()->ClosePort(port
.id
);
163 callback
.Run(status
);
166 void RunErrorCrossOriginConnectCallback(
167 const ServiceWorkerVersion::CrossOriginConnectCallback
& callback
,
168 ServiceWorkerStatusCode status
) {
169 callback
.Run(status
, false);
172 using WindowOpenedCallback
= base::Callback
<void(int, int)>;
174 // The WindowOpenedObserver class is a WebContentsObserver that will wait for a
175 // new Window's WebContents to be initialized, run the |callback| passed to its
176 // constructor then self destroy.
177 // The callback will receive the process and frame ids. If something went wrong
178 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
179 // The callback will be called in the IO thread.
180 class WindowOpenedObserver
: public WebContentsObserver
{
182 WindowOpenedObserver(WebContents
* web_contents
,
183 const WindowOpenedCallback
& callback
)
184 : WebContentsObserver(web_contents
),
188 void DidCommitProvisionalLoadForFrame(
189 RenderFrameHost
* render_frame_host
,
190 const GURL
& validated_url
,
191 ui::PageTransition transition_type
) override
{
192 DCHECK(web_contents());
194 if (render_frame_host
!= web_contents()->GetMainFrame())
197 RunCallback(render_frame_host
->GetProcess()->GetID(),
198 render_frame_host
->GetRoutingID());
201 void RenderProcessGone(base::TerminationStatus status
) override
{
202 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
205 void WebContentsDestroyed() override
{
206 RunCallback(ChildProcessHost::kInvalidUniqueID
, MSG_ROUTING_NONE
);
210 void RunCallback(int render_process_id
, int render_frame_id
) {
211 // After running the callback, |this| will stop observing, thus
212 // web_contents() should return nullptr and |RunCallback| should no longer
213 // be called. Then, |this| will self destroy.
214 DCHECK(web_contents());
216 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
217 base::Bind(callback_
,
221 base::MessageLoop::current()->DeleteSoon(FROM_HERE
, this);
224 const WindowOpenedCallback callback_
;
226 DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver
);
229 void DidOpenURL(const WindowOpenedCallback
& callback
,
230 WebContents
* web_contents
) {
231 DCHECK(web_contents
);
233 new WindowOpenedObserver(web_contents
, callback
);
238 const GURL
& script_url
,
240 const scoped_refptr
<ServiceWorkerContextWrapper
>& context_wrapper
,
241 const WindowOpenedCallback
& callback
) {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
244 BrowserContext
* browser_context
= context_wrapper
->storage_partition()
245 ? context_wrapper
->storage_partition()->browser_context()
247 // We are shutting down.
248 if (!browser_context
)
251 RenderProcessHost
* render_process_host
=
252 RenderProcessHost::FromID(process_id
);
253 if (render_process_host
->IsIsolatedGuest()) {
254 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
256 ChildProcessHost::kInvalidUniqueID
,
261 OpenURLParams
params(
262 url
, Referrer::SanitizeForRequest(
263 url
, Referrer(script_url
, blink::WebReferrerPolicyDefault
)),
264 NEW_FOREGROUND_TAB
, ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
265 true /* is_renderer_initiated */);
267 GetContentClient()->browser()->OpenURL(
268 browser_context
, params
,
269 base::Bind(&DidOpenURL
, callback
));
272 void KillEmbeddedWorkerProcess(int process_id
, ResultCode code
) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
275 RenderProcessHost
* render_process_host
=
276 RenderProcessHost::FromID(process_id
);
277 if (render_process_host
->GetHandle() != base::kNullProcessHandle
)
278 render_process_host
->ReceivedBadMessage();
283 ServiceWorkerVersion::ServiceWorkerVersion(
284 ServiceWorkerRegistration
* registration
,
285 const GURL
& script_url
,
287 base::WeakPtr
<ServiceWorkerContextCore
> context
)
288 : version_id_(version_id
),
289 registration_id_(kInvalidServiceWorkerVersionId
),
290 script_url_(script_url
),
293 script_cache_map_(this, context
),
294 ping_timed_out_(false),
296 skip_waiting_(false),
297 weak_factory_(this) {
299 DCHECK(registration
);
301 registration_id_
= registration
->id();
302 scope_
= registration
->pattern();
304 context_
->AddLiveVersion(this);
305 embedded_worker_
= context_
->embedded_worker_registry()->CreateWorker();
306 embedded_worker_
->AddListener(this);
309 ServiceWorkerVersion::~ServiceWorkerVersion() {
310 embedded_worker_
->RemoveListener(this);
312 context_
->RemoveLiveVersion(version_id_
);
313 // EmbeddedWorker's dtor sends StopWorker if it's still running.
316 void ServiceWorkerVersion::SetStatus(Status status
) {
317 if (status_
== status
)
322 if (skip_waiting_
&& status_
== ACTIVATED
) {
323 for (int request_id
: pending_skip_waiting_requests_
)
324 DidSkipWaiting(request_id
);
325 pending_skip_waiting_requests_
.clear();
328 std::vector
<base::Closure
> callbacks
;
329 callbacks
.swap(status_change_callbacks_
);
330 for (const auto& callback
: callbacks
)
333 FOR_EACH_OBSERVER(Listener
, listeners_
, OnVersionStateChanged(this));
336 void ServiceWorkerVersion::RegisterStatusChangeCallback(
337 const base::Closure
& callback
) {
338 status_change_callbacks_
.push_back(callback
);
341 ServiceWorkerVersionInfo
ServiceWorkerVersion::GetInfo() {
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
343 return ServiceWorkerVersionInfo(
348 embedded_worker()->process_id(),
349 embedded_worker()->thread_id(),
350 embedded_worker()->worker_devtools_agent_route_id());
353 void ServiceWorkerVersion::StartWorker(const StatusCallback
& callback
) {
354 StartWorker(false, callback
);
357 void ServiceWorkerVersion::StartWorker(
358 bool pause_after_download
,
359 const StatusCallback
& callback
) {
361 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
364 switch (running_status()) {
366 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
371 start_callbacks_
.push_back(callback
);
372 if (running_status() == STOPPED
) {
373 DCHECK(!cache_listener_
.get());
374 cache_listener_
.reset(new ServiceWorkerCacheListener(this, context_
));
375 embedded_worker_
->Start(
379 pause_after_download
,
380 base::Bind(&ServiceWorkerVersion::OnStartMessageSent
,
381 weak_factory_
.GetWeakPtr()));
387 void ServiceWorkerVersion::StopWorker(const StatusCallback
& callback
) {
388 if (running_status() == STOPPED
) {
389 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
392 if (stop_callbacks_
.empty()) {
393 ServiceWorkerStatusCode status
= embedded_worker_
->Stop();
394 if (status
!= SERVICE_WORKER_OK
) {
395 RunSoon(base::Bind(callback
, status
));
399 stop_callbacks_
.push_back(callback
);
402 void ServiceWorkerVersion::ScheduleUpdate() {
403 if (update_timer_
.IsRunning()) {
404 update_timer_
.Reset();
408 FROM_HERE
, base::TimeDelta::FromSeconds(kUpdateDelaySeconds
),
409 base::Bind(&ServiceWorkerVersion::StartUpdate
,
410 weak_factory_
.GetWeakPtr()));
413 void ServiceWorkerVersion::DeferScheduledUpdate() {
414 if (update_timer_
.IsRunning())
415 update_timer_
.Reset();
418 void ServiceWorkerVersion::StartUpdate() {
419 update_timer_
.Stop();
422 ServiceWorkerRegistration
* registration
=
423 context_
->GetLiveRegistration(registration_id_
);
424 if (!registration
|| !registration
->GetNewestVersion())
426 context_
->UpdateServiceWorker(registration
);
429 void ServiceWorkerVersion::DispatchMessageEvent(
430 const base::string16
& message
,
431 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
432 const StatusCallback
& callback
) {
433 for (const TransferredMessagePort
& port
: sent_message_ports
) {
434 MessagePortService::GetInstance()->HoldMessages(port
.id
);
437 DispatchMessageEventInternal(message
, sent_message_ports
, callback
);
440 void ServiceWorkerVersion::DispatchMessageEventInternal(
441 const base::string16
& message
,
442 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
443 const StatusCallback
& callback
) {
444 if (running_status() != RUNNING
) {
445 // Schedule calling this method after starting the worker.
446 StartWorker(base::Bind(
447 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
448 base::Bind(&RunErrorMessageCallback
, sent_message_ports
, callback
),
449 base::Bind(&self::DispatchMessageEventInternal
,
450 weak_factory_
.GetWeakPtr(), message
, sent_message_ports
,
455 MessagePortMessageFilter
* filter
=
456 embedded_worker_
->message_port_message_filter();
457 std::vector
<int> new_routing_ids
;
458 filter
->UpdateMessagePortsWithNewRoutes(sent_message_ports
, &new_routing_ids
);
459 ServiceWorkerStatusCode status
=
460 embedded_worker_
->SendMessage(ServiceWorkerMsg_MessageToWorker(
461 message
, sent_message_ports
, new_routing_ids
));
462 RunSoon(base::Bind(callback
, status
));
465 void ServiceWorkerVersion::DispatchInstallEvent(
466 int active_version_id
,
467 const StatusCallback
& callback
) {
468 DCHECK_EQ(INSTALLING
, status()) << status();
470 if (running_status() != RUNNING
) {
471 // Schedule calling this method after starting the worker.
473 base::Bind(&RunTaskAfterStartWorker
,
474 weak_factory_
.GetWeakPtr(),
476 base::Bind(&self::DispatchInstallEventAfterStartWorker
,
477 weak_factory_
.GetWeakPtr(),
481 DispatchInstallEventAfterStartWorker(active_version_id
, callback
);
485 void ServiceWorkerVersion::DispatchActivateEvent(
486 const StatusCallback
& callback
) {
487 DCHECK_EQ(ACTIVATING
, status()) << status();
489 if (running_status() != RUNNING
) {
490 // Schedule calling this method after starting the worker.
492 base::Bind(&RunTaskAfterStartWorker
,
493 weak_factory_
.GetWeakPtr(),
495 base::Bind(&self::DispatchActivateEventAfterStartWorker
,
496 weak_factory_
.GetWeakPtr(),
499 DispatchActivateEventAfterStartWorker(callback
);
503 void ServiceWorkerVersion::DispatchFetchEvent(
504 const ServiceWorkerFetchRequest
& request
,
505 const base::Closure
& prepare_callback
,
506 const FetchCallback
& fetch_callback
) {
507 DCHECK_EQ(ACTIVATED
, status()) << status();
509 if (running_status() != RUNNING
) {
510 // Schedule calling this method after starting the worker.
511 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
512 weak_factory_
.GetWeakPtr(),
513 base::Bind(&RunErrorFetchCallback
, fetch_callback
),
514 base::Bind(&self::DispatchFetchEvent
,
515 weak_factory_
.GetWeakPtr(),
522 prepare_callback
.Run();
524 int request_id
= fetch_callbacks_
.Add(new FetchCallback(fetch_callback
));
525 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
526 ServiceWorkerMsg_FetchEvent(request_id
, request
));
527 if (status
!= SERVICE_WORKER_OK
) {
528 fetch_callbacks_
.Remove(request_id
);
529 RunSoon(base::Bind(&RunErrorFetchCallback
,
531 SERVICE_WORKER_ERROR_FAILED
));
535 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback
& callback
) {
536 DCHECK_EQ(ACTIVATED
, status()) << status();
538 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
539 switches::kEnableServiceWorkerSync
)) {
540 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
544 if (running_status() != RUNNING
) {
545 // Schedule calling this method after starting the worker.
546 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
547 weak_factory_
.GetWeakPtr(), callback
,
548 base::Bind(&self::DispatchSyncEvent
,
549 weak_factory_
.GetWeakPtr(),
554 int request_id
= sync_callbacks_
.Add(new StatusCallback(callback
));
555 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
556 ServiceWorkerMsg_SyncEvent(request_id
));
557 if (status
!= SERVICE_WORKER_OK
) {
558 sync_callbacks_
.Remove(request_id
);
559 RunSoon(base::Bind(callback
, status
));
563 void ServiceWorkerVersion::DispatchNotificationClickEvent(
564 const StatusCallback
& callback
,
565 const std::string
& notification_id
,
566 const PlatformNotificationData
& notification_data
) {
567 DCHECK_EQ(ACTIVATED
, status()) << status();
568 if (running_status() != RUNNING
) {
569 // Schedule calling this method after starting the worker.
570 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
571 weak_factory_
.GetWeakPtr(), callback
,
572 base::Bind(&self::DispatchNotificationClickEvent
,
573 weak_factory_
.GetWeakPtr(),
574 callback
, notification_id
,
575 notification_data
)));
580 notification_click_callbacks_
.Add(new StatusCallback(callback
));
581 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
582 ServiceWorkerMsg_NotificationClickEvent(request_id
,
585 if (status
!= SERVICE_WORKER_OK
) {
586 notification_click_callbacks_
.Remove(request_id
);
587 RunSoon(base::Bind(callback
, status
));
591 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback
& callback
,
592 const std::string
& data
) {
593 DCHECK_EQ(ACTIVATED
, status()) << status();
594 if (running_status() != RUNNING
) {
595 // Schedule calling this method after starting the worker.
596 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
597 weak_factory_
.GetWeakPtr(), callback
,
598 base::Bind(&self::DispatchPushEvent
,
599 weak_factory_
.GetWeakPtr(),
604 int request_id
= push_callbacks_
.Add(new StatusCallback(callback
));
605 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
606 ServiceWorkerMsg_PushEvent(request_id
, data
));
607 if (status
!= SERVICE_WORKER_OK
) {
608 push_callbacks_
.Remove(request_id
);
609 RunSoon(base::Bind(callback
, status
));
613 void ServiceWorkerVersion::DispatchGeofencingEvent(
614 const StatusCallback
& callback
,
615 blink::WebGeofencingEventType event_type
,
616 const std::string
& region_id
,
617 const blink::WebCircularGeofencingRegion
& region
) {
618 DCHECK_EQ(ACTIVATED
, status()) << status();
620 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
621 switches::kEnableExperimentalWebPlatformFeatures
)) {
622 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
626 if (running_status() != RUNNING
) {
627 // Schedule calling this method after starting the worker.
628 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
629 weak_factory_
.GetWeakPtr(),
631 base::Bind(&self::DispatchGeofencingEvent
,
632 weak_factory_
.GetWeakPtr(),
640 int request_id
= geofencing_callbacks_
.Add(new StatusCallback(callback
));
641 ServiceWorkerStatusCode status
=
642 embedded_worker_
->SendMessage(ServiceWorkerMsg_GeofencingEvent(
643 request_id
, event_type
, region_id
, region
));
644 if (status
!= SERVICE_WORKER_OK
) {
645 geofencing_callbacks_
.Remove(request_id
);
646 RunSoon(base::Bind(callback
, status
));
650 void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
651 const CrossOriginConnectCallback
& callback
,
652 const NavigatorConnectClient
& client
) {
653 DCHECK_EQ(ACTIVATED
, status()) << status();
655 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
656 switches::kEnableExperimentalWebPlatformFeatures
)) {
657 callback
.Run(SERVICE_WORKER_ERROR_ABORT
, false);
661 if (running_status() != RUNNING
) {
662 // Schedule calling this method after starting the worker.
664 base::Bind(&RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
665 base::Bind(&RunErrorCrossOriginConnectCallback
, callback
),
666 base::Bind(&self::DispatchCrossOriginConnectEvent
,
667 weak_factory_
.GetWeakPtr(), callback
, client
)));
671 int request_id
= cross_origin_connect_callbacks_
.Add(
672 new CrossOriginConnectCallback(callback
));
673 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
674 ServiceWorkerMsg_CrossOriginConnectEvent(request_id
, client
));
675 if (status
!= SERVICE_WORKER_OK
) {
676 cross_origin_connect_callbacks_
.Remove(request_id
);
677 RunSoon(base::Bind(callback
, status
, false));
681 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
682 const NavigatorConnectClient
& client
,
683 const base::string16
& message
,
684 const std::vector
<TransferredMessagePort
>& sent_message_ports
,
685 const StatusCallback
& callback
) {
686 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
687 // have already put all the sent message ports on hold. So no need to do that
690 if (running_status() != RUNNING
) {
691 // Schedule calling this method after starting the worker.
692 StartWorker(base::Bind(
693 &RunTaskAfterStartWorker
, weak_factory_
.GetWeakPtr(),
694 base::Bind(&RunErrorMessageCallback
, sent_message_ports
, callback
),
695 base::Bind(&self::DispatchCrossOriginMessageEvent
,
696 weak_factory_
.GetWeakPtr(), client
, message
,
697 sent_message_ports
, callback
)));
701 MessagePortMessageFilter
* filter
=
702 embedded_worker_
->message_port_message_filter();
703 std::vector
<int> new_routing_ids
;
704 filter
->UpdateMessagePortsWithNewRoutes(sent_message_ports
, &new_routing_ids
);
705 ServiceWorkerStatusCode status
=
706 embedded_worker_
->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
707 client
, message
, sent_message_ports
, new_routing_ids
));
708 RunSoon(base::Bind(callback
, status
));
711 void ServiceWorkerVersion::AddControllee(
712 ServiceWorkerProviderHost
* provider_host
) {
713 DCHECK(!ContainsKey(controllee_map_
, provider_host
));
714 int controllee_id
= controllee_by_id_
.Add(provider_host
);
715 // IDMap<>'s last index is kInvalidServiceWorkerClientId.
716 CHECK(controllee_id
!= kInvalidServiceWorkerClientId
);
717 controllee_map_
[provider_host
] = controllee_id
;
718 // Reset the timer if it's running (so that it's kept alive a bit longer
719 // right after a new controllee is added).
720 ScheduleStopWorker();
723 void ServiceWorkerVersion::RemoveControllee(
724 ServiceWorkerProviderHost
* provider_host
) {
725 ControlleeMap::iterator found
= controllee_map_
.find(provider_host
);
726 DCHECK(found
!= controllee_map_
.end());
727 controllee_by_id_
.Remove(found
->second
);
728 controllee_map_
.erase(found
);
731 FOR_EACH_OBSERVER(Listener
, listeners_
, OnNoControllees(this));
736 // Schedule the stop-worker-timer if it's not running.
737 if (!stop_worker_timer_
.IsRunning())
738 ScheduleStopWorker();
741 void ServiceWorkerVersion::AddStreamingURLRequestJob(
742 const ServiceWorkerURLRequestJob
* request_job
) {
743 DCHECK(streaming_url_request_jobs_
.find(request_job
) ==
744 streaming_url_request_jobs_
.end());
745 streaming_url_request_jobs_
.insert(request_job
);
748 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
749 const ServiceWorkerURLRequestJob
* request_job
) {
750 streaming_url_request_jobs_
.erase(request_job
);
755 void ServiceWorkerVersion::AddListener(Listener
* listener
) {
756 listeners_
.AddObserver(listener
);
759 void ServiceWorkerVersion::RemoveListener(Listener
* listener
) {
760 listeners_
.RemoveObserver(listener
);
763 void ServiceWorkerVersion::Doom() {
767 if (!HasControllee())
771 void ServiceWorkerVersion::SetDevToolsAttached(bool attached
) {
772 embedded_worker()->set_devtools_attached(attached
);
775 // If devtools is detached try scheduling the timers for stopping the worker
777 if (!stop_worker_timer_
.IsRunning())
778 ScheduleStopWorker();
779 if (!ping_worker_timer_
.IsRunning())
783 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
784 const net::HttpResponseInfo
& http_info
) {
785 main_script_http_info_
.reset(new net::HttpResponseInfo(http_info
));
788 const net::HttpResponseInfo
*
789 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
790 return main_script_http_info_
.get();
793 void ServiceWorkerVersion::OnScriptLoaded() {
794 DCHECK_EQ(STARTING
, running_status());
798 void ServiceWorkerVersion::OnStarted() {
799 DCHECK_EQ(RUNNING
, running_status());
800 DCHECK(cache_listener_
.get());
801 ScheduleStopWorker();
803 // Fire all start callbacks.
804 scoped_refptr
<ServiceWorkerVersion
> protect(this);
805 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_OK
);
806 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStarted(this));
809 void ServiceWorkerVersion::OnStopped(
810 EmbeddedWorkerInstance::Status old_status
) {
811 DCHECK_EQ(STOPPED
, running_status());
812 scoped_refptr
<ServiceWorkerVersion
> protect(this);
814 bool should_restart
= !is_doomed() && !start_callbacks_
.empty() &&
815 (old_status
!= EmbeddedWorkerInstance::STARTING
);
817 ping_worker_timer_
.Stop();
819 should_restart
= false;
821 // Fire all stop callbacks.
822 RunCallbacks(this, &stop_callbacks_
, SERVICE_WORKER_OK
);
824 if (!should_restart
) {
825 // Let all start callbacks fail.
826 RunCallbacks(this, &start_callbacks_
,
827 SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
830 // Let all message callbacks fail (this will also fire and clear all
831 // callbacks for events).
832 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
833 RunIDMapCallbacks(&activate_callbacks_
,
834 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
);
835 RunIDMapCallbacks(&install_callbacks_
,
836 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
);
837 RunIDMapCallbacks(&fetch_callbacks_
,
838 SERVICE_WORKER_ERROR_FAILED
,
839 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
840 ServiceWorkerResponse());
841 RunIDMapCallbacks(&sync_callbacks_
,
842 SERVICE_WORKER_ERROR_FAILED
);
843 RunIDMapCallbacks(¬ification_click_callbacks_
,
844 SERVICE_WORKER_ERROR_FAILED
);
845 RunIDMapCallbacks(&push_callbacks_
,
846 SERVICE_WORKER_ERROR_FAILED
);
847 RunIDMapCallbacks(&geofencing_callbacks_
,
848 SERVICE_WORKER_ERROR_FAILED
);
849 RunIDMapCallbacks(&cross_origin_connect_callbacks_
,
850 SERVICE_WORKER_ERROR_FAILED
,
853 streaming_url_request_jobs_
.clear();
855 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStopped(this));
857 // There should be no more communication from/to a stopped worker. Deleting
858 // the listener prevents any pending completion callbacks from causing
859 // messages to be sent to the stopped worker.
860 cache_listener_
.reset();
862 // Restart worker if we have any start callbacks and the worker isn't doomed.
863 if (should_restart
) {
864 cache_listener_
.reset(new ServiceWorkerCacheListener(this, context_
));
865 embedded_worker_
->Start(
866 version_id_
, scope_
, script_url_
, false /* pause_after_download */,
867 base::Bind(&ServiceWorkerVersion::OnStartMessageSent
,
868 weak_factory_
.GetWeakPtr()));
872 void ServiceWorkerVersion::OnReportException(
873 const base::string16
& error_message
,
876 const GURL
& source_url
) {
881 this, error_message
, line_number
, column_number
, source_url
));
884 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier
,
886 const base::string16
& message
,
888 const GURL
& source_url
) {
889 FOR_EACH_OBSERVER(Listener
,
891 OnReportConsoleMessage(this,
899 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message
& message
) {
901 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion
, message
)
902 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments
,
903 OnGetClientDocuments
)
904 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished
,
905 OnActivateEventFinished
)
906 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished
,
907 OnInstallEventFinished
)
908 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished
,
909 OnFetchEventFinished
)
910 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished
,
912 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished
,
913 OnNotificationClickEventFinished
)
914 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished
,
916 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished
,
917 OnGeofencingEventFinished
)
918 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished
,
919 OnCrossOriginConnectEventFinished
)
920 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow
,
922 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata
,
924 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata
,
925 OnClearCachedMetadata
)
926 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument
,
927 OnPostMessageToDocument
)
928 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient
,
930 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting
,
932 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients
,
934 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong
, OnPongFromWorker
)
935 IPC_MESSAGE_UNHANDLED(handled
= false)
936 IPC_END_MESSAGE_MAP()
940 void ServiceWorkerVersion::OnStartMessageSent(
941 ServiceWorkerStatusCode status
) {
942 if (status
!= SERVICE_WORKER_OK
)
943 RunCallbacks(this, &start_callbacks_
, status
);
946 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
947 int active_version_id
,
948 const StatusCallback
& callback
) {
949 DCHECK_EQ(RUNNING
, running_status())
950 << "Worker stopped too soon after it was started.";
952 int request_id
= install_callbacks_
.Add(new StatusCallback(callback
));
953 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
954 ServiceWorkerMsg_InstallEvent(request_id
, active_version_id
));
955 if (status
!= SERVICE_WORKER_OK
) {
956 install_callbacks_
.Remove(request_id
);
957 RunSoon(base::Bind(callback
, status
));
961 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
962 const StatusCallback
& callback
) {
963 DCHECK_EQ(RUNNING
, running_status())
964 << "Worker stopped too soon after it was started.";
966 int request_id
= activate_callbacks_
.Add(new StatusCallback(callback
));
967 ServiceWorkerStatusCode status
=
968 embedded_worker_
->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id
));
969 if (status
!= SERVICE_WORKER_OK
) {
970 activate_callbacks_
.Remove(request_id
);
971 RunSoon(base::Bind(callback
, status
));
975 void ServiceWorkerVersion::OnGetClientDocuments(int request_id
) {
976 if (controllee_by_id_
.IsEmpty()) {
977 if (running_status() == RUNNING
) {
978 embedded_worker_
->SendMessage(
979 ServiceWorkerMsg_DidGetClientDocuments(request_id
,
980 std::vector
<ServiceWorkerClientInfo
>()));
984 scoped_refptr
<GetClientDocumentsCallback
> callback(
985 new GetClientDocumentsCallback(request_id
, this));
986 ControlleeByIDMap::iterator
it(&controllee_by_id_
);
987 TRACE_EVENT0("ServiceWorker",
988 "ServiceWorkerVersion::OnGetClientDocuments");
989 while (!it
.IsAtEnd()) {
990 // TODO(mlamouri): we could coalesce those requests into one.
991 it
.GetCurrentValue()->GetClientInfo(
992 base::Bind(&ServiceWorkerVersion::DidGetClientInfo
,
993 weak_factory_
.GetWeakPtr(), it
.GetCurrentKey(), callback
));
998 void ServiceWorkerVersion::OnActivateEventFinished(
1000 blink::WebServiceWorkerEventResult result
) {
1001 DCHECK(ACTIVATING
== status() ||
1002 REDUNDANT
== status()) << status();
1003 TRACE_EVENT0("ServiceWorker",
1004 "ServiceWorkerVersion::OnActivateEventFinished");
1006 StatusCallback
* callback
= activate_callbacks_
.Lookup(request_id
);
1008 NOTREACHED() << "Got unexpected message: " << request_id
;
1011 ServiceWorkerStatusCode rv
= SERVICE_WORKER_OK
;
1012 if (result
== blink::WebServiceWorkerEventResultRejected
||
1013 status() != ACTIVATING
) {
1014 rv
= SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
;
1017 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1019 RemoveCallbackAndStopIfDoomed(&activate_callbacks_
, request_id
);
1022 void ServiceWorkerVersion::OnInstallEventFinished(
1024 blink::WebServiceWorkerEventResult result
) {
1025 // Status is REDUNDANT if the worker was doomed while handling the install
1026 // event, and finished handling before being terminated.
1027 DCHECK(status() == INSTALLING
|| status() == REDUNDANT
) << status();
1028 TRACE_EVENT0("ServiceWorker",
1029 "ServiceWorkerVersion::OnInstallEventFinished");
1031 StatusCallback
* callback
= install_callbacks_
.Lookup(request_id
);
1033 NOTREACHED() << "Got unexpected message: " << request_id
;
1036 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1037 if (result
== blink::WebServiceWorkerEventResultRejected
)
1038 status
= SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
;
1040 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1041 callback
->Run(status
);
1042 RemoveCallbackAndStopIfDoomed(&install_callbacks_
, request_id
);
1045 void ServiceWorkerVersion::OnFetchEventFinished(
1047 ServiceWorkerFetchEventResult result
,
1048 const ServiceWorkerResponse
& response
) {
1049 TRACE_EVENT1("ServiceWorker",
1050 "ServiceWorkerVersion::OnFetchEventFinished",
1051 "Request id", request_id
);
1052 FetchCallback
* callback
= fetch_callbacks_
.Lookup(request_id
);
1054 NOTREACHED() << "Got unexpected message: " << request_id
;
1058 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1059 callback
->Run(SERVICE_WORKER_OK
, result
, response
);
1060 RemoveCallbackAndStopIfDoomed(&fetch_callbacks_
, request_id
);
1063 void ServiceWorkerVersion::OnSyncEventFinished(
1065 TRACE_EVENT1("ServiceWorker",
1066 "ServiceWorkerVersion::OnSyncEventFinished",
1067 "Request id", request_id
);
1068 StatusCallback
* callback
= sync_callbacks_
.Lookup(request_id
);
1070 NOTREACHED() << "Got unexpected message: " << request_id
;
1074 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1075 callback
->Run(SERVICE_WORKER_OK
);
1076 RemoveCallbackAndStopIfDoomed(&sync_callbacks_
, request_id
);
1079 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1081 TRACE_EVENT1("ServiceWorker",
1082 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1083 "Request id", request_id
);
1084 StatusCallback
* callback
= notification_click_callbacks_
.Lookup(request_id
);
1086 NOTREACHED() << "Got unexpected message: " << request_id
;
1090 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1091 callback
->Run(SERVICE_WORKER_OK
);
1092 RemoveCallbackAndStopIfDoomed(¬ification_click_callbacks_
, request_id
);
1095 void ServiceWorkerVersion::OnPushEventFinished(
1097 blink::WebServiceWorkerEventResult result
) {
1098 TRACE_EVENT1("ServiceWorker",
1099 "ServiceWorkerVersion::OnPushEventFinished",
1100 "Request id", request_id
);
1101 StatusCallback
* callback
= push_callbacks_
.Lookup(request_id
);
1103 NOTREACHED() << "Got unexpected message: " << request_id
;
1106 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
1107 if (result
== blink::WebServiceWorkerEventResultRejected
)
1108 status
= SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED
;
1110 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1111 callback
->Run(status
);
1112 RemoveCallbackAndStopIfDoomed(&push_callbacks_
, request_id
);
1115 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id
) {
1116 TRACE_EVENT1("ServiceWorker",
1117 "ServiceWorkerVersion::OnGeofencingEventFinished",
1120 StatusCallback
* callback
= geofencing_callbacks_
.Lookup(request_id
);
1122 NOTREACHED() << "Got unexpected message: " << request_id
;
1126 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1127 callback
->Run(SERVICE_WORKER_OK
);
1128 RemoveCallbackAndStopIfDoomed(&geofencing_callbacks_
, request_id
);
1131 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1133 bool accept_connection
) {
1134 TRACE_EVENT1("ServiceWorker",
1135 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1136 "Request id", request_id
);
1137 CrossOriginConnectCallback
* callback
=
1138 cross_origin_connect_callbacks_
.Lookup(request_id
);
1140 NOTREACHED() << "Got unexpected message: " << request_id
;
1144 scoped_refptr
<ServiceWorkerVersion
> protect(this);
1145 callback
->Run(SERVICE_WORKER_OK
, accept_connection
);
1146 RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_
, request_id
);
1149 void ServiceWorkerVersion::OnOpenWindow(int request_id
, const GURL
& url
) {
1150 // Just abort if we are shutting down.
1154 if (url
.GetOrigin() != script_url_
.GetOrigin()) {
1155 // There should be a same origin check by Blink, if the request is still not
1156 // same origin, the process might be compromised and should be eliminated.
1157 DVLOG(1) << "Received a cross origin openWindow() request from a service "
1158 "worker. Killing associated process.";
1159 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
1160 base::Bind(&KillEmbeddedWorkerProcess
,
1161 embedded_worker_
->process_id(),
1162 RESULT_CODE_KILLED_BAD_MESSAGE
));
1166 BrowserThread::PostTask(
1167 BrowserThread::UI
, FROM_HERE
,
1168 base::Bind(&OpenWindowOnUI
,
1171 embedded_worker_
->process_id(),
1172 make_scoped_refptr(context_
->wrapper()),
1173 base::Bind(&ServiceWorkerVersion::DidOpenWindow
,
1174 weak_factory_
.GetWeakPtr(),
1178 void ServiceWorkerVersion::DidOpenWindow(int request_id
,
1179 int render_process_id
,
1180 int render_frame_id
) {
1181 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1183 if (running_status() != RUNNING
)
1186 if (render_process_id
== ChildProcessHost::kInvalidUniqueID
&&
1187 render_frame_id
== MSG_ROUTING_NONE
) {
1188 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowError(request_id
));
1192 for (const auto& it
: controllee_map_
) {
1193 const ServiceWorkerProviderHost
* provider_host
= it
.first
;
1194 if (provider_host
->process_id() != render_process_id
||
1195 provider_host
->frame_id() != render_frame_id
) {
1199 // it.second is the client_id associated with the provider_host.
1200 provider_host
->GetClientInfo(
1201 base::Bind(&ServiceWorkerVersion::OnOpenWindowFinished
,
1202 weak_factory_
.GetWeakPtr(), request_id
, it
.second
));
1206 // If here, it means that no provider_host was found, in which case, the
1207 // renderer should still be informed that the window was opened.
1208 OnOpenWindowFinished(request_id
, 0, ServiceWorkerClientInfo());
1211 void ServiceWorkerVersion::OnOpenWindowFinished(
1214 const ServiceWorkerClientInfo
& client_info
) {
1215 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1217 if (running_status() != RUNNING
)
1220 ServiceWorkerClientInfo
client(client_info
);
1222 // If the |client_info| is empty, it means that the opened window wasn't
1223 // controlled but the action still succeeded. The renderer process is
1224 // expecting an empty client in such case.
1225 if (!client
.IsEmpty())
1226 client
.client_id
= client_id
;
1228 embedded_worker_
->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1229 request_id
, client
));
1232 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL
& url
,
1233 const std::vector
<char>& data
) {
1234 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
1235 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1236 "ServiceWorkerVersion::OnSetCachedMetadata",
1237 callback_id
, "URL", url
.spec());
1238 script_cache_map_
.WriteMetadata(
1239 url
, data
, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished
,
1240 weak_factory_
.GetWeakPtr(), callback_id
));
1243 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id
,
1245 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1246 "ServiceWorkerVersion::OnSetCachedMetadata",
1247 callback_id
, "result", result
);
1248 FOR_EACH_OBSERVER(Listener
, listeners_
, OnCachedMetadataUpdated(this));
1251 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL
& url
) {
1252 int64 callback_id
= base::TimeTicks::Now().ToInternalValue();
1253 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1254 "ServiceWorkerVersion::OnClearCachedMetadata",
1255 callback_id
, "URL", url
.spec());
1256 script_cache_map_
.ClearMetadata(
1257 url
, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished
,
1258 weak_factory_
.GetWeakPtr(), callback_id
));
1261 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id
,
1263 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1264 "ServiceWorkerVersion::OnClearCachedMetadata",
1265 callback_id
, "result", result
);
1266 FOR_EACH_OBSERVER(Listener
, listeners_
, OnCachedMetadataUpdated(this));
1269 void ServiceWorkerVersion::OnPostMessageToDocument(
1271 const base::string16
& message
,
1272 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
1273 TRACE_EVENT1("ServiceWorker",
1274 "ServiceWorkerVersion::OnPostMessageToDocument",
1275 "Client id", client_id
);
1276 ServiceWorkerProviderHost
* provider_host
=
1277 controllee_by_id_
.Lookup(client_id
);
1278 if (!provider_host
) {
1279 // The client may already have been closed, just ignore.
1282 provider_host
->PostMessage(message
, sent_message_ports
);
1285 void ServiceWorkerVersion::OnFocusClient(int request_id
, int client_id
) {
1286 TRACE_EVENT2("ServiceWorker",
1287 "ServiceWorkerVersion::OnFocusClient",
1288 "Request id", request_id
,
1289 "Client id", client_id
);
1290 ServiceWorkerProviderHost
* provider_host
=
1291 controllee_by_id_
.Lookup(client_id
);
1292 if (!provider_host
) {
1293 // The client may already have been closed, just ignore.
1297 provider_host
->Focus(
1298 base::Bind(&ServiceWorkerVersion::OnFocusClientFinished
,
1299 weak_factory_
.GetWeakPtr(),
1304 void ServiceWorkerVersion::OnFocusClientFinished(
1307 const ServiceWorkerClientInfo
& client
) {
1308 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
1310 if (running_status() != RUNNING
)
1313 ServiceWorkerClientInfo
client_info(client
);
1314 client_info
.client_id
= cliend_id
;
1316 embedded_worker_
->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1317 request_id
, client_info
));
1320 void ServiceWorkerVersion::OnSkipWaiting(int request_id
) {
1321 skip_waiting_
= true;
1322 if (status_
!= INSTALLED
)
1323 return DidSkipWaiting(request_id
);
1327 ServiceWorkerRegistration
* registration
=
1328 context_
->GetLiveRegistration(registration_id_
);
1331 pending_skip_waiting_requests_
.push_back(request_id
);
1332 if (pending_skip_waiting_requests_
.size() == 1)
1333 registration
->ActivateWaitingVersionWhenReady();
1336 void ServiceWorkerVersion::DidSkipWaiting(int request_id
) {
1337 if (running_status() == STARTING
|| running_status() == RUNNING
)
1338 embedded_worker_
->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id
));
1341 void ServiceWorkerVersion::OnClaimClients(int request_id
) {
1342 StatusCallback callback
= base::Bind(&ServiceWorkerVersion::DidClaimClients
,
1343 weak_factory_
.GetWeakPtr(), request_id
);
1344 if (status_
!= ACTIVATING
&& status_
!= ACTIVATED
) {
1345 callback
.Run(SERVICE_WORKER_ERROR_STATE
);
1349 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
1353 ServiceWorkerRegistration
* registration
=
1354 context_
->GetLiveRegistration(registration_id_
);
1355 if (!registration
) {
1356 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
1359 registration
->ClaimClients(callback
);
1362 void ServiceWorkerVersion::OnPongFromWorker() {
1363 if (ping_timed_out_
)
1365 SchedulePingWorker();
1368 void ServiceWorkerVersion::DidClaimClients(
1369 int request_id
, ServiceWorkerStatusCode status
) {
1370 if (status
== SERVICE_WORKER_ERROR_STATE
) {
1371 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1372 request_id
, blink::WebServiceWorkerError::ErrorTypeState
,
1373 base::ASCIIToUTF16(kClaimClientsStateErrorMesage
)));
1376 if (status
== SERVICE_WORKER_ERROR_ABORT
) {
1377 embedded_worker_
->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1378 request_id
, blink::WebServiceWorkerError::ErrorTypeAbort
,
1379 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage
)));
1382 DCHECK(status
== SERVICE_WORKER_OK
);
1383 embedded_worker_
->SendMessage(ServiceWorkerMsg_DidClaimClients(request_id
));
1386 void ServiceWorkerVersion::DidGetClientInfo(
1388 scoped_refptr
<GetClientDocumentsCallback
> callback
,
1389 const ServiceWorkerClientInfo
& info
) {
1390 // If the request to the provider_host returned an empty
1391 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
1392 // it with a valid RenderFrameHost. It might be because the frame was killed
1393 // or navigated in between.
1397 // We can get info for a frame that was navigating end ended up with a
1398 // different URL than expected. In such case, we should make sure to not
1399 // expose cross-origin WindowClient.
1400 if (info
.url
.GetOrigin() != script_url_
.GetOrigin())
1403 callback
->AddClientInfo(client_id
, info
);
1406 void ServiceWorkerVersion::PingWorker() {
1407 if (running_status() != STARTING
&& running_status() != RUNNING
)
1409 ServiceWorkerStatusCode status
=
1410 embedded_worker_
->SendMessage(ServiceWorkerMsg_Ping());
1411 if (status
!= SERVICE_WORKER_OK
) {
1412 // TODO(falken): Maybe try resending Ping a few times first?
1413 ping_timed_out_
= true;
1417 ping_worker_timer_
.Start(FROM_HERE
,
1418 base::TimeDelta::FromSeconds(kPingTimeoutTime
),
1419 base::Bind(&ServiceWorkerVersion::OnPingTimeout
,
1420 weak_factory_
.GetWeakPtr()));
1423 void ServiceWorkerVersion::StartPingWorker() {
1424 ping_timed_out_
= false;
1425 SchedulePingWorker();
1428 void ServiceWorkerVersion::SchedulePingWorker() {
1429 DCHECK(!ping_timed_out_
);
1430 ping_worker_timer_
.Stop();
1431 ping_worker_timer_
.Start(FROM_HERE
,
1432 base::TimeDelta::FromSeconds(kPingIntervalTime
),
1433 base::Bind(&ServiceWorkerVersion::PingWorker
,
1434 weak_factory_
.GetWeakPtr()));
1437 void ServiceWorkerVersion::OnPingTimeout() {
1438 if (running_status() != STARTING
&& running_status() != RUNNING
)
1440 ping_timed_out_
= true;
1441 // TODO(falken): Show a message to the developer that the SW was stopped due
1442 // to timeout (crbug.com/457968).
1446 void ServiceWorkerVersion::ScheduleStopWorker() {
1447 if (running_status() != RUNNING
)
1449 stop_worker_timer_
.Stop();
1450 stop_worker_timer_
.Start(
1451 FROM_HERE
, base::TimeDelta::FromSeconds(
1452 is_doomed_
? kStopDoomedWorkerDelay
: kStopWorkerDelay
),
1453 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle
,
1454 weak_factory_
.GetWeakPtr()));
1457 void ServiceWorkerVersion::StopWorkerIfIdle() {
1458 if (HasInflightRequests() && !ping_timed_out_
) {
1459 ScheduleStopWorker();
1462 if (running_status() == STOPPED
|| running_status() == STOPPING
||
1463 !stop_callbacks_
.empty()) {
1467 // TODO(falken): We may need to handle StopIfIdle failure and
1468 // forcibly fail pending callbacks so no one is stuck waiting
1470 embedded_worker_
->StopIfIdle();
1473 bool ServiceWorkerVersion::HasInflightRequests() const {
1475 !activate_callbacks_
.IsEmpty() ||
1476 !install_callbacks_
.IsEmpty() ||
1477 !fetch_callbacks_
.IsEmpty() ||
1478 !sync_callbacks_
.IsEmpty() ||
1479 !notification_click_callbacks_
.IsEmpty() ||
1480 !push_callbacks_
.IsEmpty() ||
1481 !geofencing_callbacks_
.IsEmpty() ||
1482 !cross_origin_connect_callbacks_
.IsEmpty() ||
1483 !streaming_url_request_jobs_
.empty();
1486 void ServiceWorkerVersion::DoomInternal() {
1488 DCHECK(!HasControllee());
1489 SetStatus(REDUNDANT
);
1493 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
1494 script_cache_map_
.GetResources(&resources
);
1495 context_
->storage()->PurgeResources(resources
);
1498 template <typename IDMAP
>
1499 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1502 callbacks
->Remove(request_id
);
1504 // The stop should be already scheduled, but try to stop immediately, in
1505 // order to release worker resources soon.
1510 } // namespace content