Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blobbea893b3377021c432275a2671adff3555d31b6b
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/message_port_message_filter.h"
11 #include "content/browser/message_port_service.h"
12 #include "content/browser/service_worker/embedded_worker_instance.h"
13 #include "content/browser/service_worker/embedded_worker_registry.h"
14 #include "content/browser/service_worker/service_worker_context_core.h"
15 #include "content/browser/service_worker/service_worker_registration.h"
16 #include "content/browser/service_worker/service_worker_utils.h"
17 #include "content/common/service_worker/service_worker_messages.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/common/content_switches.h"
21 namespace content {
23 typedef ServiceWorkerVersion::StatusCallback StatusCallback;
24 typedef ServiceWorkerVersion::MessageCallback MessageCallback;
26 namespace {
28 // Default delay for scheduled stop.
29 // (Note that if all references to the version is dropped the worker
30 // is also stopped without delay)
31 const int64 kStopWorkerDelay = 30; // 30 secs.
33 // Default delay for scheduled update.
34 const int kUpdateDelaySeconds = 1;
36 void RunSoon(const base::Closure& callback) {
37 if (!callback.is_null())
38 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
41 template <typename CallbackArray, typename Arg>
42 void RunCallbacks(ServiceWorkerVersion* version,
43 CallbackArray* callbacks_ptr,
44 const Arg& arg) {
45 CallbackArray callbacks;
46 callbacks.swap(*callbacks_ptr);
47 scoped_refptr<ServiceWorkerVersion> protect(version);
48 for (typename CallbackArray::const_iterator i = callbacks.begin();
49 i != callbacks.end(); ++i)
50 (*i).Run(arg);
53 template <typename IDMAP, typename Method, typename Params>
54 void RunIDMapCallbacks(IDMAP* callbacks, Method method, const Params& params) {
55 typename IDMAP::iterator iter(callbacks);
56 while (!iter.IsAtEnd()) {
57 DispatchToMethod(iter.GetCurrentValue(), method, params);
58 iter.Advance();
60 callbacks->Clear();
63 // A callback adapter to start a |task| after StartWorker.
64 void RunTaskAfterStartWorker(
65 base::WeakPtr<ServiceWorkerVersion> version,
66 const StatusCallback& error_callback,
67 const base::Closure& task,
68 ServiceWorkerStatusCode status) {
69 if (status != SERVICE_WORKER_OK) {
70 if (!error_callback.is_null())
71 error_callback.Run(status);
72 return;
74 if (version->running_status() != ServiceWorkerVersion::RUNNING) {
75 // We've tried to start the worker (and it has succeeded), but
76 // it looks it's not running yet.
77 NOTREACHED() << "The worker's not running after successful StartWorker";
78 if (!error_callback.is_null())
79 error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
80 return;
82 task.Run();
85 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
86 ServiceWorkerStatusCode status) {
87 callback.Run(status,
88 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
89 ServiceWorkerResponse());
92 void RunErrorMessageCallback(
93 const std::vector<int>& sent_message_port_ids,
94 const ServiceWorkerVersion::StatusCallback& callback,
95 ServiceWorkerStatusCode status) {
96 // Transfering the message ports failed, so destroy the ports.
97 for (int message_port_id : sent_message_port_ids) {
98 MessagePortService::GetInstance()->ClosePort(message_port_id);
100 callback.Run(status);
103 } // namespace
105 ServiceWorkerVersion::ServiceWorkerVersion(
106 ServiceWorkerRegistration* registration,
107 const GURL& script_url,
108 int64 version_id,
109 base::WeakPtr<ServiceWorkerContextCore> context)
110 : version_id_(version_id),
111 registration_id_(kInvalidServiceWorkerVersionId),
112 script_url_(script_url),
113 status_(NEW),
114 context_(context),
115 script_cache_map_(this, context),
116 is_doomed_(false),
117 weak_factory_(this) {
118 DCHECK(context_);
119 DCHECK(registration);
120 if (registration) {
121 registration_id_ = registration->id();
122 scope_ = registration->pattern();
124 context_->AddLiveVersion(this);
125 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
126 embedded_worker_->AddListener(this);
129 ServiceWorkerVersion::~ServiceWorkerVersion() {
130 embedded_worker_->RemoveListener(this);
131 if (context_)
132 context_->RemoveLiveVersion(version_id_);
133 // EmbeddedWorker's dtor sends StopWorker if it's still running.
136 void ServiceWorkerVersion::SetStatus(Status status) {
137 if (status_ == status)
138 return;
140 // Schedule to stop worker after registration successfully completed.
141 if (status_ == ACTIVATING && status == ACTIVATED && !HasControllee())
142 ScheduleStopWorker();
144 status_ = status;
146 std::vector<base::Closure> callbacks;
147 callbacks.swap(status_change_callbacks_);
148 for (std::vector<base::Closure>::const_iterator i = callbacks.begin();
149 i != callbacks.end(); ++i) {
150 (*i).Run();
153 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
156 void ServiceWorkerVersion::RegisterStatusChangeCallback(
157 const base::Closure& callback) {
158 status_change_callbacks_.push_back(callback);
161 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
163 return ServiceWorkerVersionInfo(
164 running_status(),
165 status(),
166 script_url(),
167 version_id(),
168 embedded_worker()->process_id(),
169 embedded_worker()->thread_id(),
170 embedded_worker()->worker_devtools_agent_route_id());
173 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
174 StartWorker(false, callback);
177 void ServiceWorkerVersion::StartWorker(
178 bool pause_after_download,
179 const StatusCallback& callback) {
180 switch (running_status()) {
181 case RUNNING:
182 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
183 return;
184 case STOPPING:
185 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
186 return;
187 case STOPPED:
188 case STARTING:
189 start_callbacks_.push_back(callback);
190 if (running_status() == STOPPED) {
191 DCHECK(!cache_listener_.get());
192 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
193 embedded_worker_->Start(
194 version_id_,
195 scope_,
196 script_url_,
197 pause_after_download,
198 base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
199 weak_factory_.GetWeakPtr()));
201 return;
205 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
206 if (running_status() == STOPPED) {
207 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
208 return;
210 if (stop_callbacks_.empty()) {
211 ServiceWorkerStatusCode status = embedded_worker_->Stop();
212 if (status != SERVICE_WORKER_OK) {
213 RunSoon(base::Bind(callback, status));
214 return;
217 stop_callbacks_.push_back(callback);
220 void ServiceWorkerVersion::ScheduleUpdate() {
221 if (update_timer_.IsRunning()) {
222 update_timer_.Reset();
223 return;
225 update_timer_.Start(
226 FROM_HERE, base::TimeDelta::FromSeconds(kUpdateDelaySeconds),
227 base::Bind(&ServiceWorkerVersion::StartUpdate,
228 weak_factory_.GetWeakPtr()));
231 void ServiceWorkerVersion::DeferScheduledUpdate() {
232 if (update_timer_.IsRunning())
233 update_timer_.Reset();
236 void ServiceWorkerVersion::StartUpdate() {
237 update_timer_.Stop();
238 if (!context_)
239 return;
240 ServiceWorkerRegistration* registration =
241 context_->GetLiveRegistration(registration_id_);
242 if (!registration || !registration->GetNewestVersion())
243 return;
244 context_->UpdateServiceWorker(registration);
247 void ServiceWorkerVersion::SendMessage(
248 const IPC::Message& message, const StatusCallback& callback) {
249 if (running_status() != RUNNING) {
250 // Schedule calling this method after starting the worker.
251 StartWorker(base::Bind(&RunTaskAfterStartWorker,
252 weak_factory_.GetWeakPtr(), callback,
253 base::Bind(&self::SendMessage,
254 weak_factory_.GetWeakPtr(),
255 message, callback)));
256 return;
259 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message);
260 RunSoon(base::Bind(callback, status));
263 void ServiceWorkerVersion::DispatchMessageEvent(
264 const base::string16& message,
265 const std::vector<int>& sent_message_port_ids,
266 const StatusCallback& callback) {
267 for (int message_port_id : sent_message_port_ids) {
268 MessagePortService::GetInstance()->HoldMessages(message_port_id);
271 DispatchMessageEventInternal(message, sent_message_port_ids, callback);
274 void ServiceWorkerVersion::DispatchMessageEventInternal(
275 const base::string16& message,
276 const std::vector<int>& sent_message_port_ids,
277 const StatusCallback& callback) {
278 if (running_status() != RUNNING) {
279 // Schedule calling this method after starting the worker.
280 StartWorker(base::Bind(
281 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
282 base::Bind(&RunErrorMessageCallback, sent_message_port_ids, callback),
283 base::Bind(&self::DispatchMessageEventInternal,
284 weak_factory_.GetWeakPtr(), message, sent_message_port_ids,
285 callback)));
286 return;
289 MessagePortMessageFilter* filter =
290 embedded_worker_->message_port_message_filter();
291 std::vector<int> new_routing_ids;
292 filter->UpdateMessagePortsWithNewRoutes(sent_message_port_ids,
293 &new_routing_ids);
294 ServiceWorkerStatusCode status =
295 embedded_worker_->SendMessage(ServiceWorkerMsg_MessageToWorker(
296 message, sent_message_port_ids, new_routing_ids));
297 RunSoon(base::Bind(callback, status));
300 void ServiceWorkerVersion::DispatchInstallEvent(
301 int active_version_id,
302 const StatusCallback& callback) {
303 DCHECK_EQ(INSTALLING, status()) << status();
305 if (running_status() != RUNNING) {
306 // Schedule calling this method after starting the worker.
307 StartWorker(
308 base::Bind(&RunTaskAfterStartWorker,
309 weak_factory_.GetWeakPtr(),
310 callback,
311 base::Bind(&self::DispatchInstallEventAfterStartWorker,
312 weak_factory_.GetWeakPtr(),
313 active_version_id,
314 callback)));
315 } else {
316 DispatchInstallEventAfterStartWorker(active_version_id, callback);
320 void ServiceWorkerVersion::DispatchActivateEvent(
321 const StatusCallback& callback) {
322 DCHECK_EQ(ACTIVATING, status()) << status();
324 if (running_status() != RUNNING) {
325 // Schedule calling this method after starting the worker.
326 StartWorker(
327 base::Bind(&RunTaskAfterStartWorker,
328 weak_factory_.GetWeakPtr(),
329 callback,
330 base::Bind(&self::DispatchActivateEventAfterStartWorker,
331 weak_factory_.GetWeakPtr(),
332 callback)));
333 } else {
334 DispatchActivateEventAfterStartWorker(callback);
338 void ServiceWorkerVersion::DispatchFetchEvent(
339 const ServiceWorkerFetchRequest& request,
340 const base::Closure& prepare_callback,
341 const FetchCallback& fetch_callback) {
342 DCHECK_EQ(ACTIVATED, status()) << status();
344 if (running_status() != RUNNING) {
345 // Schedule calling this method after starting the worker.
346 StartWorker(base::Bind(&RunTaskAfterStartWorker,
347 weak_factory_.GetWeakPtr(),
348 base::Bind(&RunErrorFetchCallback, fetch_callback),
349 base::Bind(&self::DispatchFetchEvent,
350 weak_factory_.GetWeakPtr(),
351 request,
352 prepare_callback,
353 fetch_callback)));
354 return;
357 prepare_callback.Run();
359 int request_id = fetch_callbacks_.Add(new FetchCallback(fetch_callback));
360 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
361 ServiceWorkerMsg_FetchEvent(request_id, request));
362 if (status != SERVICE_WORKER_OK) {
363 fetch_callbacks_.Remove(request_id);
364 RunSoon(base::Bind(&RunErrorFetchCallback,
365 fetch_callback,
366 SERVICE_WORKER_ERROR_FAILED));
370 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
371 DCHECK_EQ(ACTIVATED, status()) << status();
373 if (!CommandLine::ForCurrentProcess()->HasSwitch(
374 switches::kEnableServiceWorkerSync)) {
375 callback.Run(SERVICE_WORKER_ERROR_ABORT);
376 return;
379 if (running_status() != RUNNING) {
380 // Schedule calling this method after starting the worker.
381 StartWorker(base::Bind(&RunTaskAfterStartWorker,
382 weak_factory_.GetWeakPtr(), callback,
383 base::Bind(&self::DispatchSyncEvent,
384 weak_factory_.GetWeakPtr(),
385 callback)));
386 return;
389 int request_id = sync_callbacks_.Add(new StatusCallback(callback));
390 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
391 ServiceWorkerMsg_SyncEvent(request_id));
392 if (status != SERVICE_WORKER_OK) {
393 sync_callbacks_.Remove(request_id);
394 RunSoon(base::Bind(callback, status));
398 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
399 const std::string& data) {
400 DCHECK_EQ(ACTIVATED, status()) << status();
402 if (!CommandLine::ForCurrentProcess()->HasSwitch(
403 switches::kEnableExperimentalWebPlatformFeatures)) {
404 callback.Run(SERVICE_WORKER_ERROR_ABORT);
405 return;
408 if (running_status() != RUNNING) {
409 // Schedule calling this method after starting the worker.
410 StartWorker(base::Bind(&RunTaskAfterStartWorker,
411 weak_factory_.GetWeakPtr(), callback,
412 base::Bind(&self::DispatchPushEvent,
413 weak_factory_.GetWeakPtr(),
414 callback, data)));
415 return;
418 int request_id = push_callbacks_.Add(new StatusCallback(callback));
419 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
420 ServiceWorkerMsg_PushEvent(request_id, data));
421 if (status != SERVICE_WORKER_OK) {
422 push_callbacks_.Remove(request_id);
423 RunSoon(base::Bind(callback, status));
427 void ServiceWorkerVersion::DispatchGeofencingEvent(
428 const StatusCallback& callback,
429 blink::WebGeofencingEventType event_type,
430 const std::string& region_id,
431 const blink::WebCircularGeofencingRegion& region) {
432 DCHECK_EQ(ACTIVATED, status()) << status();
434 if (!CommandLine::ForCurrentProcess()->HasSwitch(
435 switches::kEnableExperimentalWebPlatformFeatures)) {
436 callback.Run(SERVICE_WORKER_ERROR_ABORT);
437 return;
440 if (running_status() != RUNNING) {
441 // Schedule calling this method after starting the worker.
442 StartWorker(base::Bind(&RunTaskAfterStartWorker,
443 weak_factory_.GetWeakPtr(),
444 callback,
445 base::Bind(&self::DispatchGeofencingEvent,
446 weak_factory_.GetWeakPtr(),
447 callback,
448 event_type,
449 region_id,
450 region)));
451 return;
454 int request_id = geofencing_callbacks_.Add(new StatusCallback(callback));
455 ServiceWorkerStatusCode status =
456 embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
457 request_id, event_type, region_id, region));
458 if (status != SERVICE_WORKER_OK) {
459 geofencing_callbacks_.Remove(request_id);
460 RunSoon(base::Bind(callback, status));
464 void ServiceWorkerVersion::AddControllee(
465 ServiceWorkerProviderHost* provider_host) {
466 DCHECK(!ContainsKey(controllee_map_, provider_host));
467 int controllee_id = controllee_by_id_.Add(provider_host);
468 controllee_map_[provider_host] = controllee_id;
469 if (stop_worker_timer_.IsRunning())
470 stop_worker_timer_.Stop();
473 void ServiceWorkerVersion::RemoveControllee(
474 ServiceWorkerProviderHost* provider_host) {
475 ControlleeMap::iterator found = controllee_map_.find(provider_host);
476 DCHECK(found != controllee_map_.end());
477 controllee_by_id_.Remove(found->second);
478 controllee_map_.erase(found);
479 if (HasControllee())
480 return;
481 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
482 if (is_doomed_) {
483 DoomInternal();
484 return;
486 ScheduleStopWorker();
489 void ServiceWorkerVersion::AddListener(Listener* listener) {
490 listeners_.AddObserver(listener);
493 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
494 listeners_.RemoveObserver(listener);
497 void ServiceWorkerVersion::Doom() {
498 if (is_doomed_)
499 return;
500 is_doomed_ = true;
501 if (!HasControllee())
502 DoomInternal();
505 void ServiceWorkerVersion::OnStarted() {
506 DCHECK_EQ(RUNNING, running_status());
507 DCHECK(cache_listener_.get());
508 if (status() == ACTIVATED && !HasControllee())
509 ScheduleStopWorker();
510 // Fire all start callbacks.
511 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
512 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
515 void ServiceWorkerVersion::OnStopped() {
516 DCHECK_EQ(STOPPED, running_status());
517 scoped_refptr<ServiceWorkerVersion> protect(this);
519 // Fire all stop callbacks.
520 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
522 // Let all start callbacks fail.
523 RunCallbacks(
524 this, &start_callbacks_, SERVICE_WORKER_ERROR_START_WORKER_FAILED);
526 // Let all message callbacks fail (this will also fire and clear all
527 // callbacks for events).
528 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
529 RunIDMapCallbacks(&activate_callbacks_,
530 &StatusCallback::Run,
531 MakeTuple(SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED));
532 RunIDMapCallbacks(&install_callbacks_,
533 &StatusCallback::Run,
534 MakeTuple(SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED));
535 RunIDMapCallbacks(&fetch_callbacks_,
536 &FetchCallback::Run,
537 MakeTuple(SERVICE_WORKER_ERROR_FAILED,
538 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
539 ServiceWorkerResponse()));
540 RunIDMapCallbacks(&sync_callbacks_,
541 &StatusCallback::Run,
542 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
543 RunIDMapCallbacks(&push_callbacks_,
544 &StatusCallback::Run,
545 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
546 RunIDMapCallbacks(&geofencing_callbacks_,
547 &StatusCallback::Run,
548 MakeTuple(SERVICE_WORKER_ERROR_FAILED));
550 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
552 // There should be no more communication from/to a stopped worker. Deleting
553 // the listener prevents any pending completion callbacks from causing
554 // messages to be sent to the stopped worker.
555 cache_listener_.reset();
558 void ServiceWorkerVersion::OnReportException(
559 const base::string16& error_message,
560 int line_number,
561 int column_number,
562 const GURL& source_url) {
563 FOR_EACH_OBSERVER(
564 Listener,
565 listeners_,
566 OnErrorReported(
567 this, error_message, line_number, column_number, source_url));
570 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
571 int message_level,
572 const base::string16& message,
573 int line_number,
574 const GURL& source_url) {
575 FOR_EACH_OBSERVER(Listener,
576 listeners_,
577 OnReportConsoleMessage(this,
578 source_identifier,
579 message_level,
580 message,
581 line_number,
582 source_url));
585 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
586 bool handled = true;
587 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
588 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
589 OnGetClientDocuments)
590 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
591 OnActivateEventFinished)
592 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
593 OnInstallEventFinished)
594 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
595 OnFetchEventFinished)
596 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
597 OnSyncEventFinished)
598 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
599 OnPushEventFinished)
600 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
601 OnGeofencingEventFinished)
602 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
603 OnPostMessageToDocument)
604 IPC_MESSAGE_UNHANDLED(handled = false)
605 IPC_END_MESSAGE_MAP()
606 return handled;
609 void ServiceWorkerVersion::OnStartMessageSent(
610 ServiceWorkerStatusCode status) {
611 if (status != SERVICE_WORKER_OK)
612 RunCallbacks(this, &start_callbacks_, status);
615 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
616 int active_version_id,
617 const StatusCallback& callback) {
618 DCHECK_EQ(RUNNING, running_status())
619 << "Worker stopped too soon after it was started.";
621 int request_id = install_callbacks_.Add(new StatusCallback(callback));
622 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
623 ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
624 if (status != SERVICE_WORKER_OK) {
625 install_callbacks_.Remove(request_id);
626 RunSoon(base::Bind(callback, status));
630 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
631 const StatusCallback& callback) {
632 DCHECK_EQ(RUNNING, running_status())
633 << "Worker stopped too soon after it was started.";
635 int request_id = activate_callbacks_.Add(new StatusCallback(callback));
636 ServiceWorkerStatusCode status =
637 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
638 if (status != SERVICE_WORKER_OK) {
639 activate_callbacks_.Remove(request_id);
640 RunSoon(base::Bind(callback, status));
644 void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
645 std::vector<int> client_ids;
646 ControlleeByIDMap::iterator it(&controllee_by_id_);
647 TRACE_EVENT0("ServiceWorker",
648 "ServiceWorkerVersion::OnGetClientDocuments");
649 while (!it.IsAtEnd()) {
650 client_ids.push_back(it.GetCurrentKey());
651 it.Advance();
653 // Don't bother if it's no longer running.
654 if (running_status() == RUNNING) {
655 embedded_worker_->SendMessage(
656 ServiceWorkerMsg_DidGetClientDocuments(request_id, client_ids));
660 void ServiceWorkerVersion::OnActivateEventFinished(
661 int request_id,
662 blink::WebServiceWorkerEventResult result) {
663 DCHECK(ACTIVATING == status() ||
664 REDUNDANT == status()) << status();
665 TRACE_EVENT0("ServiceWorker",
666 "ServiceWorkerVersion::OnActivateEventFinished");
668 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
669 if (!callback) {
670 NOTREACHED() << "Got unexpected message: " << request_id;
671 return;
673 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
674 if (result == blink::WebServiceWorkerEventResultRejected ||
675 status() != ACTIVATING) {
676 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
679 scoped_refptr<ServiceWorkerVersion> protect(this);
680 callback->Run(rv);
681 activate_callbacks_.Remove(request_id);
684 void ServiceWorkerVersion::OnInstallEventFinished(
685 int request_id,
686 blink::WebServiceWorkerEventResult result) {
687 DCHECK_EQ(INSTALLING, status()) << status();
688 TRACE_EVENT0("ServiceWorker",
689 "ServiceWorkerVersion::OnInstallEventFinished");
691 StatusCallback* callback = install_callbacks_.Lookup(request_id);
692 if (!callback) {
693 NOTREACHED() << "Got unexpected message: " << request_id;
694 return;
696 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
697 if (result == blink::WebServiceWorkerEventResultRejected)
698 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
700 scoped_refptr<ServiceWorkerVersion> protect(this);
701 callback->Run(status);
702 install_callbacks_.Remove(request_id);
705 void ServiceWorkerVersion::OnFetchEventFinished(
706 int request_id,
707 ServiceWorkerFetchEventResult result,
708 const ServiceWorkerResponse& response) {
709 TRACE_EVENT1("ServiceWorker",
710 "ServiceWorkerVersion::OnFetchEventFinished",
711 "Request id", request_id);
712 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
713 if (!callback) {
714 NOTREACHED() << "Got unexpected message: " << request_id;
715 return;
718 scoped_refptr<ServiceWorkerVersion> protect(this);
719 callback->Run(SERVICE_WORKER_OK, result, response);
720 fetch_callbacks_.Remove(request_id);
723 void ServiceWorkerVersion::OnSyncEventFinished(
724 int request_id) {
725 TRACE_EVENT1("ServiceWorker",
726 "ServiceWorkerVersion::OnSyncEventFinished",
727 "Request id", request_id);
728 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
729 if (!callback) {
730 NOTREACHED() << "Got unexpected message: " << request_id;
731 return;
734 scoped_refptr<ServiceWorkerVersion> protect(this);
735 callback->Run(SERVICE_WORKER_OK);
736 sync_callbacks_.Remove(request_id);
739 void ServiceWorkerVersion::OnPushEventFinished(
740 int request_id) {
741 TRACE_EVENT1("ServiceWorker",
742 "ServiceWorkerVersion::OnPushEventFinished",
743 "Request id", request_id);
744 StatusCallback* callback = push_callbacks_.Lookup(request_id);
745 if (!callback) {
746 NOTREACHED() << "Got unexpected message: " << request_id;
747 return;
750 scoped_refptr<ServiceWorkerVersion> protect(this);
751 callback->Run(SERVICE_WORKER_OK);
752 push_callbacks_.Remove(request_id);
755 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
756 TRACE_EVENT1("ServiceWorker",
757 "ServiceWorkerVersion::OnGeofencingEventFinished",
758 "Request id",
759 request_id);
760 StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
761 if (!callback) {
762 NOTREACHED() << "Got unexpected message: " << request_id;
763 return;
766 scoped_refptr<ServiceWorkerVersion> protect(this);
767 callback->Run(SERVICE_WORKER_OK);
768 geofencing_callbacks_.Remove(request_id);
771 void ServiceWorkerVersion::OnPostMessageToDocument(
772 int client_id,
773 const base::string16& message,
774 const std::vector<int>& sent_message_port_ids) {
775 TRACE_EVENT1("ServiceWorker",
776 "ServiceWorkerVersion::OnPostMessageToDocument",
777 "Client id", client_id);
778 ServiceWorkerProviderHost* provider_host =
779 controllee_by_id_.Lookup(client_id);
780 if (!provider_host) {
781 // The client may already have been closed, just ignore.
782 return;
784 provider_host->PostMessage(message, sent_message_port_ids);
787 void ServiceWorkerVersion::ScheduleStopWorker() {
788 if (running_status() != RUNNING)
789 return;
790 if (stop_worker_timer_.IsRunning()) {
791 stop_worker_timer_.Reset();
792 return;
794 stop_worker_timer_.Start(
795 FROM_HERE, base::TimeDelta::FromSeconds(kStopWorkerDelay),
796 base::Bind(&ServiceWorkerVersion::StopWorker,
797 weak_factory_.GetWeakPtr(),
798 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)));
801 void ServiceWorkerVersion::DoomInternal() {
802 DCHECK(!HasControllee());
803 SetStatus(REDUNDANT);
804 StopWorker(base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
805 if (!context_)
806 return;
807 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
808 script_cache_map_.GetResources(&resources);
809 context_->storage()->PurgeResources(resources);
812 } // namespace content