Simplify ChildProcessLauncher
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_version.cc
blob98590e007ff616bc609461001276996baf621f5c
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/metrics/histogram_macros.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "content/browser/bad_message.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/message_port_message_filter.h"
17 #include "content/browser/message_port_service.h"
18 #include "content/browser/service_worker/embedded_worker_instance.h"
19 #include "content/browser/service_worker/embedded_worker_registry.h"
20 #include "content/browser/service_worker/service_worker_context_core.h"
21 #include "content/browser/service_worker/service_worker_context_wrapper.h"
22 #include "content/browser/service_worker/service_worker_registration.h"
23 #include "content/browser/service_worker/service_worker_utils.h"
24 #include "content/browser/storage_partition_impl.h"
25 #include "content/common/service_worker/service_worker_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/content_browser_client.h"
28 #include "content/public/browser/page_navigator.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_observer.h"
33 #include "content/public/common/child_process_host.h"
34 #include "content/public/common/content_client.h"
35 #include "content/public/common/content_switches.h"
36 #include "content/public/common/result_codes.h"
37 #include "net/http/http_response_info.h"
39 namespace content {
41 using StatusCallback = ServiceWorkerVersion::StatusCallback;
42 using GetClientsCallback =
43 base::Callback<void(const std::vector<ServiceWorkerClientInfo>&)>;
45 namespace {
47 // Delay between the timeout timer firing.
48 const int kTimeoutTimerDelaySeconds = 30;
50 // Time to wait until stopping an idle worker.
51 const int kIdleWorkerTimeoutSeconds = 30;
53 // Default delay for scheduled update.
54 const int kUpdateDelaySeconds = 1;
56 // Timeout for waiting for a response to a ping.
57 const int kPingTimeoutSeconds = 30;
59 // If the SW was destructed while starting up, how many seconds it
60 // had to start up for this to be considered a timeout occurrence.
61 const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5;
63 const char kClaimClientsStateErrorMesage[] =
64 "Only the active worker can claim clients.";
66 const char kClaimClientsShutdownErrorMesage[] =
67 "Failed to claim clients due to Service Worker system shutdown.";
69 void RunSoon(const base::Closure& callback) {
70 if (!callback.is_null())
71 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
74 template <typename CallbackArray, typename Arg>
75 void RunCallbacks(ServiceWorkerVersion* version,
76 CallbackArray* callbacks_ptr,
77 const Arg& arg) {
78 CallbackArray callbacks;
79 callbacks.swap(*callbacks_ptr);
80 scoped_refptr<ServiceWorkerVersion> protect(version);
81 for (const auto& callback : callbacks)
82 callback.Run(arg);
85 template <typename IDMAP, typename... Params>
86 void RunIDMapCallbacks(IDMAP* callbacks, const Params&... params) {
87 typename IDMAP::iterator iter(callbacks);
88 while (!iter.IsAtEnd()) {
89 iter.GetCurrentValue()->Run(params...);
90 iter.Advance();
92 callbacks->Clear();
95 template <typename CallbackType, typename... Params>
96 bool RunIDMapCallback(IDMap<CallbackType, IDMapOwnPointer>* callbacks,
97 int request_id,
98 const Params&... params) {
99 CallbackType* callback = callbacks->Lookup(request_id);
100 if (!callback)
101 return false;
103 callback->Run(params...);
104 callbacks->Remove(request_id);
105 return true;
108 void RunStartWorkerCallback(
109 const StatusCallback& callback,
110 scoped_refptr<ServiceWorkerRegistration> protect,
111 ServiceWorkerStatusCode status) {
112 callback.Run(status);
115 // A callback adapter to start a |task| after StartWorker.
116 void RunTaskAfterStartWorker(
117 base::WeakPtr<ServiceWorkerVersion> version,
118 const StatusCallback& error_callback,
119 const base::Closure& task,
120 ServiceWorkerStatusCode status) {
121 if (status != SERVICE_WORKER_OK) {
122 if (!error_callback.is_null())
123 error_callback.Run(status);
124 return;
126 if (version->running_status() != ServiceWorkerVersion::RUNNING) {
127 // We've tried to start the worker (and it has succeeded), but
128 // it looks it's not running yet.
129 NOTREACHED() << "The worker's not running after successful StartWorker";
130 if (!error_callback.is_null())
131 error_callback.Run(SERVICE_WORKER_ERROR_START_WORKER_FAILED);
132 return;
134 task.Run();
137 void RunErrorFetchCallback(const ServiceWorkerVersion::FetchCallback& callback,
138 ServiceWorkerStatusCode status) {
139 callback.Run(status,
140 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
141 ServiceWorkerResponse());
144 void RunErrorMessageCallback(
145 const std::vector<TransferredMessagePort>& sent_message_ports,
146 const ServiceWorkerVersion::StatusCallback& callback,
147 ServiceWorkerStatusCode status) {
148 // Transfering the message ports failed, so destroy the ports.
149 for (const TransferredMessagePort& port : sent_message_ports) {
150 MessagePortService::GetInstance()->ClosePort(port.id);
152 callback.Run(status);
155 void RunErrorCrossOriginConnectCallback(
156 const ServiceWorkerVersion::CrossOriginConnectCallback& callback,
157 ServiceWorkerStatusCode status) {
158 callback.Run(status, false /* accept_connection */);
161 using WindowOpenedCallback = base::Callback<void(int, int)>;
163 // The WindowOpenedObserver class is a WebContentsObserver that will wait for a
164 // new Window's WebContents to be initialized, run the |callback| passed to its
165 // constructor then self destroy.
166 // The callback will receive the process and frame ids. If something went wrong
167 // those will be (kInvalidUniqueID, MSG_ROUTING_NONE).
168 // The callback will be called in the IO thread.
169 class WindowOpenedObserver : public WebContentsObserver {
170 public:
171 WindowOpenedObserver(WebContents* web_contents,
172 const WindowOpenedCallback& callback)
173 : WebContentsObserver(web_contents),
174 callback_(callback)
177 void DidCommitProvisionalLoadForFrame(
178 RenderFrameHost* render_frame_host,
179 const GURL& validated_url,
180 ui::PageTransition transition_type) override {
181 DCHECK(web_contents());
183 if (render_frame_host != web_contents()->GetMainFrame())
184 return;
186 RunCallback(render_frame_host->GetProcess()->GetID(),
187 render_frame_host->GetRoutingID());
190 void RenderProcessGone(base::TerminationStatus status) override {
191 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
194 void WebContentsDestroyed() override {
195 RunCallback(ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE);
198 private:
199 void RunCallback(int render_process_id, int render_frame_id) {
200 // After running the callback, |this| will stop observing, thus
201 // web_contents() should return nullptr and |RunCallback| should no longer
202 // be called. Then, |this| will self destroy.
203 DCHECK(web_contents());
205 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
206 base::Bind(callback_,
207 render_process_id,
208 render_frame_id));
209 Observe(nullptr);
210 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
213 const WindowOpenedCallback callback_;
215 DISALLOW_COPY_AND_ASSIGN(WindowOpenedObserver);
218 void DidOpenURL(const WindowOpenedCallback& callback,
219 WebContents* web_contents) {
220 DCHECK(web_contents);
222 new WindowOpenedObserver(web_contents, callback);
225 void OpenWindowOnUI(
226 const GURL& url,
227 const GURL& script_url,
228 int process_id,
229 const scoped_refptr<ServiceWorkerContextWrapper>& context_wrapper,
230 const WindowOpenedCallback& callback) {
231 DCHECK_CURRENTLY_ON(BrowserThread::UI);
233 BrowserContext* browser_context = context_wrapper->storage_partition()
234 ? context_wrapper->storage_partition()->browser_context()
235 : nullptr;
236 // We are shutting down.
237 if (!browser_context)
238 return;
240 RenderProcessHost* render_process_host =
241 RenderProcessHost::FromID(process_id);
242 if (render_process_host->IsIsolatedGuest()) {
243 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
244 base::Bind(callback,
245 ChildProcessHost::kInvalidUniqueID,
246 MSG_ROUTING_NONE));
247 return;
250 OpenURLParams params(
251 url, Referrer::SanitizeForRequest(
252 url, Referrer(script_url, blink::WebReferrerPolicyDefault)),
253 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
254 true /* is_renderer_initiated */);
256 GetContentClient()->browser()->OpenURL(
257 browser_context, params,
258 base::Bind(&DidOpenURL, callback));
261 void KillEmbeddedWorkerProcess(int process_id, ResultCode code) {
262 DCHECK_CURRENTLY_ON(BrowserThread::UI);
263 RenderProcessHost* render_process_host =
264 RenderProcessHost::FromID(process_id);
265 if (render_process_host->GetHandle() != base::kNullProcessHandle) {
266 bad_message::ReceivedBadMessage(render_process_host,
267 bad_message::SERVICE_WORKER_BAD_URL);
271 void ClearTick(base::TimeTicks* time) {
272 *time = base::TimeTicks();
275 void RestartTick(base::TimeTicks* time) {
276 *time = base::TimeTicks().Now();
279 base::TimeDelta GetTickDuration(const base::TimeTicks& time) {
280 if (time.is_null())
281 return base::TimeDelta();
282 return base::TimeTicks().Now() - time;
285 void OnGetClientsFromUI(
286 // The tuple contains process_id, frame_id, client_uuid.
287 const std::vector<Tuple<int,int,std::string>>& clients_info,
288 const GURL& script_url,
289 const GetClientsCallback& callback) {
290 std::vector<ServiceWorkerClientInfo> clients;
292 for (const auto& it : clients_info) {
293 ServiceWorkerClientInfo info =
294 ServiceWorkerProviderHost::GetClientInfoOnUI(get<0>(it), get<1>(it));
296 // If the request to the provider_host returned an empty
297 // ServiceWorkerClientInfo, that means that it wasn't possible to associate
298 // it with a valid RenderFrameHost. It might be because the frame was killed
299 // or navigated in between.
300 if (info.IsEmpty())
301 continue;
303 // We can get info for a frame that was navigating end ended up with a
304 // different URL than expected. In such case, we should make sure to not
305 // expose cross-origin WindowClient.
306 if (info.url.GetOrigin() != script_url.GetOrigin())
307 return;
309 info.client_uuid = get<2>(it);
310 clients.push_back(info);
313 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
314 base::Bind(callback, clients));
317 } // namespace
319 const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5;
320 const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
322 ServiceWorkerVersion::ServiceWorkerVersion(
323 ServiceWorkerRegistration* registration,
324 const GURL& script_url,
325 int64 version_id,
326 base::WeakPtr<ServiceWorkerContextCore> context)
327 : version_id_(version_id),
328 registration_id_(kInvalidServiceWorkerVersionId),
329 script_url_(script_url),
330 status_(NEW),
331 context_(context),
332 script_cache_map_(this, context),
333 ping_state_(NOT_PINGING),
334 weak_factory_(this) {
335 DCHECK(context_);
336 DCHECK(registration);
337 if (registration) {
338 registration_id_ = registration->id();
339 scope_ = registration->pattern();
341 context_->AddLiveVersion(this);
342 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
343 embedded_worker_->AddListener(this);
346 ServiceWorkerVersion::~ServiceWorkerVersion() {
347 // The user may have closed the tab waiting for SW to start up.
348 if (GetTickDuration(start_time_) >
349 base::TimeDelta::FromSeconds(
350 kDestructedStartingWorkerTimeoutThresholdSeconds)) {
351 DCHECK(timeout_timer_.IsRunning());
352 DCHECK(!embedded_worker_->devtools_attached());
353 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT);
356 embedded_worker_->RemoveListener(this);
357 if (context_)
358 context_->RemoveLiveVersion(version_id_);
359 // EmbeddedWorker's dtor sends StopWorker if it's still running.
362 void ServiceWorkerVersion::SetStatus(Status status) {
363 if (status_ == status)
364 return;
366 status_ = status;
368 if (skip_waiting_ && status_ == ACTIVATED) {
369 for (int request_id : pending_skip_waiting_requests_)
370 DidSkipWaiting(request_id);
371 pending_skip_waiting_requests_.clear();
374 std::vector<base::Closure> callbacks;
375 callbacks.swap(status_change_callbacks_);
376 for (const auto& callback : callbacks)
377 callback.Run();
379 FOR_EACH_OBSERVER(Listener, listeners_, OnVersionStateChanged(this));
382 void ServiceWorkerVersion::RegisterStatusChangeCallback(
383 const base::Closure& callback) {
384 status_change_callbacks_.push_back(callback);
387 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
388 DCHECK_CURRENTLY_ON(BrowserThread::IO);
389 return ServiceWorkerVersionInfo(
390 running_status(), status(), script_url(), registration_id(), version_id(),
391 embedded_worker()->process_id(), embedded_worker()->thread_id(),
392 embedded_worker()->worker_devtools_agent_route_id());
395 void ServiceWorkerVersion::StartWorker(const StatusCallback& callback) {
396 StartWorker(false, callback);
399 void ServiceWorkerVersion::StartWorker(
400 bool pause_after_download,
401 const StatusCallback& callback) {
402 if (!context_) {
403 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
404 return;
407 // Ensure the live registration during starting worker so that the worker can
408 // get associated with it in SWDispatcherHost::OnSetHostedVersionId().
409 context_->storage()->FindRegistrationForId(
410 registration_id_,
411 scope_.GetOrigin(),
412 base::Bind(&ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker,
413 weak_factory_.GetWeakPtr(),
414 pause_after_download,
415 callback));
418 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
419 if (running_status() == STOPPED) {
420 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
421 return;
423 if (stop_callbacks_.empty()) {
424 ServiceWorkerStatusCode status = embedded_worker_->Stop();
425 if (status != SERVICE_WORKER_OK) {
426 RunSoon(base::Bind(callback, status));
427 return;
430 stop_callbacks_.push_back(callback);
433 void ServiceWorkerVersion::ScheduleUpdate() {
434 if (update_timer_.IsRunning()) {
435 update_timer_.Reset();
436 return;
438 update_timer_.Start(
439 FROM_HERE, base::TimeDelta::FromSeconds(kUpdateDelaySeconds),
440 base::Bind(&ServiceWorkerVersion::StartUpdate,
441 weak_factory_.GetWeakPtr()));
444 void ServiceWorkerVersion::DeferScheduledUpdate() {
445 if (update_timer_.IsRunning())
446 update_timer_.Reset();
449 void ServiceWorkerVersion::StartUpdate() {
450 update_timer_.Stop();
451 if (!context_)
452 return;
453 ServiceWorkerRegistration* registration =
454 context_->GetLiveRegistration(registration_id_);
455 if (!registration || !registration->GetNewestVersion())
456 return;
457 context_->UpdateServiceWorker(registration);
460 void ServiceWorkerVersion::DispatchMessageEvent(
461 const base::string16& message,
462 const std::vector<TransferredMessagePort>& sent_message_ports,
463 const StatusCallback& callback) {
464 for (const TransferredMessagePort& port : sent_message_ports) {
465 MessagePortService::GetInstance()->HoldMessages(port.id);
468 DispatchMessageEventInternal(message, sent_message_ports, callback);
471 void ServiceWorkerVersion::DispatchMessageEventInternal(
472 const base::string16& message,
473 const std::vector<TransferredMessagePort>& sent_message_ports,
474 const StatusCallback& callback) {
475 if (running_status() != RUNNING) {
476 // Schedule calling this method after starting the worker.
477 StartWorker(base::Bind(
478 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
479 base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
480 base::Bind(&self::DispatchMessageEventInternal,
481 weak_factory_.GetWeakPtr(), message, sent_message_ports,
482 callback)));
483 return;
486 MessagePortMessageFilter* filter =
487 embedded_worker_->message_port_message_filter();
488 std::vector<int> new_routing_ids;
489 filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
490 ServiceWorkerStatusCode status =
491 embedded_worker_->SendMessage(ServiceWorkerMsg_MessageToWorker(
492 message, sent_message_ports, new_routing_ids));
493 RunSoon(base::Bind(callback, status));
496 void ServiceWorkerVersion::DispatchInstallEvent(
497 const StatusCallback& callback) {
498 DCHECK_EQ(INSTALLING, status()) << status();
500 if (running_status() != RUNNING) {
501 // Schedule calling this method after starting the worker.
502 StartWorker(
503 base::Bind(&RunTaskAfterStartWorker,
504 weak_factory_.GetWeakPtr(),
505 callback,
506 base::Bind(&self::DispatchInstallEventAfterStartWorker,
507 weak_factory_.GetWeakPtr(),
508 callback)));
509 } else {
510 DispatchInstallEventAfterStartWorker(callback);
514 void ServiceWorkerVersion::DispatchActivateEvent(
515 const StatusCallback& callback) {
516 DCHECK_EQ(ACTIVATING, status()) << status();
518 if (running_status() != RUNNING) {
519 // Schedule calling this method after starting the worker.
520 StartWorker(
521 base::Bind(&RunTaskAfterStartWorker,
522 weak_factory_.GetWeakPtr(),
523 callback,
524 base::Bind(&self::DispatchActivateEventAfterStartWorker,
525 weak_factory_.GetWeakPtr(),
526 callback)));
527 } else {
528 DispatchActivateEventAfterStartWorker(callback);
532 void ServiceWorkerVersion::DispatchFetchEvent(
533 const ServiceWorkerFetchRequest& request,
534 const base::Closure& prepare_callback,
535 const FetchCallback& fetch_callback) {
536 DCHECK_EQ(ACTIVATED, status()) << status();
538 if (running_status() != RUNNING) {
539 // Schedule calling this method after starting the worker.
540 StartWorker(base::Bind(&RunTaskAfterStartWorker,
541 weak_factory_.GetWeakPtr(),
542 base::Bind(&RunErrorFetchCallback, fetch_callback),
543 base::Bind(&self::DispatchFetchEvent,
544 weak_factory_.GetWeakPtr(),
545 request,
546 prepare_callback,
547 fetch_callback)));
548 return;
551 prepare_callback.Run();
553 int request_id = AddRequest(fetch_callback, &fetch_callbacks_, REQUEST_FETCH);
554 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
555 ServiceWorkerMsg_FetchEvent(request_id, request));
556 if (status != SERVICE_WORKER_OK) {
557 fetch_callbacks_.Remove(request_id);
558 RunSoon(base::Bind(&RunErrorFetchCallback,
559 fetch_callback,
560 SERVICE_WORKER_ERROR_FAILED));
564 void ServiceWorkerVersion::DispatchSyncEvent(const StatusCallback& callback) {
565 DCHECK_EQ(ACTIVATED, status()) << status();
567 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
568 switches::kEnableServiceWorkerSync)) {
569 callback.Run(SERVICE_WORKER_ERROR_ABORT);
570 return;
573 if (running_status() != RUNNING) {
574 // Schedule calling this method after starting the worker.
575 StartWorker(base::Bind(&RunTaskAfterStartWorker,
576 weak_factory_.GetWeakPtr(), callback,
577 base::Bind(&self::DispatchSyncEvent,
578 weak_factory_.GetWeakPtr(),
579 callback)));
580 return;
583 int request_id = AddRequest(callback, &sync_callbacks_, REQUEST_SYNC);
584 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
585 ServiceWorkerMsg_SyncEvent(request_id));
586 if (status != SERVICE_WORKER_OK) {
587 sync_callbacks_.Remove(request_id);
588 RunSoon(base::Bind(callback, status));
592 void ServiceWorkerVersion::DispatchNotificationClickEvent(
593 const StatusCallback& callback,
594 const std::string& notification_id,
595 const PlatformNotificationData& notification_data) {
596 DCHECK_EQ(ACTIVATED, status()) << status();
597 if (running_status() != RUNNING) {
598 // Schedule calling this method after starting the worker.
599 StartWorker(base::Bind(&RunTaskAfterStartWorker,
600 weak_factory_.GetWeakPtr(), callback,
601 base::Bind(&self::DispatchNotificationClickEvent,
602 weak_factory_.GetWeakPtr(),
603 callback, notification_id,
604 notification_data)));
605 return;
608 int request_id = AddRequest(callback, &notification_click_callbacks_,
609 REQUEST_NOTIFICATION_CLICK);
610 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
611 ServiceWorkerMsg_NotificationClickEvent(request_id,
612 notification_id,
613 notification_data));
614 if (status != SERVICE_WORKER_OK) {
615 notification_click_callbacks_.Remove(request_id);
616 RunSoon(base::Bind(callback, status));
620 void ServiceWorkerVersion::DispatchPushEvent(const StatusCallback& callback,
621 const std::string& data) {
622 DCHECK_EQ(ACTIVATED, status()) << status();
623 if (running_status() != RUNNING) {
624 // Schedule calling this method after starting the worker.
625 StartWorker(base::Bind(&RunTaskAfterStartWorker,
626 weak_factory_.GetWeakPtr(), callback,
627 base::Bind(&self::DispatchPushEvent,
628 weak_factory_.GetWeakPtr(),
629 callback, data)));
630 return;
633 int request_id = AddRequest(callback, &push_callbacks_, REQUEST_PUSH);
634 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
635 ServiceWorkerMsg_PushEvent(request_id, data));
636 if (status != SERVICE_WORKER_OK) {
637 push_callbacks_.Remove(request_id);
638 RunSoon(base::Bind(callback, status));
642 void ServiceWorkerVersion::DispatchGeofencingEvent(
643 const StatusCallback& callback,
644 blink::WebGeofencingEventType event_type,
645 const std::string& region_id,
646 const blink::WebCircularGeofencingRegion& region) {
647 DCHECK_EQ(ACTIVATED, status()) << status();
649 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
650 switches::kEnableExperimentalWebPlatformFeatures)) {
651 callback.Run(SERVICE_WORKER_ERROR_ABORT);
652 return;
655 if (running_status() != RUNNING) {
656 // Schedule calling this method after starting the worker.
657 StartWorker(base::Bind(&RunTaskAfterStartWorker,
658 weak_factory_.GetWeakPtr(),
659 callback,
660 base::Bind(&self::DispatchGeofencingEvent,
661 weak_factory_.GetWeakPtr(),
662 callback,
663 event_type,
664 region_id,
665 region)));
666 return;
669 int request_id =
670 AddRequest(callback, &geofencing_callbacks_, REQUEST_GEOFENCING);
671 ServiceWorkerStatusCode status =
672 embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
673 request_id, event_type, region_id, region));
674 if (status != SERVICE_WORKER_OK) {
675 geofencing_callbacks_.Remove(request_id);
676 RunSoon(base::Bind(callback, status));
680 void ServiceWorkerVersion::DispatchCrossOriginConnectEvent(
681 const CrossOriginConnectCallback& callback,
682 const NavigatorConnectClient& client) {
683 DCHECK_EQ(ACTIVATED, status()) << status();
685 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
686 switches::kEnableExperimentalWebPlatformFeatures)) {
687 callback.Run(SERVICE_WORKER_ERROR_ABORT, false);
688 return;
691 if (running_status() != RUNNING) {
692 // Schedule calling this method after starting the worker.
693 StartWorker(
694 base::Bind(&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
695 base::Bind(&RunErrorCrossOriginConnectCallback, callback),
696 base::Bind(&self::DispatchCrossOriginConnectEvent,
697 weak_factory_.GetWeakPtr(), callback, client)));
698 return;
701 int request_id = AddRequest(callback, &cross_origin_connect_callbacks_,
702 REQUEST_CROSS_ORIGIN_CONNECT);
703 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
704 ServiceWorkerMsg_CrossOriginConnectEvent(request_id, client));
705 if (status != SERVICE_WORKER_OK) {
706 cross_origin_connect_callbacks_.Remove(request_id);
707 RunSoon(base::Bind(callback, status, false));
711 void ServiceWorkerVersion::DispatchCrossOriginMessageEvent(
712 const NavigatorConnectClient& client,
713 const base::string16& message,
714 const std::vector<TransferredMessagePort>& sent_message_ports,
715 const StatusCallback& callback) {
716 // Unlike in the case of DispatchMessageEvent, here the caller is assumed to
717 // have already put all the sent message ports on hold. So no need to do that
718 // here again.
720 if (running_status() != RUNNING) {
721 // Schedule calling this method after starting the worker.
722 StartWorker(base::Bind(
723 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(),
724 base::Bind(&RunErrorMessageCallback, sent_message_ports, callback),
725 base::Bind(&self::DispatchCrossOriginMessageEvent,
726 weak_factory_.GetWeakPtr(), client, message,
727 sent_message_ports, callback)));
728 return;
731 MessagePortMessageFilter* filter =
732 embedded_worker_->message_port_message_filter();
733 std::vector<int> new_routing_ids;
734 filter->UpdateMessagePortsWithNewRoutes(sent_message_ports, &new_routing_ids);
735 ServiceWorkerStatusCode status =
736 embedded_worker_->SendMessage(ServiceWorkerMsg_CrossOriginMessageToWorker(
737 client, message, sent_message_ports, new_routing_ids));
738 RunSoon(base::Bind(callback, status));
741 void ServiceWorkerVersion::AddControllee(
742 ServiceWorkerProviderHost* provider_host) {
743 const std::string& uuid = provider_host->client_uuid();
744 CHECK(!provider_host->client_uuid().empty());
745 DCHECK(!ContainsKey(controllee_map_, uuid));
746 controllee_map_[uuid] = provider_host;
747 // Keep the worker alive a bit longer right after a new controllee is added.
748 RestartTick(&idle_time_);
751 void ServiceWorkerVersion::RemoveControllee(
752 ServiceWorkerProviderHost* provider_host) {
753 const std::string& uuid = provider_host->client_uuid();
754 DCHECK(ContainsKey(controllee_map_, uuid));
755 controllee_map_.erase(uuid);
756 if (HasControllee())
757 return;
758 FOR_EACH_OBSERVER(Listener, listeners_, OnNoControllees(this));
759 if (is_doomed_) {
760 DoomInternal();
761 return;
765 void ServiceWorkerVersion::AddStreamingURLRequestJob(
766 const ServiceWorkerURLRequestJob* request_job) {
767 DCHECK(streaming_url_request_jobs_.find(request_job) ==
768 streaming_url_request_jobs_.end());
769 streaming_url_request_jobs_.insert(request_job);
772 void ServiceWorkerVersion::RemoveStreamingURLRequestJob(
773 const ServiceWorkerURLRequestJob* request_job) {
774 streaming_url_request_jobs_.erase(request_job);
775 if (is_doomed_)
776 StopWorkerIfIdle();
779 void ServiceWorkerVersion::AddListener(Listener* listener) {
780 listeners_.AddObserver(listener);
783 void ServiceWorkerVersion::RemoveListener(Listener* listener) {
784 listeners_.RemoveObserver(listener);
787 void ServiceWorkerVersion::ReportError(ServiceWorkerStatusCode status,
788 const std::string& status_message) {
789 if (status_message.empty()) {
790 OnReportException(base::UTF8ToUTF16(ServiceWorkerStatusToString(status)),
791 -1, -1, GURL());
792 } else {
793 OnReportException(base::UTF8ToUTF16(status_message), -1, -1, GURL());
797 void ServiceWorkerVersion::Doom() {
798 if (is_doomed_)
799 return;
800 is_doomed_ = true;
801 if (!HasControllee())
802 DoomInternal();
805 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
806 embedded_worker()->set_devtools_attached(attached);
807 if (attached) {
808 // TODO(falken): Canceling the timeouts when debugging could cause
809 // heisenbugs; we should instead run them as normal show an educational
810 // message in DevTools when they occur. crbug.com/470419
812 // Don't record the startup time metric once DevTools is attached.
813 ClearTick(&start_time_);
814 skip_recording_startup_time_ = true;
816 // Cancel request timeouts.
817 SetAllRequestTimes(base::TimeTicks());
818 return;
820 if (!start_callbacks_.empty()) {
821 // Reactivate the timer for start timeout.
822 DCHECK(timeout_timer_.IsRunning());
823 DCHECK(running_status() == STARTING || running_status() == STOPPING)
824 << running_status();
825 RestartTick(&start_time_);
828 // Reactivate request timeouts.
829 SetAllRequestTimes(base::TimeTicks::Now());
832 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
833 const net::HttpResponseInfo& http_info) {
834 main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
837 const net::HttpResponseInfo*
838 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
839 return main_script_http_info_.get();
842 ServiceWorkerVersion::RequestInfo::RequestInfo(int id, RequestType type)
843 : id(id), type(type), time(base::TimeTicks::Now()) {
846 ServiceWorkerVersion::RequestInfo::~RequestInfo() {
849 void ServiceWorkerVersion::OnScriptLoaded() {
850 DCHECK_EQ(STARTING, running_status());
851 // Activate ping/pong now that JavaScript execution will start.
852 ping_state_ = PINGING;
855 void ServiceWorkerVersion::OnStarting() {
856 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
859 void ServiceWorkerVersion::OnStarted() {
860 DCHECK_EQ(RUNNING, running_status());
861 RestartTick(&idle_time_);
863 // Fire all start callbacks.
864 scoped_refptr<ServiceWorkerVersion> protect(this);
865 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
866 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
869 void ServiceWorkerVersion::OnStopping() {
870 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
873 void ServiceWorkerVersion::OnStopped(
874 EmbeddedWorkerInstance::Status old_status) {
875 DCHECK_EQ(STOPPED, running_status());
876 scoped_refptr<ServiceWorkerVersion> protect(this);
878 bool should_restart = !is_doomed() && !start_callbacks_.empty() &&
879 (old_status != EmbeddedWorkerInstance::STARTING);
881 StopTimeoutTimer();
882 if (ping_state_ == PING_TIMED_OUT)
883 should_restart = false;
885 // Fire all stop callbacks.
886 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK);
888 if (!should_restart) {
889 // Let all start callbacks fail.
890 RunCallbacks(this, &start_callbacks_,
891 SERVICE_WORKER_ERROR_START_WORKER_FAILED);
894 // Let all message callbacks fail (this will also fire and clear all
895 // callbacks for events).
896 // TODO(kinuko): Consider if we want to add queue+resend mechanism here.
897 RunIDMapCallbacks(&activate_callbacks_,
898 SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
899 RunIDMapCallbacks(&install_callbacks_,
900 SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
901 RunIDMapCallbacks(&fetch_callbacks_,
902 SERVICE_WORKER_ERROR_FAILED,
903 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK,
904 ServiceWorkerResponse());
905 RunIDMapCallbacks(&sync_callbacks_,
906 SERVICE_WORKER_ERROR_FAILED);
907 RunIDMapCallbacks(&notification_click_callbacks_,
908 SERVICE_WORKER_ERROR_FAILED);
909 RunIDMapCallbacks(&push_callbacks_,
910 SERVICE_WORKER_ERROR_FAILED);
911 RunIDMapCallbacks(&geofencing_callbacks_,
912 SERVICE_WORKER_ERROR_FAILED);
913 RunIDMapCallbacks(&cross_origin_connect_callbacks_,
914 SERVICE_WORKER_ERROR_FAILED,
915 false);
917 streaming_url_request_jobs_.clear();
919 FOR_EACH_OBSERVER(Listener, listeners_, OnRunningStateChanged(this));
921 // Restart worker if we have any start callbacks and the worker isn't doomed.
922 if (should_restart)
923 StartWorkerInternal(false /* pause_after_download */);
926 void ServiceWorkerVersion::OnReportException(
927 const base::string16& error_message,
928 int line_number,
929 int column_number,
930 const GURL& source_url) {
931 FOR_EACH_OBSERVER(
932 Listener,
933 listeners_,
934 OnErrorReported(
935 this, error_message, line_number, column_number, source_url));
938 void ServiceWorkerVersion::OnReportConsoleMessage(int source_identifier,
939 int message_level,
940 const base::string16& message,
941 int line_number,
942 const GURL& source_url) {
943 FOR_EACH_OBSERVER(Listener,
944 listeners_,
945 OnReportConsoleMessage(this,
946 source_identifier,
947 message_level,
948 message,
949 line_number,
950 source_url));
953 bool ServiceWorkerVersion::OnMessageReceived(const IPC::Message& message) {
954 bool handled = true;
955 IPC_BEGIN_MESSAGE_MAP(ServiceWorkerVersion, message)
956 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GetClients,
957 OnGetClients)
958 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ActivateEventFinished,
959 OnActivateEventFinished)
960 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_InstallEventFinished,
961 OnInstallEventFinished)
962 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FetchEventFinished,
963 OnFetchEventFinished)
964 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SyncEventFinished,
965 OnSyncEventFinished)
966 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_NotificationClickEventFinished,
967 OnNotificationClickEventFinished)
968 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
969 OnPushEventFinished)
970 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
971 OnGeofencingEventFinished)
972 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_CrossOriginConnectEventFinished,
973 OnCrossOriginConnectEventFinished)
974 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_OpenWindow,
975 OnOpenWindow)
976 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SetCachedMetadata,
977 OnSetCachedMetadata)
978 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata,
979 OnClearCachedMetadata)
980 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToClient,
981 OnPostMessageToClient)
982 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient,
983 OnFocusClient)
984 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
985 OnSkipWaiting)
986 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
987 OnClaimClients)
988 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
989 IPC_MESSAGE_UNHANDLED(handled = false)
990 IPC_END_MESSAGE_MAP()
991 return handled;
994 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
995 ServiceWorkerStatusCode status) {
996 if (status != SERVICE_WORKER_OK)
997 RunCallbacks(this, &start_callbacks_, status);
1000 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
1001 const StatusCallback& callback) {
1002 DCHECK_EQ(RUNNING, running_status())
1003 << "Worker stopped too soon after it was started.";
1005 int request_id = AddRequest(callback, &install_callbacks_, REQUEST_INSTALL);
1006 ServiceWorkerStatusCode status = embedded_worker_->SendMessage(
1007 ServiceWorkerMsg_InstallEvent(request_id));
1008 if (status != SERVICE_WORKER_OK) {
1009 install_callbacks_.Remove(request_id);
1010 RunSoon(base::Bind(callback, status));
1014 void ServiceWorkerVersion::DispatchActivateEventAfterStartWorker(
1015 const StatusCallback& callback) {
1016 DCHECK_EQ(RUNNING, running_status())
1017 << "Worker stopped too soon after it was started.";
1019 int request_id = AddRequest(callback, &activate_callbacks_, REQUEST_ACTIVATE);
1020 ServiceWorkerStatusCode status =
1021 embedded_worker_->SendMessage(ServiceWorkerMsg_ActivateEvent(request_id));
1022 if (status != SERVICE_WORKER_OK) {
1023 activate_callbacks_.Remove(request_id);
1024 RunSoon(base::Bind(callback, status));
1028 void ServiceWorkerVersion::OnGetClients(
1029 int request_id,
1030 const ServiceWorkerClientQueryOptions& options) {
1031 if (controllee_map_.empty() && !options.include_uncontrolled) {
1032 if (running_status() == RUNNING) {
1033 embedded_worker_->SendMessage(
1034 ServiceWorkerMsg_DidGetClients(request_id,
1035 std::vector<ServiceWorkerClientInfo>()));
1037 return;
1040 TRACE_EVENT0("ServiceWorker",
1041 "ServiceWorkerVersion::OnGetClients");
1043 // 4.3.1 matchAll(options)
1044 std::vector<Tuple<int,int,std::string>> clients_info;
1045 if (!options.include_uncontrolled) {
1046 for (auto& controllee : controllee_map_) {
1047 int process_id = controllee.second->process_id();
1048 int frame_id = controllee.second->frame_id();
1049 const std::string& client_uuid = controllee.first;
1050 clients_info.push_back(MakeTuple(process_id, frame_id, client_uuid));
1052 } else {
1053 for (auto it =
1054 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1055 !it->IsAtEnd(); it->Advance()) {
1056 ServiceWorkerProviderHost* host = it->GetProviderHost();
1057 clients_info.push_back(
1058 MakeTuple(host->process_id(), host->frame_id(), host->client_uuid()));
1062 BrowserThread::PostTask(
1063 BrowserThread::UI, FROM_HERE,
1064 base::Bind(&OnGetClientsFromUI, clients_info, script_url_,
1065 base::Bind(&ServiceWorkerVersion::DidGetClients,
1066 weak_factory_.GetWeakPtr(),
1067 request_id)));
1071 void ServiceWorkerVersion::OnActivateEventFinished(
1072 int request_id,
1073 blink::WebServiceWorkerEventResult result) {
1074 DCHECK(ACTIVATING == status() ||
1075 REDUNDANT == status()) << status();
1076 TRACE_EVENT0("ServiceWorker",
1077 "ServiceWorkerVersion::OnActivateEventFinished");
1079 StatusCallback* callback = activate_callbacks_.Lookup(request_id);
1080 if (!callback) {
1081 NOTREACHED() << "Got unexpected message: " << request_id;
1082 return;
1084 ServiceWorkerStatusCode rv = SERVICE_WORKER_OK;
1085 if (result == blink::WebServiceWorkerEventResultRejected ||
1086 status() != ACTIVATING) {
1087 rv = SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED;
1090 scoped_refptr<ServiceWorkerVersion> protect(this);
1091 callback->Run(rv);
1092 RemoveCallbackAndStopIfDoomed(&activate_callbacks_, request_id);
1095 void ServiceWorkerVersion::OnInstallEventFinished(
1096 int request_id,
1097 blink::WebServiceWorkerEventResult result) {
1098 // Status is REDUNDANT if the worker was doomed while handling the install
1099 // event, and finished handling before being terminated.
1100 DCHECK(status() == INSTALLING || status() == REDUNDANT) << status();
1101 TRACE_EVENT0("ServiceWorker",
1102 "ServiceWorkerVersion::OnInstallEventFinished");
1104 StatusCallback* callback = install_callbacks_.Lookup(request_id);
1105 if (!callback) {
1106 NOTREACHED() << "Got unexpected message: " << request_id;
1107 return;
1109 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1110 if (result == blink::WebServiceWorkerEventResultRejected)
1111 status = SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED;
1113 scoped_refptr<ServiceWorkerVersion> protect(this);
1114 callback->Run(status);
1115 RemoveCallbackAndStopIfDoomed(&install_callbacks_, request_id);
1118 void ServiceWorkerVersion::OnFetchEventFinished(
1119 int request_id,
1120 ServiceWorkerFetchEventResult result,
1121 const ServiceWorkerResponse& response) {
1122 TRACE_EVENT1("ServiceWorker",
1123 "ServiceWorkerVersion::OnFetchEventFinished",
1124 "Request id", request_id);
1125 FetchCallback* callback = fetch_callbacks_.Lookup(request_id);
1126 if (!callback) {
1127 NOTREACHED() << "Got unexpected message: " << request_id;
1128 return;
1131 scoped_refptr<ServiceWorkerVersion> protect(this);
1132 callback->Run(SERVICE_WORKER_OK, result, response);
1133 RemoveCallbackAndStopIfDoomed(&fetch_callbacks_, request_id);
1136 void ServiceWorkerVersion::OnSyncEventFinished(
1137 int request_id) {
1138 TRACE_EVENT1("ServiceWorker",
1139 "ServiceWorkerVersion::OnSyncEventFinished",
1140 "Request id", request_id);
1141 StatusCallback* callback = sync_callbacks_.Lookup(request_id);
1142 if (!callback) {
1143 NOTREACHED() << "Got unexpected message: " << request_id;
1144 return;
1147 scoped_refptr<ServiceWorkerVersion> protect(this);
1148 callback->Run(SERVICE_WORKER_OK);
1149 RemoveCallbackAndStopIfDoomed(&sync_callbacks_, request_id);
1152 void ServiceWorkerVersion::OnNotificationClickEventFinished(
1153 int request_id) {
1154 TRACE_EVENT1("ServiceWorker",
1155 "ServiceWorkerVersion::OnNotificationClickEventFinished",
1156 "Request id", request_id);
1157 StatusCallback* callback = notification_click_callbacks_.Lookup(request_id);
1158 if (!callback) {
1159 NOTREACHED() << "Got unexpected message: " << request_id;
1160 return;
1163 scoped_refptr<ServiceWorkerVersion> protect(this);
1164 callback->Run(SERVICE_WORKER_OK);
1165 RemoveCallbackAndStopIfDoomed(&notification_click_callbacks_, request_id);
1168 void ServiceWorkerVersion::OnPushEventFinished(
1169 int request_id,
1170 blink::WebServiceWorkerEventResult result) {
1171 TRACE_EVENT1("ServiceWorker",
1172 "ServiceWorkerVersion::OnPushEventFinished",
1173 "Request id", request_id);
1174 StatusCallback* callback = push_callbacks_.Lookup(request_id);
1175 if (!callback) {
1176 NOTREACHED() << "Got unexpected message: " << request_id;
1177 return;
1179 ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
1180 if (result == blink::WebServiceWorkerEventResultRejected)
1181 status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
1183 scoped_refptr<ServiceWorkerVersion> protect(this);
1184 callback->Run(status);
1185 RemoveCallbackAndStopIfDoomed(&push_callbacks_, request_id);
1188 void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
1189 TRACE_EVENT1("ServiceWorker",
1190 "ServiceWorkerVersion::OnGeofencingEventFinished",
1191 "Request id",
1192 request_id);
1193 StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
1194 if (!callback) {
1195 NOTREACHED() << "Got unexpected message: " << request_id;
1196 return;
1199 scoped_refptr<ServiceWorkerVersion> protect(this);
1200 callback->Run(SERVICE_WORKER_OK);
1201 RemoveCallbackAndStopIfDoomed(&geofencing_callbacks_, request_id);
1204 void ServiceWorkerVersion::OnCrossOriginConnectEventFinished(
1205 int request_id,
1206 bool accept_connection) {
1207 TRACE_EVENT1("ServiceWorker",
1208 "ServiceWorkerVersion::OnCrossOriginConnectEventFinished",
1209 "Request id", request_id);
1210 CrossOriginConnectCallback* callback =
1211 cross_origin_connect_callbacks_.Lookup(request_id);
1212 if (!callback) {
1213 NOTREACHED() << "Got unexpected message: " << request_id;
1214 return;
1217 scoped_refptr<ServiceWorkerVersion> protect(this);
1218 callback->Run(SERVICE_WORKER_OK, accept_connection);
1219 RemoveCallbackAndStopIfDoomed(&cross_origin_connect_callbacks_, request_id);
1222 void ServiceWorkerVersion::OnOpenWindow(int request_id, GURL url) {
1223 // Just abort if we are shutting down.
1224 if (!context_)
1225 return;
1227 if (!url.is_valid()) {
1228 DVLOG(1) << "Received unexpected invalid URL from renderer process.";
1229 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1230 base::Bind(&KillEmbeddedWorkerProcess,
1231 embedded_worker_->process_id(),
1232 RESULT_CODE_KILLED_BAD_MESSAGE));
1233 return;
1236 // The renderer treats all URLs in the about: scheme as being about:blank.
1237 // Canonicalize about: URLs to about:blank.
1238 if (url.SchemeIs(url::kAboutScheme))
1239 url = GURL(url::kAboutBlankURL);
1241 // Reject requests for URLs that the process is not allowed to access. It's
1242 // possible to receive such requests since the renderer-side checks are
1243 // slightly different. For example, the view-source scheme will not be
1244 // filtered out by Blink.
1245 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
1246 embedded_worker_->process_id(), url)) {
1247 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
1248 request_id, url.spec() + " cannot be opened."));
1249 return;
1252 BrowserThread::PostTask(
1253 BrowserThread::UI, FROM_HERE,
1254 base::Bind(&OpenWindowOnUI,
1255 url,
1256 script_url_,
1257 embedded_worker_->process_id(),
1258 make_scoped_refptr(context_->wrapper()),
1259 base::Bind(&ServiceWorkerVersion::DidOpenWindow,
1260 weak_factory_.GetWeakPtr(),
1261 request_id)));
1264 void ServiceWorkerVersion::DidOpenWindow(int request_id,
1265 int render_process_id,
1266 int render_frame_id) {
1267 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1269 if (running_status() != RUNNING)
1270 return;
1272 if (render_process_id == ChildProcessHost::kInvalidUniqueID &&
1273 render_frame_id == MSG_ROUTING_NONE) {
1274 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowError(
1275 request_id, "Something went wrong while trying to open the window."));
1276 return;
1279 for (auto it =
1280 context_->GetClientProviderHostIterator(script_url_.GetOrigin());
1281 !it->IsAtEnd(); it->Advance()) {
1282 ServiceWorkerProviderHost* provider_host = it->GetProviderHost();
1283 if (provider_host->process_id() != render_process_id ||
1284 provider_host->frame_id() != render_frame_id) {
1285 continue;
1287 provider_host->GetClientInfo(base::Bind(
1288 &ServiceWorkerVersion::OnOpenWindowFinished, weak_factory_.GetWeakPtr(),
1289 request_id, provider_host->client_uuid()));
1290 return;
1293 // If here, it means that no provider_host was found, in which case, the
1294 // renderer should still be informed that the window was opened.
1295 OnOpenWindowFinished(request_id, std::string(), ServiceWorkerClientInfo());
1298 void ServiceWorkerVersion::OnOpenWindowFinished(
1299 int request_id,
1300 const std::string& client_uuid,
1301 const ServiceWorkerClientInfo& client_info) {
1302 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1304 if (running_status() != RUNNING)
1305 return;
1307 ServiceWorkerClientInfo client(client_info);
1309 // If the |client_info| is empty, it means that the opened window wasn't
1310 // controlled but the action still succeeded. The renderer process is
1311 // expecting an empty client in such case.
1312 if (!client.IsEmpty())
1313 client.client_uuid = client_uuid;
1315 embedded_worker_->SendMessage(ServiceWorkerMsg_OpenWindowResponse(
1316 request_id, client));
1319 void ServiceWorkerVersion::OnSetCachedMetadata(const GURL& url,
1320 const std::vector<char>& data) {
1321 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1322 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1323 "ServiceWorkerVersion::OnSetCachedMetadata",
1324 callback_id, "URL", url.spec());
1325 script_cache_map_.WriteMetadata(
1326 url, data, base::Bind(&ServiceWorkerVersion::OnSetCachedMetadataFinished,
1327 weak_factory_.GetWeakPtr(), callback_id));
1330 void ServiceWorkerVersion::OnSetCachedMetadataFinished(int64 callback_id,
1331 int result) {
1332 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1333 "ServiceWorkerVersion::OnSetCachedMetadata",
1334 callback_id, "result", result);
1335 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1338 void ServiceWorkerVersion::OnClearCachedMetadata(const GURL& url) {
1339 int64 callback_id = base::TimeTicks::Now().ToInternalValue();
1340 TRACE_EVENT_ASYNC_BEGIN1("ServiceWorker",
1341 "ServiceWorkerVersion::OnClearCachedMetadata",
1342 callback_id, "URL", url.spec());
1343 script_cache_map_.ClearMetadata(
1344 url, base::Bind(&ServiceWorkerVersion::OnClearCachedMetadataFinished,
1345 weak_factory_.GetWeakPtr(), callback_id));
1348 void ServiceWorkerVersion::OnClearCachedMetadataFinished(int64 callback_id,
1349 int result) {
1350 TRACE_EVENT_ASYNC_END1("ServiceWorker",
1351 "ServiceWorkerVersion::OnClearCachedMetadata",
1352 callback_id, "result", result);
1353 FOR_EACH_OBSERVER(Listener, listeners_, OnCachedMetadataUpdated(this));
1356 void ServiceWorkerVersion::OnPostMessageToClient(
1357 const std::string& client_uuid,
1358 const base::string16& message,
1359 const std::vector<TransferredMessagePort>& sent_message_ports) {
1360 if (!context_)
1361 return;
1362 TRACE_EVENT1("ServiceWorker",
1363 "ServiceWorkerVersion::OnPostMessageToDocument",
1364 "Client id", client_uuid);
1365 ServiceWorkerProviderHost* provider_host =
1366 context_->GetProviderHostByClientID(client_uuid);
1367 if (!provider_host) {
1368 // The client may already have been closed, just ignore.
1369 return;
1371 if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
1372 // The client does not belong to the same origin as this ServiceWorker,
1373 // possibly due to timing issue or bad message.
1374 return;
1376 provider_host->PostMessage(message, sent_message_ports);
1379 void ServiceWorkerVersion::OnFocusClient(int request_id,
1380 const std::string& client_uuid) {
1381 if (!context_)
1382 return;
1383 TRACE_EVENT2("ServiceWorker",
1384 "ServiceWorkerVersion::OnFocusClient",
1385 "Request id", request_id,
1386 "Client id", client_uuid);
1387 ServiceWorkerProviderHost* provider_host =
1388 context_->GetProviderHostByClientID(client_uuid);
1389 if (!provider_host) {
1390 // The client may already have been closed, just ignore.
1391 return;
1393 if (provider_host->document_url().GetOrigin() != script_url_.GetOrigin()) {
1394 // The client does not belong to the same origin as this ServiceWorker,
1395 // possibly due to timing issue or bad message.
1396 return;
1398 provider_host->Focus(base::Bind(&ServiceWorkerVersion::OnFocusClientFinished,
1399 weak_factory_.GetWeakPtr(), request_id,
1400 client_uuid));
1403 void ServiceWorkerVersion::OnFocusClientFinished(
1404 int request_id,
1405 const std::string& cliend_uuid,
1406 const ServiceWorkerClientInfo& client) {
1407 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1409 if (running_status() != RUNNING)
1410 return;
1412 ServiceWorkerClientInfo client_info(client);
1413 client_info.client_uuid = cliend_uuid;
1415 embedded_worker_->SendMessage(ServiceWorkerMsg_FocusClientResponse(
1416 request_id, client_info));
1419 void ServiceWorkerVersion::OnSkipWaiting(int request_id) {
1420 skip_waiting_ = true;
1421 if (status_ != INSTALLED)
1422 return DidSkipWaiting(request_id);
1424 if (!context_)
1425 return;
1426 ServiceWorkerRegistration* registration =
1427 context_->GetLiveRegistration(registration_id_);
1428 if (!registration)
1429 return;
1430 pending_skip_waiting_requests_.push_back(request_id);
1431 if (pending_skip_waiting_requests_.size() == 1)
1432 registration->ActivateWaitingVersionWhenReady();
1435 void ServiceWorkerVersion::DidSkipWaiting(int request_id) {
1436 if (running_status() == STARTING || running_status() == RUNNING)
1437 embedded_worker_->SendMessage(ServiceWorkerMsg_DidSkipWaiting(request_id));
1440 void ServiceWorkerVersion::OnClaimClients(int request_id) {
1441 if (status_ != ACTIVATING && status_ != ACTIVATED) {
1442 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1443 request_id, blink::WebServiceWorkerError::ErrorTypeState,
1444 base::ASCIIToUTF16(kClaimClientsStateErrorMesage)));
1445 return;
1447 if (context_) {
1448 if (ServiceWorkerRegistration* registration =
1449 context_->GetLiveRegistration(registration_id_)) {
1450 registration->ClaimClients();
1451 embedded_worker_->SendMessage(
1452 ServiceWorkerMsg_DidClaimClients(request_id));
1453 return;
1457 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError(
1458 request_id, blink::WebServiceWorkerError::ErrorTypeAbort,
1459 base::ASCIIToUTF16(kClaimClientsShutdownErrorMesage)));
1462 void ServiceWorkerVersion::OnPongFromWorker() {
1463 ClearTick(&ping_time_);
1466 void ServiceWorkerVersion::DidEnsureLiveRegistrationForStartWorker(
1467 bool pause_after_download,
1468 const StatusCallback& callback,
1469 ServiceWorkerStatusCode status,
1470 const scoped_refptr<ServiceWorkerRegistration>& protect) {
1471 if (status != SERVICE_WORKER_OK || is_doomed()) {
1472 RecordStartWorkerResult(status);
1473 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
1474 return;
1477 switch (running_status()) {
1478 case RUNNING:
1479 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
1480 return;
1481 case STOPPING:
1482 case STOPPED:
1483 case STARTING:
1484 if (start_callbacks_.empty()) {
1485 start_callbacks_.push_back(
1486 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
1487 weak_factory_.GetWeakPtr()));
1489 // Keep the live registration while starting the worker.
1490 start_callbacks_.push_back(
1491 base::Bind(&RunStartWorkerCallback, callback, protect));
1492 StartWorkerInternal(pause_after_download);
1493 return;
1497 void ServiceWorkerVersion::StartWorkerInternal(bool pause_after_download) {
1498 if (!timeout_timer_.IsRunning())
1499 StartTimeoutTimer();
1500 if (running_status() == STOPPED) {
1501 embedded_worker_->Start(
1502 version_id_, scope_, script_url_, pause_after_download,
1503 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
1504 weak_factory_.GetWeakPtr()));
1508 void ServiceWorkerVersion::DidGetClients(
1509 int request_id,
1510 const std::vector<ServiceWorkerClientInfo>& clients) {
1511 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1512 if (running_status() != RUNNING)
1513 return;
1515 embedded_worker_->SendMessage(
1516 ServiceWorkerMsg_DidGetClients(request_id, clients));
1519 void ServiceWorkerVersion::StartTimeoutTimer() {
1520 DCHECK(!timeout_timer_.IsRunning());
1522 if (embedded_worker_->devtools_attached()) {
1523 // Don't record the startup time metric once DevTools is attached.
1524 ClearTick(&start_time_);
1525 skip_recording_startup_time_ = true;
1526 } else {
1527 RestartTick(&start_time_);
1528 skip_recording_startup_time_ = false;
1531 ClearTick(&idle_time_);
1532 ClearTick(&ping_time_);
1533 ping_state_ = NOT_PINGING;
1535 timeout_timer_.Start(FROM_HERE,
1536 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds),
1537 this, &ServiceWorkerVersion::OnTimeoutTimer);
1540 void ServiceWorkerVersion::StopTimeoutTimer() {
1541 timeout_timer_.Stop();
1544 void ServiceWorkerVersion::OnTimeoutTimer() {
1545 DCHECK(running_status() == STARTING || running_status() == RUNNING ||
1546 running_status() == STOPPING)
1547 << running_status();
1549 // Starting a worker hasn't finished within a certain period.
1550 if (GetTickDuration(start_time_) >
1551 base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) {
1552 DCHECK(running_status() == STARTING || running_status() == STOPPING)
1553 << running_status();
1554 scoped_refptr<ServiceWorkerVersion> protect(this);
1555 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT);
1556 if (running_status() == STARTING)
1557 embedded_worker_->Stop();
1558 return;
1561 // Requests have not finished within a certain period.
1562 bool request_timed_out = false;
1563 while (!requests_.empty()) {
1564 RequestInfo info = requests_.front();
1565 if (GetTickDuration(info.time) <
1566 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes))
1567 break;
1568 if (OnRequestTimeout(info))
1569 request_timed_out = true;
1570 requests_.pop();
1572 if (request_timed_out && running_status() != STOPPING)
1573 embedded_worker_->Stop();
1575 // For the timeouts below, there are no callbacks to timeout so there is
1576 // nothing more to do if the worker is already stopping.
1577 if (running_status() == STOPPING)
1578 return;
1580 // The worker has been idle for longer than a certain period.
1581 if (GetTickDuration(idle_time_) >
1582 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) {
1583 StopWorkerIfIdle();
1584 return;
1587 // The worker hasn't responded to ping within a certain period.
1588 if (GetTickDuration(ping_time_) >
1589 base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) {
1590 OnPingTimeout();
1591 return;
1594 if (ping_state_ == PINGING && ping_time_.is_null())
1595 PingWorker();
1598 void ServiceWorkerVersion::PingWorker() {
1599 DCHECK(running_status() == STARTING || running_status() == RUNNING);
1600 DCHECK_EQ(PINGING, ping_state_);
1601 ServiceWorkerStatusCode status =
1602 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping());
1603 if (status != SERVICE_WORKER_OK) {
1604 // TODO(falken): Maybe try resending Ping a few times first?
1605 ping_state_ = PING_TIMED_OUT;
1606 StopWorkerIfIdle();
1607 return;
1609 RestartTick(&ping_time_);
1612 void ServiceWorkerVersion::OnPingTimeout() {
1613 DCHECK(running_status() == STARTING || running_status() == RUNNING);
1614 ping_state_ = PING_TIMED_OUT;
1615 // TODO(falken): Show a message to the developer that the SW was stopped due
1616 // to timeout (crbug.com/457968). Also, change the error code to
1617 // SERVICE_WORKER_ERROR_TIMEOUT.
1618 StopWorkerIfIdle();
1621 void ServiceWorkerVersion::StopWorkerIfIdle() {
1622 if (HasInflightRequests() && ping_state_ != PING_TIMED_OUT)
1623 return;
1624 if (running_status() == STOPPED || running_status() == STOPPING ||
1625 !stop_callbacks_.empty()) {
1626 return;
1629 // TODO(falken): We may need to handle StopIfIdle failure and
1630 // forcibly fail pending callbacks so no one is stuck waiting
1631 // for the worker.
1632 embedded_worker_->StopIfIdle();
1635 bool ServiceWorkerVersion::HasInflightRequests() const {
1636 return
1637 !activate_callbacks_.IsEmpty() ||
1638 !install_callbacks_.IsEmpty() ||
1639 !fetch_callbacks_.IsEmpty() ||
1640 !sync_callbacks_.IsEmpty() ||
1641 !notification_click_callbacks_.IsEmpty() ||
1642 !push_callbacks_.IsEmpty() ||
1643 !geofencing_callbacks_.IsEmpty() ||
1644 !cross_origin_connect_callbacks_.IsEmpty() ||
1645 !streaming_url_request_jobs_.empty();
1648 void ServiceWorkerVersion::RecordStartWorkerResult(
1649 ServiceWorkerStatusCode status) {
1650 base::TimeTicks start_time = start_time_;
1651 ClearTick(&start_time_);
1653 // Failing to start a doomed worker isn't interesting and very common when
1654 // update dooms because the script is byte-to-byte identical.
1655 if (is_doomed_)
1656 return;
1658 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status,
1659 SERVICE_WORKER_ERROR_MAX_VALUE);
1660 if (status == SERVICE_WORKER_OK && !start_time.is_null() &&
1661 !skip_recording_startup_time_) {
1662 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time",
1663 GetTickDuration(start_time));
1666 if (status != SERVICE_WORKER_ERROR_TIMEOUT)
1667 return;
1668 EmbeddedWorkerInstance::StartingPhase phase =
1669 EmbeddedWorkerInstance::NOT_STARTING;
1670 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status();
1671 // Build an artifical JavaScript exception to show in the ServiceWorker
1672 // log for developers; it's not user-facing so it's not a localized resource.
1673 std::string message = "ServiceWorker startup timed out. ";
1674 if (running_status != EmbeddedWorkerInstance::STARTING) {
1675 message.append("The worker had unexpected status: ");
1676 message.append(EmbeddedWorkerInstance::StatusToString(running_status));
1677 } else {
1678 phase = embedded_worker_->starting_phase();
1679 message.append("The worker was in startup phase: ");
1680 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
1682 message.append(".");
1683 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
1684 DVLOG(1) << message;
1685 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.TimeoutPhase",
1686 phase,
1687 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
1690 void ServiceWorkerVersion::DoomInternal() {
1691 DCHECK(is_doomed_);
1692 DCHECK(!HasControllee());
1693 SetStatus(REDUNDANT);
1694 StopWorkerIfIdle();
1695 if (!context_)
1696 return;
1697 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
1698 script_cache_map_.GetResources(&resources);
1699 context_->storage()->PurgeResources(resources);
1702 template <typename IDMAP>
1703 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1704 IDMAP* callbacks,
1705 int request_id) {
1706 RestartTick(&idle_time_);
1707 callbacks->Remove(request_id);
1708 if (is_doomed_) {
1709 // The stop should be already scheduled, but try to stop immediately, in
1710 // order to release worker resources soon.
1711 StopWorkerIfIdle();
1715 template <typename CallbackType>
1716 int ServiceWorkerVersion::AddRequest(
1717 const CallbackType& callback,
1718 IDMap<CallbackType, IDMapOwnPointer>* callback_map,
1719 RequestType request_type) {
1720 int request_id = callback_map->Add(new CallbackType(callback));
1721 requests_.push(RequestInfo(request_id, request_type));
1722 return request_id;
1725 bool ServiceWorkerVersion::OnRequestTimeout(const RequestInfo& info) {
1726 switch (info.type) {
1727 case REQUEST_ACTIVATE:
1728 return RunIDMapCallback(&activate_callbacks_, info.id,
1729 SERVICE_WORKER_ERROR_TIMEOUT);
1730 case REQUEST_INSTALL:
1731 return RunIDMapCallback(&install_callbacks_, info.id,
1732 SERVICE_WORKER_ERROR_TIMEOUT);
1733 case REQUEST_FETCH:
1734 return RunIDMapCallback(
1735 &fetch_callbacks_, info.id, SERVICE_WORKER_ERROR_TIMEOUT,
1736 /* The other args are ignored for non-OK status. */
1737 SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, ServiceWorkerResponse());
1738 case REQUEST_SYNC:
1739 return RunIDMapCallback(&sync_callbacks_, info.id,
1740 SERVICE_WORKER_ERROR_TIMEOUT);
1741 case REQUEST_NOTIFICATION_CLICK:
1742 return RunIDMapCallback(&notification_click_callbacks_, info.id,
1743 SERVICE_WORKER_ERROR_TIMEOUT);
1744 case REQUEST_PUSH:
1745 return RunIDMapCallback(&push_callbacks_, info.id,
1746 SERVICE_WORKER_ERROR_TIMEOUT);
1747 case REQUEST_GEOFENCING:
1748 return RunIDMapCallback(&geofencing_callbacks_, info.id,
1749 SERVICE_WORKER_ERROR_TIMEOUT);
1750 case REQUEST_CROSS_ORIGIN_CONNECT:
1751 return RunIDMapCallback(&cross_origin_connect_callbacks_, info.id,
1752 SERVICE_WORKER_ERROR_TIMEOUT,
1753 false /* accept_connection */);
1755 NOTREACHED() << "Got unexpected request type: " << info.type;
1756 return false;
1759 void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) {
1760 std::queue<RequestInfo> new_requests;
1761 while (!requests_.empty()) {
1762 RequestInfo info = requests_.front();
1763 info.time = ticks;
1764 new_requests.push(info);
1765 requests_.pop();
1767 requests_ = new_requests;
1770 } // namespace content