1 // Copyright 2014 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. 4 5 #include "content/child/service_worker/service_worker_provider_context.h" 6 7 #include "base/bind.h" 8 #include "base/message_loop/message_loop_proxy.h" 9 #include "base/stl_util.h" 10 #include "content/child/child_thread.h" 11 #include "content/child/service_worker/service_worker_dispatcher.h" 12 #include "content/child/service_worker/service_worker_handle_reference.h" 13 #include "content/child/service_worker/service_worker_registration_handle_reference.h" 14 #include "content/child/thread_safe_sender.h" 15 #include "content/child/worker_task_runner.h" 16 #include "content/common/service_worker/service_worker_messages.h" 17 18 namespace content { 19 20 ServiceWorkerProviderContext::ServiceWorkerProviderContext(int provider_id) 21 : provider_id_(provider_id), 22 main_thread_loop_proxy_(base::MessageLoopProxy::current()) { 23 if (!ChildThread::current()) 24 return; // May be null in some tests. 25 thread_safe_sender_ = ChildThread::current()->thread_safe_sender(); 26 ServiceWorkerDispatcher* dispatcher = 27 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance( 28 thread_safe_sender_.get()); 29 DCHECK(dispatcher); 30 dispatcher->AddProviderContext(this); 31 } 32 33 ServiceWorkerProviderContext::~ServiceWorkerProviderContext() { 34 if (ServiceWorkerDispatcher* dispatcher = 35 ServiceWorkerDispatcher::GetThreadSpecificInstance()) { 36 dispatcher->RemoveProviderContext(this); 37 } 38 } 39 40 ServiceWorkerHandleReference* ServiceWorkerProviderContext::installing() { 41 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 42 return installing_.get(); 43 } 44 45 ServiceWorkerHandleReference* ServiceWorkerProviderContext::waiting() { 46 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 47 return waiting_.get(); 48 } 49 50 ServiceWorkerHandleReference* ServiceWorkerProviderContext::active() { 51 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 52 return active_.get(); 53 } 54 55 ServiceWorkerHandleReference* ServiceWorkerProviderContext::controller() { 56 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 57 return controller_.get(); 58 } 59 60 ServiceWorkerRegistrationHandleReference* 61 ServiceWorkerProviderContext::registration() { 62 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 63 return registration_.get(); 64 } 65 66 ServiceWorkerVersionAttributes 67 ServiceWorkerProviderContext::GetVersionAttributes() { 68 ServiceWorkerVersionAttributes attrs; 69 if (installing()) 70 attrs.installing = installing()->info(); 71 if (waiting()) 72 attrs.waiting = waiting()->info(); 73 if (active()) 74 attrs.active = active()->info(); 75 return attrs; 76 } 77 78 void ServiceWorkerProviderContext::OnAssociateRegistration( 79 const ServiceWorkerRegistrationObjectInfo& info, 80 const ServiceWorkerVersionAttributes& attrs) { 81 DCHECK(!registration_); 82 DCHECK_NE(kInvalidServiceWorkerRegistrationHandleId, info.handle_id); 83 registration_ = ServiceWorkerRegistrationHandleReference::Adopt( 84 info, thread_safe_sender_.get()); 85 installing_ = ServiceWorkerHandleReference::Adopt( 86 attrs.installing, thread_safe_sender_.get()); 87 waiting_ = ServiceWorkerHandleReference::Adopt( 88 attrs.waiting, thread_safe_sender_.get()); 89 active_ = ServiceWorkerHandleReference::Adopt( 90 attrs.active, thread_safe_sender_.get()); 91 } 92 93 void ServiceWorkerProviderContext::OnDisassociateRegistration() { 94 controller_.reset(); 95 active_.reset(); 96 waiting_.reset(); 97 installing_.reset(); 98 registration_.reset(); 99 } 100 101 void ServiceWorkerProviderContext::OnServiceWorkerStateChanged( 102 int handle_id, 103 blink::WebServiceWorkerState state) { 104 ServiceWorkerHandleReference* which = NULL; 105 if (handle_id == controller_handle_id()) 106 which = controller_.get(); 107 else if (handle_id == active_handle_id()) 108 which = active_.get(); 109 else if (handle_id == waiting_handle_id()) 110 which = waiting_.get(); 111 else if (handle_id == installing_handle_id()) 112 which = installing_.get(); 113 114 // We should only get messages for ServiceWorkers associated with 115 // this provider. 116 DCHECK(which); 117 118 which->set_state(state); 119 120 // TODO(kinuko): We can forward the message to other threads here 121 // when we support navigator.serviceWorker in dedicated workers. 122 } 123 124 void ServiceWorkerProviderContext::OnSetInstallingServiceWorker( 125 int registration_handle_id, 126 const ServiceWorkerObjectInfo& info) { 127 DCHECK(IsAssociatedWithRegistration(registration_handle_id)); 128 installing_ = 129 ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()); 130 } 131 132 void ServiceWorkerProviderContext::OnSetWaitingServiceWorker( 133 int registration_handle_id, 134 const ServiceWorkerObjectInfo& info) { 135 DCHECK(IsAssociatedWithRegistration(registration_handle_id)); 136 waiting_ = 137 ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()); 138 } 139 140 void ServiceWorkerProviderContext::OnSetActiveServiceWorker( 141 int registration_handle_id, 142 const ServiceWorkerObjectInfo& info) { 143 DCHECK(IsAssociatedWithRegistration(registration_handle_id)); 144 active_ = 145 ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()); 146 } 147 148 void ServiceWorkerProviderContext::OnSetControllerServiceWorker( 149 int registration_handle_id, 150 const ServiceWorkerObjectInfo& info) { 151 DCHECK(IsAssociatedWithRegistration(registration_handle_id)); 152 153 // This context is is the primary owner of this handle, keeps the 154 // initial reference until it goes away. 155 controller_ = 156 ServiceWorkerHandleReference::Adopt(info, thread_safe_sender_.get()); 157 158 // TODO(kinuko): We can forward the message to other threads here 159 // when we support navigator.serviceWorker in dedicated workers. 160 } 161 162 int ServiceWorkerProviderContext::installing_handle_id() const { 163 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 164 return installing_ ? installing_->info().handle_id 165 : kInvalidServiceWorkerHandleId; 166 } 167 168 int ServiceWorkerProviderContext::waiting_handle_id() const { 169 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 170 return waiting_ ? waiting_->info().handle_id 171 : kInvalidServiceWorkerHandleId; 172 } 173 174 int ServiceWorkerProviderContext::active_handle_id() const { 175 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 176 return active_ ? active_->info().handle_id 177 : kInvalidServiceWorkerHandleId; 178 } 179 180 int ServiceWorkerProviderContext::controller_handle_id() const { 181 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 182 return controller_ ? controller_->info().handle_id 183 : kInvalidServiceWorkerHandleId; 184 } 185 186 int ServiceWorkerProviderContext::registration_handle_id() const { 187 DCHECK(main_thread_loop_proxy_->RunsTasksOnCurrentThread()); 188 return registration_ ? registration_->info().handle_id 189 : kInvalidServiceWorkerRegistrationHandleId; 190 } 191 192 bool ServiceWorkerProviderContext::IsAssociatedWithRegistration( 193 int registration_handle_id) const { 194 if (!registration_) 195 return false; 196 if (registration_handle_id == kInvalidServiceWorkerRegistrationHandleId) 197 return false; 198 return registration_->info().handle_id == registration_handle_id; 199 } 200 201 } // namespace content 202