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_provider_host.h"
8 #include "base/stl_util.h"
9 #include "content/browser/frame_host/frame_tree.h"
10 #include "content/browser/frame_host/frame_tree_node.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/message_port_message_filter.h"
13 #include "content/browser/service_worker/service_worker_context_core.h"
14 #include "content/browser/service_worker/service_worker_context_request_handler.h"
15 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
16 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
17 #include "content/browser/service_worker/service_worker_handle.h"
18 #include "content/browser/service_worker/service_worker_registration_handle.h"
19 #include "content/browser/service_worker/service_worker_utils.h"
20 #include "content/browser/service_worker/service_worker_version.h"
21 #include "content/browser/web_contents/web_contents_impl.h"
22 #include "content/common/resource_request_body.h"
23 #include "content/common/service_worker/service_worker_messages.h"
24 #include "content/common/service_worker/service_worker_types.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/common/child_process_host.h"
34 ServiceWorkerClientInfo
FocusOnUIThread(
35 int render_process_id
,
36 int render_frame_id
) {
37 RenderFrameHostImpl
* render_frame_host
=
38 RenderFrameHostImpl::FromID(render_process_id
, render_frame_id
);
39 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
40 WebContents::FromRenderFrameHost(render_frame_host
));
42 if (!render_frame_host
|| !web_contents
)
43 return ServiceWorkerClientInfo();
45 FrameTreeNode
* frame_tree_node
= render_frame_host
->frame_tree_node();
47 // Focus the frame in the frame tree node, in case it has changed.
48 frame_tree_node
->frame_tree()->SetFocusedFrame(frame_tree_node
);
50 // Focus the frame's view to make sure the frame is now considered as focused.
51 render_frame_host
->GetView()->Focus();
53 // Move the web contents to the foreground.
54 web_contents
->Activate();
56 return ServiceWorkerProviderHost::GetClientInfoOnUI(
57 render_process_id
, render_frame_id
);
60 } // anonymous namespace
62 ServiceWorkerProviderHost::OneShotGetReadyCallback::OneShotGetReadyCallback(
63 const GetRegistrationForReadyCallback
& callback
)
68 ServiceWorkerProviderHost::OneShotGetReadyCallback::~OneShotGetReadyCallback() {
71 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
72 int render_process_id
,
75 ServiceWorkerProviderType provider_type
,
76 base::WeakPtr
<ServiceWorkerContextCore
> context
,
77 ServiceWorkerDispatcherHost
* dispatcher_host
)
78 : client_uuid_(base::GenerateGUID()),
79 render_process_id_(render_process_id
),
80 render_frame_id_(render_frame_id
),
81 render_thread_id_(kDocumentMainThreadId
),
82 provider_id_(provider_id
),
83 provider_type_(provider_type
),
85 dispatcher_host_(dispatcher_host
),
86 allow_association_(true),
88 DCHECK_NE(ChildProcessHost::kInvalidUniqueID
, render_process_id_
);
89 DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN
, provider_type_
);
90 if (provider_type_
== SERVICE_WORKER_PROVIDER_FOR_CONTROLLER
) {
91 // Actual thread id is set when the service worker context gets started.
92 render_thread_id_
= kInvalidEmbeddedWorkerThreadId
;
94 context_
->RegisterProviderHostByClientID(client_uuid_
, this);
97 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
99 context_
->UnregisterProviderHostByClientID(client_uuid_
);
101 // Clear docurl so the deferred activation of a waiting worker
102 // won't associate the new version with a provider being destroyed.
103 document_url_
= GURL();
104 if (controlling_version_
.get())
105 controlling_version_
->RemoveControllee(this);
107 for (auto& key_registration
: matching_registrations_
) {
108 DecreaseProcessReference(key_registration
.second
->pattern());
109 key_registration
.second
->RemoveListener(this);
112 for (const GURL
& pattern
: associated_patterns_
)
113 DecreaseProcessReference(pattern
);
116 void ServiceWorkerProviderHost::OnVersionAttributesChanged(
117 ServiceWorkerRegistration
* registration
,
118 ChangedVersionAttributesMask changed_mask
,
119 const ServiceWorkerRegistrationInfo
& info
) {
120 if (!get_ready_callback_
|| get_ready_callback_
->called
)
122 if (changed_mask
.active_changed() && registration
->active_version()) {
123 // Wait until the state change so we don't send the get for ready
124 // registration complete message before set version attributes message.
125 registration
->active_version()->RegisterStatusChangeCallback(base::Bind(
126 &ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded
,
131 void ServiceWorkerProviderHost::OnRegistrationFailed(
132 ServiceWorkerRegistration
* registration
) {
133 if (associated_registration_
== registration
)
134 DisassociateRegistration();
135 RemoveMatchingRegistration(registration
);
138 void ServiceWorkerProviderHost::OnRegistrationFinishedUninstalling(
139 ServiceWorkerRegistration
* registration
) {
140 RemoveMatchingRegistration(registration
);
143 void ServiceWorkerProviderHost::OnSkippedWaiting(
144 ServiceWorkerRegistration
* registration
) {
145 if (associated_registration_
!= registration
)
147 // A client is "using" a registration if it is controlled by the active
148 // worker of the registration. skipWaiting doesn't cause a client to start
149 // using the registration.
150 if (!controlling_version_
)
152 ServiceWorkerVersion
* active_version
= registration
->active_version();
153 DCHECK_EQ(active_version
->status(), ServiceWorkerVersion::ACTIVATING
);
154 SetControllerVersionAttribute(active_version
);
157 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL
& url
) {
158 DCHECK(!url
.has_ref());
162 void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL
& url
) {
163 topmost_frame_url_
= url
;
166 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
167 ServiceWorkerVersion
* version
) {
168 if (version
== controlling_version_
.get())
171 scoped_refptr
<ServiceWorkerVersion
> previous_version
= controlling_version_
;
172 controlling_version_
= version
;
174 version
->AddControllee(this);
175 if (previous_version
.get())
176 previous_version
->RemoveControllee(this);
178 if (!dispatcher_host_
)
179 return; // Could be NULL in some tests.
181 bool should_notify_controllerchange
=
182 is_claiming_
|| (previous_version
&& version
&& version
->skip_waiting());
184 // SetController message should be sent only for controllees.
185 DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLEE
, provider_type_
);
186 Send(new ServiceWorkerMsg_SetControllerServiceWorker(
187 render_thread_id_
, provider_id(),
188 CreateAndRegisterServiceWorkerHandle(version
),
189 should_notify_controllerchange
));
192 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id
) {
194 return true; // System is shutting down.
195 if (active_version())
196 return false; // Unexpected bad message.
198 ServiceWorkerVersion
* live_version
= context_
->GetLiveVersion(version_id
);
200 return true; // Was deleted before it got started.
202 ServiceWorkerVersionInfo info
= live_version
->GetInfo();
203 if (info
.running_status
!= ServiceWorkerVersion::STARTING
||
204 info
.process_id
!= render_process_id_
) {
205 // If we aren't trying to start this version in our process
206 // something is amiss.
210 running_hosted_version_
= live_version
;
214 void ServiceWorkerProviderHost::AssociateRegistration(
215 ServiceWorkerRegistration
* registration
) {
216 DCHECK(CanAssociateRegistration(registration
));
217 associated_registration_
= registration
;
218 AddMatchingRegistration(registration
);
219 SendAssociateRegistrationMessage();
220 SetControllerVersionAttribute(registration
->active_version());
223 void ServiceWorkerProviderHost::DisassociateRegistration() {
224 queued_events_
.clear();
225 if (!associated_registration_
.get())
227 associated_registration_
= NULL
;
228 SetControllerVersionAttribute(NULL
);
230 if (!dispatcher_host_
)
233 // Disassociation message should be sent only for controllees.
234 DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLEE
, provider_type_
);
235 Send(new ServiceWorkerMsg_DisassociateRegistration(
236 render_thread_id_
, provider_id()));
239 void ServiceWorkerProviderHost::AddMatchingRegistration(
240 ServiceWorkerRegistration
* registration
) {
241 DCHECK(ServiceWorkerUtils::ScopeMatches(
242 registration
->pattern(), document_url_
));
243 size_t key
= registration
->pattern().spec().size();
244 if (ContainsKey(matching_registrations_
, key
))
246 IncreaseProcessReference(registration
->pattern());
247 registration
->AddListener(this);
248 matching_registrations_
[key
] = registration
;
249 ReturnRegistrationForReadyIfNeeded();
252 void ServiceWorkerProviderHost::RemoveMatchingRegistration(
253 ServiceWorkerRegistration
* registration
) {
254 size_t key
= registration
->pattern().spec().size();
255 DCHECK(ContainsKey(matching_registrations_
, key
));
256 DecreaseProcessReference(registration
->pattern());
257 registration
->RemoveListener(this);
258 matching_registrations_
.erase(key
);
261 ServiceWorkerRegistration
*
262 ServiceWorkerProviderHost::MatchRegistration() const {
263 ServiceWorkerRegistrationMap::const_reverse_iterator it
=
264 matching_registrations_
.rbegin();
265 for (; it
!= matching_registrations_
.rend(); ++it
) {
266 if (it
->second
->is_uninstalled())
268 if (it
->second
->is_uninstalling())
270 return it
->second
.get();
275 scoped_ptr
<ServiceWorkerRequestHandler
>
276 ServiceWorkerProviderHost::CreateRequestHandler(
277 FetchRequestMode request_mode
,
278 FetchCredentialsMode credentials_mode
,
279 ResourceType resource_type
,
280 RequestContextType request_context_type
,
281 RequestContextFrameType frame_type
,
282 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
,
283 scoped_refptr
<ResourceRequestBody
> body
) {
284 if (IsHostToRunningServiceWorker()) {
285 return scoped_ptr
<ServiceWorkerRequestHandler
>(
286 new ServiceWorkerContextRequestHandler(
287 context_
, AsWeakPtr(), blob_storage_context
, resource_type
));
289 if (ServiceWorkerUtils::IsMainResourceType(resource_type
) ||
290 controlling_version()) {
291 return scoped_ptr
<ServiceWorkerRequestHandler
>(
292 new ServiceWorkerControlleeRequestHandler(context_
,
294 blob_storage_context
,
298 request_context_type
,
302 return scoped_ptr
<ServiceWorkerRequestHandler
>();
305 ServiceWorkerObjectInfo
306 ServiceWorkerProviderHost::CreateAndRegisterServiceWorkerHandle(
307 ServiceWorkerVersion
* version
) {
308 DCHECK(dispatcher_host_
);
309 ServiceWorkerObjectInfo info
;
310 if (context_
&& version
) {
311 scoped_ptr
<ServiceWorkerHandle
> handle
=
312 ServiceWorkerHandle::Create(context_
, AsWeakPtr(), version
);
313 info
= handle
->GetObjectInfo();
314 dispatcher_host_
->RegisterServiceWorkerHandle(handle
.Pass());
319 bool ServiceWorkerProviderHost::CanAssociateRegistration(
320 ServiceWorkerRegistration
* registration
) {
323 if (running_hosted_version_
.get())
325 if (!registration
|| associated_registration_
.get() || !allow_association_
)
330 void ServiceWorkerProviderHost::PostMessage(
331 const base::string16
& message
,
332 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
333 if (!dispatcher_host_
)
334 return; // Could be NULL in some tests.
336 std::vector
<int> new_routing_ids
;
337 dispatcher_host_
->message_port_message_filter()->
338 UpdateMessagePortsWithNewRoutes(sent_message_ports
,
341 Send(new ServiceWorkerMsg_MessageToDocument(
342 kDocumentMainThreadId
, provider_id(),
348 void ServiceWorkerProviderHost::Focus(const GetClientInfoCallback
& callback
) {
349 BrowserThread::PostTaskAndReplyWithResult(
350 BrowserThread::UI
, FROM_HERE
,
351 base::Bind(&FocusOnUIThread
,
357 void ServiceWorkerProviderHost::GetClientInfo(
358 const GetClientInfoCallback
& callback
) const {
359 BrowserThread::PostTaskAndReplyWithResult(
360 BrowserThread::UI
, FROM_HERE
,
361 base::Bind(&ServiceWorkerProviderHost::GetClientInfoOnUI
,
368 ServiceWorkerClientInfo
ServiceWorkerProviderHost::GetClientInfoOnUI(
369 int render_process_id
, int render_frame_id
) {
370 RenderFrameHostImpl
* render_frame_host
=
371 RenderFrameHostImpl::FromID(render_process_id
, render_frame_id
);
372 if (!render_frame_host
)
373 return ServiceWorkerClientInfo();
375 // TODO(mlamouri,michaeln): it is possible to end up collecting information
376 // for a frame that is actually being navigated and isn't exactly what we are
378 return ServiceWorkerClientInfo(
379 render_frame_host
->GetVisibilityState(),
380 render_frame_host
->IsFocused(),
381 render_frame_host
->GetLastCommittedURL(),
382 render_frame_host
->GetParent() ? REQUEST_CONTEXT_FRAME_TYPE_NESTED
383 : REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL
,
384 blink::WebServiceWorkerClientTypeWindow
);
387 void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
388 const GURL
& pattern
) {
389 associated_patterns_
.push_back(pattern
);
390 IncreaseProcessReference(pattern
);
393 void ServiceWorkerProviderHost::ClaimedByRegistration(
394 ServiceWorkerRegistration
* registration
) {
395 DCHECK(registration
->active_version());
397 if (registration
== associated_registration_
) {
398 SetControllerVersionAttribute(registration
->active_version());
399 } else if (allow_association_
) {
400 DisassociateRegistration();
401 AssociateRegistration(registration
);
403 is_claiming_
= false;
406 bool ServiceWorkerProviderHost::GetRegistrationForReady(
407 const GetRegistrationForReadyCallback
& callback
) {
408 if (get_ready_callback_
)
410 get_ready_callback_
.reset(new OneShotGetReadyCallback(callback
));
411 ReturnRegistrationForReadyIfNeeded();
415 void ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() {
416 DCHECK_NE(ChildProcessHost::kInvalidUniqueID
, render_process_id_
);
417 DCHECK_NE(MSG_ROUTING_NONE
, render_frame_id_
);
418 DCHECK_EQ(kDocumentMainThreadId
, render_thread_id_
);
419 DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN
, provider_type_
);
421 for (const GURL
& pattern
: associated_patterns_
)
422 DecreaseProcessReference(pattern
);
424 for (auto& key_registration
: matching_registrations_
)
425 DecreaseProcessReference(key_registration
.second
->pattern());
427 if (associated_registration_
.get()) {
428 if (dispatcher_host_
) {
429 Send(new ServiceWorkerMsg_DisassociateRegistration(
430 render_thread_id_
, provider_id()));
434 render_process_id_
= ChildProcessHost::kInvalidUniqueID
;
435 render_frame_id_
= MSG_ROUTING_NONE
;
436 render_thread_id_
= kInvalidEmbeddedWorkerThreadId
;
437 provider_id_
= kInvalidServiceWorkerProviderId
;
438 provider_type_
= SERVICE_WORKER_PROVIDER_UNKNOWN
;
439 dispatcher_host_
= nullptr;
442 void ServiceWorkerProviderHost::CompleteCrossSiteTransfer(
446 ServiceWorkerProviderType new_provider_type
,
447 ServiceWorkerDispatcherHost
* new_dispatcher_host
) {
448 DCHECK_EQ(ChildProcessHost::kInvalidUniqueID
, render_process_id_
);
449 DCHECK_NE(ChildProcessHost::kInvalidUniqueID
, new_process_id
);
450 DCHECK_NE(MSG_ROUTING_NONE
, new_frame_id
);
452 render_process_id_
= new_process_id
;
453 render_frame_id_
= new_frame_id
;
454 render_thread_id_
= kDocumentMainThreadId
;
455 provider_id_
= new_provider_id
;
456 provider_type_
= new_provider_type
;
457 dispatcher_host_
= new_dispatcher_host
;
459 for (const GURL
& pattern
: associated_patterns_
)
460 IncreaseProcessReference(pattern
);
462 for (auto& key_registration
: matching_registrations_
)
463 IncreaseProcessReference(key_registration
.second
->pattern());
465 if (associated_registration_
.get()) {
466 SendAssociateRegistrationMessage();
467 if (dispatcher_host_
&& associated_registration_
->active_version()) {
468 Send(new ServiceWorkerMsg_SetControllerServiceWorker(
469 render_thread_id_
, provider_id(),
470 CreateAndRegisterServiceWorkerHandle(
471 associated_registration_
->active_version()),
472 false /* shouldNotifyControllerChange */));
477 void ServiceWorkerProviderHost::SendUpdateFoundMessage(
478 int registration_handle_id
) {
479 if (!dispatcher_host_
)
480 return; // Could be nullptr in some tests.
482 if (!IsReadyToSendMessages()) {
483 queued_events_
.push_back(
484 base::Bind(&ServiceWorkerProviderHost::SendUpdateFoundMessage
,
485 AsWeakPtr(), registration_handle_id
));
489 Send(new ServiceWorkerMsg_UpdateFound(
490 render_thread_id_
, registration_handle_id
));
493 void ServiceWorkerProviderHost::SendSetVersionAttributesMessage(
494 int registration_handle_id
,
495 ChangedVersionAttributesMask changed_mask
,
496 ServiceWorkerVersion
* installing_version
,
497 ServiceWorkerVersion
* waiting_version
,
498 ServiceWorkerVersion
* active_version
) {
499 if (!dispatcher_host_
)
500 return; // Could be nullptr in some tests.
501 if (!changed_mask
.changed())
504 if (!IsReadyToSendMessages()) {
505 queued_events_
.push_back(
506 base::Bind(&ServiceWorkerProviderHost::SendSetVersionAttributesMessage
,
507 AsWeakPtr(), registration_handle_id
, changed_mask
,
508 make_scoped_refptr(installing_version
),
509 make_scoped_refptr(waiting_version
),
510 make_scoped_refptr(active_version
)));
514 ServiceWorkerVersionAttributes attrs
;
515 if (changed_mask
.installing_changed())
516 attrs
.installing
= CreateAndRegisterServiceWorkerHandle(installing_version
);
517 if (changed_mask
.waiting_changed())
518 attrs
.waiting
= CreateAndRegisterServiceWorkerHandle(waiting_version
);
519 if (changed_mask
.active_changed())
520 attrs
.active
= CreateAndRegisterServiceWorkerHandle(active_version
);
522 Send(new ServiceWorkerMsg_SetVersionAttributes(
523 render_thread_id_
, provider_id_
, registration_handle_id
,
524 changed_mask
.changed(), attrs
));
527 void ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage(
528 int worker_handle_id
,
529 blink::WebServiceWorkerState state
) {
530 if (!dispatcher_host_
)
533 if (!IsReadyToSendMessages()) {
534 queued_events_
.push_back(base::Bind(
535 &ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage
,
536 AsWeakPtr(), worker_handle_id
, state
));
540 Send(new ServiceWorkerMsg_ServiceWorkerStateChanged(
541 render_thread_id_
, worker_handle_id
, state
));
544 void ServiceWorkerProviderHost::SetReadyToSendMessagesToWorker(
545 int render_thread_id
) {
546 DCHECK(!IsReadyToSendMessages());
547 render_thread_id_
= render_thread_id
;
549 for (const auto& event
: queued_events_
)
551 queued_events_
.clear();
554 void ServiceWorkerProviderHost::SendAssociateRegistrationMessage() {
555 if (!dispatcher_host_
)
558 ServiceWorkerRegistrationHandle
* handle
=
559 dispatcher_host_
->GetOrCreateRegistrationHandle(
560 AsWeakPtr(), associated_registration_
.get());
562 ServiceWorkerVersionAttributes attrs
;
563 attrs
.installing
= CreateAndRegisterServiceWorkerHandle(
564 associated_registration_
->installing_version());
565 attrs
.waiting
= CreateAndRegisterServiceWorkerHandle(
566 associated_registration_
->waiting_version());
567 attrs
.active
= CreateAndRegisterServiceWorkerHandle(
568 associated_registration_
->active_version());
570 // Association message should be sent only for controllees.
571 DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLEE
, provider_type_
);
572 dispatcher_host_
->Send(new ServiceWorkerMsg_AssociateRegistration(
573 render_thread_id_
, provider_id(), handle
->GetObjectInfo(), attrs
));
576 void ServiceWorkerProviderHost::IncreaseProcessReference(
577 const GURL
& pattern
) {
578 if (context_
&& context_
->process_manager()) {
579 context_
->process_manager()->AddProcessReferenceToPattern(
580 pattern
, render_process_id_
);
584 void ServiceWorkerProviderHost::DecreaseProcessReference(
585 const GURL
& pattern
) {
586 if (context_
&& context_
->process_manager()) {
587 context_
->process_manager()->RemoveProcessReferenceFromPattern(
588 pattern
, render_process_id_
);
592 void ServiceWorkerProviderHost::ReturnRegistrationForReadyIfNeeded() {
593 if (!get_ready_callback_
|| get_ready_callback_
->called
)
595 ServiceWorkerRegistration
* registration
= MatchRegistration();
598 if (registration
->active_version()) {
599 get_ready_callback_
->callback
.Run(registration
);
600 get_ready_callback_
->callback
.Reset();
601 get_ready_callback_
->called
= true;
606 bool ServiceWorkerProviderHost::IsReadyToSendMessages() const {
607 return render_thread_id_
!= kInvalidEmbeddedWorkerThreadId
;
610 bool ServiceWorkerProviderHost::IsContextAlive() {
611 return context_
!= NULL
;
614 void ServiceWorkerProviderHost::Send(IPC::Message
* message
) const {
615 DCHECK(dispatcher_host_
);
616 DCHECK(IsReadyToSendMessages());
617 dispatcher_host_
->Send(message
);
620 } // namespace content