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
= 10;
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);
114 cache_listener_
.reset(new ServiceWorkerCacheListener(this, context
));
115 embedded_worker_
->AddListener(cache_listener_
.get());
118 ServiceWorkerVersion::~ServiceWorkerVersion() {
119 embedded_worker_
->RemoveListener(this);
121 context_
->RemoveLiveVersion(version_id_
);
122 // EmbeddedWorker's dtor sends StopWorker if it's still running.
125 void ServiceWorkerVersion::SetStatus(Status status
) {
126 if (status_
== status
)
129 // Schedule to stop worker after registration successfully completed.
130 if (status_
== ACTIVATING
&& status
== ACTIVATED
&& !HasControllee())
131 ScheduleStopWorker();
135 std::vector
<base::Closure
> callbacks
;
136 callbacks
.swap(status_change_callbacks_
);
137 for (std::vector
<base::Closure
>::const_iterator i
= callbacks
.begin();
138 i
!= callbacks
.end(); ++i
) {
142 FOR_EACH_OBSERVER(Listener
, listeners_
, OnVersionStateChanged(this));
145 void ServiceWorkerVersion::RegisterStatusChangeCallback(
146 const base::Closure
& callback
) {
147 status_change_callbacks_
.push_back(callback
);
150 ServiceWorkerVersionInfo
ServiceWorkerVersion::GetInfo() {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
152 return ServiceWorkerVersionInfo(
157 embedded_worker()->process_id(),
158 embedded_worker()->thread_id(),
159 embedded_worker()->worker_devtools_agent_route_id());
162 void ServiceWorkerVersion::StartWorker(const StatusCallback
& callback
) {
163 StartWorkerWithCandidateProcesses(std::vector
<int>(), false, callback
);
166 void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
167 const std::vector
<int>& possible_process_ids
,
168 bool pause_after_download
,
169 const StatusCallback
& callback
) {
170 switch (running_status()) {
172 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
175 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
));
179 start_callbacks_
.push_back(callback
);
180 if (running_status() == STOPPED
) {
181 embedded_worker_
->Start(
185 pause_after_download
,
186 possible_process_ids
,
187 base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError
,
188 weak_factory_
.GetWeakPtr()));
194 void ServiceWorkerVersion::StopWorker(const StatusCallback
& callback
) {
195 if (running_status() == STOPPED
) {
196 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
199 if (stop_callbacks_
.empty()) {
200 ServiceWorkerStatusCode status
= embedded_worker_
->Stop();
201 if (status
!= SERVICE_WORKER_OK
) {
202 RunSoon(base::Bind(callback
, status
));
206 stop_callbacks_
.push_back(callback
);
209 void ServiceWorkerVersion::ScheduleUpdate() {
210 if (update_timer_
.IsRunning()) {
211 update_timer_
.Reset();
215 FROM_HERE
, base::TimeDelta::FromSeconds(kUpdateDelaySeconds
),
216 base::Bind(&ServiceWorkerVersion::StartUpdate
,
217 weak_factory_
.GetWeakPtr()));
220 void ServiceWorkerVersion::DeferScheduledUpdate() {
221 if (update_timer_
.IsRunning())
222 update_timer_
.Reset();
225 void ServiceWorkerVersion::StartUpdate() {
226 update_timer_
.Stop();
229 ServiceWorkerRegistration
* registration
=
230 context_
->GetLiveRegistration(registration_id_
);
231 if (!registration
|| !registration
->GetNewestVersion())
233 context_
->UpdateServiceWorker(registration
);
236 void ServiceWorkerVersion::SendMessage(
237 const IPC::Message
& message
, const StatusCallback
& callback
) {
238 if (running_status() != RUNNING
) {
239 // Schedule calling this method after starting the worker.
240 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
241 weak_factory_
.GetWeakPtr(), callback
,
242 base::Bind(&self::SendMessage
,
243 weak_factory_
.GetWeakPtr(),
244 message
, callback
)));
248 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(message
);
249 RunSoon(base::Bind(callback
, status
));
252 void ServiceWorkerVersion::DispatchInstallEvent(
253 int active_version_id
,
254 const StatusCallback
& callback
) {
255 DCHECK_EQ(INSTALLING
, status()) << status();
257 if (running_status() != RUNNING
) {
258 // Schedule calling this method after starting the worker.
260 base::Bind(&RunTaskAfterStartWorker
,
261 weak_factory_
.GetWeakPtr(),
263 base::Bind(&self::DispatchInstallEventAfterStartWorker
,
264 weak_factory_
.GetWeakPtr(),
268 DispatchInstallEventAfterStartWorker(active_version_id
, callback
);
272 void ServiceWorkerVersion::DispatchActivateEvent(
273 const StatusCallback
& callback
) {
274 DCHECK_EQ(ACTIVATING
, status()) << status();
276 if (running_status() != RUNNING
) {
277 // Schedule calling this method after starting the worker.
279 base::Bind(&RunTaskAfterStartWorker
,
280 weak_factory_
.GetWeakPtr(),
282 base::Bind(&self::DispatchActivateEventAfterStartWorker
,
283 weak_factory_
.GetWeakPtr(),
286 DispatchActivateEventAfterStartWorker(callback
);
290 void ServiceWorkerVersion::DispatchFetchEvent(
291 const ServiceWorkerFetchRequest
& request
,
292 const base::Closure
& prepare_callback
,
293 const FetchCallback
& fetch_callback
) {
294 DCHECK_EQ(ACTIVATED
, status()) << status();
296 if (running_status() != RUNNING
) {
297 // Schedule calling this method after starting the worker.
298 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
299 weak_factory_
.GetWeakPtr(),
300 base::Bind(&RunErrorFetchCallback
, fetch_callback
),
301 base::Bind(&self::DispatchFetchEvent
,
302 weak_factory_
.GetWeakPtr(),
309 prepare_callback
.Run();
311 int request_id
= fetch_callbacks_
.Add(new FetchCallback(fetch_callback
));
312 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
313 ServiceWorkerMsg_FetchEvent(request_id
, request
));
314 if (status
!= SERVICE_WORKER_OK
) {
315 fetch_callbacks_
.Remove(request_id
);
316 RunSoon(base::Bind(&RunErrorFetchCallback
,
318 SERVICE_WORKER_ERROR_FAILED
));
322 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback
& callback
) {
323 DCHECK_EQ(ACTIVATED
, status()) << status();
325 if (!CommandLine::ForCurrentProcess()->HasSwitch(
326 switches::kEnableServiceWorkerSync
)) {
327 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
331 if (running_status() != RUNNING
) {
332 // Schedule calling this method after starting the worker.
333 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
334 weak_factory_
.GetWeakPtr(), callback
,
335 base::Bind(&self::DispatchSyncEvent
,
336 weak_factory_
.GetWeakPtr(),
341 int request_id
= sync_callbacks_
.Add(new StatusCallback(callback
));
342 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
343 ServiceWorkerMsg_SyncEvent(request_id
));
344 if (status
!= SERVICE_WORKER_OK
) {
345 sync_callbacks_
.Remove(request_id
);
346 RunSoon(base::Bind(callback
, status
));
350 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback
& callback
,
351 const std::string
& data
) {
352 DCHECK_EQ(ACTIVATED
, status()) << status();
354 if (!CommandLine::ForCurrentProcess()->HasSwitch(
355 switches::kEnableExperimentalWebPlatformFeatures
)) {
356 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
360 if (running_status() != RUNNING
) {
361 // Schedule calling this method after starting the worker.
362 StartWorker(base::Bind(&RunTaskAfterStartWorker
,
363 weak_factory_
.GetWeakPtr(), callback
,
364 base::Bind(&self::DispatchPushEvent
,
365 weak_factory_
.GetWeakPtr(),
370 int request_id
= push_callbacks_
.Add(new StatusCallback(callback
));
371 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
372 ServiceWorkerMsg_PushEvent(request_id
, data
));
373 if (status
!= SERVICE_WORKER_OK
) {
374 push_callbacks_
.Remove(request_id
);
375 RunSoon(base::Bind(callback
, status
));
379 void ServiceWorkerVersion::AddProcessToWorker(int process_id
) {
380 embedded_worker_
->AddProcessReference(process_id
);
383 void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id
) {
384 embedded_worker_
->ReleaseProcessReference(process_id
);
387 bool ServiceWorkerVersion::HasProcessToRun() const {
388 return embedded_worker_
->HasProcessToRun();
391 void ServiceWorkerVersion::AddControllee(
392 ServiceWorkerProviderHost
* provider_host
) {
393 DCHECK(!ContainsKey(controllee_map_
, provider_host
));
394 int controllee_id
= controllee_by_id_
.Add(provider_host
);
395 controllee_map_
[provider_host
] = controllee_id
;
396 AddProcessToWorker(provider_host
->process_id());
397 if (stop_worker_timer_
.IsRunning())
398 stop_worker_timer_
.Stop();
401 void ServiceWorkerVersion::RemoveControllee(
402 ServiceWorkerProviderHost
* provider_host
) {
403 ControlleeMap::iterator found
= controllee_map_
.find(provider_host
);
404 DCHECK(found
!= controllee_map_
.end());
405 controllee_by_id_
.Remove(found
->second
);
406 controllee_map_
.erase(found
);
407 RemoveProcessFromWorker(provider_host
->process_id());
410 FOR_EACH_OBSERVER(Listener
, listeners_
, OnNoControllees(this));
415 ScheduleStopWorker();
418 void ServiceWorkerVersion::AddPotentialControllee(
419 ServiceWorkerProviderHost
* provider_host
) {
420 AddProcessToWorker(provider_host
->process_id());
423 void ServiceWorkerVersion::RemovePotentialControllee(
424 ServiceWorkerProviderHost
* provider_host
) {
425 RemoveProcessFromWorker(provider_host
->process_id());
428 void ServiceWorkerVersion::AddListener(Listener
* listener
) {
429 listeners_
.AddObserver(listener
);
432 void ServiceWorkerVersion::RemoveListener(Listener
* listener
) {
433 listeners_
.RemoveObserver(listener
);
436 void ServiceWorkerVersion::Doom() {
440 if (!HasControllee())
444 void ServiceWorkerVersion::OnStarted() {
445 DCHECK_EQ(RUNNING
, running_status());
446 if (status() == ACTIVATED
&& !HasControllee())
447 ScheduleStopWorker();
448 // Fire all start callbacks.
449 RunCallbacks(this, &start_callbacks_
, SERVICE_WORKER_OK
);
450 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStarted(this));
453 void ServiceWorkerVersion::OnStopped() {
454 DCHECK_EQ(STOPPED
, running_status());
455 scoped_refptr
<ServiceWorkerVersion
> protect(this);
457 // Fire all stop callbacks.
458 RunCallbacks(this, &stop_callbacks_
, SERVICE_WORKER_OK
);
460 // Let all start callbacks fail.
462 this, &start_callbacks_
, SERVICE_WORKER_ERROR_START_WORKER_FAILED
);
464 // Let all message callbacks fail (this will also fire and clear all
465 // callbacks for events).
466 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
467 RunIDMapCallbacks(&activate_callbacks_
,
468 &StatusCallback::Run
,
469 MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
));
470 RunIDMapCallbacks(&install_callbacks_
,
471 &StatusCallback::Run
,
472 MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
));
473 RunIDMapCallbacks(&fetch_callbacks_
,
475 MakeTuple(SERVICE_WORKER_ERROR_FAILED
,
476 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK
,
477 ServiceWorkerResponse()));
478 RunIDMapCallbacks(&sync_callbacks_
,
479 &StatusCallback::Run
,
480 MakeTuple(SERVICE_WORKER_ERROR_FAILED
));
481 RunIDMapCallbacks(&push_callbacks_
,
482 &StatusCallback::Run
,
483 MakeTuple(SERVICE_WORKER_ERROR_FAILED
));
485 FOR_EACH_OBSERVER(Listener
, listeners_
, OnWorkerStopped(this));
488 void ServiceWorkerVersion::OnReportException(
489 const base::string16
& error_message
,
492 const GURL
& source_url
) {
497 this, error_message
, line_number
, column_number
, source_url
));
500 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier
,
502 const base::string16
& message
,
504 const GURL
& source_url
) {
505 FOR_EACH_OBSERVER(Listener
,
507 OnReportConsoleMessage(this,
515 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message
& message
) {
517 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion
, message
)
518 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments
,
519 OnGetClientDocuments
)
520 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished
,
521 OnActivateEventFinished
)
522 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished
,
523 OnInstallEventFinished
)
524 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished
,
525 OnFetchEventFinished
)
526 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished
,
528 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished
,
530 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument
,
531 OnPostMessageToDocument
)
532 IPC_MESSAGE_UNHANDLED(handled
= false)
533 IPC_END_MESSAGE_MAP()
537 void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
538 ServiceWorkerStatusCode status
) {
539 if (status
!= SERVICE_WORKER_OK
)
540 RunCallbacks(this, &start_callbacks_
, status
);
543 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
544 int active_version_id
,
545 const StatusCallback
& callback
) {
546 DCHECK_EQ(RUNNING
, running_status())
547 << "Worker stopped too soon after it was started.";
549 int request_id
= install_callbacks_
.Add(new StatusCallback(callback
));
550 ServiceWorkerStatusCode status
= embedded_worker_
->SendMessage(
551 ServiceWorkerMsg_InstallEvent(request_id
, active_version_id
));
552 if (status
!= SERVICE_WORKER_OK
) {
553 install_callbacks_
.Remove(request_id
);
554 RunSoon(base::Bind(callback
, status
));
558 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
559 const StatusCallback
& callback
) {
560 DCHECK_EQ(RUNNING
, running_status())
561 << "Worker stopped too soon after it was started.";
563 int request_id
= activate_callbacks_
.Add(new StatusCallback(callback
));
564 ServiceWorkerStatusCode status
=
565 embedded_worker_
->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id
));
566 if (status
!= SERVICE_WORKER_OK
) {
567 activate_callbacks_
.Remove(request_id
);
568 RunSoon(base::Bind(callback
, status
));
572 void ServiceWorkerVersion::OnGetClientDocuments(int request_id
) {
573 std::vector
<int> client_ids
;
574 ControlleeByIDMap::iterator
it(&controllee_by_id_
);
575 while (!it
.IsAtEnd()) {
576 client_ids
.push_back(it
.GetCurrentKey());
579 // Don't bother if it's no longer running.
580 if (running_status() == RUNNING
) {
581 embedded_worker_
->SendMessage(
582 ServiceWorkerMsg_DidGetClientDocuments(request_id
, client_ids
));
586 void ServiceWorkerVersion::OnActivateEventFinished(
588 blink::WebServiceWorkerEventResult result
) {
589 DCHECK(ACTIVATING
== status() ||
590 REDUNDANT
== status()) << status();
592 StatusCallback
* callback
= activate_callbacks_
.Lookup(request_id
);
594 NOTREACHED() << "Got unexpected message: " << request_id
;
597 ServiceWorkerStatusCode rv
= SERVICE_WORKER_OK
;
598 if (result
== blink::WebServiceWorkerEventResultRejected
||
599 status() != ACTIVATING
) {
600 rv
= SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED
;
603 scoped_refptr
<ServiceWorkerVersion
> protect(this);
605 activate_callbacks_
.Remove(request_id
);
608 void ServiceWorkerVersion::OnInstallEventFinished(
610 blink::WebServiceWorkerEventResult result
) {
611 DCHECK_EQ(INSTALLING
, status()) << status();
613 StatusCallback
* callback
= install_callbacks_
.Lookup(request_id
);
615 NOTREACHED() << "Got unexpected message: " << request_id
;
618 ServiceWorkerStatusCode status
= SERVICE_WORKER_OK
;
619 if (result
== blink::WebServiceWorkerEventResultRejected
)
620 status
= SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED
;
622 scoped_refptr
<ServiceWorkerVersion
> protect(this);
623 callback
->Run(status
);
624 install_callbacks_
.Remove(request_id
);
627 void ServiceWorkerVersion::OnFetchEventFinished(
629 ServiceWorkerFetchEventResult result
,
630 const ServiceWorkerResponse
& response
) {
631 FetchCallback
* callback
= fetch_callbacks_
.Lookup(request_id
);
633 NOTREACHED() << "Got unexpected message: " << request_id
;
637 scoped_refptr
<ServiceWorkerVersion
> protect(this);
638 callback
->Run(SERVICE_WORKER_OK
, result
, response
);
639 fetch_callbacks_
.Remove(request_id
);
642 void ServiceWorkerVersion::OnSyncEventFinished(
644 StatusCallback
* callback
= sync_callbacks_
.Lookup(request_id
);
646 NOTREACHED() << "Got unexpected message: " << request_id
;
650 scoped_refptr
<ServiceWorkerVersion
> protect(this);
651 callback
->Run(SERVICE_WORKER_OK
);
652 sync_callbacks_
.Remove(request_id
);
655 void ServiceWorkerVersion::OnPushEventFinished(
657 StatusCallback
* callback
= push_callbacks_
.Lookup(request_id
);
659 NOTREACHED() << "Got unexpected message: " << request_id
;
663 scoped_refptr
<ServiceWorkerVersion
> protect(this);
664 callback
->Run(SERVICE_WORKER_OK
);
665 push_callbacks_
.Remove(request_id
);
668 void ServiceWorkerVersion::OnPostMessageToDocument(
670 const base::string16
& message
,
671 const std::vector
<int>& sent_message_port_ids
) {
672 ServiceWorkerProviderHost
* provider_host
=
673 controllee_by_id_
.Lookup(client_id
);
674 if (!provider_host
) {
675 // The client may already have been closed, just ignore.
678 provider_host
->PostMessage(message
, sent_message_port_ids
);
681 void ServiceWorkerVersion::ScheduleStopWorker() {
682 if (running_status() != RUNNING
)
684 if (stop_worker_timer_
.IsRunning()) {
685 stop_worker_timer_
.Reset();
688 stop_worker_timer_
.Start(
689 FROM_HERE
, base::TimeDelta::FromSeconds(kStopWorkerDelay
),
690 base::Bind(&ServiceWorkerVersion::StopWorker
,
691 weak_factory_
.GetWeakPtr(),
692 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
)));
695 void ServiceWorkerVersion::DoomInternal() {
696 DCHECK(!HasControllee());
697 SetStatus(REDUNDANT
);
698 StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
701 std::vector
<ServiceWorkerDatabase::ResourceRecord
> resources
;
702 script_cache_map_
.GetResources(&resources
);
703 context_
->storage()->PurgeResources(resources
);
706 } // namespace content