Simplify ChildProcessLauncher
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_provider_host.cc
blobeaa46e36188d8eec529b004942dc71ad7814f567
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/guid.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"
30 namespace content {
32 namespace {
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)
64 : callback(callback),
65 called(false) {
68 ServiceWorkerProviderHost::OneShotGetReadyCallback::~OneShotGetReadyCallback() {
71 ServiceWorkerProviderHost::ServiceWorkerProviderHost(
72 int render_process_id,
73 int render_frame_id,
74 int provider_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),
84 context_(context),
85 dispatcher_host_(dispatcher_host),
86 allow_association_(true),
87 is_claiming_(false) {
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() {
98 if (context_)
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)
121 return;
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,
127 AsWeakPtr()));
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)
146 return;
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_)
151 return;
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());
159 document_url_ = url;
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())
169 return;
171 scoped_refptr<ServiceWorkerVersion> previous_version = controlling_version_;
172 controlling_version_ = version;
173 if (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) {
193 if (!context_)
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);
199 if (!live_version)
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.
207 return false;
210 running_hosted_version_ = live_version;
211 return true;
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())
226 return;
227 associated_registration_ = NULL;
228 SetControllerVersionAttribute(NULL);
230 if (!dispatcher_host_)
231 return;
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))
245 return;
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())
267 continue;
268 if (it->second->is_uninstalling())
269 return nullptr;
270 return it->second.get();
272 return nullptr;
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_,
293 AsWeakPtr(),
294 blob_storage_context,
295 request_mode,
296 credentials_mode,
297 resource_type,
298 request_context_type,
299 frame_type,
300 body));
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());
316 return info;
319 bool ServiceWorkerProviderHost::CanAssociateRegistration(
320 ServiceWorkerRegistration* registration) {
321 if (!context_)
322 return false;
323 if (running_hosted_version_.get())
324 return false;
325 if (!registration || associated_registration_.get() || !allow_association_)
326 return false;
327 return true;
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,
339 &new_routing_ids);
341 Send(new ServiceWorkerMsg_MessageToDocument(
342 kDocumentMainThreadId, provider_id(),
343 message,
344 sent_message_ports,
345 new_routing_ids));
348 void ServiceWorkerProviderHost::Focus(const GetClientInfoCallback& callback) {
349 BrowserThread::PostTaskAndReplyWithResult(
350 BrowserThread::UI, FROM_HERE,
351 base::Bind(&FocusOnUIThread,
352 render_process_id_,
353 render_frame_id_),
354 callback);
357 void ServiceWorkerProviderHost::GetClientInfo(
358 const GetClientInfoCallback& callback) const {
359 BrowserThread::PostTaskAndReplyWithResult(
360 BrowserThread::UI, FROM_HERE,
361 base::Bind(&ServiceWorkerProviderHost::GetClientInfoOnUI,
362 render_process_id_,
363 render_frame_id_),
364 callback);
367 // static
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
377 // expecting.
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());
396 is_claiming_ = true;
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_)
409 return false;
410 get_ready_callback_.reset(new OneShotGetReadyCallback(callback));
411 ReturnRegistrationForReadyIfNeeded();
412 return true;
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(
443 int new_process_id,
444 int new_frame_id,
445 int new_provider_id,
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));
486 return;
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())
502 return;
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)));
511 return;
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_)
531 return;
533 if (!IsReadyToSendMessages()) {
534 queued_events_.push_back(base::Bind(
535 &ServiceWorkerProviderHost::SendServiceWorkerStateChangedMessage,
536 AsWeakPtr(), worker_handle_id, state));
537 return;
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_)
550 event.Run();
551 queued_events_.clear();
554 void ServiceWorkerProviderHost::SendAssociateRegistrationMessage() {
555 if (!dispatcher_host_)
556 return;
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)
594 return;
595 ServiceWorkerRegistration* registration = MatchRegistration();
596 if (!registration)
597 return;
598 if (registration->active_version()) {
599 get_ready_callback_->callback.Run(registration);
600 get_ready_callback_->callback.Reset();
601 get_ready_callback_->called = true;
602 return;
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