Service Worker: in Unregister, wait until after the active worker no longer controls...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blobf73ecfb65a373bbc61f3c1be7dbda83dd923a984
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 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,
42 const Arg& arg) {
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)
48 (*i).Run(arg);
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);
56 iter.Advance();
58 callbacks->Clear();
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);
70 return;
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);
78 return;
80 task.Run();
83 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
84 ServiceWorkerStatusCode status) {
85 callback.Run(status,
86 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
87 ServiceWorkerResponse());
90 } // namespace
92 ServiceWorkerVersion::ServiceWorkerVersion(
93 ServiceWorkerRegistration* registration,
94 int64 version_id,
95 base::WeakPtr<ServiceWorkerContextCore> context)
96 : version_id_(version_id),
97 registration_id_(kInvalidServiceWorkerVersionId),
98 status_(NEW),
99 context_(context),
100 script_cache_map_(this, context),
101 is_doomed_(false),
102 weak_factory_(this) {
103 DCHECK(context_);
104 DCHECK(registration);
105 if (registration) {
106 registration_id_ = registration->id();
107 script_url_ = registration->script_url();
108 scope_ = registration->pattern();
110 context_->AddLiveVersion(this);
111 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
112 embedded_worker_->AddListener(this);
113 stores_listener_.reset(new ServiceWorkerStoresListener(this));
114 embedded_worker_->AddListener(stores_listener_.get());
117 ServiceWorkerVersion::~ServiceWorkerVersion() {
118 embedded_worker_->RemoveListener(this);
119 if (context_)
120 context_->RemoveLiveVersion(version_id_);
121 // EmbeddedWorker's dtor sends StopWorker if it's still running.
124 void ServiceWorkerVersion::SetStatus(Status status) {
125 if (status_ == status)
126 return;
128 // Schedule to stop worker after registration successfully completed.
129 if (status_ == ACTIVATING && status == ACTIVATED && !HasControllee())
130 ScheduleStopWorker();
132 status_ = status;
134 std::vector<base::Closure> callbacks;
135 callbacks.swap(status_change_callbacks_);
136 for (std::vector<base::Closure>::const_iterator i = callbacks.begin();
137 i != callbacks.end(); ++i) {
138 (*i).Run();
141 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
144 void ServiceWorkerVersion::RegisterStatusChangeCallback(
145 const base::Closure& callback) {
146 status_change_callbacks_.push_back(callback);
149 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
151 return ServiceWorkerVersionInfo(
152 running_status(),
153 status(),
154 version_id(),
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 StartWorkerWithCandidateProcesses(std::vector<int>(), false, callback);
164 void ServiceWorkerVersion::StartWorkerWithCandidateProcesses(
165 const std::vector<int>& possible_process_ids,
166 bool pause_after_download,
167 const StatusCallback& callback) {
168 switch (running_status()) {
169 case RUNNING:
170 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
171 return;
172 case STOPPING:
173 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
174 return;
175 case STOPPED:
176 case STARTING:
177 start_callbacks_.push_back(callback);
178 if (running_status() == STOPPED) {
179 embedded_worker_->Start(
180 version_id_,
181 scope_,
182 script_url_,
183 pause_after_download,
184 possible_process_ids,
185 base::Bind(&ServiceWorkerVersion::RunStartWorkerCallbacksOnError,
186 weak_factory_.GetWeakPtr()));
188 return;
192 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
193 if (running_status() == STOPPED) {
194 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
195 return;
197 if (stop_callbacks_.empty()) {
198 ServiceWorkerStatusCode status = embedded_worker_->Stop();
199 if (status != SERVICE_WORKER_OK) {
200 RunSoon(base::Bind(callback, status));
201 return;
204 stop_callbacks_.push_back(callback);
207 void ServiceWorkerVersion::ScheduleUpdate() {
208 if (update_timer_.IsRunning()) {
209 update_timer_.Reset();
210 return;
212 update_timer_.Start(
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();
225 if (!context_)
226 return;
227 ServiceWorkerRegistration* registration =
228 context_->GetLiveRegistration(registration_id_);
229 if (!registration)
230 return;
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)));
243 return;
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.
257 StartWorker(
258 base::Bind(&RunTaskAfterStartWorker,
259 weak_factory_.GetWeakPtr(),
260 callback,
261 base::Bind(&self::DispatchInstallEventAfterStartWorker,
262 weak_factory_.GetWeakPtr(),
263 active_version_id,
264 callback)));
265 } else {
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.
276 StartWorker(
277 base::Bind(&RunTaskAfterStartWorker,
278 weak_factory_.GetWeakPtr(),
279 callback,
280 base::Bind(&self::DispatchActivateEventAfterStartWorker,
281 weak_factory_.GetWeakPtr(),
282 callback)));
283 } else {
284 DispatchActivateEventAfterStartWorker(callback);
288 void ServiceWorkerVersion::DispatchFetchEvent(
289 const ServiceWorkerFetchRequest& request,
290 const FetchCallback& callback) {
291 DCHECK_EQ(ACTIVATED, status()) << status();
293 if (running_status() != RUNNING) {
294 // Schedule calling this method after starting the worker.
295 StartWorker(base::Bind(&RunTaskAfterStartWorker,
296 weak_factory_.GetWeakPtr(),
297 base::Bind(&RunErrorFetchCallback, callback),
298 base::Bind(&self::DispatchFetchEvent,
299 weak_factory_.GetWeakPtr(),
300 request, callback)));
301 return;
304 int request_id = fetch_callbacks_.Add(new FetchCallback(callback));
305 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
306 ServiceWorkerMsg_FetchEvent(request_id, request));
307 if (status != SERVICE_WORKER_OK) {
308 fetch_callbacks_.Remove(request_id);
309 RunSoon(base::Bind(&RunErrorFetchCallback,
310 callback,
311 SERVICE_WORKER_ERROR_FAILED));
315 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
316 DCHECK_EQ(ACTIVATED, status()) << status();
318 if (!CommandLine::ForCurrentProcess()->HasSwitch(
319 switches::kEnableServiceWorkerSync)) {
320 callback.Run(SERVICE_WORKER_ERROR_ABORT);
321 return;
324 if (running_status() != RUNNING) {
325 // Schedule calling this method after starting the worker.
326 StartWorker(base::Bind(&RunTaskAfterStartWorker,
327 weak_factory_.GetWeakPtr(), callback,
328 base::Bind(&self::DispatchSyncEvent,
329 weak_factory_.GetWeakPtr(),
330 callback)));
331 return;
334 int request_id = sync_callbacks_.Add(new StatusCallback(callback));
335 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
336 ServiceWorkerMsg_SyncEvent(request_id));
337 if (status != SERVICE_WORKER_OK) {
338 sync_callbacks_.Remove(request_id);
339 RunSoon(base::Bind(callback, status));
343 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
344 const std::string& data) {
345 DCHECK_EQ(ACTIVATED, status()) << status();
347 if (!CommandLine::ForCurrentProcess()->HasSwitch(
348 switches::kEnableExperimentalWebPlatformFeatures)) {
349 callback.Run(SERVICE_WORKER_ERROR_ABORT);
350 return;
353 if (running_status() != RUNNING) {
354 // Schedule calling this method after starting the worker.
355 StartWorker(base::Bind(&RunTaskAfterStartWorker,
356 weak_factory_.GetWeakPtr(), callback,
357 base::Bind(&self::DispatchPushEvent,
358 weak_factory_.GetWeakPtr(),
359 callback, data)));
360 return;
363 int request_id = push_callbacks_.Add(new StatusCallback(callback));
364 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
365 ServiceWorkerMsg_PushEvent(request_id, data));
366 if (status != SERVICE_WORKER_OK) {
367 push_callbacks_.Remove(request_id);
368 RunSoon(base::Bind(callback, status));
372 void ServiceWorkerVersion::AddProcessToWorker(int process_id) {
373 embedded_worker_->AddProcessReference(process_id);
376 void ServiceWorkerVersion::RemoveProcessFromWorker(int process_id) {
377 embedded_worker_->ReleaseProcessReference(process_id);
380 bool ServiceWorkerVersion::HasProcessToRun() const {
381 return embedded_worker_->HasProcessToRun();
384 void ServiceWorkerVersion::AddControllee(
385 ServiceWorkerProviderHost* provider_host) {
386 DCHECK(!ContainsKey(controllee_map_, provider_host));
387 int controllee_id = controllee_by_id_.Add(provider_host);
388 controllee_map_[provider_host] = controllee_id;
389 AddProcessToWorker(provider_host->process_id());
390 if (stop_worker_timer_.IsRunning())
391 stop_worker_timer_.Stop();
394 void ServiceWorkerVersion::RemoveControllee(
395 ServiceWorkerProviderHost* provider_host) {
396 ControlleeMap::iterator found = controllee_map_.find(provider_host);
397 DCHECK(found != controllee_map_.end());
398 controllee_by_id_.Remove(found->second);
399 controllee_map_.erase(found);
400 RemoveProcessFromWorker(provider_host->process_id());
401 if (HasControllee())
402 return;
403 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
404 if (is_doomed_) {
405 DoomInternal();
406 return;
408 ScheduleStopWorker();
411 void ServiceWorkerVersion::AddPotentialControllee(
412 ServiceWorkerProviderHost* provider_host) {
413 AddProcessToWorker(provider_host->process_id());
416 void ServiceWorkerVersion::RemovePotentialControllee(
417 ServiceWorkerProviderHost* provider_host) {
418 RemoveProcessFromWorker(provider_host->process_id());
421 void ServiceWorkerVersion::AddListener(Listener* listener) {
422 listeners_.AddObserver(listener);
425 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
426 listeners_.RemoveObserver(listener);
429 void ServiceWorkerVersion::Doom() {
430 if (is_doomed_)
431 return;
432 is_doomed_ = true;
433 if (!HasControllee())
434 DoomInternal();
437 void ServiceWorkerVersion::OnStarted() {
438 DCHECK_EQ(RUNNING, running_status());
439 if (status() == ACTIVATED && !HasControllee())
440 ScheduleStopWorker();
441 // Fire all start callbacks.
442 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
443 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
446 void ServiceWorkerVersion::OnStopped() {
447 DCHECK_EQ(STOPPED, running_status());
448 scoped_refptr<ServiceWorkerVersion> protect(this);
450 // Fire all stop callbacks.
451 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
453 // Let all start callbacks fail.
454 RunCallbacks(
455 this, &start_callbacks_, SERVICE_WORKER_ERROR_START_WORKER_FAILED);
457 // Let all message callbacks fail (this will also fire and clear all
458 // callbacks for events).
459 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
460 RunIDMapCallbacks(&activate_callbacks_,
461 &StatusCallback::Run,
462 MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED));
463 RunIDMapCallbacks(&install_callbacks_,
464 &StatusCallback::Run,
465 MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED));
466 RunIDMapCallbacks(&fetch_callbacks_,
467 &FetchCallback::Run,
468 MakeTuple(SERVICE_WORKER_ERROR_FAILED,
469 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
470 ServiceWorkerResponse()));
471 RunIDMapCallbacks(&sync_callbacks_,
472 &StatusCallback::Run,
473 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
474 RunIDMapCallbacks(&push_callbacks_,
475 &StatusCallback::Run,
476 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
478 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
481 void ServiceWorkerVersion::OnReportException(
482 const base::string16& error_message,
483 int line_number,
484 int column_number,
485 const GURL& source_url) {
486 FOR_EACH_OBSERVER(
487 Listener,
488 listeners_,
489 OnErrorReported(
490 this, error_message, line_number, column_number, source_url));
493 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
494 int message_level,
495 const base::string16& message,
496 int line_number,
497 const GURL& source_url) {
498 FOR_EACH_OBSERVER(Listener,
499 listeners_,
500 OnReportConsoleMessage(this,
501 source_identifier,
502 message_level,
503 message,
504 line_number,
505 source_url));
508 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
509 bool handled = true;
510 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
511 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
512 OnGetClientDocuments)
513 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
514 OnActivateEventFinished)
515 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
516 OnInstallEventFinished)
517 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
518 OnFetchEventFinished)
519 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
520 OnSyncEventFinished)
521 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
522 OnPushEventFinished)
523 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
524 OnPostMessageToDocument)
525 IPC_MESSAGE_UNHANDLED(handled = false)
526 IPC_END_MESSAGE_MAP()
527 return handled;
530 void ServiceWorkerVersion::RunStartWorkerCallbacksOnError(
531 ServiceWorkerStatusCode status) {
532 if (status != SERVICE_WORKER_OK)
533 RunCallbacks(this, &start_callbacks_, status);
536 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
537 int active_version_id,
538 const StatusCallback& callback) {
539 DCHECK_EQ(RUNNING, running_status())
540 << "Worker stopped too soon after it was started.";
542 int request_id = install_callbacks_.Add(new StatusCallback(callback));
543 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
544 ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
545 if (status != SERVICE_WORKER_OK) {
546 install_callbacks_.Remove(request_id);
547 RunSoon(base::Bind(callback, status));
551 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
552 const StatusCallback& callback) {
553 DCHECK_EQ(RUNNING, running_status())
554 << "Worker stopped too soon after it was started.";
556 int request_id = activate_callbacks_.Add(new StatusCallback(callback));
557 ServiceWorkerStatusCode status =
558 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
559 if (status != SERVICE_WORKER_OK) {
560 activate_callbacks_.Remove(request_id);
561 RunSoon(base::Bind(callback, status));
565 void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
566 std::vector<int> client_ids;
567 ControlleeByIDMap::iterator it(&controllee_by_id_);
568 while (!it.IsAtEnd()) {
569 client_ids.push_back(it.GetCurrentKey());
570 it.Advance();
572 // Don't bother if it's no longer running.
573 if (running_status() == RUNNING) {
574 embedded_worker_->SendMessage(
575 ServiceWorkerMsg_DidGetClientDocuments(request_id, client_ids));
579 void ServiceWorkerVersion::OnActivateEventFinished(
580 int request_id,
581 blink::WebServiceWorkerEventResult result) {
582 DCHECK(ACTIVATING == status() ||
583 REDUNDANT == status()) << status();
585 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
586 if (!callback) {
587 NOTREACHED() << "Got unexpected message: " << request_id;
588 return;
590 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
591 if (result == blink::WebServiceWorkerEventResultRejected ||
592 status() != ACTIVATING) {
593 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
596 scoped_refptr<ServiceWorkerVersion> protect(this);
597 callback->Run(rv);
598 activate_callbacks_.Remove(request_id);
601 void ServiceWorkerVersion::OnInstallEventFinished(
602 int request_id,
603 blink::WebServiceWorkerEventResult result) {
604 DCHECK_EQ(INSTALLING, status()) << status();
606 StatusCallback* callback = install_callbacks_.Lookup(request_id);
607 if (!callback) {
608 NOTREACHED() << "Got unexpected message: " << request_id;
609 return;
611 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
612 if (result == blink::WebServiceWorkerEventResultRejected)
613 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
615 scoped_refptr<ServiceWorkerVersion> protect(this);
616 callback->Run(status);
617 install_callbacks_.Remove(request_id);
620 void ServiceWorkerVersion::OnFetchEventFinished(
621 int request_id,
622 ServiceWorkerFetchEventResult result,
623 const ServiceWorkerResponse& response) {
624 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
625 if (!callback) {
626 NOTREACHED() << "Got unexpected message: " << request_id;
627 return;
630 scoped_refptr<ServiceWorkerVersion> protect(this);
631 callback->Run(SERVICE_WORKER_OK, result, response);
632 fetch_callbacks_.Remove(request_id);
635 void ServiceWorkerVersion::OnSyncEventFinished(
636 int request_id) {
637 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
638 if (!callback) {
639 NOTREACHED() << "Got unexpected message: " << request_id;
640 return;
643 scoped_refptr<ServiceWorkerVersion> protect(this);
644 callback->Run(SERVICE_WORKER_OK);
645 sync_callbacks_.Remove(request_id);
648 void ServiceWorkerVersion::OnPushEventFinished(
649 int request_id) {
650 StatusCallback* callback = push_callbacks_.Lookup(request_id);
651 if (!callback) {
652 NOTREACHED() << "Got unexpected message: " << request_id;
653 return;
656 scoped_refptr<ServiceWorkerVersion> protect(this);
657 callback->Run(SERVICE_WORKER_OK);
658 push_callbacks_.Remove(request_id);
661 void ServiceWorkerVersion::OnPostMessageToDocument(
662 int client_id,
663 const base::string16& message,
664 const std::vector<int>& sent_message_port_ids) {
665 ServiceWorkerProviderHost* provider_host =
666 controllee_by_id_.Lookup(client_id);
667 if (!provider_host) {
668 // The client may already have been closed, just ignore.
669 return;
671 provider_host->PostMessage(message, sent_message_port_ids);
674 void ServiceWorkerVersion::ScheduleStopWorker() {
675 if (running_status() != RUNNING)
676 return;
677 if (stop_worker_timer_.IsRunning()) {
678 stop_worker_timer_.Reset();
679 return;
681 stop_worker_timer_.Start(
682 FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay),
683 base::Bind(&ServiceWorkerVersion::StopWorker,
684 weak_factory_.GetWeakPtr(),
685 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
688 void ServiceWorkerVersion::DoomInternal() {
689 DCHECK(!HasControllee());
690 SetStatus(REDUNDANT);
691 StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
692 if (!context_)
693 return;
694 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
695 script_cache_map_.GetResources(&resources);
696 context_->storage()->PurgeResources(resources);
699 } // namespace content