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/stl_util.h"
9 #include "base/strings/string16.h"
10 #include "content/browser/service_worker/embedded_worker_instance.h"
11 #include "content/browser/service_worker/embedded_worker_registry.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_registration.h"
14 #include "content/browser/service_worker/service_worker_utils.h"
15 #include "content/common/service_worker/service_worker_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/content_switches.h"
21 typedef ServiceWorkerVersion::StatusCallback StatusCallback
;
22 typedef ServiceWorkerVersion::MessageCallback MessageCallback
;
26 // Default delay for scheduled stop.
27 // (Note that if all references to the version is dropped the worker
28 // is also stopped without delay)
29 const int64 kStopWorkerDelay
= 30; // 30 secs.
31 // Default delay for scheduled update.
32 const int kUpdateDelaySeconds
= 1;
34 void RunSoon(const base::Closure
& callback
) {
35 if (!callback
.is_null())
36 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
39 template <typename CallbackArray
, typename Arg
>
40 void RunCallbacks(ServiceWorkerVersion
* version
,
41 CallbackArray
* callbacks_ptr
,
43 CallbackArray callbacks
;
44 callbacks
.swap(*callbacks_ptr
);
45 scoped_refptr
<ServiceWorkerVersion
> protect(version
);
46 for (typename
CallbackArray::const_iterator i
= callbacks
.begin();
47 i
!= callbacks
.end(); ++i
)
51 template <typename IDMAP
, typename Method
, typename Params
>
52 void RunIDMapCallbacks(IDMAP
* callbacks
, Method method
, const Params
& params
) {
53 typename
IDMAP::iterator
iter(callbacks
);
54 while (!iter
.IsAtEnd()) {
55 DispatchToMethod(iter
.GetCurrentValue(), method
, params
);
61 // A callback adapter to start a |task| after StartWorker.
62 void RunTaskAfterStartWorker(
63 base::WeakPtr
<ServiceWorkerVersion
> version
,
64 const StatusCallback
& error_callback
,
65 const base::Closure
& task
,
66 ServiceWorkerStatusCode status
) {
67 if (status
!= SERVICE_WORKER_OK
) {
68 if (!error_callback
.is_null())
69 error_callback
.Run(status
);
72 if (version
->running_status() != ServiceWorkerVersion::RUNNING
) {
73 // We've tried to start the worker (and it has succeeded), but
74 // it looks it's not running yet.
75 NOTREACHED() << "The worker's not running after successful StartWorker";
76 if (!error_callback
.is_null())
77 error_callback
.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
83 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback
& callback
,
84 ServiceWorkerStatusCode status
) {
86 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
87 ServiceWorkerResponse());
92 ServiceWorkerVersion::ServiceWorkerVersion(
93 ServiceWorkerRegistration
* registration
,
94 const GURL
& script_url
,
96 base::WeakPtr
<ServiceWorkerContextCore
> context
)
97 : version_id_(version_id
),
98 registration_id_(kInvalidServiceWorkerVersionId
),
99 script_url_(script_url
),
102 script_cache_map_(this, context
),
104 weak_factory_(this) {
106 DCHECK(registration
);
108 registration_id_
= registration
->id();
109 scope_
= registration
->pattern();
111 context_
->AddLiveVersion(this);
112 embedded_worker_
= context_
->embedded_worker_registry()->CreateWorker();
113 embedded_worker_
->AddListener(this);
116 ServiceWorkerVersion::~ServiceWorkerVersion() {
117 embedded_worker_
->RemoveListener(this);
119 context_
->RemoveLiveVersion(version_id_
);
120 // EmbeddedWorker's dtor sends StopWorker if it's still running.
123 void ServiceWorkerVersion::SetStatus(Status status
) {
124 if (status_
== status
)
127 // Schedule to stop worker after registration successfully completed.
128 if (status_
== ACTIVATING
&& status
== ACTIVATED
&& !HasControllee())
129 ScheduleStopWorker();
133 std::vector
<base::Closure
> callbacks
;
134 callbacks
.swap(status_change_callbacks_
);
135 for (std::vector
<base::Closure
>::const_iterator i
= callbacks
.begin();
136 i
!= callbacks
.end(); ++i
) {
140 FOR_EACH_OBSERVER(Listener
, listeners_
, OnVersionStateChanged(this));
143 void ServiceWorkerVersion::RegisterStatusChangeCallback(
144 const base::Closure
& callback
) {
145 status_change_callbacks_
.push_back(callback
);
148 ServiceWorkerVersionInfo
ServiceWorkerVersion::GetInfo() {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
150 return ServiceWorkerVersionInfo(
155 embedded_worker()->process_id(),
156 embedded_worker()->thread_id(),
157 embedded_worker()->worker_devtools_agent_route_id());
160 void ServiceWorkerVersion::StartWorker(const StatusCallback
& callback
) {
161 StartWorker(false, callback
);
164 void ServiceWorkerVersion::StartWorker(
165 bool pause_after_download
,
166 const StatusCallback
& callback
) {
167 switch (running_status()) {
169 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
172 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
176 start_callbacks_
.push_back(callback
);
177 if (running_status() == STOPPED
) {
178 DCHECK(!cache_listener_
.get());
179 cache_listener_
.reset(new ServiceWorkerCacheListener(this, context_
));
180 embedded_worker_
->Start(
184 pause_after_download
,
185 base::Bind(&ServiceWorkerVersion::OnStartMessageSent
,
186 weak_factory_
.GetWeakPtr()));
192 void ServiceWorkerVersion::StopWorker(const StatusCallback
& callback
) {
193 if (running_status() == STOPPED
) {
194 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
197 if (stop_callbacks_
.empty()) {
198 ServiceWorkerStatusCode status
= embedded_worker_
->Stop();
199 if (status
!= SERVICE_WORKER_OK
) {
200 RunSoon(base::Bind(callback
, status
));
204 stop_callbacks_
.push_back(callback
);
207 void ServiceWorkerVersion::ScheduleUpdate() {
208 if (update_timer_
.IsRunning()) {
209 update_timer_
.Reset();
213 FROM_HERE
, base::TimeDelta::FromSeconds(kUpdateDelaySeconds
),
214 base::Bind(&ServiceWorkerVersion::StartUpdate
,
215 weak_factory_
.GetWeakPtr()));
218 void ServiceWorkerVersion::DeferScheduledUpdate() {
219 if (update_timer_
.IsRunning())
220 update_timer_
.Reset();
223 void ServiceWorkerVersion::StartUpdate() {
224 update_timer_
.Stop();
227 ServiceWorkerRegistration
* registration
=
228 context_
->GetLiveRegistration(registration_id_
);
229 if (!registration
|| !registration
->GetNewestVersion())
231 context_
->UpdateServiceWorker(registration
);
234 void ServiceWorkerVersion::SendMessage(
235 const IPC::Message
& message
, const StatusCallback
& callback
) {
236 if (running_status() != RUNNING
) {
237 // Schedule calling this method after starting the worker.
238 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
239 weak_factory_
.GetWeakPtr(), callback
,
240 base::Bind(&self::SendMessage
,
241 weak_factory_
.GetWeakPtr(),
242 message
, callback
)));
246 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(message
);
247 RunSoon(base::Bind(callback
, status
));
250 void ServiceWorkerVersion::DispatchInstallEvent(
251 int active_version_id
,
252 const StatusCallback
& callback
) {
253 DCHECK_EQ(INSTALLING
, status()) << status();
255 if (running_status() != RUNNING
) {
256 // Schedule calling this method after starting the worker.
258 base::Bind(&RunTaskAfterStartWorker
,
259 weak_factory_
.GetWeakPtr(),
261 base::Bind(&self::DispatchInstallEventAfterStartWorker
,
262 weak_factory_
.GetWeakPtr(),
266 DispatchInstallEventAfterStartWorker(active_version_id
, callback
);
270 void ServiceWorkerVersion::DispatchActivateEvent(
271 const StatusCallback
& callback
) {
272 DCHECK_EQ(ACTIVATING
, status()) << status();
274 if (running_status() != RUNNING
) {
275 // Schedule calling this method after starting the worker.
277 base::Bind(&RunTaskAfterStartWorker
,
278 weak_factory_
.GetWeakPtr(),
280 base::Bind(&self::DispatchActivateEventAfterStartWorker
,
281 weak_factory_
.GetWeakPtr(),
284 DispatchActivateEventAfterStartWorker(callback
);
288 void ServiceWorkerVersion::DispatchFetchEvent(
289 const ServiceWorkerFetchRequest
& request
,
290 const base::Closure
& prepare_callback
,
291 const FetchCallback
& fetch_callback
) {
292 DCHECK_EQ(ACTIVATED
, status()) << status();
294 if (running_status() != RUNNING
) {
295 // Schedule calling this method after starting the worker.
296 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
297 weak_factory_
.GetWeakPtr(),
298 base::Bind(&RunErrorFetchCallback
, fetch_callback
),
299 base::Bind(&self::DispatchFetchEvent
,
300 weak_factory_
.GetWeakPtr(),
307 prepare_callback
.Run();
309 int request_id
= fetch_callbacks_
.Add(new FetchCallback(fetch_callback
));
310 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
311 ServiceWorkerMsg_FetchEvent(request_id
, request
));
312 if (status
!= SERVICE_WORKER_OK
) {
313 fetch_callbacks_
.Remove(request_id
);
314 RunSoon(base::Bind(&RunErrorFetchCallback
,
316 SERVICE_WORKER_ERROR_FAILED
));
320 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback
& callback
) {
321 DCHECK_EQ(ACTIVATED
, status()) << status();
323 if (!CommandLine::ForCurrentProcess()->HasSwitch(
324 switches::kEnableServiceWorkerSync
)) {
325 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
329 if (running_status() != RUNNING
) {
330 // Schedule calling this method after starting the worker.
331 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
332 weak_factory_
.GetWeakPtr(), callback
,
333 base::Bind(&self::DispatchSyncEvent
,
334 weak_factory_
.GetWeakPtr(),
339 int request_id
= sync_callbacks_
.Add(new StatusCallback(callback
));
340 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
341 ServiceWorkerMsg_SyncEvent(request_id
));
342 if (status
!= SERVICE_WORKER_OK
) {
343 sync_callbacks_
.Remove(request_id
);
344 RunSoon(base::Bind(callback
, status
));
348 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback
& callback
,
349 const std::string
& data
) {
350 DCHECK_EQ(ACTIVATED
, status()) << status();
352 if (!CommandLine::ForCurrentProcess()->HasSwitch(
353 switches::kEnableExperimentalWebPlatformFeatures
)) {
354 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
358 if (running_status() != RUNNING
) {
359 // Schedule calling this method after starting the worker.
360 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
361 weak_factory_
.GetWeakPtr(), callback
,
362 base::Bind(&self::DispatchPushEvent
,
363 weak_factory_
.GetWeakPtr(),
368 int request_id
= push_callbacks_
.Add(new StatusCallback(callback
));
369 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
370 ServiceWorkerMsg_PushEvent(request_id
, data
));
371 if (status
!= SERVICE_WORKER_OK
) {
372 push_callbacks_
.Remove(request_id
);
373 RunSoon(base::Bind(callback
, status
));
377 void ServiceWorkerVersion::AddControllee(
378 ServiceWorkerProviderHost
* provider_host
) {
379 DCHECK(!ContainsKey(controllee_map_
, provider_host
));
380 int controllee_id
= controllee_by_id_
.Add(provider_host
);
381 controllee_map_
[provider_host
] = controllee_id
;
382 if (stop_worker_timer_
.IsRunning())
383 stop_worker_timer_
.Stop();
386 void ServiceWorkerVersion::RemoveControllee(
387 ServiceWorkerProviderHost
* provider_host
) {
388 ControlleeMap::iterator found
= controllee_map_
.find(provider_host
);
389 DCHECK(found
!= controllee_map_
.end());
390 controllee_by_id_
.Remove(found
->second
);
391 controllee_map_
.erase(found
);
394 FOR_EACH_OBSERVER(Listener
, listeners_
, OnNoControllees(this));
399 ScheduleStopWorker();
402 void ServiceWorkerVersion::AddListener(Listener
* listener
) {
403 listeners_
.AddObserver(listener
);
406 void ServiceWorkerVersion::RemoveListener(Listener
* listener
) {
407 listeners_
.RemoveObserver(listener
);
410 void ServiceWorkerVersion::Doom() {
414 if (!HasControllee())
418 void ServiceWorkerVersion::OnStarted() {
419 DCHECK_EQ(RUNNING
, running_status());
420 DCHECK(cache_listener_
.get());
421 if (status() == ACTIVATED
&& !HasControllee())
422 ScheduleStopWorker();
423 // Fire all start callbacks.
424 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_OK
);
425 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStarted(this));
428 void ServiceWorkerVersion::OnStopped() {
429 DCHECK_EQ(STOPPED
, running_status());
430 scoped_refptr
<ServiceWorkerVersion
> protect(this);
432 // Fire all stop callbacks.
433 RunCallbacks(this, &stop_callbacks_
, SERVICE_WORKER_OK
);
435 // Let all start callbacks fail.
437 this, &start_callbacks_
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
439 // Let all message callbacks fail (this will also fire and clear all
440 // callbacks for events).
441 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
442 RunIDMapCallbacks(&activate_callbacks_
,
443 &StatusCallback::Run
,
444 MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
));
445 RunIDMapCallbacks(&install_callbacks_
,
446 &StatusCallback::Run
,
447 MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
));
448 RunIDMapCallbacks(&fetch_callbacks_
,
450 MakeTuple(SERVICE_WORKER_ERROR_FAILED
,
451 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
452 ServiceWorkerResponse()));
453 RunIDMapCallbacks(&sync_callbacks_
,
454 &StatusCallback::Run
,
455 MakeTuple(SERVICE_WORKER_ERROR_FAILED
));
456 RunIDMapCallbacks(&push_callbacks_
,
457 &StatusCallback::Run
,
458 MakeTuple(SERVICE_WORKER_ERROR_FAILED
));
460 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStopped(this));
462 // There should be no more communication from/to a stopped worker. Deleting
463 // the listener prevents any pending completion callbacks from causing
464 // messages to be sent to the stopped worker.
465 cache_listener_
.reset();
468 void ServiceWorkerVersion::OnReportException(
469 const base::string16
& error_message
,
472 const GURL
& source_url
) {
477 this, error_message
, line_number
, column_number
, source_url
));
480 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier
,
482 const base::string16
& message
,
484 const GURL
& source_url
) {
485 FOR_EACH_OBSERVER(Listener
,
487 OnReportConsoleMessage(this,
495 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message
& message
) {
497 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion
, message
)
498 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments
,
499 OnGetClientDocuments
)
500 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished
,
501 OnActivateEventFinished
)
502 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished
,
503 OnInstallEventFinished
)
504 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished
,
505 OnFetchEventFinished
)
506 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished
,
508 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished
,
510 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument
,
511 OnPostMessageToDocument
)
512 IPC_MESSAGE_UNHANDLED(handled
= false)
513 IPC_END_MESSAGE_MAP()
517 void ServiceWorkerVersion::OnStartMessageSent(
518 ServiceWorkerStatusCode status
) {
519 if (status
!= SERVICE_WORKER_OK
)
520 RunCallbacks(this, &start_callbacks_
, status
);
523 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
524 int active_version_id
,
525 const StatusCallback
& callback
) {
526 DCHECK_EQ(RUNNING
, running_status())
527 << "Worker stopped too soon after it was started.";
529 int request_id
= install_callbacks_
.Add(new StatusCallback(callback
));
530 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
531 ServiceWorkerMsg_InstallEvent(request_id
, active_version_id
));
532 if (status
!= SERVICE_WORKER_OK
) {
533 install_callbacks_
.Remove(request_id
);
534 RunSoon(base::Bind(callback
, status
));
538 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
539 const StatusCallback
& callback
) {
540 DCHECK_EQ(RUNNING
, running_status())
541 << "Worker stopped too soon after it was started.";
543 int request_id
= activate_callbacks_
.Add(new StatusCallback(callback
));
544 ServiceWorkerStatusCode status
=
545 embedded_worker_
->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id
));
546 if (status
!= SERVICE_WORKER_OK
) {
547 activate_callbacks_
.Remove(request_id
);
548 RunSoon(base::Bind(callback
, status
));
552 void ServiceWorkerVersion::OnGetClientDocuments(int request_id
) {
553 std::vector
<int> client_ids
;
554 ControlleeByIDMap::iterator
it(&controllee_by_id_
);
555 TRACE_EVENT0("ServiceWorker",
556 "ServiceWorkerVersion::OnGetClientDocuments");
557 while (!it
.IsAtEnd()) {
558 client_ids
.push_back(it
.GetCurrentKey());
561 // Don't bother if it's no longer running.
562 if (running_status() == RUNNING
) {
563 embedded_worker_
->SendMessage(
564 ServiceWorkerMsg_DidGetClientDocuments(request_id
, client_ids
));
568 void ServiceWorkerVersion::OnActivateEventFinished(
570 blink::WebServiceWorkerEventResult result
) {
571 DCHECK(ACTIVATING
== status() ||
572 REDUNDANT
== status()) << status();
573 TRACE_EVENT0("ServiceWorker",
574 "ServiceWorkerVersion::OnActivateEventFinished");
576 StatusCallback
* callback
= activate_callbacks_
.Lookup(request_id
);
578 NOTREACHED() << "Got unexpected message: " << request_id
;
581 ServiceWorkerStatusCode rv
= SERVICE_WORKER_OK
;
582 if (result
== blink::WebServiceWorkerEventResultRejected
||
583 status() != ACTIVATING
) {
584 rv
= SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
;
587 scoped_refptr
<ServiceWorkerVersion
> protect(this);
589 activate_callbacks_
.Remove(request_id
);
592 void ServiceWorkerVersion::OnInstallEventFinished(
594 blink::WebServiceWorkerEventResult result
) {
595 DCHECK_EQ(INSTALLING
, status()) << status();
596 TRACE_EVENT0("ServiceWorker",
597 "ServiceWorkerVersion::OnInstallEventFinished");
599 StatusCallback
* callback
= install_callbacks_
.Lookup(request_id
);
601 NOTREACHED() << "Got unexpected message: " << request_id
;
604 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
605 if (result
== blink::WebServiceWorkerEventResultRejected
)
606 status
= SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
;
608 scoped_refptr
<ServiceWorkerVersion
> protect(this);
609 callback
->Run(status
);
610 install_callbacks_
.Remove(request_id
);
613 void ServiceWorkerVersion::OnFetchEventFinished(
615 ServiceWorkerFetchEventResult result
,
616 const ServiceWorkerResponse
& response
) {
617 TRACE_EVENT1("ServiceWorker",
618 "ServiceWorkerVersion::OnFetchEventFinished",
619 "Request id", request_id
);
620 FetchCallback
* callback
= fetch_callbacks_
.Lookup(request_id
);
622 NOTREACHED() << "Got unexpected message: " << request_id
;
626 scoped_refptr
<ServiceWorkerVersion
> protect(this);
627 callback
->Run(SERVICE_WORKER_OK
, result
, response
);
628 fetch_callbacks_
.Remove(request_id
);
631 void ServiceWorkerVersion::OnSyncEventFinished(
633 TRACE_EVENT1("ServiceWorker",
634 "ServiceWorkerVersion::OnSyncEventFinished",
635 "Request id", request_id
);
636 StatusCallback
* callback
= sync_callbacks_
.Lookup(request_id
);
638 NOTREACHED() << "Got unexpected message: " << request_id
;
642 scoped_refptr
<ServiceWorkerVersion
> protect(this);
643 callback
->Run(SERVICE_WORKER_OK
);
644 sync_callbacks_
.Remove(request_id
);
647 void ServiceWorkerVersion::OnPushEventFinished(
649 TRACE_EVENT1("ServiceWorker",
650 "ServiceWorkerVersion::OnPushEventFinished",
651 "Request id", request_id
);
652 StatusCallback
* callback
= push_callbacks_
.Lookup(request_id
);
654 NOTREACHED() << "Got unexpected message: " << request_id
;
658 scoped_refptr
<ServiceWorkerVersion
> protect(this);
659 callback
->Run(SERVICE_WORKER_OK
);
660 push_callbacks_
.Remove(request_id
);
663 void ServiceWorkerVersion::OnPostMessageToDocument(
665 const base::string16
& message
,
666 const std::vector
<int>& sent_message_port_ids
) {
667 TRACE_EVENT1("ServiceWorker",
668 "ServiceWorkerVersion::OnPostMessageToDocument",
669 "Client id", client_id
);
670 ServiceWorkerProviderHost
* provider_host
=
671 controllee_by_id_
.Lookup(client_id
);
672 if (!provider_host
) {
673 // The client may already have been closed, just ignore.
676 provider_host
->PostMessage(message
, sent_message_port_ids
);
679 void ServiceWorkerVersion::ScheduleStopWorker() {
680 if (running_status() != RUNNING
)
682 if (stop_worker_timer_
.IsRunning()) {
683 stop_worker_timer_
.Reset();
686 stop_worker_timer_
.Start(
687 FROM_HERE
, base::TimeDelta::FromSeconds(kStopWorkerDelay
),
688 base::Bind(&ServiceWorkerVersion::StopWorker
,
689 weak_factory_
.GetWeakPtr(),
690 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
)));
693 void ServiceWorkerVersion::DoomInternal() {
694 DCHECK(!HasControllee());
695 SetStatus(REDUNDANT
);
696 StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
699 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
700 script_cache_map_
.GetResources(&resources
);
701 context_
->storage()->PurgeResources(resources
);
704 } // namespace content