Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blob6909f354f1e4e8273f1a5f6d80d8cde084d3755a
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_metrics.h"
10 #include "content/browser/service_worker/service_worker_register_job.h"
11 #include "content/common/service_worker/service_worker_utils.h"
12 #include "content/public/browser/browser_thread.h"
14 namespace content {
16 namespace {
18 ServiceWorkerVersionInfo GetVersionInfo(ServiceWorkerVersion* version) {
19 if (!version)
20 return ServiceWorkerVersionInfo();
21 return version->GetInfo();
24 } // namespace
26 ServiceWorkerRegistration::ServiceWorkerRegistration(
27 const GURL& pattern,
28 int64 registration_id,
29 base::WeakPtr<ServiceWorkerContextCore> context)
30 : pattern_(pattern),
31 registration_id_(registration_id),
32 is_deleted_(false),
33 is_uninstalling_(false),
34 is_uninstalled_(false),
35 should_activate_when_ready_(false),
36 force_update_on_page_load_(false),
37 resources_total_size_bytes_(0),
38 context_(context) {
39 DCHECK_CURRENTLY_ON(BrowserThread::IO);
40 DCHECK(context_);
41 context_->AddLiveRegistration(this);
44 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
45 DCHECK_CURRENTLY_ON(BrowserThread::IO);
46 DCHECK(!listeners_.might_have_observers());
47 if (context_)
48 context_->RemoveLiveRegistration(registration_id_);
49 if (active_version())
50 active_version()->RemoveListener(this);
53 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
54 if (installing_version())
55 return installing_version();
56 if (waiting_version())
57 return waiting_version();
58 return active_version();
61 void ServiceWorkerRegistration::AddListener(Listener* listener) {
62 listeners_.AddObserver(listener);
65 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
66 listeners_.RemoveObserver(listener);
69 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
70 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
73 void ServiceWorkerRegistration::NotifyUpdateFound() {
74 FOR_EACH_OBSERVER(Listener, listeners_, OnUpdateFound(this));
77 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
78 DCHECK_CURRENTLY_ON(BrowserThread::IO);
79 return ServiceWorkerRegistrationInfo(
80 pattern(), registration_id_,
81 is_deleted_ ? ServiceWorkerRegistrationInfo::IS_DELETED
82 : ServiceWorkerRegistrationInfo::IS_NOT_DELETED,
83 force_update_on_page_load_ ? ServiceWorkerRegistrationInfo::IS_FORCED
84 : ServiceWorkerRegistrationInfo::IS_NOT_FORCED,
85 GetVersionInfo(active_version_.get()),
86 GetVersionInfo(waiting_version_.get()),
87 GetVersionInfo(installing_version_.get()), resources_total_size_bytes_);
90 void ServiceWorkerRegistration::SetActiveVersion(
91 const scoped_refptr<ServiceWorkerVersion>& version) {
92 should_activate_when_ready_ = false;
93 if (active_version_ == version)
94 return;
96 ChangedVersionAttributesMask mask;
97 if (version)
98 UnsetVersionInternal(version.get(), &mask);
99 if (active_version_)
100 active_version_->RemoveListener(this);
101 active_version_ = version;
102 if (active_version_)
103 active_version_->AddListener(this);
104 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
106 FOR_EACH_OBSERVER(Listener, listeners_,
107 OnVersionAttributesChanged(this, mask, GetInfo()));
110 void ServiceWorkerRegistration::SetWaitingVersion(
111 const scoped_refptr<ServiceWorkerVersion>& version) {
112 should_activate_when_ready_ = false;
113 if (waiting_version_ == version)
114 return;
116 ChangedVersionAttributesMask mask;
117 if (version)
118 UnsetVersionInternal(version.get(), &mask);
119 waiting_version_ = version;
120 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
122 FOR_EACH_OBSERVER(Listener, listeners_,
123 OnVersionAttributesChanged(this, mask, GetInfo()));
126 void ServiceWorkerRegistration::SetInstallingVersion(
127 const scoped_refptr<ServiceWorkerVersion>& version) {
128 if (installing_version_ == version)
129 return;
131 ChangedVersionAttributesMask mask;
132 if (version)
133 UnsetVersionInternal(version.get(), &mask);
134 installing_version_ = version;
135 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
137 FOR_EACH_OBSERVER(Listener, listeners_,
138 OnVersionAttributesChanged(this, mask, GetInfo()));
141 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
142 if (!version)
143 return;
144 ChangedVersionAttributesMask mask;
145 UnsetVersionInternal(version, &mask);
146 if (mask.changed()) {
147 ServiceWorkerRegistrationInfo info = GetInfo();
148 FOR_EACH_OBSERVER(Listener, listeners_,
149 OnVersionAttributesChanged(this, mask, info));
153 void ServiceWorkerRegistration::UnsetVersionInternal(
154 ServiceWorkerVersion* version,
155 ChangedVersionAttributesMask* mask) {
156 DCHECK(version);
157 if (installing_version_.get() == version) {
158 installing_version_ = NULL;
159 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
160 } else if (waiting_version_.get() == version) {
161 waiting_version_ = NULL;
162 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
163 } else if (active_version_.get() == version) {
164 active_version_->RemoveListener(this);
165 active_version_ = NULL;
166 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
170 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
171 DCHECK(waiting_version());
172 should_activate_when_ready_ = true;
174 if (!active_version() || !active_version()->HasControllee() ||
175 waiting_version()->skip_waiting())
176 ActivateWaitingVersion();
179 void ServiceWorkerRegistration::ClaimClients() {
180 DCHECK(context_);
181 DCHECK(active_version());
183 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
184 context_->GetProviderHostIterator();
185 !it->IsAtEnd(); it->Advance()) {
186 ServiceWorkerProviderHost* host = it->GetProviderHost();
187 if (host->IsHostToRunningServiceWorker())
188 continue;
189 if (host->controlling_version() == active_version())
190 continue;
191 if (host->MatchRegistration() == this)
192 host->ClaimedByRegistration(this);
196 void ServiceWorkerRegistration::ClearWhenReady() {
197 DCHECK(context_);
198 if (is_uninstalling_)
199 return;
200 is_uninstalling_ = true;
202 context_->storage()->NotifyUninstallingRegistration(this);
203 context_->storage()->DeleteRegistration(
204 id(),
205 pattern().GetOrigin(),
206 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
208 if (!active_version() || !active_version()->HasControllee())
209 Clear();
212 void ServiceWorkerRegistration::AbortPendingClear(
213 const StatusCallback& callback) {
214 DCHECK(context_);
215 if (!is_uninstalling()) {
216 callback.Run(SERVICE_WORKER_OK);
217 return;
219 is_uninstalling_ = false;
220 context_->storage()->NotifyDoneUninstallingRegistration(this);
222 scoped_refptr<ServiceWorkerVersion> most_recent_version =
223 waiting_version() ? waiting_version() : active_version();
224 DCHECK(most_recent_version.get());
225 context_->storage()->NotifyInstallingRegistration(this);
226 context_->storage()->StoreRegistration(
227 this,
228 most_recent_version.get(),
229 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
230 this,
231 callback,
232 most_recent_version));
235 void ServiceWorkerRegistration::GetUserData(
236 const std::string& key,
237 const GetUserDataCallback& callback) {
238 DCHECK(context_);
239 context_->storage()->GetUserData(registration_id_, key, callback);
242 void ServiceWorkerRegistration::StoreUserData(
243 const std::string& key,
244 const std::string& data,
245 const StatusCallback& callback) {
246 DCHECK(context_);
247 context_->storage()->StoreUserData(
248 registration_id_, pattern().GetOrigin(), key, data, callback);
251 void ServiceWorkerRegistration::ClearUserData(
252 const std::string& key,
253 const StatusCallback& callback) {
254 DCHECK(context_);
255 context_->storage()->ClearUserData(registration_id_, key, callback);
258 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
259 if (!context_)
260 return;
261 DCHECK_EQ(active_version(), version);
262 if (is_uninstalling_)
263 Clear();
264 else if (should_activate_when_ready_)
265 ActivateWaitingVersion();
266 is_uninstalling_ = false;
267 should_activate_when_ready_ = false;
270 void ServiceWorkerRegistration::ActivateWaitingVersion() {
271 DCHECK(context_);
272 DCHECK(waiting_version());
273 DCHECK(should_activate_when_ready_);
274 should_activate_when_ready_ = false;
275 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
276 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
278 if (activating_version->is_redundant())
279 return; // Activation is no longer relevant.
281 // "5. If exitingWorker is not null,
282 if (exiting_version.get()) {
283 // TODO(michaeln): should wait for events to be complete
284 // "1. Wait for exitingWorker to finish handling any in-progress requests."
285 // "2. Terminate exitingWorker."
286 exiting_version->StopWorker(
287 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
288 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
289 // "redundant" as the arguments."
290 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
293 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
294 // "7. Set serviceWorkerRegistration.waitingWorker to null."
295 SetActiveVersion(activating_version);
297 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
298 // "activating" as arguments."
299 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
300 // "9. Fire a simple event named controllerchange..."
301 if (activating_version->skip_waiting())
302 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
304 // "10. Queue a task to fire an event named activate..."
305 activating_version->DispatchActivateEvent(
306 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
307 this, activating_version));
310 void ServiceWorkerRegistration::DeleteVersion(
311 const scoped_refptr<ServiceWorkerVersion>& version) {
312 DCHECK_EQ(id(), version->registration_id());
314 UnsetVersion(version.get());
316 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
317 context_->GetProviderHostIterator();
318 !it->IsAtEnd(); it->Advance()) {
319 ServiceWorkerProviderHost* host = it->GetProviderHost();
320 if (host->controlling_version() == version)
321 host->NotifyControllerLost();
324 version->Doom();
326 if (!active_version() && !waiting_version()) {
327 // Delete the records from the db.
328 context_->storage()->DeleteRegistration(
329 id(), pattern().GetOrigin(),
330 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
331 // But not from memory if there is a version in the pipeline.
332 // TODO(falken): Fix this logic. There could be a running register job for
333 // this registration that hasn't set installing_version() yet.
334 if (installing_version()) {
335 is_deleted_ = false;
336 } else {
337 is_uninstalled_ = true;
338 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
343 void ServiceWorkerRegistration::OnActivateEventFinished(
344 ServiceWorkerVersion* activating_version,
345 ServiceWorkerStatusCode status) {
346 if (!context_ || activating_version != active_version() ||
347 activating_version->status() != ServiceWorkerVersion::ACTIVATING)
348 return;
350 // |status| is just for UMA. Once we've attempted to dispatch the activate
351 // event to an installed worker, it's committed to becoming active.
352 ServiceWorkerMetrics::RecordActivateEventStatus(status);
354 // "Run the Update State algorithm passing registration's active worker and
355 // 'activated' as the arguments."
356 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
357 context_->storage()->UpdateToActiveState(
358 this, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
361 void ServiceWorkerRegistration::OnDeleteFinished(
362 ServiceWorkerStatusCode status) {
363 // Intentionally empty completion callback, used to prevent
364 // |this| from being deleted until the storage method completes.
367 void ServiceWorkerRegistration::Clear() {
368 is_uninstalling_ = false;
369 is_uninstalled_ = true;
370 if (context_)
371 context_->storage()->NotifyDoneUninstallingRegistration(this);
373 ChangedVersionAttributesMask mask;
374 if (installing_version_.get()) {
375 installing_version_->Doom();
376 installing_version_ = NULL;
377 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
379 if (waiting_version_.get()) {
380 waiting_version_->Doom();
381 waiting_version_ = NULL;
382 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
384 if (active_version_.get()) {
385 active_version_->Doom();
386 active_version_->RemoveListener(this);
387 active_version_ = NULL;
388 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
390 if (mask.changed()) {
391 ServiceWorkerRegistrationInfo info = GetInfo();
392 FOR_EACH_OBSERVER(Listener, listeners_,
393 OnVersionAttributesChanged(this, mask, info));
396 FOR_EACH_OBSERVER(
397 Listener, listeners_, OnRegistrationFinishedUninstalling(this));
400 void ServiceWorkerRegistration::OnRestoreFinished(
401 const StatusCallback& callback,
402 scoped_refptr<ServiceWorkerVersion> version,
403 ServiceWorkerStatusCode status) {
404 if (!context_) {
405 callback.Run(SERVICE_WORKER_ERROR_ABORT);
406 return;
408 context_->storage()->NotifyDoneInstallingRegistration(
409 this, version.get(), status);
410 callback.Run(status);
413 } // namespace content