The serviceworker update algo has to wait until documents close prior to performing...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blob2820ec85f841238cb77424f4bae4553db20a7765
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"
19 namespace content {
21 typedef ServiceWorkerVersion::StatusCallback StatusCallback;
22 typedef ServiceWorkerVersion::MessageCallback MessageCallback;
24 namespace {
26 // Default delay to stop the worker context after all documents that
27 // are associated to the worker are closed.
28 // (Note that if all references to the version is dropped the worker
29 // is also stopped without delay)
30 const int64 kStopWorkerDelay = 30; // 30 secs.
32 // Default delay for scheduled update.
33 const int kUpdateDelaySeconds = 10;
35 void RunSoon(const base::Closure& callback) {
36 if (!callback.is_null())
37 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
40 template <typename CallbackArray, typename Arg>
41 void RunCallbacks(ServiceWorkerVersion* version,
42 CallbackArray* callbacks_ptr,
43 const Arg& arg) {
44 CallbackArray callbacks;
45 callbacks.swap(*callbacks_ptr);
46 scoped_refptr<ServiceWorkerVersion> protect(version);
47 for (typename CallbackArray::const_iterator i = callbacks.begin();
48 i != callbacks.end(); ++i)
49 (*i).Run(arg);
52 template <typename IDMAP, typename Method, typename Params>
53 void RunIDMapCallbacks(IDMAP* callbacks, Method method, const Params& params) {
54 typename IDMAP::iterator iter(callbacks);
55 while (!iter.IsAtEnd()) {
56 DispatchToMethod(iter.GetCurrentValue(), method, params);
57 iter.Advance();
59 callbacks->Clear();
62 // A callback adapter to start a |task| after StartWorker.
63 void RunTaskAfterStartWorker(
64 base::WeakPtr<ServiceWorkerVersion> version,
65 const StatusCallback& error_callback,
66 const base::Closure& task,
67 ServiceWorkerStatusCode status) {
68 if (status != SERVICE_WORKER_OK) {
69 if (!error_callback.is_null())
70 error_callback.Run(status);
71 return;
73 if (version->running_status() != ServiceWorkerVersion::RUNNING) {
74 // We've tried to start the worker (and it has succeeded), but
75 // it looks it's not running yet.
76 NOTREACHED() << "The worker's not running after successful StartWorker";
77 if (!error_callback.is_null())
78 error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
79 return;
81 task.Run();
84 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
85 ServiceWorkerStatusCode status) {
86 callback.Run(status,
87 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
88 ServiceWorkerResponse());
91 } // namespace
93 ServiceWorkerVersion::ServiceWorkerVersion(
94 ServiceWorkerRegistration* registration,
95 int64 version_id,
96 base::WeakPtr<ServiceWorkerContextCore> context)
97 : version_id_(version_id),
98 registration_id_(kInvalidServiceWorkerVersionId),
99 status_(NEW),
100 context_(context),
101 script_cache_map_(this, context),
102 is_doomed_(false),
103 weak_factory_(this) {
104 DCHECK(context_);
105 DCHECK(registration);
106 if (registration) {
107 registration_id_ = registration->id();
108 script_url_ = registration->script_url();
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);
118 if (context_)
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)
125 return;
127 status_ = status;
129 std::vector<base::Closure> callbacks;
130 callbacks.swap(status_change_callbacks_);
131 for (std::vector<base::Closure>::const_iterator i = callbacks.begin();
132 i != callbacks.end(); ++i) {
133 (*i).Run();
136 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
139 void ServiceWorkerVersion::RegisterStatusChangeCallback(
140 const base::Closure& callback) {
141 status_change_callbacks_.push_back(callback);
144 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
146 return ServiceWorkerVersionInfo(
147 running_status(),
148 status(),
149 version_id(),
150 embedded_worker()->process_id(),
151 embedded_worker()->thread_id(),
152 embedded_worker()->worker_devtools_agent_route_id());
155 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
156 StartWorkerWithCandidateProcesses(std::vector<int>(), false, callback);
159 void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
160 const std::vector<int>& possible_process_ids,
161 bool pause_after_download,
162 const StatusCallback& callback) {
163 switch (running_status()) {
164 case RUNNING:
165 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
166 return;
167 case STOPPING:
168 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
169 return;
170 case STOPPED:
171 case STARTING:
172 start_callbacks_.push_back(callback);
173 if (running_status() == STOPPED) {
174 embedded_worker_->Start(
175 version_id_,
176 scope_,
177 script_url_,
178 pause_after_download,
179 possible_process_ids,
180 base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError,
181 weak_factory_.GetWeakPtr()));
183 return;
187 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
188 if (running_status() == STOPPED) {
189 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
190 return;
192 if (stop_callbacks_.empty()) {
193 ServiceWorkerStatusCode status = embedded_worker_->Stop();
194 if (status != SERVICE_WORKER_OK) {
195 RunSoon(base::Bind(callback, status));
196 return;
199 stop_callbacks_.push_back(callback);
202 void ServiceWorkerVersion::ScheduleUpdate() {
203 if (update_timer_.IsRunning()) {
204 update_timer_.Reset();
205 return;
207 update_timer_.Start(
208 FROM_HERE, base::TimeDelta::FromSeconds(kUpdateDelaySeconds),
209 base::Bind(&ServiceWorkerVersion::StartUpdate,
210 weak_factory_.GetWeakPtr()));
213 void ServiceWorkerVersion::DeferScheduledUpdate() {
214 if (update_timer_.IsRunning())
215 update_timer_.Reset();
218 void ServiceWorkerVersion::StartUpdate() {
219 update_timer_.Stop();
220 if (!context_)
221 return;
222 ServiceWorkerRegistration* registration =
223 context_->GetLiveRegistration(registration_id_);
224 if (!registration)
225 return;
226 context_->UpdateServiceWorker(registration);
229 void ServiceWorkerVersion::SendMessage(
230 const IPC::Message& message, const StatusCallback& callback) {
231 if (running_status() != RUNNING) {
232 // Schedule calling this method after starting the worker.
233 StartWorker(base::Bind(&RunTaskAfterStartWorker,
234 weak_factory_.GetWeakPtr(), callback,
235 base::Bind(&self::SendMessage,
236 weak_factory_.GetWeakPtr(),
237 message, callback)));
238 return;
241 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message);
242 RunSoon(base::Bind(callback, status));
245 void ServiceWorkerVersion::DispatchInstallEvent(
246 int active_version_id,
247 const StatusCallback& callback) {
248 DCHECK_EQ(INSTALLING, status()) << status();
250 if (running_status() != RUNNING) {
251 // Schedule calling this method after starting the worker.
252 StartWorker(
253 base::Bind(&RunTaskAfterStartWorker,
254 weak_factory_.GetWeakPtr(),
255 callback,
256 base::Bind(&self::DispatchInstallEventAfterStartWorker,
257 weak_factory_.GetWeakPtr(),
258 active_version_id,
259 callback)));
260 } else {
261 DispatchInstallEventAfterStartWorker(active_version_id, callback);
265 void ServiceWorkerVersion::DispatchActivateEvent(
266 const StatusCallback& callback) {
267 DCHECK_EQ(ACTIVATING, status()) << status();
269 if (running_status() != RUNNING) {
270 // Schedule calling this method after starting the worker.
271 StartWorker(
272 base::Bind(&RunTaskAfterStartWorker,
273 weak_factory_.GetWeakPtr(),
274 callback,
275 base::Bind(&self::DispatchActivateEventAfterStartWorker,
276 weak_factory_.GetWeakPtr(),
277 callback)));
278 } else {
279 DispatchActivateEventAfterStartWorker(callback);
283 void ServiceWorkerVersion::DispatchFetchEvent(
284 const ServiceWorkerFetchRequest& request,
285 const FetchCallback& callback) {
286 DCHECK_EQ(ACTIVATED, status()) << status();
288 if (running_status() != RUNNING) {
289 // Schedule calling this method after starting the worker.
290 StartWorker(base::Bind(&RunTaskAfterStartWorker,
291 weak_factory_.GetWeakPtr(),
292 base::Bind(&RunErrorFetchCallback, callback),
293 base::Bind(&self::DispatchFetchEvent,
294 weak_factory_.GetWeakPtr(),
295 request, callback)));
296 return;
299 int request_id = fetch_callbacks_.Add(new FetchCallback(callback));
300 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
301 ServiceWorkerMsg_FetchEvent(request_id, request));
302 if (status != SERVICE_WORKER_OK) {
303 fetch_callbacks_.Remove(request_id);
304 RunSoon(base::Bind(&RunErrorFetchCallback,
305 callback,
306 SERVICE_WORKER_ERROR_FAILED));
310 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
311 DCHECK_EQ(ACTIVATED, status()) << status();
313 if (!CommandLine::ForCurrentProcess()->HasSwitch(
314 switches::kEnableServiceWorkerSync)) {
315 callback.Run(SERVICE_WORKER_ERROR_ABORT);
316 return;
319 if (running_status() != RUNNING) {
320 // Schedule calling this method after starting the worker.
321 StartWorker(base::Bind(&RunTaskAfterStartWorker,
322 weak_factory_.GetWeakPtr(), callback,
323 base::Bind(&self::DispatchSyncEvent,
324 weak_factory_.GetWeakPtr(),
325 callback)));
326 return;
329 int request_id = sync_callbacks_.Add(new StatusCallback(callback));
330 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
331 ServiceWorkerMsg_SyncEvent(request_id));
332 if (status != SERVICE_WORKER_OK) {
333 sync_callbacks_.Remove(request_id);
334 RunSoon(base::Bind(callback, status));
338 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
339 const std::string& data) {
340 DCHECK_EQ(ACTIVATED, status()) << status();
342 if (!CommandLine::ForCurrentProcess()->HasSwitch(
343 switches::kEnableExperimentalWebPlatformFeatures)) {
344 callback.Run(SERVICE_WORKER_ERROR_ABORT);
345 return;
348 if (running_status() != RUNNING) {
349 // Schedule calling this method after starting the worker.
350 StartWorker(base::Bind(&RunTaskAfterStartWorker,
351 weak_factory_.GetWeakPtr(), callback,
352 base::Bind(&self::DispatchPushEvent,
353 weak_factory_.GetWeakPtr(),
354 callback, data)));
355 return;
358 int request_id = push_callbacks_.Add(new StatusCallback(callback));
359 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
360 ServiceWorkerMsg_PushEvent(request_id, data));
361 if (status != SERVICE_WORKER_OK) {
362 push_callbacks_.Remove(request_id);
363 RunSoon(base::Bind(callback, status));
367 void ServiceWorkerVersion::AddProcessToWorker(int process_id) {
368 embedded_worker_->AddProcessReference(process_id);
371 void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) {
372 embedded_worker_->ReleaseProcessReference(process_id);
375 bool ServiceWorkerVersion::HasProcessToRun() const {
376 return embedded_worker_->HasProcessToRun();
379 void ServiceWorkerVersion::AddControllee(
380 ServiceWorkerProviderHost* provider_host) {
381 DCHECK(!ContainsKey(controllee_map_, provider_host));
382 int controllee_id = controllee_by_id_.Add(provider_host);
383 controllee_map_[provider_host] = controllee_id;
384 AddProcessToWorker(provider_host->process_id());
385 if (stop_worker_timer_.IsRunning())
386 stop_worker_timer_.Stop();
389 void ServiceWorkerVersion::RemoveControllee(
390 ServiceWorkerProviderHost* provider_host) {
391 ControlleeMap::iterator found = controllee_map_.find(provider_host);
392 DCHECK(found != controllee_map_.end());
393 controllee_by_id_.Remove(found->second);
394 controllee_map_.erase(found);
395 RemoveProcessFromWorker(provider_host->process_id());
396 if (HasControllee())
397 return;
398 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
399 if (is_doomed_) {
400 DoomInternal();
401 return;
403 ScheduleStopWorker();
406 void ServiceWorkerVersion::AddPotentialControllee(
407 ServiceWorkerProviderHost* provider_host) {
408 AddProcessToWorker(provider_host->process_id());
411 void ServiceWorkerVersion::RemovePotentialControllee(
412 ServiceWorkerProviderHost* provider_host) {
413 RemoveProcessFromWorker(provider_host->process_id());
416 void ServiceWorkerVersion::AddListener(Listener* listener) {
417 listeners_.AddObserver(listener);
420 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
421 listeners_.RemoveObserver(listener);
424 void ServiceWorkerVersion::Doom() {
425 if (is_doomed_)
426 return;
427 is_doomed_ = true;
428 if (!HasControllee())
429 DoomInternal();
432 void ServiceWorkerVersion::OnStarted() {
433 DCHECK_EQ(RUNNING, running_status());
434 // Fire all start callbacks.
435 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
436 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
439 void ServiceWorkerVersion::OnStopped() {
440 DCHECK_EQ(STOPPED, running_status());
441 scoped_refptr<ServiceWorkerVersion> protect(this);
443 // Fire all stop callbacks.
444 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
446 // Let all start callbacks fail.
447 RunCallbacks(
448 this, &start_callbacks_, SERVICE_WORKER_ERROR_START_WORKER_FAILED);
450 // Let all message callbacks fail (this will also fire and clear all
451 // callbacks for events).
452 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
453 RunIDMapCallbacks(&activate_callbacks_,
454 &StatusCallback::Run,
455 MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED));
456 RunIDMapCallbacks(&install_callbacks_,
457 &StatusCallback::Run,
458 MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED));
459 RunIDMapCallbacks(&fetch_callbacks_,
460 &FetchCallback::Run,
461 MakeTuple(SERVICE_WORKER_ERROR_FAILED,
462 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
463 ServiceWorkerResponse()));
464 RunIDMapCallbacks(&sync_callbacks_,
465 &StatusCallback::Run,
466 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
467 RunIDMapCallbacks(&push_callbacks_,
468 &StatusCallback::Run,
469 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
471 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
474 void ServiceWorkerVersion::OnReportException(
475 const base::string16& error_message,
476 int line_number,
477 int column_number,
478 const GURL& source_url) {
479 FOR_EACH_OBSERVER(
480 Listener,
481 listeners_,
482 OnErrorReported(
483 this, error_message, line_number, column_number, source_url));
486 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
487 int message_level,
488 const base::string16& message,
489 int line_number,
490 const GURL& source_url) {
491 FOR_EACH_OBSERVER(Listener,
492 listeners_,
493 OnReportConsoleMessage(this,
494 source_identifier,
495 message_level,
496 message,
497 line_number,
498 source_url));
501 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
502 bool handled = true;
503 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
504 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
505 OnGetClientDocuments)
506 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
507 OnActivateEventFinished)
508 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
509 OnInstallEventFinished)
510 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
511 OnFetchEventFinished)
512 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
513 OnSyncEventFinished)
514 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
515 OnPushEventFinished)
516 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
517 OnPostMessageToDocument)
518 IPC_MESSAGE_UNHANDLED(handled = false)
519 IPC_END_MESSAGE_MAP()
520 return handled;
523 void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
524 ServiceWorkerStatusCode status) {
525 if (status != SERVICE_WORKER_OK)
526 RunCallbacks(this, &start_callbacks_, status);
529 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
530 int active_version_id,
531 const StatusCallback& callback) {
532 DCHECK_EQ(RUNNING, running_status())
533 << "Worker stopped too soon after it was started.";
535 int request_id = install_callbacks_.Add(new StatusCallback(callback));
536 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
537 ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
538 if (status != SERVICE_WORKER_OK) {
539 install_callbacks_.Remove(request_id);
540 RunSoon(base::Bind(callback, status));
544 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
545 const StatusCallback& callback) {
546 DCHECK_EQ(RUNNING, running_status())
547 << "Worker stopped too soon after it was started.";
549 int request_id = activate_callbacks_.Add(new StatusCallback(callback));
550 ServiceWorkerStatusCode status =
551 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
552 if (status != SERVICE_WORKER_OK) {
553 activate_callbacks_.Remove(request_id);
554 RunSoon(base::Bind(callback, status));
558 void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
559 std::vector<int> client_ids;
560 ControlleeByIDMap::iterator it(&controllee_by_id_);
561 while (!it.IsAtEnd()) {
562 client_ids.push_back(it.GetCurrentKey());
563 it.Advance();
565 // Don't bother if it's no longer running.
566 if (running_status() == RUNNING) {
567 embedded_worker_->SendMessage(
568 ServiceWorkerMsg_DidGetClientDocuments(request_id, client_ids));
572 void ServiceWorkerVersion::OnActivateEventFinished(
573 int request_id,
574 blink::WebServiceWorkerEventResult result) {
575 DCHECK(ACTIVATING == status() ||
576 REDUNDANT == status()) << status();
578 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
579 if (!callback) {
580 NOTREACHED() << "Got unexpected message: " << request_id;
581 return;
583 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
584 if (result == blink::WebServiceWorkerEventResultRejected ||
585 status() != ACTIVATING) {
586 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
589 scoped_refptr<ServiceWorkerVersion> protect(this);
590 callback->Run(rv);
591 activate_callbacks_.Remove(request_id);
594 void ServiceWorkerVersion::OnInstallEventFinished(
595 int request_id,
596 blink::WebServiceWorkerEventResult result) {
597 DCHECK_EQ(INSTALLING, status()) << status();
599 StatusCallback* callback = install_callbacks_.Lookup(request_id);
600 if (!callback) {
601 NOTREACHED() << "Got unexpected message: " << request_id;
602 return;
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(
614 int request_id,
615 ServiceWorkerFetchEventResult result,
616 const ServiceWorkerResponse& response) {
617 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
618 if (!callback) {
619 NOTREACHED() << "Got unexpected message: " << request_id;
620 return;
623 scoped_refptr<ServiceWorkerVersion> protect(this);
624 callback->Run(SERVICE_WORKER_OK, result, response);
625 fetch_callbacks_.Remove(request_id);
628 void ServiceWorkerVersion::OnSyncEventFinished(
629 int request_id) {
630 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
631 if (!callback) {
632 NOTREACHED() << "Got unexpected message: " << request_id;
633 return;
636 scoped_refptr<ServiceWorkerVersion> protect(this);
637 callback->Run(SERVICE_WORKER_OK);
638 sync_callbacks_.Remove(request_id);
641 void ServiceWorkerVersion::OnPushEventFinished(
642 int request_id) {
643 StatusCallback* callback = push_callbacks_.Lookup(request_id);
644 if (!callback) {
645 NOTREACHED() << "Got unexpected message: " << request_id;
646 return;
649 scoped_refptr<ServiceWorkerVersion> protect(this);
650 callback->Run(SERVICE_WORKER_OK);
651 push_callbacks_.Remove(request_id);
654 void ServiceWorkerVersion::OnPostMessageToDocument(
655 int client_id,
656 const base::string16& message,
657 const std::vector<int>& sent_message_port_ids) {
658 ServiceWorkerProviderHost* provider_host =
659 controllee_by_id_.Lookup(client_id);
660 if (!provider_host) {
661 // The client may already have been closed, just ignore.
662 return;
664 provider_host->PostMessage(message, sent_message_port_ids);
667 void ServiceWorkerVersion::ScheduleStopWorker() {
668 if (running_status() != RUNNING)
669 return;
670 if (stop_worker_timer_.IsRunning()) {
671 stop_worker_timer_.Reset();
672 return;
674 stop_worker_timer_.Start(
675 FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay),
676 base::Bind(&ServiceWorkerVersion::StopWorker,
677 weak_factory_.GetWeakPtr(),
678 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
681 void ServiceWorkerVersion::DoomInternal() {
682 DCHECK(!HasControllee());
683 SetStatus(REDUNDANT);
684 StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
685 if (!context_)
686 return;
687 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
688 script_cache_map_.GetResources(&resources);
689 context_->storage()->PurgeResources(resources);
692 } // namespace content