cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blob62a6a6029ff47545d29b5f3434101158c090118e
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 = 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,
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 const GURL& script_url,
95 int64 version_id,
96 base::WeakPtr<ServiceWorkerContextCore> context)
97 : version_id_(version_id),
98 registration_id_(kInvalidServiceWorkerVersionId),
99 script_url_(script_url),
100 status_(NEW),
101 context_(context),
102 script_cache_map_(this, context),
103 is_doomed_(false),
104 weak_factory_(this) {
105 DCHECK(context_);
106 DCHECK(registration);
107 if (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);
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 // Schedule to stop worker after registration successfully completed.
128 if (status_ == ACTIVATING && status == ACTIVATED && !HasControllee())
129 ScheduleStopWorker();
131 status_ = status;
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) {
137 (*i).Run();
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(
151 running_status(),
152 status(),
153 script_url(),
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 StartWorker(false, callback);
164 void ServiceWorkerVersion::StartWorker(
165 bool pause_after_download,
166 const StatusCallback& callback) {
167 switch (running_status()) {
168 case RUNNING:
169 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
170 return;
171 case STOPPING:
172 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
173 return;
174 case STOPPED:
175 case STARTING:
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(
181 version_id_,
182 scope_,
183 script_url_,
184 pause_after_download,
185 base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
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 || !registration->GetNewestVersion())
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 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(),
301 request,
302 prepare_callback,
303 fetch_callback)));
304 return;
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,
315 fetch_callback,
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);
326 return;
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(),
335 callback)));
336 return;
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);
355 return;
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(),
364 callback, data)));
365 return;
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);
392 if (HasControllee())
393 return;
394 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
395 if (is_doomed_) {
396 DoomInternal();
397 return;
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() {
411 if (is_doomed_)
412 return;
413 is_doomed_ = true;
414 if (!HasControllee())
415 DoomInternal();
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.
436 RunCallbacks(
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_,
449 &FetchCallback::Run,
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,
470 int line_number,
471 int column_number,
472 const GURL& source_url) {
473 FOR_EACH_OBSERVER(
474 Listener,
475 listeners_,
476 OnErrorReported(
477 this, error_message, line_number, column_number, source_url));
480 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
481 int message_level,
482 const base::string16& message,
483 int line_number,
484 const GURL& source_url) {
485 FOR_EACH_OBSERVER(Listener,
486 listeners_,
487 OnReportConsoleMessage(this,
488 source_identifier,
489 message_level,
490 message,
491 line_number,
492 source_url));
495 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
496 bool handled = true;
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,
507 OnSyncEventFinished)
508 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
509 OnPushEventFinished)
510 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
511 OnPostMessageToDocument)
512 IPC_MESSAGE_UNHANDLED(handled = false)
513 IPC_END_MESSAGE_MAP()
514 return handled;
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());
559 it.Advance();
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(
569 int request_id,
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);
577 if (!callback) {
578 NOTREACHED() << "Got unexpected message: " << request_id;
579 return;
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);
588 callback->Run(rv);
589 activate_callbacks_.Remove(request_id);
592 void ServiceWorkerVersion::OnInstallEventFinished(
593 int request_id,
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);
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 TRACE_EVENT1("ServiceWorker",
618 "ServiceWorkerVersion::OnFetchEventFinished",
619 "Request id", request_id);
620 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
621 if (!callback) {
622 NOTREACHED() << "Got unexpected message: " << request_id;
623 return;
626 scoped_refptr<ServiceWorkerVersion> protect(this);
627 callback->Run(SERVICE_WORKER_OK, result, response);
628 fetch_callbacks_.Remove(request_id);
631 void ServiceWorkerVersion::OnSyncEventFinished(
632 int request_id) {
633 TRACE_EVENT1("ServiceWorker",
634 "ServiceWorkerVersion::OnSyncEventFinished",
635 "Request id", request_id);
636 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
637 if (!callback) {
638 NOTREACHED() << "Got unexpected message: " << request_id;
639 return;
642 scoped_refptr<ServiceWorkerVersion> protect(this);
643 callback->Run(SERVICE_WORKER_OK);
644 sync_callbacks_.Remove(request_id);
647 void ServiceWorkerVersion::OnPushEventFinished(
648 int request_id) {
649 TRACE_EVENT1("ServiceWorker",
650 "ServiceWorkerVersion::OnPushEventFinished",
651 "Request id", request_id);
652 StatusCallback* callback = push_callbacks_.Lookup(request_id);
653 if (!callback) {
654 NOTREACHED() << "Got unexpected message: " << request_id;
655 return;
658 scoped_refptr<ServiceWorkerVersion> protect(this);
659 callback->Run(SERVICE_WORKER_OK);
660 push_callbacks_.Remove(request_id);
663 void ServiceWorkerVersion::OnPostMessageToDocument(
664 int client_id,
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.
674 return;
676 provider_host->PostMessage(message, sent_message_port_ids);
679 void ServiceWorkerVersion::ScheduleStopWorker() {
680 if (running_status() != RUNNING)
681 return;
682 if (stop_worker_timer_.IsRunning()) {
683 stop_worker_timer_.Reset();
684 return;
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));
697 if (!context_)
698 return;
699 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
700 script_cache_map_.GetResources(&resources);
701 context_->storage()->PurgeResources(resources);
704 } // namespace content