ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blobae48d1dc0f889baa6052bc62e1d2a5c58ee1ed00
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_registration.h"
7 #include "content/browser/service_worker/service_worker_context_core.h"
8 #include "content/browser/service_worker/service_worker_info.h"
9 #include "content/browser/service_worker/service_worker_register_job.h"
10 #include "content/browser/service_worker/service_worker_utils.h"
11 #include "content/public/browser/browser_thread.h"
13 namespace content {
15 namespace {
17 ServiceWorkerVersionInfo GetVersionInfo(ServiceWorkerVersion* version) {
18 if (!version)
19 return ServiceWorkerVersionInfo();
20 return version->GetInfo();
23 } // namespace
25 ServiceWorkerRegistration::ServiceWorkerRegistration(
26 const GURL& pattern,
27 int64 registration_id,
28 base::WeakPtr<ServiceWorkerContextCore> context)
29 : pattern_(pattern),
30 registration_id_(registration_id),
31 is_deleted_(false),
32 is_uninstalling_(false),
33 is_uninstalled_(false),
34 should_activate_when_ready_(false),
35 resources_total_size_bytes_(0),
36 context_(context) {
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
38 DCHECK(context_);
39 context_->AddLiveRegistration(this);
42 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
44 DCHECK(!listeners_.might_have_observers());
45 if (context_)
46 context_->RemoveLiveRegistration(registration_id_);
47 if (active_version())
48 active_version()->RemoveListener(this);
51 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
52 if (installing_version())
53 return installing_version();
54 if (waiting_version())
55 return waiting_version();
56 return active_version();
59 void ServiceWorkerRegistration::AddListener(Listener* listener) {
60 listeners_.AddObserver(listener);
63 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
64 listeners_.RemoveObserver(listener);
67 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
68 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
71 void ServiceWorkerRegistration::NotifyUpdateFound() {
72 FOR_EACH_OBSERVER(Listener, listeners_, OnUpdateFound(this));
75 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
77 return ServiceWorkerRegistrationInfo(
78 pattern(),
79 registration_id_,
80 GetVersionInfo(active_version_.get()),
81 GetVersionInfo(waiting_version_.get()),
82 GetVersionInfo(installing_version_.get()),
83 resources_total_size_bytes_);
86 void ServiceWorkerRegistration::SetActiveVersion(
87 ServiceWorkerVersion* version) {
88 should_activate_when_ready_ = false;
89 SetVersionInternal(version, &active_version_,
90 ChangedVersionAttributesMask::ACTIVE_VERSION);
93 void ServiceWorkerRegistration::SetWaitingVersion(
94 ServiceWorkerVersion* version) {
95 should_activate_when_ready_ = false;
96 SetVersionInternal(version, &waiting_version_,
97 ChangedVersionAttributesMask::WAITING_VERSION);
100 void ServiceWorkerRegistration::SetInstallingVersion(
101 ServiceWorkerVersion* version) {
102 SetVersionInternal(version, &installing_version_,
103 ChangedVersionAttributesMask::INSTALLING_VERSION);
106 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
107 if (!version)
108 return;
109 ChangedVersionAttributesMask mask;
110 UnsetVersionInternal(version, &mask);
111 if (mask.changed()) {
112 ServiceWorkerRegistrationInfo info = GetInfo();
113 FOR_EACH_OBSERVER(Listener, listeners_,
114 OnVersionAttributesChanged(this, mask, info));
118 void ServiceWorkerRegistration::SetVersionInternal(
119 ServiceWorkerVersion* version,
120 scoped_refptr<ServiceWorkerVersion>* data_member,
121 int change_flag) {
122 if (version == data_member->get())
123 return;
124 scoped_refptr<ServiceWorkerVersion> protect(version);
125 ChangedVersionAttributesMask mask;
126 if (version)
127 UnsetVersionInternal(version, &mask);
128 if (*data_member && *data_member == active_version_)
129 active_version_->RemoveListener(this);
130 *data_member = version;
131 if (active_version_.get() && active_version_.get() == version)
132 active_version_->AddListener(this);
133 mask.add(change_flag);
134 ServiceWorkerRegistrationInfo info = GetInfo();
135 FOR_EACH_OBSERVER(Listener, listeners_,
136 OnVersionAttributesChanged(this, mask, info));
139 void ServiceWorkerRegistration::UnsetVersionInternal(
140 ServiceWorkerVersion* version,
141 ChangedVersionAttributesMask* mask) {
142 DCHECK(version);
143 if (installing_version_.get() == version) {
144 installing_version_ = NULL;
145 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
146 } else if (waiting_version_.get() == version) {
147 waiting_version_ = NULL;
148 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
149 } else if (active_version_.get() == version) {
150 active_version_->RemoveListener(this);
151 active_version_ = NULL;
152 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
156 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
157 DCHECK(waiting_version());
158 should_activate_when_ready_ = true;
160 if (!active_version() || !active_version()->HasControllee() ||
161 waiting_version()->skip_waiting())
162 ActivateWaitingVersion();
165 void ServiceWorkerRegistration::ClaimClients(const StatusCallback& callback) {
166 DCHECK(context_);
167 DCHECK(active_version());
168 // TODO(xiang): Should better not hit the database http://crbug.com/454250.
169 context_->storage()->GetRegistrationsForOrigin(
170 pattern_.GetOrigin(),
171 base::Bind(&ServiceWorkerRegistration::DidGetRegistrationsForClaimClients,
172 this, callback, active_version_));
175 void ServiceWorkerRegistration::ClearWhenReady() {
176 DCHECK(context_);
177 if (is_uninstalling_)
178 return;
179 is_uninstalling_ = true;
181 context_->storage()->NotifyUninstallingRegistration(this);
182 context_->storage()->DeleteRegistration(
183 id(),
184 pattern().GetOrigin(),
185 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
187 if (!active_version() || !active_version()->HasControllee())
188 Clear();
191 void ServiceWorkerRegistration::AbortPendingClear(
192 const StatusCallback& callback) {
193 DCHECK(context_);
194 if (!is_uninstalling()) {
195 callback.Run(SERVICE_WORKER_OK);
196 return;
198 is_uninstalling_ = false;
199 context_->storage()->NotifyDoneUninstallingRegistration(this);
201 scoped_refptr<ServiceWorkerVersion> most_recent_version =
202 waiting_version() ? waiting_version() : active_version();
203 DCHECK(most_recent_version.get());
204 context_->storage()->NotifyInstallingRegistration(this);
205 context_->storage()->StoreRegistration(
206 this,
207 most_recent_version.get(),
208 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
209 this,
210 callback,
211 most_recent_version));
214 void ServiceWorkerRegistration::GetUserData(
215 const std::string& key,
216 const GetUserDataCallback& callback) {
217 DCHECK(context_);
218 context_->storage()->GetUserData(registration_id_, key, callback);
221 void ServiceWorkerRegistration::StoreUserData(
222 const std::string& key,
223 const std::string& data,
224 const StatusCallback& callback) {
225 DCHECK(context_);
226 context_->storage()->StoreUserData(
227 registration_id_, pattern().GetOrigin(), key, data, callback);
230 void ServiceWorkerRegistration::ClearUserData(
231 const std::string& key,
232 const StatusCallback& callback) {
233 DCHECK(context_);
234 context_->storage()->ClearUserData(registration_id_, key, callback);
237 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
238 DCHECK_EQ(active_version(), version);
239 if (is_uninstalling_)
240 Clear();
241 else if (should_activate_when_ready_)
242 ActivateWaitingVersion();
243 is_uninstalling_ = false;
244 should_activate_when_ready_ = false;
247 void ServiceWorkerRegistration::ActivateWaitingVersion() {
248 DCHECK(context_);
249 DCHECK(waiting_version());
250 DCHECK(should_activate_when_ready_);
251 should_activate_when_ready_ = false;
252 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
253 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
255 if (activating_version->is_doomed() ||
256 activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
257 return; // Activation is no longer relevant.
260 // "5. If exitingWorker is not null,
261 if (exiting_version.get()) {
262 // TODO(michaeln): should wait for events to be complete
263 // "1. Wait for exitingWorker to finish handling any in-progress requests."
264 // "2. Terminate exitingWorker."
265 exiting_version->StopWorker(
266 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
267 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
268 // "redundant" as the arguments."
269 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
272 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
273 // "7. Set serviceWorkerRegistration.waitingWorker to null."
274 SetActiveVersion(activating_version.get());
276 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
277 // "activating" as arguments."
278 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
279 // "9. Fire a simple event named controllerchange..."
280 if (activating_version->skip_waiting())
281 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
283 // "10. Queue a task to fire an event named activate..."
284 activating_version->DispatchActivateEvent(
285 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
286 this, activating_version));
289 void ServiceWorkerRegistration::OnActivateEventFinished(
290 ServiceWorkerVersion* activating_version,
291 ServiceWorkerStatusCode status) {
292 if (!context_ || activating_version != active_version())
293 return;
294 // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
295 // unexpectedly terminated) we may want to retry sending the event again.
296 if (status != SERVICE_WORKER_OK) {
297 // "11. If activateFailed is true, then:..."
298 UnsetVersion(activating_version);
299 activating_version->Doom();
300 if (!waiting_version()) {
301 // Delete the records from the db.
302 context_->storage()->DeleteRegistration(
303 id(), pattern().GetOrigin(),
304 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
305 // But not from memory if there is a version in the pipeline.
306 if (installing_version())
307 is_deleted_ = false;
308 else
309 is_uninstalled_ = true;
311 return;
314 // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
315 // and "activated" as the arguments."
316 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
317 if (context_) {
318 context_->storage()->UpdateToActiveState(
319 this,
320 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
324 void ServiceWorkerRegistration::OnDeleteFinished(
325 ServiceWorkerStatusCode status) {
326 // Intentionally empty completion callback, used to prevent
327 // |this| from being deleted until the storage method completes.
330 void ServiceWorkerRegistration::Clear() {
331 is_uninstalling_ = false;
332 is_uninstalled_ = true;
333 if (context_)
334 context_->storage()->NotifyDoneUninstallingRegistration(this);
336 ChangedVersionAttributesMask mask;
337 if (installing_version_.get()) {
338 installing_version_->Doom();
339 installing_version_ = NULL;
340 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
342 if (waiting_version_.get()) {
343 waiting_version_->Doom();
344 waiting_version_ = NULL;
345 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
347 if (active_version_.get()) {
348 active_version_->Doom();
349 active_version_->RemoveListener(this);
350 active_version_ = NULL;
351 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
353 if (mask.changed()) {
354 ServiceWorkerRegistrationInfo info = GetInfo();
355 FOR_EACH_OBSERVER(Listener, listeners_,
356 OnVersionAttributesChanged(this, mask, info));
360 void ServiceWorkerRegistration::OnRestoreFinished(
361 const StatusCallback& callback,
362 scoped_refptr<ServiceWorkerVersion> version,
363 ServiceWorkerStatusCode status) {
364 if (!context_) {
365 callback.Run(SERVICE_WORKER_ERROR_ABORT);
366 return;
368 context_->storage()->NotifyDoneInstallingRegistration(
369 this, version.get(), status);
370 callback.Run(status);
373 void ServiceWorkerRegistration::DidGetRegistrationsForClaimClients(
374 const StatusCallback& callback,
375 scoped_refptr<ServiceWorkerVersion> version,
376 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
377 if (!context_) {
378 callback.Run(SERVICE_WORKER_ERROR_ABORT);
379 return;
381 if (!active_version() || version != active_version()) {
382 callback.Run(SERVICE_WORKER_ERROR_STATE);
383 return;
386 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
387 context_->GetProviderHostIterator();
388 !it->IsAtEnd(); it->Advance()) {
389 ServiceWorkerProviderHost* host = it->GetProviderHost();
390 if (ShouldClaim(host, registrations))
391 host->ClaimedByRegistration(this);
393 callback.Run(SERVICE_WORKER_OK);
396 bool ServiceWorkerRegistration::ShouldClaim(
397 ServiceWorkerProviderHost* provider_host,
398 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
399 if (provider_host->IsHostToRunningServiceWorker())
400 return false;
401 if (provider_host->controlling_version() == active_version())
402 return false;
404 LongestScopeMatcher matcher(provider_host->document_url());
405 if (!matcher.MatchLongest(pattern_))
406 return false;
407 for (const ServiceWorkerRegistrationInfo& info : registrations) {
408 ServiceWorkerRegistration* registration =
409 context_->GetLiveRegistration(info.registration_id);
410 if (registration &&
411 (registration->is_uninstalling() || registration->is_uninstalled()))
412 continue;
413 if (matcher.MatchLongest(info.pattern))
414 return false;
416 return true;
419 } // namespace content