Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blobab9bb6dc3d68cb873ae941921353b38f0b21ec38
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/browser/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 resources_total_size_bytes_(0),
37 context_(context) {
38 DCHECK_CURRENTLY_ON(BrowserThread::IO);
39 DCHECK(context_);
40 context_->AddLiveRegistration(this);
43 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
44 DCHECK_CURRENTLY_ON(BrowserThread::IO);
45 DCHECK(!listeners_.might_have_observers());
46 if (context_)
47 context_->RemoveLiveRegistration(registration_id_);
48 if (active_version())
49 active_version()->RemoveListener(this);
52 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
53 if (installing_version())
54 return installing_version();
55 if (waiting_version())
56 return waiting_version();
57 return active_version();
60 void ServiceWorkerRegistration::AddListener(Listener* listener) {
61 listeners_.AddObserver(listener);
64 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
65 listeners_.RemoveObserver(listener);
68 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
69 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
72 void ServiceWorkerRegistration::NotifyUpdateFound() {
73 FOR_EACH_OBSERVER(Listener, listeners_, OnUpdateFound(this));
76 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
77 DCHECK_CURRENTLY_ON(BrowserThread::IO);
78 return ServiceWorkerRegistrationInfo(
79 pattern(), registration_id_,
80 is_deleted_ ? ServiceWorkerRegistrationInfo::IS_DELETED
81 : ServiceWorkerRegistrationInfo::IS_NOT_DELETED,
82 GetVersionInfo(active_version_.get()),
83 GetVersionInfo(waiting_version_.get()),
84 GetVersionInfo(installing_version_.get()), resources_total_size_bytes_);
87 void ServiceWorkerRegistration::SetActiveVersion(
88 const scoped_refptr<ServiceWorkerVersion>& version) {
89 should_activate_when_ready_ = false;
90 if (active_version_ == version)
91 return;
93 ChangedVersionAttributesMask mask;
94 if (version)
95 UnsetVersionInternal(version.get(), &mask);
96 if (active_version_)
97 active_version_->RemoveListener(this);
98 active_version_ = version;
99 if (active_version_)
100 active_version_->AddListener(this);
101 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
103 FOR_EACH_OBSERVER(Listener, listeners_,
104 OnVersionAttributesChanged(this, mask, GetInfo()));
107 void ServiceWorkerRegistration::SetWaitingVersion(
108 const scoped_refptr<ServiceWorkerVersion>& version) {
109 should_activate_when_ready_ = false;
110 if (waiting_version_ == version)
111 return;
113 ChangedVersionAttributesMask mask;
114 if (version)
115 UnsetVersionInternal(version.get(), &mask);
116 waiting_version_ = version;
117 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
119 FOR_EACH_OBSERVER(Listener, listeners_,
120 OnVersionAttributesChanged(this, mask, GetInfo()));
123 void ServiceWorkerRegistration::SetInstallingVersion(
124 const scoped_refptr<ServiceWorkerVersion>& version) {
125 if (installing_version_ == version)
126 return;
128 ChangedVersionAttributesMask mask;
129 if (version)
130 UnsetVersionInternal(version.get(), &mask);
131 installing_version_ = version;
132 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
134 FOR_EACH_OBSERVER(Listener, listeners_,
135 OnVersionAttributesChanged(this, mask, GetInfo()));
138 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
139 if (!version)
140 return;
141 ChangedVersionAttributesMask mask;
142 UnsetVersionInternal(version, &mask);
143 if (mask.changed()) {
144 ServiceWorkerRegistrationInfo info = GetInfo();
145 FOR_EACH_OBSERVER(Listener, listeners_,
146 OnVersionAttributesChanged(this, mask, info));
150 void ServiceWorkerRegistration::UnsetVersionInternal(
151 ServiceWorkerVersion* version,
152 ChangedVersionAttributesMask* mask) {
153 DCHECK(version);
154 if (installing_version_.get() == version) {
155 installing_version_ = NULL;
156 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
157 } else if (waiting_version_.get() == version) {
158 waiting_version_ = NULL;
159 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
160 } else if (active_version_.get() == version) {
161 active_version_->RemoveListener(this);
162 active_version_ = NULL;
163 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
167 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
168 DCHECK(waiting_version());
169 should_activate_when_ready_ = true;
171 if (!active_version() || !active_version()->HasControllee() ||
172 waiting_version()->skip_waiting())
173 ActivateWaitingVersion();
176 void ServiceWorkerRegistration::ClaimClients() {
177 DCHECK(context_);
178 DCHECK(active_version());
180 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
181 context_->GetProviderHostIterator();
182 !it->IsAtEnd(); it->Advance()) {
183 ServiceWorkerProviderHost* host = it->GetProviderHost();
184 if (host->IsHostToRunningServiceWorker())
185 continue;
186 if (host->controlling_version() == active_version())
187 continue;
188 if (host->MatchRegistration() == this)
189 host->ClaimedByRegistration(this);
193 void ServiceWorkerRegistration::ClearWhenReady() {
194 DCHECK(context_);
195 if (is_uninstalling_)
196 return;
197 is_uninstalling_ = true;
199 context_->storage()->NotifyUninstallingRegistration(this);
200 context_->storage()->DeleteRegistration(
201 id(),
202 pattern().GetOrigin(),
203 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
205 if (!active_version() || !active_version()->HasControllee())
206 Clear();
209 void ServiceWorkerRegistration::AbortPendingClear(
210 const StatusCallback& callback) {
211 DCHECK(context_);
212 if (!is_uninstalling()) {
213 callback.Run(SERVICE_WORKER_OK);
214 return;
216 is_uninstalling_ = false;
217 context_->storage()->NotifyDoneUninstallingRegistration(this);
219 scoped_refptr<ServiceWorkerVersion> most_recent_version =
220 waiting_version() ? waiting_version() : active_version();
221 DCHECK(most_recent_version.get());
222 context_->storage()->NotifyInstallingRegistration(this);
223 context_->storage()->StoreRegistration(
224 this,
225 most_recent_version.get(),
226 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
227 this,
228 callback,
229 most_recent_version));
232 void ServiceWorkerRegistration::GetUserData(
233 const std::string& key,
234 const GetUserDataCallback& callback) {
235 DCHECK(context_);
236 context_->storage()->GetUserData(registration_id_, key, callback);
239 void ServiceWorkerRegistration::StoreUserData(
240 const std::string& key,
241 const std::string& data,
242 const StatusCallback& callback) {
243 DCHECK(context_);
244 context_->storage()->StoreUserData(
245 registration_id_, pattern().GetOrigin(), key, data, callback);
248 void ServiceWorkerRegistration::ClearUserData(
249 const std::string& key,
250 const StatusCallback& callback) {
251 DCHECK(context_);
252 context_->storage()->ClearUserData(registration_id_, key, callback);
255 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
256 if (!context_)
257 return;
258 DCHECK_EQ(active_version(), version);
259 if (is_uninstalling_)
260 Clear();
261 else if (should_activate_when_ready_)
262 ActivateWaitingVersion();
263 is_uninstalling_ = false;
264 should_activate_when_ready_ = false;
267 void ServiceWorkerRegistration::ActivateWaitingVersion() {
268 DCHECK(context_);
269 DCHECK(waiting_version());
270 DCHECK(should_activate_when_ready_);
271 should_activate_when_ready_ = false;
272 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
273 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
275 if (activating_version->is_redundant())
276 return; // Activation is no longer relevant.
278 // "5. If exitingWorker is not null,
279 if (exiting_version.get()) {
280 // TODO(michaeln): should wait for events to be complete
281 // "1. Wait for exitingWorker to finish handling any in-progress requests."
282 // "2. Terminate exitingWorker."
283 exiting_version->StopWorker(
284 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
285 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
286 // "redundant" as the arguments."
287 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
290 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
291 // "7. Set serviceWorkerRegistration.waitingWorker to null."
292 SetActiveVersion(activating_version);
294 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
295 // "activating" as arguments."
296 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
297 // "9. Fire a simple event named controllerchange..."
298 if (activating_version->skip_waiting())
299 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
301 // "10. Queue a task to fire an event named activate..."
302 activating_version->DispatchActivateEvent(
303 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
304 this, activating_version));
307 void ServiceWorkerRegistration::DeleteVersion(
308 const scoped_refptr<ServiceWorkerVersion>& version) {
309 DCHECK_EQ(id(), version->registration_id());
311 UnsetVersion(version.get());
313 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
314 context_->GetProviderHostIterator();
315 !it->IsAtEnd(); it->Advance()) {
316 ServiceWorkerProviderHost* host = it->GetProviderHost();
317 if (host->controlling_version() == version)
318 host->NotifyControllerLost();
321 version->Doom();
323 if (!active_version() && !waiting_version()) {
324 // Delete the records from the db.
325 context_->storage()->DeleteRegistration(
326 id(), pattern().GetOrigin(),
327 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
328 // But not from memory if there is a version in the pipeline.
329 // TODO(falken): Fix this logic. There could be a running register job for
330 // this registration that hasn't set installing_version() yet.
331 if (installing_version()) {
332 is_deleted_ = false;
333 } else {
334 is_uninstalled_ = true;
335 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
340 void ServiceWorkerRegistration::OnActivateEventFinished(
341 ServiceWorkerVersion* activating_version,
342 ServiceWorkerStatusCode status) {
343 if (!context_ || activating_version != active_version() ||
344 activating_version->status() != ServiceWorkerVersion::ACTIVATING)
345 return;
347 // |status| is just for UMA. Once we've attempted to dispatch the activate
348 // event to an installed worker, it's committed to becoming active.
349 ServiceWorkerMetrics::RecordActivateEventStatus(status);
351 // "Run the Update State algorithm passing registration's active worker and
352 // 'activated' as the arguments."
353 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
354 context_->storage()->UpdateToActiveState(
355 this, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
358 void ServiceWorkerRegistration::OnDeleteFinished(
359 ServiceWorkerStatusCode status) {
360 // Intentionally empty completion callback, used to prevent
361 // |this| from being deleted until the storage method completes.
364 void ServiceWorkerRegistration::Clear() {
365 is_uninstalling_ = false;
366 is_uninstalled_ = true;
367 if (context_)
368 context_->storage()->NotifyDoneUninstallingRegistration(this);
370 ChangedVersionAttributesMask mask;
371 if (installing_version_.get()) {
372 installing_version_->Doom();
373 installing_version_ = NULL;
374 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
376 if (waiting_version_.get()) {
377 waiting_version_->Doom();
378 waiting_version_ = NULL;
379 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
381 if (active_version_.get()) {
382 active_version_->Doom();
383 active_version_->RemoveListener(this);
384 active_version_ = NULL;
385 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
387 if (mask.changed()) {
388 ServiceWorkerRegistrationInfo info = GetInfo();
389 FOR_EACH_OBSERVER(Listener, listeners_,
390 OnVersionAttributesChanged(this, mask, info));
393 FOR_EACH_OBSERVER(
394 Listener, listeners_, OnRegistrationFinishedUninstalling(this));
397 void ServiceWorkerRegistration::OnRestoreFinished(
398 const StatusCallback& callback,
399 scoped_refptr<ServiceWorkerVersion> version,
400 ServiceWorkerStatusCode status) {
401 if (!context_) {
402 callback.Run(SERVICE_WORKER_ERROR_ABORT);
403 return;
405 context_->storage()->NotifyDoneInstallingRegistration(
406 this, version.get(), status);
407 callback.Run(status);
410 } // namespace content