ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blobd6468fda7154264c99632e318529d5820c923f16
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/memory/ref_counted.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "content/browser/message_port_message_filter.h"
14 #include "content/browser/message_port_service.h"
15 #include "content/browser/service_worker/embedded_worker_instance.h"
16 #include "content/browser/service_worker/embedded_worker_registry.h"
17 #include "content/browser/service_worker/service_worker_context_core.h"
18 #include "content/browser/service_worker/service_worker_context_wrapper.h"
19 #include "content/browser/service_worker/service_worker_registration.h"
20 #include "content/browser/service_worker/service_worker_utils.h"
21 #include "content/browser/storage_partition_impl.h"
22 #include "content/common/service_worker/service_worker_messages.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/content_browser_client.h"
25 #include "content/public/browser/page_navigator.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/browser/web_contents_observer.h"
30 #include "content/public/common/child_process_host.h"
31 #include "content/public/common/content_client.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/result_codes.h"
34 #include "net/http/http_response_info.h"
36 namespace content {
38 typedef ServiceWorkerVersion::StatusCallback StatusCallback;
39 typedef ServiceWorkerVersion::MessageCallback MessageCallback;
41 class ServiceWorkerVersion::GetClientDocumentsCallback
42 : public base::RefCounted<GetClientDocumentsCallback> {
43 public:
44 GetClientDocumentsCallback(int request_id,
45 ServiceWorkerVersion* version)
46 : request_id_(request_id),
47 version_(version) {
48 DCHECK(version_);
51 void AddClientInfo(int client_id, const ServiceWorkerClientInfo& info) {
52 clients_.push_back(info);
53 clients_.back().client_id = client_id;
56 private:
57 friend class base::RefCounted<GetClientDocumentsCallback>;
59 virtual ~GetClientDocumentsCallback() {
60 DCHECK_CURRENTLY_ON(BrowserThread::IO);
62 if (version_->running_status() == RUNNING) {
63 version_->embedded_worker_->SendMessage(
64 ServiceWorkerMsg_DidGetClientDocuments(request_id_, clients_));
68 std::vector<ServiceWorkerClientInfo> clients_;
69 int request_id_;
70 scoped_refptr<ServiceWorkerVersion> version_;
72 DISALLOW_COPY_AND_ASSIGN(GetClientDocumentsCallback);
75 namespace {
77 // Default delay for scheduled stop.
78 // (Note that if all references to the version is dropped the worker
79 // is also stopped without delay)
80 const int64 kStopWorkerDelay = 30; // 30 secs.
82 // Delay for attempting to stop a doomed worker with in-flight requests.
83 const int64 kStopDoomedWorkerDelay = 5; // 5 secs.
85 // Default delay for scheduled update.
86 const int kUpdateDelaySeconds = 1;
88 // Delay between sending pings to the worker.
89 const int kPingIntervalTime = 10; // 10 secs.
91 // Timeout for waiting for a response to a ping.
92 const int kPingTimeoutTime = 30; // 30 secs.
94 const char kClaimClientsStateErrorMesage[] =
95 "Only the active worker can claim clients.";
97 const char kClaimClientsShutdownErrorMesage[] =
98 "Failed to claim clients due to Service Worker system shutdown.";
100 void RunSoon(const base::Closure& callback) {
101 if (!callback.is_null())
102 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
105 template <typename CallbackArray, typename Arg>
106 void RunCallbacks(ServiceWorkerVersion* version,
107 CallbackArray* callbacks_ptr,
108 const Arg& arg) {
109 CallbackArray callbacks;
110 callbacks.swap(*callbacks_ptr);
111 scoped_refptr<ServiceWorkerVersion> protect(version);
112 for (const auto& callback : callbacks)
113 callback.Run(arg);
116 template <typename IDMAP, typename... Params>
117 void RunIDMapCallbacks(IDMAP* callbacks, const Params&... params) {
118 typename IDMAP::iterator iter(callbacks);
119 while (!iter.IsAtEnd()) {
120 iter.GetCurrentValue()->Run(params...);
121 iter.Advance();
123 callbacks->Clear();
126 // A callback adapter to start a |task| after StartWorker.
127 void RunTaskAfterStartWorker(
128 base::WeakPtr<ServiceWorkerVersion> version,
129 const StatusCallback& error_callback,
130 const base::Closure& task,
131 ServiceWorkerStatusCode status) {
132 if (status != SERVICE_WORKER_OK) {
133 if (!error_callback.is_null())
134 error_callback.Run(status);
135 return;
137 if (version->running_status() != ServiceWorkerVersion::RUNNING) {
138 // We've tried to start the worker (and it has succeeded), but
139 // it looks it's not running yet.
140 NOTREACHED() << "The worker's not running after successful StartWorker";
141 if (!error_callback.is_null())
142 error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
143 return;
145 task.Run();
148 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
149 ServiceWorkerStatusCode status) {
150 callback.Run(status,
151 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
152 ServiceWorkerResponse());
155 void RunErrorMessageCallback(
156 const std::vector<TransferredMessagePort>& sent_message_ports,
157 const ServiceWorkerVersion::StatusCallback& callback,
158 ServiceWorkerStatusCode status) {
159 // Transfering the message ports failed, so destroy the ports.
160 for (const TransferredMessagePort& port : sent_message_ports) {
161 MessagePortService::GetInstance()->ClosePort(port.id);
163 callback.Run(status);
166 void RunErrorCrossOriginConnectCallback(
167 const ServiceWorkerVersion::CrossOriginConnectCallback& callback,
168 ServiceWorkerStatusCode status) {
169 callback.Run(status, false);
172 using WindowOpenedCallback = base::Callback<void(int, int)>;
174 // The WindowOpenedObserver class is a WebContentsObserver that will wait for a
175 // new Window's WebContents to be initialized, run the |callback| passed to its
176 // constructor then self destroy.
177 // The callback will receive the process and frame ids. If something went wrong
178 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
179 // The callback will be called in the IO thread.
180 class WindowOpenedObserver : public WebContentsObserver {
181 public:
182 WindowOpenedObserver(WebContents* web_contents,
183 const WindowOpenedCallback& callback)
184 : WebContentsObserver(web_contents),
185 callback_(callback)
188 void DidCommitProvisionalLoadForFrame(
189 RenderFrameHost* render_frame_host,
190 const GURL& validated_url,
191 ui::PageTransition transition_type) override {
192 DCHECK(web_contents());
194 if (render_frame_host != web_contents()->GetMainFrame())
195 return;
197 RunCallback(render_frame_host->GetProcess()->GetID(),
198 render_frame_host->GetRoutingID());
201 void RenderProcessGone(base::TerminationStatus status) override {
202 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
205 void WebContentsDestroyed() override {
206 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
209 private:
210 void RunCallback(int render_process_id, int render_frame_id) {
211 // After running the callback, |this| will stop observing, thus
212 // web_contents() should return nullptr and |RunCallback| should no longer
213 // be called. Then, |this| will self destroy.
214 DCHECK(web_contents());
216 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
217 base::Bind(callback_,
218 render_process_id,
219 render_frame_id));
220 Observe(nullptr);
221 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
224 const WindowOpenedCallback callback_;
226 DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver);
229 void DidOpenURL(const WindowOpenedCallback& callback,
230 WebContents* web_contents) {
231 DCHECK(web_contents);
233 new WindowOpenedObserver(web_contents, callback);
236 void OpenWindowOnUI(
237 const GURL& url,
238 const GURL& script_url,
239 int process_id,
240 const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper,
241 const WindowOpenedCallback& callback) {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI);
244 BrowserContext* browser_context = context_wrapper->storage_partition()
245 ? context_wrapper->storage_partition()->browser_context()
246 : nullptr;
247 // We are shutting down.
248 if (!browser_context)
249 return;
251 RenderProcessHost* render_process_host =
252 RenderProcessHost::FromID(process_id);
253 if (render_process_host->IsIsolatedGuest()) {
254 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
255 base::Bind(callback,
256 ChildProcessHost::kInvalidUniqueID,
257 MSG_ROUTING_NONE));
258 return;
261 OpenURLParams params(
262 url, Referrer::SanitizeForRequest(
263 url, Referrer(script_url, blink::WebReferrerPolicyDefault)),
264 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
265 true /* is_renderer_initiated */);
267 GetContentClient()->browser()->OpenURL(
268 browser_context, params,
269 base::Bind(&DidOpenURL, callback));
272 void KillEmbeddedWorkerProcess(int process_id, ResultCode code) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI);
275 RenderProcessHost* render_process_host =
276 RenderProcessHost::FromID(process_id);
277 if (render_process_host->GetHandle() != base::kNullProcessHandle)
278 render_process_host->ReceivedBadMessage();
281 } // namespace
283 ServiceWorkerVersion::ServiceWorkerVersion(
284 ServiceWorkerRegistration* registration,
285 const GURL& script_url,
286 int64 version_id,
287 base::WeakPtr<ServiceWorkerContextCore> context)
288 : version_id_(version_id),
289 registration_id_(kInvalidServiceWorkerVersionId),
290 script_url_(script_url),
291 status_(NEW),
292 context_(context),
293 script_cache_map_(this, context),
294 ping_timed_out_(false),
295 is_doomed_(false),
296 skip_waiting_(false),
297 weak_factory_(this) {
298 DCHECK(context_);
299 DCHECK(registration);
300 if (registration) {
301 registration_id_ = registration->id();
302 scope_ = registration->pattern();
304 context_->AddLiveVersion(this);
305 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
306 embedded_worker_->AddListener(this);
309 ServiceWorkerVersion::~ServiceWorkerVersion() {
310 embedded_worker_->RemoveListener(this);
311 if (context_)
312 context_->RemoveLiveVersion(version_id_);
313 // EmbeddedWorker's dtor sends StopWorker if it's still running.
316 void ServiceWorkerVersion::SetStatus(Status status) {
317 if (status_ == status)
318 return;
320 status_ = status;
322 if (skip_waiting_ && status_ == ACTIVATED) {
323 for (int request_id : pending_skip_waiting_requests_)
324 DidSkipWaiting(request_id);
325 pending_skip_waiting_requests_.clear();
328 std::vector<base::Closure> callbacks;
329 callbacks.swap(status_change_callbacks_);
330 for (const auto& callback : callbacks)
331 callback.Run();
333 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
336 void ServiceWorkerVersion::RegisterStatusChangeCallback(
337 const base::Closure& callback) {
338 status_change_callbacks_.push_back(callback);
341 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
342 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
343 return ServiceWorkerVersionInfo(
344 running_status(),
345 status(),
346 script_url(),
347 version_id(),
348 embedded_worker()->process_id(),
349 embedded_worker()->thread_id(),
350 embedded_worker()->worker_devtools_agent_route_id());
353 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
354 StartWorker(false, callback);
357 void ServiceWorkerVersion::StartWorker(
358 bool pause_after_download,
359 const StatusCallback& callback) {
360 if (is_doomed()) {
361 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
362 return;
364 switch (running_status()) {
365 case RUNNING:
366 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
367 return;
368 case STOPPING:
369 case STOPPED:
370 case STARTING:
371 start_callbacks_.push_back(callback);
372 if (running_status() == STOPPED) {
373 DCHECK(!cache_listener_.get());
374 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
375 embedded_worker_->Start(
376 version_id_,
377 scope_,
378 script_url_,
379 pause_after_download,
380 base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
381 weak_factory_.GetWeakPtr()));
383 return;
387 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
388 if (running_status() == STOPPED) {
389 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
390 return;
392 if (stop_callbacks_.empty()) {
393 ServiceWorkerStatusCode status = embedded_worker_->Stop();
394 if (status != SERVICE_WORKER_OK) {
395 RunSoon(base::Bind(callback, status));
396 return;
399 stop_callbacks_.push_back(callback);
402 void ServiceWorkerVersion::ScheduleUpdate() {
403 if (update_timer_.IsRunning()) {
404 update_timer_.Reset();
405 return;
407 update_timer_.Start(
408 FROM_HERE, base::TimeDelta::FromSeconds(kUpdateDelaySeconds),
409 base::Bind(&ServiceWorkerVersion::StartUpdate,
410 weak_factory_.GetWeakPtr()));
413 void ServiceWorkerVersion::DeferScheduledUpdate() {
414 if (update_timer_.IsRunning())
415 update_timer_.Reset();
418 void ServiceWorkerVersion::StartUpdate() {
419 update_timer_.Stop();
420 if (!context_)
421 return;
422 ServiceWorkerRegistration* registration =
423 context_->GetLiveRegistration(registration_id_);
424 if (!registration || !registration->GetNewestVersion())
425 return;
426 context_->UpdateServiceWorker(registration);
429 void ServiceWorkerVersion::DispatchMessageEvent(
430 const base::string16& message,
431 const std::vector<TransferredMessagePort>& sent_message_ports,
432 const StatusCallback& callback) {
433 for (const TransferredMessagePort& port : sent_message_ports) {
434 MessagePortService::GetInstance()->HoldMessages(port.id);
437 DispatchMessageEventInternal(message, sent_message_ports, callback);
440 void ServiceWorkerVersion::DispatchMessageEventInternal(
441 const base::string16& message,
442 const std::vector<TransferredMessagePort>& sent_message_ports,
443 const StatusCallback& callback) {
444 if (running_status() != RUNNING) {
445 // Schedule calling this method after starting the worker.
446 StartWorker(base::Bind(
447 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
448 base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
449 base::Bind(&self::DispatchMessageEventInternal,
450 weak_factory_.GetWeakPtr(), message, sent_message_ports,
451 callback)));
452 return;
455 MessagePortMessageFilter* filter =
456 embedded_worker_->message_port_message_filter();
457 std::vector<int> new_routing_ids;
458 filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
459 ServiceWorkerStatusCode status =
460 embedded_worker_->SendMessage(ServiceWorkerMsg_MessageToWorker(
461 message, sent_message_ports, new_routing_ids));
462 RunSoon(base::Bind(callback, status));
465 void ServiceWorkerVersion::DispatchInstallEvent(
466 int active_version_id,
467 const StatusCallback& callback) {
468 DCHECK_EQ(INSTALLING, status()) << status();
470 if (running_status() != RUNNING) {
471 // Schedule calling this method after starting the worker.
472 StartWorker(
473 base::Bind(&RunTaskAfterStartWorker,
474 weak_factory_.GetWeakPtr(),
475 callback,
476 base::Bind(&self::DispatchInstallEventAfterStartWorker,
477 weak_factory_.GetWeakPtr(),
478 active_version_id,
479 callback)));
480 } else {
481 DispatchInstallEventAfterStartWorker(active_version_id, callback);
485 void ServiceWorkerVersion::DispatchActivateEvent(
486 const StatusCallback& callback) {
487 DCHECK_EQ(ACTIVATING, status()) << status();
489 if (running_status() != RUNNING) {
490 // Schedule calling this method after starting the worker.
491 StartWorker(
492 base::Bind(&RunTaskAfterStartWorker,
493 weak_factory_.GetWeakPtr(),
494 callback,
495 base::Bind(&self::DispatchActivateEventAfterStartWorker,
496 weak_factory_.GetWeakPtr(),
497 callback)));
498 } else {
499 DispatchActivateEventAfterStartWorker(callback);
503 void ServiceWorkerVersion::DispatchFetchEvent(
504 const ServiceWorkerFetchRequest& request,
505 const base::Closure& prepare_callback,
506 const FetchCallback& fetch_callback) {
507 DCHECK_EQ(ACTIVATED, status()) << status();
509 if (running_status() != RUNNING) {
510 // Schedule calling this method after starting the worker.
511 StartWorker(base::Bind(&RunTaskAfterStartWorker,
512 weak_factory_.GetWeakPtr(),
513 base::Bind(&RunErrorFetchCallback, fetch_callback),
514 base::Bind(&self::DispatchFetchEvent,
515 weak_factory_.GetWeakPtr(),
516 request,
517 prepare_callback,
518 fetch_callback)));
519 return;
522 prepare_callback.Run();
524 int request_id = fetch_callbacks_.Add(new FetchCallback(fetch_callback));
525 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
526 ServiceWorkerMsg_FetchEvent(request_id, request));
527 if (status != SERVICE_WORKER_OK) {
528 fetch_callbacks_.Remove(request_id);
529 RunSoon(base::Bind(&RunErrorFetchCallback,
530 fetch_callback,
531 SERVICE_WORKER_ERROR_FAILED));
535 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
536 DCHECK_EQ(ACTIVATED, status()) << status();
538 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
539 switches::kEnableServiceWorkerSync)) {
540 callback.Run(SERVICE_WORKER_ERROR_ABORT);
541 return;
544 if (running_status() != RUNNING) {
545 // Schedule calling this method after starting the worker.
546 StartWorker(base::Bind(&RunTaskAfterStartWorker,
547 weak_factory_.GetWeakPtr(), callback,
548 base::Bind(&self::DispatchSyncEvent,
549 weak_factory_.GetWeakPtr(),
550 callback)));
551 return;
554 int request_id = sync_callbacks_.Add(new StatusCallback(callback));
555 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
556 ServiceWorkerMsg_SyncEvent(request_id));
557 if (status != SERVICE_WORKER_OK) {
558 sync_callbacks_.Remove(request_id);
559 RunSoon(base::Bind(callback, status));
563 void ServiceWorkerVersion::DispatchNotificationClickEvent(
564 const StatusCallback& callback,
565 const std::string& notification_id,
566 const PlatformNotificationData& notification_data) {
567 DCHECK_EQ(ACTIVATED, status()) << status();
568 if (running_status() != RUNNING) {
569 // Schedule calling this method after starting the worker.
570 StartWorker(base::Bind(&RunTaskAfterStartWorker,
571 weak_factory_.GetWeakPtr(), callback,
572 base::Bind(&self::DispatchNotificationClickEvent,
573 weak_factory_.GetWeakPtr(),
574 callback, notification_id,
575 notification_data)));
576 return;
579 int request_id =
580 notification_click_callbacks_.Add(new StatusCallback(callback));
581 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
582 ServiceWorkerMsg_NotificationClickEvent(request_id,
583 notification_id,
584 notification_data));
585 if (status != SERVICE_WORKER_OK) {
586 notification_click_callbacks_.Remove(request_id);
587 RunSoon(base::Bind(callback, status));
591 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
592 const std::string& data) {
593 DCHECK_EQ(ACTIVATED, status()) << status();
594 if (running_status() != RUNNING) {
595 // Schedule calling this method after starting the worker.
596 StartWorker(base::Bind(&RunTaskAfterStartWorker,
597 weak_factory_.GetWeakPtr(), callback,
598 base::Bind(&self::DispatchPushEvent,
599 weak_factory_.GetWeakPtr(),
600 callback, data)));
601 return;
604 int request_id = push_callbacks_.Add(new StatusCallback(callback));
605 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
606 ServiceWorkerMsg_PushEvent(request_id, data));
607 if (status != SERVICE_WORKER_OK) {
608 push_callbacks_.Remove(request_id);
609 RunSoon(base::Bind(callback, status));
613 void ServiceWorkerVersion::DispatchGeofencingEvent(
614 const StatusCallback& callback,
615 blink::WebGeofencingEventType event_type,
616 const std::string& region_id,
617 const blink::WebCircularGeofencingRegion& region) {
618 DCHECK_EQ(ACTIVATED, status()) << status();
620 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
621 switches::kEnableExperimentalWebPlatformFeatures)) {
622 callback.Run(SERVICE_WORKER_ERROR_ABORT);
623 return;
626 if (running_status() != RUNNING) {
627 // Schedule calling this method after starting the worker.
628 StartWorker(base::Bind(&RunTaskAfterStartWorker,
629 weak_factory_.GetWeakPtr(),
630 callback,
631 base::Bind(&self::DispatchGeofencingEvent,
632 weak_factory_.GetWeakPtr(),
633 callback,
634 event_type,
635 region_id,
636 region)));
637 return;
640 int request_id = geofencing_callbacks_.Add(new StatusCallback(callback));
641 ServiceWorkerStatusCode status =
642 embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
643 request_id, event_type, region_id, region));
644 if (status != SERVICE_WORKER_OK) {
645 geofencing_callbacks_.Remove(request_id);
646 RunSoon(base::Bind(callback, status));
650 void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
651 const CrossOriginConnectCallback& callback,
652 const NavigatorConnectClient& client) {
653 DCHECK_EQ(ACTIVATED, status()) << status();
655 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
656 switches::kEnableExperimentalWebPlatformFeatures)) {
657 callback.Run(SERVICE_WORKER_ERROR_ABORT, false);
658 return;
661 if (running_status() != RUNNING) {
662 // Schedule calling this method after starting the worker.
663 StartWorker(
664 base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
665 base::Bind(&RunErrorCrossOriginConnectCallback, callback),
666 base::Bind(&self::DispatchCrossOriginConnectEvent,
667 weak_factory_.GetWeakPtr(), callback, client)));
668 return;
671 int request_id = cross_origin_connect_callbacks_.Add(
672 new CrossOriginConnectCallback(callback));
673 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
674 ServiceWorkerMsg_CrossOriginConnectEvent(request_id, client));
675 if (status != SERVICE_WORKER_OK) {
676 cross_origin_connect_callbacks_.Remove(request_id);
677 RunSoon(base::Bind(callback, status, false));
681 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
682 const NavigatorConnectClient& client,
683 const base::string16& message,
684 const std::vector<TransferredMessagePort>& sent_message_ports,
685 const StatusCallback& callback) {
686 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
687 // have already put all the sent message ports on hold. So no need to do that
688 // here again.
690 if (running_status() != RUNNING) {
691 // Schedule calling this method after starting the worker.
692 StartWorker(base::Bind(
693 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
694 base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
695 base::Bind(&self::DispatchCrossOriginMessageEvent,
696 weak_factory_.GetWeakPtr(), client, message,
697 sent_message_ports, callback)));
698 return;
701 MessagePortMessageFilter* filter =
702 embedded_worker_->message_port_message_filter();
703 std::vector<int> new_routing_ids;
704 filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
705 ServiceWorkerStatusCode status =
706 embedded_worker_->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
707 client, message, sent_message_ports, new_routing_ids));
708 RunSoon(base::Bind(callback, status));
711 void ServiceWorkerVersion::AddControllee(
712 ServiceWorkerProviderHost* provider_host) {
713 DCHECK(!ContainsKey(controllee_map_, provider_host));
714 int controllee_id = controllee_by_id_.Add(provider_host);
715 // IDMap<>'s last index is kInvalidServiceWorkerClientId.
716 CHECK(controllee_id != kInvalidServiceWorkerClientId);
717 controllee_map_[provider_host] = controllee_id;
718 // Reset the timer if it's running (so that it's kept alive a bit longer
719 // right after a new controllee is added).
720 ScheduleStopWorker();
723 void ServiceWorkerVersion::RemoveControllee(
724 ServiceWorkerProviderHost* provider_host) {
725 ControlleeMap::iterator found = controllee_map_.find(provider_host);
726 DCHECK(found != controllee_map_.end());
727 controllee_by_id_.Remove(found->second);
728 controllee_map_.erase(found);
729 if (HasControllee())
730 return;
731 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
732 if (is_doomed_) {
733 DoomInternal();
734 return;
736 // Schedule the stop-worker-timer if it's not running.
737 if (!stop_worker_timer_.IsRunning())
738 ScheduleStopWorker();
741 void ServiceWorkerVersion::AddStreamingURLRequestJob(
742 const ServiceWorkerURLRequestJob* request_job) {
743 DCHECK(streaming_url_request_jobs_.find(request_job) ==
744 streaming_url_request_jobs_.end());
745 streaming_url_request_jobs_.insert(request_job);
748 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
749 const ServiceWorkerURLRequestJob* request_job) {
750 streaming_url_request_jobs_.erase(request_job);
751 if (is_doomed_)
752 StopWorkerIfIdle();
755 void ServiceWorkerVersion::AddListener(Listener* listener) {
756 listeners_.AddObserver(listener);
759 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
760 listeners_.RemoveObserver(listener);
763 void ServiceWorkerVersion::Doom() {
764 if (is_doomed_)
765 return;
766 is_doomed_ = true;
767 if (!HasControllee())
768 DoomInternal();
771 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
772 embedded_worker()->set_devtools_attached(attached);
773 if (attached)
774 return;
775 // If devtools is detached try scheduling the timers for stopping the worker
776 // now.
777 if (!stop_worker_timer_.IsRunning())
778 ScheduleStopWorker();
779 if (!ping_worker_timer_.IsRunning())
780 StartPingWorker();
783 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
784 const net::HttpResponseInfo& http_info) {
785 main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
788 const net::HttpResponseInfo*
789 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
790 return main_script_http_info_.get();
793 void ServiceWorkerVersion::OnScriptLoaded() {
794 DCHECK_EQ(STARTING, running_status());
795 StartPingWorker();
798 void ServiceWorkerVersion::OnStarted() {
799 DCHECK_EQ(RUNNING, running_status());
800 DCHECK(cache_listener_.get());
801 ScheduleStopWorker();
803 // Fire all start callbacks.
804 scoped_refptr<ServiceWorkerVersion> protect(this);
805 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
806 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this));
809 void ServiceWorkerVersion::OnStopped(
810 EmbeddedWorkerInstance::Status old_status) {
811 DCHECK_EQ(STOPPED, running_status());
812 scoped_refptr<ServiceWorkerVersion> protect(this);
814 bool should_restart = !is_doomed() && !start_callbacks_.empty() &&
815 (old_status != EmbeddedWorkerInstance::STARTING);
817 ping_worker_timer_.Stop();
818 if (ping_timed_out_)
819 should_restart = false;
821 // Fire all stop callbacks.
822 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
824 if (!should_restart) {
825 // Let all start callbacks fail.
826 RunCallbacks(this, &start_callbacks_,
827 SERVICE_WORKER_ERROR_START_WORKER_FAILED);
830 // Let all message callbacks fail (this will also fire and clear all
831 // callbacks for events).
832 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
833 RunIDMapCallbacks(&activate_callbacks_,
834 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
835 RunIDMapCallbacks(&install_callbacks_,
836 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
837 RunIDMapCallbacks(&fetch_callbacks_,
838 SERVICE_WORKER_ERROR_FAILED,
839 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
840 ServiceWorkerResponse());
841 RunIDMapCallbacks(&sync_callbacks_,
842 SERVICE_WORKER_ERROR_FAILED);
843 RunIDMapCallbacks(&notification_click_callbacks_,
844 SERVICE_WORKER_ERROR_FAILED);
845 RunIDMapCallbacks(&push_callbacks_,
846 SERVICE_WORKER_ERROR_FAILED);
847 RunIDMapCallbacks(&geofencing_callbacks_,
848 SERVICE_WORKER_ERROR_FAILED);
849 RunIDMapCallbacks(&cross_origin_connect_callbacks_,
850 SERVICE_WORKER_ERROR_FAILED,
851 false);
853 streaming_url_request_jobs_.clear();
855 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
857 // There should be no more communication from/to a stopped worker. Deleting
858 // the listener prevents any pending completion callbacks from causing
859 // messages to be sent to the stopped worker.
860 cache_listener_.reset();
862 // Restart worker if we have any start callbacks and the worker isn't doomed.
863 if (should_restart) {
864 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
865 embedded_worker_->Start(
866 version_id_, scope_, script_url_, false /* pause_after_download */,
867 base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
868 weak_factory_.GetWeakPtr()));
872 void ServiceWorkerVersion::OnReportException(
873 const base::string16& error_message,
874 int line_number,
875 int column_number,
876 const GURL& source_url) {
877 FOR_EACH_OBSERVER(
878 Listener,
879 listeners_,
880 OnErrorReported(
881 this, error_message, line_number, column_number, source_url));
884 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
885 int message_level,
886 const base::string16& message,
887 int line_number,
888 const GURL& source_url) {
889 FOR_EACH_OBSERVER(Listener,
890 listeners_,
891 OnReportConsoleMessage(this,
892 source_identifier,
893 message_level,
894 message,
895 line_number,
896 source_url));
899 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
900 bool handled = true;
901 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
902 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClientDocuments,
903 OnGetClientDocuments)
904 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
905 OnActivateEventFinished)
906 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
907 OnInstallEventFinished)
908 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
909 OnFetchEventFinished)
910 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
911 OnSyncEventFinished)
912 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished,
913 OnNotificationClickEventFinished)
914 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
915 OnPushEventFinished)
916 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
917 OnGeofencingEventFinished)
918 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished,
919 OnCrossOriginConnectEventFinished)
920 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
921 OnOpenWindow)
922 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata,
923 OnSetCachedMetadata)
924 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata,
925 OnClearCachedMetadata)
926 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
927 OnPostMessageToDocument)
928 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient,
929 OnFocusClient)
930 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
931 OnSkipWaiting)
932 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
933 OnClaimClients)
934 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
935 IPC_MESSAGE_UNHANDLED(handled = false)
936 IPC_END_MESSAGE_MAP()
937 return handled;
940 void ServiceWorkerVersion::OnStartMessageSent(
941 ServiceWorkerStatusCode status) {
942 if (status != SERVICE_WORKER_OK)
943 RunCallbacks(this, &start_callbacks_, status);
946 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
947 int active_version_id,
948 const StatusCallback& callback) {
949 DCHECK_EQ(RUNNING, running_status())
950 << "Worker stopped too soon after it was started.";
952 int request_id = install_callbacks_.Add(new StatusCallback(callback));
953 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
954 ServiceWorkerMsg_InstallEvent(request_id, active_version_id));
955 if (status != SERVICE_WORKER_OK) {
956 install_callbacks_.Remove(request_id);
957 RunSoon(base::Bind(callback, status));
961 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
962 const StatusCallback& callback) {
963 DCHECK_EQ(RUNNING, running_status())
964 << "Worker stopped too soon after it was started.";
966 int request_id = activate_callbacks_.Add(new StatusCallback(callback));
967 ServiceWorkerStatusCode status =
968 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
969 if (status != SERVICE_WORKER_OK) {
970 activate_callbacks_.Remove(request_id);
971 RunSoon(base::Bind(callback, status));
975 void ServiceWorkerVersion::OnGetClientDocuments(int request_id) {
976 if (controllee_by_id_.IsEmpty()) {
977 if (running_status() == RUNNING) {
978 embedded_worker_->SendMessage(
979 ServiceWorkerMsg_DidGetClientDocuments(request_id,
980 std::vector<ServiceWorkerClientInfo>()));
982 return;
984 scoped_refptr<GetClientDocumentsCallback> callback(
985 new GetClientDocumentsCallback(request_id, this));
986 ControlleeByIDMap::iterator it(&controllee_by_id_);
987 TRACE_EVENT0("ServiceWorker",
988 "ServiceWorkerVersion::OnGetClientDocuments");
989 while (!it.IsAtEnd()) {
990 // TODO(mlamouri): we could coalesce those requests into one.
991 it.GetCurrentValue()->GetClientInfo(
992 base::Bind(&ServiceWorkerVersion::DidGetClientInfo,
993 weak_factory_.GetWeakPtr(), it.GetCurrentKey(), callback));
994 it.Advance();
998 void ServiceWorkerVersion::OnActivateEventFinished(
999 int request_id,
1000 blink::WebServiceWorkerEventResult result) {
1001 DCHECK(ACTIVATING == status() ||
1002 REDUNDANT == status()) << status();
1003 TRACE_EVENT0("ServiceWorker",
1004 "ServiceWorkerVersion::OnActivateEventFinished");
1006 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
1007 if (!callback) {
1008 NOTREACHED() << "Got unexpected message: " << request_id;
1009 return;
1011 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
1012 if (result == blink::WebServiceWorkerEventResultRejected ||
1013 status() != ACTIVATING) {
1014 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
1017 scoped_refptr<ServiceWorkerVersion> protect(this);
1018 callback->Run(rv);
1019 RemoveCallbackAndStopIfDoomed(&activate_callbacks_, request_id);
1022 void ServiceWorkerVersion::OnInstallEventFinished(
1023 int request_id,
1024 blink::WebServiceWorkerEventResult result) {
1025 // Status is REDUNDANT if the worker was doomed while handling the install
1026 // event, and finished handling before being terminated.
1027 DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
1028 TRACE_EVENT0("ServiceWorker",
1029 "ServiceWorkerVersion::OnInstallEventFinished");
1031 StatusCallback* callback = install_callbacks_.Lookup(request_id);
1032 if (!callback) {
1033 NOTREACHED() << "Got unexpected message: " << request_id;
1034 return;
1036 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1037 if (result == blink::WebServiceWorkerEventResultRejected)
1038 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
1040 scoped_refptr<ServiceWorkerVersion> protect(this);
1041 callback->Run(status);
1042 RemoveCallbackAndStopIfDoomed(&install_callbacks_, request_id);
1045 void ServiceWorkerVersion::OnFetchEventFinished(
1046 int request_id,
1047 ServiceWorkerFetchEventResult result,
1048 const ServiceWorkerResponse& response) {
1049 TRACE_EVENT1("ServiceWorker",
1050 "ServiceWorkerVersion::OnFetchEventFinished",
1051 "Request id", request_id);
1052 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
1053 if (!callback) {
1054 NOTREACHED() << "Got unexpected message: " << request_id;
1055 return;
1058 scoped_refptr<ServiceWorkerVersion> protect(this);
1059 callback->Run(SERVICE_WORKER_OK, result, response);
1060 RemoveCallbackAndStopIfDoomed(&fetch_callbacks_, request_id);
1063 void ServiceWorkerVersion::OnSyncEventFinished(
1064 int request_id) {
1065 TRACE_EVENT1("ServiceWorker",
1066 "ServiceWorkerVersion::OnSyncEventFinished",
1067 "Request id", request_id);
1068 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
1069 if (!callback) {
1070 NOTREACHED() << "Got unexpected message: " << request_id;
1071 return;
1074 scoped_refptr<ServiceWorkerVersion> protect(this);
1075 callback->Run(SERVICE_WORKER_OK);
1076 RemoveCallbackAndStopIfDoomed(&sync_callbacks_, request_id);
1079 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1080 int request_id) {
1081 TRACE_EVENT1("ServiceWorker",
1082 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1083 "Request id", request_id);
1084 StatusCallback* callback = notification_click_callbacks_.Lookup(request_id);
1085 if (!callback) {
1086 NOTREACHED() << "Got unexpected message: " << request_id;
1087 return;
1090 scoped_refptr<ServiceWorkerVersion> protect(this);
1091 callback->Run(SERVICE_WORKER_OK);
1092 RemoveCallbackAndStopIfDoomed(&notification_click_callbacks_, request_id);
1095 void ServiceWorkerVersion::OnPushEventFinished(
1096 int request_id,
1097 blink::WebServiceWorkerEventResult result) {
1098 TRACE_EVENT1("ServiceWorker",
1099 "ServiceWorkerVersion::OnPushEventFinished",
1100 "Request id", request_id);
1101 StatusCallback* callback = push_callbacks_.Lookup(request_id);
1102 if (!callback) {
1103 NOTREACHED() << "Got unexpected message: " << request_id;
1104 return;
1106 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1107 if (result == blink::WebServiceWorkerEventResultRejected)
1108 status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
1110 scoped_refptr<ServiceWorkerVersion> protect(this);
1111 callback->Run(status);
1112 RemoveCallbackAndStopIfDoomed(&push_callbacks_, request_id);
1115 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
1116 TRACE_EVENT1("ServiceWorker",
1117 "ServiceWorkerVersion::OnGeofencingEventFinished",
1118 "Request id",
1119 request_id);
1120 StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
1121 if (!callback) {
1122 NOTREACHED() << "Got unexpected message: " << request_id;
1123 return;
1126 scoped_refptr<ServiceWorkerVersion> protect(this);
1127 callback->Run(SERVICE_WORKER_OK);
1128 RemoveCallbackAndStopIfDoomed(&geofencing_callbacks_, request_id);
1131 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1132 int request_id,
1133 bool accept_connection) {
1134 TRACE_EVENT1("ServiceWorker",
1135 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1136 "Request id", request_id);
1137 CrossOriginConnectCallback* callback =
1138 cross_origin_connect_callbacks_.Lookup(request_id);
1139 if (!callback) {
1140 NOTREACHED() << "Got unexpected message: " << request_id;
1141 return;
1144 scoped_refptr<ServiceWorkerVersion> protect(this);
1145 callback->Run(SERVICE_WORKER_OK, accept_connection);
1146 RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_, request_id);
1149 void ServiceWorkerVersion::OnOpenWindow(int request_id, const GURL& url) {
1150 // Just abort if we are shutting down.
1151 if (!context_)
1152 return;
1154 if (url.GetOrigin() != script_url_.GetOrigin()) {
1155 // There should be a same origin check by Blink, if the request is still not
1156 // same origin, the process might be compromised and should be eliminated.
1157 DVLOG(1) << "Received a cross origin openWindow() request from a service "
1158 "worker. Killing associated process.";
1159 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1160 base::Bind(&KillEmbeddedWorkerProcess,
1161 embedded_worker_->process_id(),
1162 RESULT_CODE_KILLED_BAD_MESSAGE));
1163 return;
1166 BrowserThread::PostTask(
1167 BrowserThread::UI, FROM_HERE,
1168 base::Bind(&OpenWindowOnUI,
1169 url,
1170 script_url_,
1171 embedded_worker_->process_id(),
1172 make_scoped_refptr(context_->wrapper()),
1173 base::Bind(&ServiceWorkerVersion::DidOpenWindow,
1174 weak_factory_.GetWeakPtr(),
1175 request_id)));
1178 void ServiceWorkerVersion::DidOpenWindow(int request_id,
1179 int render_process_id,
1180 int render_frame_id) {
1181 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1183 if (running_status() != RUNNING)
1184 return;
1186 if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
1187 render_frame_id == MSG_ROUTING_NONE) {
1188 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(request_id));
1189 return;
1192 for (const auto& it : controllee_map_) {
1193 const ServiceWorkerProviderHost* provider_host = it.first;
1194 if (provider_host->process_id() != render_process_id ||
1195 provider_host->frame_id() != render_frame_id) {
1196 continue;
1199 // it.second is the client_id associated with the provider_host.
1200 provider_host->GetClientInfo(
1201 base::Bind(&ServiceWorkerVersion::OnOpenWindowFinished,
1202 weak_factory_.GetWeakPtr(), request_id, it.second));
1203 return;
1206 // If here, it means that no provider_host was found, in which case, the
1207 // renderer should still be informed that the window was opened.
1208 OnOpenWindowFinished(request_id, 0, ServiceWorkerClientInfo());
1211 void ServiceWorkerVersion::OnOpenWindowFinished(
1212 int request_id,
1213 int client_id,
1214 const ServiceWorkerClientInfo& client_info) {
1215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1217 if (running_status() != RUNNING)
1218 return;
1220 ServiceWorkerClientInfo client(client_info);
1222 // If the |client_info| is empty, it means that the opened window wasn't
1223 // controlled but the action still succeeded. The renderer process is
1224 // expecting an empty client in such case.
1225 if (!client.IsEmpty())
1226 client.client_id = client_id;
1228 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1229 request_id, client));
1232 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL& url,
1233 const std::vector<char>& data) {
1234 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1235 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1236 "ServiceWorkerVersion::OnSetCachedMetadata",
1237 callback_id, "URL", url.spec());
1238 script_cache_map_.WriteMetadata(
1239 url, data, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
1240 weak_factory_.GetWeakPtr(), callback_id));
1243 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id,
1244 int result) {
1245 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1246 "ServiceWorkerVersion::OnSetCachedMetadata",
1247 callback_id, "result", result);
1248 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1251 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL& url) {
1252 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1253 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1254 "ServiceWorkerVersion::OnClearCachedMetadata",
1255 callback_id, "URL", url.spec());
1256 script_cache_map_.ClearMetadata(
1257 url, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
1258 weak_factory_.GetWeakPtr(), callback_id));
1261 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id,
1262 int result) {
1263 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1264 "ServiceWorkerVersion::OnClearCachedMetadata",
1265 callback_id, "result", result);
1266 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1269 void ServiceWorkerVersion::OnPostMessageToDocument(
1270 int client_id,
1271 const base::string16& message,
1272 const std::vector<TransferredMessagePort>& sent_message_ports) {
1273 TRACE_EVENT1("ServiceWorker",
1274 "ServiceWorkerVersion::OnPostMessageToDocument",
1275 "Client id", client_id);
1276 ServiceWorkerProviderHost* provider_host =
1277 controllee_by_id_.Lookup(client_id);
1278 if (!provider_host) {
1279 // The client may already have been closed, just ignore.
1280 return;
1282 provider_host->PostMessage(message, sent_message_ports);
1285 void ServiceWorkerVersion::OnFocusClient(int request_id, int client_id) {
1286 TRACE_EVENT2("ServiceWorker",
1287 "ServiceWorkerVersion::OnFocusClient",
1288 "Request id", request_id,
1289 "Client id", client_id);
1290 ServiceWorkerProviderHost* provider_host =
1291 controllee_by_id_.Lookup(client_id);
1292 if (!provider_host) {
1293 // The client may already have been closed, just ignore.
1294 return;
1297 provider_host->Focus(
1298 base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
1299 weak_factory_.GetWeakPtr(),
1300 request_id,
1301 client_id));
1304 void ServiceWorkerVersion::OnFocusClientFinished(
1305 int request_id,
1306 int cliend_id,
1307 const ServiceWorkerClientInfo& client) {
1308 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1310 if (running_status() != RUNNING)
1311 return;
1313 ServiceWorkerClientInfo client_info(client);
1314 client_info.client_id = cliend_id;
1316 embedded_worker_->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1317 request_id, client_info));
1320 void ServiceWorkerVersion::OnSkipWaiting(int request_id) {
1321 skip_waiting_ = true;
1322 if (status_ != INSTALLED)
1323 return DidSkipWaiting(request_id);
1325 if (!context_)
1326 return;
1327 ServiceWorkerRegistration* registration =
1328 context_->GetLiveRegistration(registration_id_);
1329 if (!registration)
1330 return;
1331 pending_skip_waiting_requests_.push_back(request_id);
1332 if (pending_skip_waiting_requests_.size() == 1)
1333 registration->ActivateWaitingVersionWhenReady();
1336 void ServiceWorkerVersion::DidSkipWaiting(int request_id) {
1337 if (running_status() == STARTING || running_status() == RUNNING)
1338 embedded_worker_->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id));
1341 void ServiceWorkerVersion::OnClaimClients(int request_id) {
1342 StatusCallback callback = base::Bind(&ServiceWorkerVersion::DidClaimClients,
1343 weak_factory_.GetWeakPtr(), request_id);
1344 if (status_ != ACTIVATING && status_ != ACTIVATED) {
1345 callback.Run(SERVICE_WORKER_ERROR_STATE);
1346 return;
1348 if (!context_) {
1349 callback.Run(SERVICE_WORKER_ERROR_ABORT);
1350 return;
1353 ServiceWorkerRegistration* registration =
1354 context_->GetLiveRegistration(registration_id_);
1355 if (!registration) {
1356 callback.Run(SERVICE_WORKER_ERROR_ABORT);
1357 return;
1359 registration->ClaimClients(callback);
1362 void ServiceWorkerVersion::OnPongFromWorker() {
1363 if (ping_timed_out_)
1364 return;
1365 SchedulePingWorker();
1368 void ServiceWorkerVersion::DidClaimClients(
1369 int request_id, ServiceWorkerStatusCode status) {
1370 if (status == SERVICE_WORKER_ERROR_STATE) {
1371 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1372 request_id, blink::WebServiceWorkerError::ErrorTypeState,
1373 base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
1374 return;
1376 if (status == SERVICE_WORKER_ERROR_ABORT) {
1377 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1378 request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
1379 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage)));
1380 return;
1382 DCHECK(status == SERVICE_WORKER_OK);
1383 embedded_worker_->SendMessage(ServiceWorkerMsg_DidClaimClients(request_id));
1386 void ServiceWorkerVersion::DidGetClientInfo(
1387 int client_id,
1388 scoped_refptr<GetClientDocumentsCallback> callback,
1389 const ServiceWorkerClientInfo& info) {
1390 // If the request to the provider_host returned an empty
1391 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
1392 // it with a valid RenderFrameHost. It might be because the frame was killed
1393 // or navigated in between.
1394 if (info.IsEmpty())
1395 return;
1397 // We can get info for a frame that was navigating end ended up with a
1398 // different URL than expected. In such case, we should make sure to not
1399 // expose cross-origin WindowClient.
1400 if (info.url.GetOrigin() != script_url_.GetOrigin())
1401 return;
1403 callback->AddClientInfo(client_id, info);
1406 void ServiceWorkerVersion::PingWorker() {
1407 if (running_status() != STARTING && running_status() != RUNNING)
1408 return;
1409 ServiceWorkerStatusCode status =
1410 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping());
1411 if (status != SERVICE_WORKER_OK) {
1412 // TODO(falken): Maybe try resending Ping a few times first?
1413 ping_timed_out_ = true;
1414 StopWorkerIfIdle();
1415 return;
1417 ping_worker_timer_.Start(FROM_HERE,
1418 base::TimeDelta::FromSeconds(kPingTimeoutTime),
1419 base::Bind(&ServiceWorkerVersion::OnPingTimeout,
1420 weak_factory_.GetWeakPtr()));
1423 void ServiceWorkerVersion::StartPingWorker() {
1424 ping_timed_out_ = false;
1425 SchedulePingWorker();
1428 void ServiceWorkerVersion::SchedulePingWorker() {
1429 DCHECK(!ping_timed_out_);
1430 ping_worker_timer_.Stop();
1431 ping_worker_timer_.Start(FROM_HERE,
1432 base::TimeDelta::FromSeconds(kPingIntervalTime),
1433 base::Bind(&ServiceWorkerVersion::PingWorker,
1434 weak_factory_.GetWeakPtr()));
1437 void ServiceWorkerVersion::OnPingTimeout() {
1438 if (running_status() != STARTING && running_status() != RUNNING)
1439 return;
1440 ping_timed_out_ = true;
1441 // TODO(falken): Show a message to the developer that the SW was stopped due
1442 // to timeout (crbug.com/457968).
1443 StopWorkerIfIdle();
1446 void ServiceWorkerVersion::ScheduleStopWorker() {
1447 if (running_status() != RUNNING)
1448 return;
1449 stop_worker_timer_.Stop();
1450 stop_worker_timer_.Start(
1451 FROM_HERE, base::TimeDelta::FromSeconds(
1452 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay),
1453 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle,
1454 weak_factory_.GetWeakPtr()));
1457 void ServiceWorkerVersion::StopWorkerIfIdle() {
1458 if (HasInflightRequests() && !ping_timed_out_) {
1459 ScheduleStopWorker();
1460 return;
1462 if (running_status() == STOPPED || running_status() == STOPPING ||
1463 !stop_callbacks_.empty()) {
1464 return;
1467 // TODO(falken): We may need to handle StopIfIdle failure and
1468 // forcibly fail pending callbacks so no one is stuck waiting
1469 // for the worker.
1470 embedded_worker_->StopIfIdle();
1473 bool ServiceWorkerVersion::HasInflightRequests() const {
1474 return
1475 !activate_callbacks_.IsEmpty() ||
1476 !install_callbacks_.IsEmpty() ||
1477 !fetch_callbacks_.IsEmpty() ||
1478 !sync_callbacks_.IsEmpty() ||
1479 !notification_click_callbacks_.IsEmpty() ||
1480 !push_callbacks_.IsEmpty() ||
1481 !geofencing_callbacks_.IsEmpty() ||
1482 !cross_origin_connect_callbacks_.IsEmpty() ||
1483 !streaming_url_request_jobs_.empty();
1486 void ServiceWorkerVersion::DoomInternal() {
1487 DCHECK(is_doomed_);
1488 DCHECK(!HasControllee());
1489 SetStatus(REDUNDANT);
1490 StopWorkerIfIdle();
1491 if (!context_)
1492 return;
1493 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
1494 script_cache_map_.GetResources(&resources);
1495 context_->storage()->PurgeResources(resources);
1498 template <typename IDMAP>
1499 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1500 IDMAP* callbacks,
1501 int request_id) {
1502 callbacks->Remove(request_id);
1503 if (is_doomed_) {
1504 // The stop should be already scheduled, but try to stop immediately, in
1505 // order to release worker resources soon.
1506 StopWorkerIfIdle();
1510 } // namespace content