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"
7 #include "base/stl_util.h"
8 #include "content/browser/frame_host/frame_tree.h"
9 #include "content/browser/frame_host/frame_tree_node.h"
10 #include "content/browser/frame_host/render_frame_host_impl.h"
11 #include "content/browser/message_port_message_filter.h"
12 #include "content/browser/service_worker/service_worker_context_core.h"
13 #include "content/browser/service_worker/service_worker_context_request_handler.h"
14 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
15 #include "content/browser/service_worker/service_worker_dispatcher_host.h"
16 #include "content/browser/service_worker/service_worker_handle.h"
17 #include "content/browser/service_worker/service_worker_registration_handle.h"
18 #include "content/browser/service_worker/service_worker_utils.h"
19 #include "content/browser/service_worker/service_worker_version.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/common/resource_request_body.h"
22 #include "content/common/service_worker/service_worker_messages.h"
23 #include "content/common/service_worker/service_worker_types.h"
24 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/child_process_host.h"
33 ServiceWorkerClientInfo
GetClientInfoOnUIThread(
34 int render_process_id
,
35 int render_frame_id
) {
36 RenderFrameHostImpl
* render_frame_host
=
37 RenderFrameHostImpl::FromID(render_process_id
, render_frame_id
);
38 if (!render_frame_host
)
39 return ServiceWorkerClientInfo();
41 // TODO(mlamouri,michaeln): it is possible to end up collecting information
42 // for a frame that is actually being navigated and isn't exactly what we are
44 return ServiceWorkerClientInfo(
45 render_frame_host
->GetVisibilityState(),
46 render_frame_host
->IsFocused(),
47 render_frame_host
->GetLastCommittedURL(),
48 render_frame_host
->GetParent() ? REQUEST_CONTEXT_FRAME_TYPE_NESTED
49 : REQUEST_CONTEXT_FRAME_TYPE_TOP_LEVEL
);
52 ServiceWorkerClientInfo
FocusOnUIThread(
53 int render_process_id
,
54 int render_frame_id
) {
55 RenderFrameHostImpl
* render_frame_host
=
56 RenderFrameHostImpl::FromID(render_process_id
, render_frame_id
);
57 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
58 WebContents::FromRenderFrameHost(render_frame_host
));
60 if (!render_frame_host
|| !web_contents
)
61 return ServiceWorkerClientInfo();
63 FrameTreeNode
* frame_tree_node
= render_frame_host
->frame_tree_node();
65 // Focus the frame in the frame tree node, in case it has changed.
66 frame_tree_node
->frame_tree()->SetFocusedFrame(frame_tree_node
);
68 // Focus the frame's view to make sure the frame is now considered as focused.
69 render_frame_host
->GetView()->Focus();
71 // Move the web contents to the foreground.
72 web_contents
->Activate();
74 return GetClientInfoOnUIThread(render_process_id
, render_frame_id
);
77 } // anonymous namespace
79 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
80 int render_process_id
,
83 ServiceWorkerProviderType provider_type
,
84 base::WeakPtr
<ServiceWorkerContextCore
> context
,
85 ServiceWorkerDispatcherHost
* dispatcher_host
)
86 : render_process_id_(render_process_id
),
87 render_frame_id_(render_frame_id
),
88 render_thread_id_(kDocumentMainThreadId
),
89 provider_id_(provider_id
),
90 provider_type_(provider_type
),
92 dispatcher_host_(dispatcher_host
),
93 allow_association_(true),
95 DCHECK_NE(ChildProcessHost::kInvalidUniqueID
, render_process_id_
);
96 DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN
, provider_type_
);
97 if (provider_type_
== SERVICE_WORKER_PROVIDER_FOR_CONTROLLER
) {
98 // Actual thread id is set when the service worker context gets started.
99 render_thread_id_
= kInvalidEmbeddedWorkerThreadId
;
103 ServiceWorkerProviderHost::~ServiceWorkerProviderHost() {
104 // Clear docurl so the deferred activation of a waiting worker
105 // won't associate the new version with a provider being destroyed.
106 document_url_
= GURL();
107 if (controlling_version_
.get())
108 controlling_version_
->RemoveControllee(this);
109 if (associated_registration_
.get()) {
110 DecreaseProcessReference(associated_registration_
->pattern());
111 associated_registration_
->RemoveListener(this);
114 for (const GURL
& pattern
: associated_patterns_
)
115 DecreaseProcessReference(pattern
);
118 void ServiceWorkerProviderHost::OnRegistrationFailed(
119 ServiceWorkerRegistration
* registration
) {
120 DCHECK_EQ(associated_registration_
.get(), registration
);
121 DisassociateRegistration();
124 void ServiceWorkerProviderHost::OnSkippedWaiting(
125 ServiceWorkerRegistration
* registration
) {
126 DCHECK_EQ(associated_registration_
.get(), registration
);
127 // A client is "using" a registration if it is controlled by the active
128 // worker of the registration. skipWaiting doesn't cause a client to start
129 // using the registration.
130 if (!controlling_version_
)
132 ServiceWorkerVersion
* active_version
= registration
->active_version();
133 DCHECK_EQ(active_version
->status(), ServiceWorkerVersion::ACTIVATING
);
134 SetControllerVersionAttribute(active_version
);
137 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL
& url
) {
138 DCHECK(!url
.has_ref());
142 void ServiceWorkerProviderHost::SetTopmostFrameUrl(const GURL
& url
) {
143 topmost_frame_url_
= url
;
146 void ServiceWorkerProviderHost::SetControllerVersionAttribute(
147 ServiceWorkerVersion
* version
) {
148 if (version
== controlling_version_
.get())
151 scoped_refptr
<ServiceWorkerVersion
> previous_version
= controlling_version_
;
152 controlling_version_
= version
;
154 version
->AddControllee(this);
155 if (previous_version
.get())
156 previous_version
->RemoveControllee(this);
158 if (!dispatcher_host_
)
159 return; // Could be NULL in some tests.
161 bool should_notify_controllerchange
=
162 is_claiming_
|| (previous_version
&& version
&& version
->skip_waiting());
164 // SetController message should be sent only for controllees.
165 DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLEE
, provider_type_
);
166 Send(new ServiceWorkerMsg_SetControllerServiceWorker(
167 render_thread_id_
, provider_id(),
168 CreateAndRegisterServiceWorkerHandle(version
),
169 should_notify_controllerchange
));
172 bool ServiceWorkerProviderHost::SetHostedVersionId(int64 version_id
) {
174 return true; // System is shutting down.
175 if (active_version())
176 return false; // Unexpected bad message.
178 ServiceWorkerVersion
* live_version
= context_
->GetLiveVersion(version_id
);
180 return true; // Was deleted before it got started.
182 ServiceWorkerVersionInfo info
= live_version
->GetInfo();
183 if (info
.running_status
!= ServiceWorkerVersion::STARTING
||
184 info
.process_id
!= render_process_id_
) {
185 // If we aren't trying to start this version in our process
186 // something is amiss.
190 running_hosted_version_
= live_version
;
194 void ServiceWorkerProviderHost::AssociateRegistration(
195 ServiceWorkerRegistration
* registration
) {
196 DCHECK(CanAssociateRegistration(registration
));
197 IncreaseProcessReference(registration
->pattern());
198 associated_registration_
= registration
;
199 associated_registration_
->AddListener(this);
200 SendAssociateRegistrationMessage();
201 SetControllerVersionAttribute(registration
->active_version());
204 void ServiceWorkerProviderHost::DisassociateRegistration() {
205 queued_events_
.clear();
206 if (!associated_registration_
.get())
208 DecreaseProcessReference(associated_registration_
->pattern());
209 associated_registration_
->RemoveListener(this);
210 associated_registration_
= NULL
;
211 SetControllerVersionAttribute(NULL
);
213 if (!dispatcher_host_
)
216 // Disassociation message should be sent only for controllees.
217 DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLEE
, provider_type_
);
218 Send(new ServiceWorkerMsg_DisassociateRegistration(
219 render_thread_id_
, provider_id()));
222 scoped_ptr
<ServiceWorkerRequestHandler
>
223 ServiceWorkerProviderHost::CreateRequestHandler(
224 FetchRequestMode request_mode
,
225 FetchCredentialsMode credentials_mode
,
226 ResourceType resource_type
,
227 RequestContextType request_context_type
,
228 RequestContextFrameType frame_type
,
229 base::WeakPtr
<storage::BlobStorageContext
> blob_storage_context
,
230 scoped_refptr
<ResourceRequestBody
> body
) {
231 if (IsHostToRunningServiceWorker()) {
232 return scoped_ptr
<ServiceWorkerRequestHandler
>(
233 new ServiceWorkerContextRequestHandler(
234 context_
, AsWeakPtr(), blob_storage_context
, resource_type
));
236 if (ServiceWorkerUtils::IsMainResourceType(resource_type
) ||
237 controlling_version()) {
238 return scoped_ptr
<ServiceWorkerRequestHandler
>(
239 new ServiceWorkerControlleeRequestHandler(context_
,
241 blob_storage_context
,
245 request_context_type
,
249 return scoped_ptr
<ServiceWorkerRequestHandler
>();
252 ServiceWorkerObjectInfo
253 ServiceWorkerProviderHost::CreateAndRegisterServiceWorkerHandle(
254 ServiceWorkerVersion
* version
) {
255 DCHECK(dispatcher_host_
);
256 ServiceWorkerObjectInfo info
;
257 if (context_
&& version
) {
258 scoped_ptr
<ServiceWorkerHandle
> handle
=
259 ServiceWorkerHandle::Create(context_
, AsWeakPtr(), version
);
260 info
= handle
->GetObjectInfo();
261 dispatcher_host_
->RegisterServiceWorkerHandle(handle
.Pass());
266 bool ServiceWorkerProviderHost::CanAssociateRegistration(
267 ServiceWorkerRegistration
* registration
) {
270 if (running_hosted_version_
.get())
272 if (!registration
|| associated_registration_
.get() || !allow_association_
)
277 void ServiceWorkerProviderHost::PostMessage(
278 const base::string16
& message
,
279 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
280 if (!dispatcher_host_
)
281 return; // Could be NULL in some tests.
283 std::vector
<int> new_routing_ids
;
284 dispatcher_host_
->message_port_message_filter()->
285 UpdateMessagePortsWithNewRoutes(sent_message_ports
,
288 Send(new ServiceWorkerMsg_MessageToDocument(
289 kDocumentMainThreadId
, provider_id(),
295 void ServiceWorkerProviderHost::Focus(const GetClientInfoCallback
& callback
) {
296 BrowserThread::PostTaskAndReplyWithResult(
297 BrowserThread::UI
, FROM_HERE
,
298 base::Bind(&FocusOnUIThread
,
304 void ServiceWorkerProviderHost::GetClientInfo(
305 const GetClientInfoCallback
& callback
) const {
306 BrowserThread::PostTaskAndReplyWithResult(
307 BrowserThread::UI
, FROM_HERE
,
308 base::Bind(&GetClientInfoOnUIThread
,
314 void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
315 const GURL
& pattern
) {
316 associated_patterns_
.push_back(pattern
);
317 IncreaseProcessReference(pattern
);
320 void ServiceWorkerProviderHost::ClaimedByRegistration(
321 ServiceWorkerRegistration
* registration
) {
322 DCHECK(registration
->active_version());
324 if (registration
== associated_registration_
) {
325 SetControllerVersionAttribute(registration
->active_version());
326 } else if (allow_association_
) {
327 DisassociateRegistration();
328 AssociateRegistration(registration
);
330 is_claiming_
= false;
333 void ServiceWorkerProviderHost::PrepareForCrossSiteTransfer() {
334 DCHECK_NE(ChildProcessHost::kInvalidUniqueID
, render_process_id_
);
335 DCHECK_NE(MSG_ROUTING_NONE
, render_frame_id_
);
336 DCHECK_EQ(kDocumentMainThreadId
, render_thread_id_
);
337 DCHECK_NE(SERVICE_WORKER_PROVIDER_UNKNOWN
, provider_type_
);
339 for (const GURL
& pattern
: associated_patterns_
)
340 DecreaseProcessReference(pattern
);
342 if (associated_registration_
.get()) {
343 DecreaseProcessReference(associated_registration_
->pattern());
344 if (dispatcher_host_
) {
345 Send(new ServiceWorkerMsg_DisassociateRegistration(
346 render_thread_id_
, provider_id()));
350 render_process_id_
= ChildProcessHost::kInvalidUniqueID
;
351 render_frame_id_
= MSG_ROUTING_NONE
;
352 render_thread_id_
= kInvalidEmbeddedWorkerThreadId
;
353 provider_id_
= kInvalidServiceWorkerProviderId
;
354 provider_type_
= SERVICE_WORKER_PROVIDER_UNKNOWN
;
355 dispatcher_host_
= nullptr;
358 void ServiceWorkerProviderHost::CompleteCrossSiteTransfer(
362 ServiceWorkerProviderType new_provider_type
,
363 ServiceWorkerDispatcherHost
* new_dispatcher_host
) {
364 DCHECK_EQ(ChildProcessHost::kInvalidUniqueID
, render_process_id_
);
365 DCHECK_NE(ChildProcessHost::kInvalidUniqueID
, new_process_id
);
366 DCHECK_NE(MSG_ROUTING_NONE
, new_frame_id
);
368 render_process_id_
= new_process_id
;
369 render_frame_id_
= new_frame_id
;
370 render_thread_id_
= kDocumentMainThreadId
;
371 provider_id_
= new_provider_id
;
372 provider_type_
= new_provider_type
;
373 dispatcher_host_
= new_dispatcher_host
;
375 for (const GURL
& pattern
: associated_patterns_
)
376 IncreaseProcessReference(pattern
);
378 if (associated_registration_
.get()) {
379 IncreaseProcessReference(associated_registration_
->pattern());
380 SendAssociateRegistrationMessage();
381 if (dispatcher_host_
&& associated_registration_
->active_version()) {
382 Send(new ServiceWorkerMsg_SetControllerServiceWorker(
383 render_thread_id_
, provider_id(),
384 CreateAndRegisterServiceWorkerHandle(
385 associated_registration_
->active_version()),
386 false /* shouldNotifyControllerChange */));
391 void ServiceWorkerProviderHost::SendUpdateFoundMessage(
392 const ServiceWorkerRegistrationObjectInfo
& object_info
) {
393 if (!dispatcher_host_
)
394 return; // Could be nullptr in some tests.
396 if (!IsReadyToSendMessages()) {
397 queued_events_
.push_back(
398 base::Bind(&ServiceWorkerProviderHost::SendUpdateFoundMessage
,
399 AsWeakPtr(), object_info
));
403 Send(new ServiceWorkerMsg_UpdateFound(render_thread_id_
, object_info
));
406 void ServiceWorkerProviderHost::SendSetVersionAttributesMessage(
407 int registration_handle_id
,
408 ChangedVersionAttributesMask changed_mask
,
409 ServiceWorkerVersion
* installing_version
,
410 ServiceWorkerVersion
* waiting_version
,
411 ServiceWorkerVersion
* active_version
) {
412 if (!dispatcher_host_
)
413 return; // Could be nullptr in some tests.
414 if (!changed_mask
.changed())
417 if (!IsReadyToSendMessages()) {
418 queued_events_
.push_back(
419 base::Bind(&ServiceWorkerProviderHost::SendSetVersionAttributesMessage
,
420 AsWeakPtr(), registration_handle_id
, changed_mask
,
421 make_scoped_refptr(installing_version
),
422 make_scoped_refptr(waiting_version
),
423 make_scoped_refptr(active_version
)));
427 ServiceWorkerVersionAttributes attrs
;
428 if (changed_mask
.installing_changed())
429 attrs
.installing
= CreateAndRegisterServiceWorkerHandle(installing_version
);
430 if (changed_mask
.waiting_changed())
431 attrs
.waiting
= CreateAndRegisterServiceWorkerHandle(waiting_version
);
432 if (changed_mask
.active_changed())
433 attrs
.active
= CreateAndRegisterServiceWorkerHandle(active_version
);
435 Send(new ServiceWorkerMsg_SetVersionAttributes(
436 render_thread_id_
, provider_id_
, registration_handle_id
,
437 changed_mask
.changed(), attrs
));
440 void ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage(
441 int worker_handle_id
,
442 blink::WebServiceWorkerState state
) {
443 if (!dispatcher_host_
)
446 if (!IsReadyToSendMessages()) {
447 queued_events_
.push_back(base::Bind(
448 &ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage
,
449 AsWeakPtr(), worker_handle_id
, state
));
453 Send(new ServiceWorkerMsg_ServiceWorkerStateChanged(
454 render_thread_id_
, worker_handle_id
, state
));
457 void ServiceWorkerProviderHost::SetReadyToSendMessagesToWorker(
458 int render_thread_id
) {
459 DCHECK(!IsReadyToSendMessages());
460 render_thread_id_
= render_thread_id
;
462 for (const auto& event
: queued_events_
)
464 queued_events_
.clear();
467 void ServiceWorkerProviderHost::SendAssociateRegistrationMessage() {
468 if (!dispatcher_host_
)
471 ServiceWorkerRegistrationHandle
* handle
=
472 dispatcher_host_
->GetOrCreateRegistrationHandle(
473 AsWeakPtr(), associated_registration_
.get());
475 ServiceWorkerVersionAttributes attrs
;
476 attrs
.installing
= CreateAndRegisterServiceWorkerHandle(
477 associated_registration_
->installing_version());
478 attrs
.waiting
= CreateAndRegisterServiceWorkerHandle(
479 associated_registration_
->waiting_version());
480 attrs
.active
= CreateAndRegisterServiceWorkerHandle(
481 associated_registration_
->active_version());
483 // Association message should be sent only for controllees.
484 DCHECK_EQ(SERVICE_WORKER_PROVIDER_FOR_CONTROLLEE
, provider_type_
);
485 dispatcher_host_
->Send(new ServiceWorkerMsg_AssociateRegistration(
486 render_thread_id_
, provider_id(), handle
->GetObjectInfo(), attrs
));
489 void ServiceWorkerProviderHost::IncreaseProcessReference(
490 const GURL
& pattern
) {
491 if (context_
&& context_
->process_manager()) {
492 context_
->process_manager()->AddProcessReferenceToPattern(
493 pattern
, render_process_id_
);
497 void ServiceWorkerProviderHost::DecreaseProcessReference(
498 const GURL
& pattern
) {
499 if (context_
&& context_
->process_manager()) {
500 context_
->process_manager()->RemoveProcessReferenceFromPattern(
501 pattern
, render_process_id_
);
505 bool ServiceWorkerProviderHost::IsReadyToSendMessages() const {
506 return render_thread_id_
!= kInvalidEmbeddedWorkerThreadId
;
509 bool ServiceWorkerProviderHost::IsContextAlive() {
510 return context_
!= NULL
;
513 void ServiceWorkerProviderHost::Send(IPC::Message
* message
) const {
514 DCHECK(dispatcher_host_
);
515 DCHECK(IsReadyToSendMessages());
516 dispatcher_host_
->Send(message
);
519 } // namespace content