Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blob0445f08f7e646ba73497be4257adeb4d6ad008c3
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 *data_member = version;
129 if (active_version_.get() && active_version_.get() == version)
130 active_version_->AddListener(this);
131 mask.add(change_flag);
132 ServiceWorkerRegistrationInfo info = GetInfo();
133 FOR_EACH_OBSERVER(Listener, listeners_,
134 OnVersionAttributesChanged(this, mask, info));
137 void ServiceWorkerRegistration::UnsetVersionInternal(
138 ServiceWorkerVersion* version,
139 ChangedVersionAttributesMask* mask) {
140 DCHECK(version);
141 if (installing_version_.get() == version) {
142 installing_version_ = NULL;
143 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
144 } else if (waiting_version_.get() == version) {
145 waiting_version_ = NULL;
146 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
147 } else if (active_version_.get() == version) {
148 active_version_->RemoveListener(this);
149 active_version_ = NULL;
150 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
154 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
155 DCHECK(waiting_version());
156 should_activate_when_ready_ = true;
157 if (!active_version() || !active_version()->HasControllee())
158 ActivateWaitingVersion();
161 void ServiceWorkerRegistration::ClearWhenReady() {
162 DCHECK(context_);
163 if (is_uninstalling_)
164 return;
165 is_uninstalling_ = true;
167 context_->storage()->NotifyUninstallingRegistration(this);
168 context_->storage()->DeleteRegistration(
169 id(),
170 pattern().GetOrigin(),
171 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
173 if (!active_version() || !active_version()->HasControllee())
174 Clear();
177 void ServiceWorkerRegistration::AbortPendingClear(
178 const StatusCallback& callback) {
179 DCHECK(context_);
180 if (!is_uninstalling()) {
181 callback.Run(SERVICE_WORKER_OK);
182 return;
184 is_uninstalling_ = false;
185 context_->storage()->NotifyDoneUninstallingRegistration(this);
187 scoped_refptr<ServiceWorkerVersion> most_recent_version =
188 waiting_version() ? waiting_version() : active_version();
189 DCHECK(most_recent_version.get());
190 context_->storage()->NotifyInstallingRegistration(this);
191 context_->storage()->StoreRegistration(
192 this,
193 most_recent_version.get(),
194 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
195 this,
196 callback,
197 most_recent_version));
200 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
201 DCHECK_EQ(active_version(), version);
202 if (is_uninstalling_)
203 Clear();
204 else if (should_activate_when_ready_)
205 ActivateWaitingVersion();
206 is_uninstalling_ = false;
207 should_activate_when_ready_ = false;
210 void ServiceWorkerRegistration::ActivateWaitingVersion() {
211 DCHECK(context_);
212 DCHECK(waiting_version());
213 DCHECK(should_activate_when_ready_);
214 should_activate_when_ready_ = false;
215 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
216 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
218 if (activating_version->is_doomed() ||
219 activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
220 return; // Activation is no longer relevant.
223 // "4. If exitingWorker is not null,
224 if (exiting_version.get()) {
225 DCHECK(!exiting_version->HasControllee());
226 // TODO(michaeln): should wait for events to be complete
227 // "1. Wait for exitingWorker to finish handling any in-progress requests."
228 // "2. Terminate exitingWorker."
229 exiting_version->StopWorker(
230 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
231 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
232 // "redundant" as the arguments."
233 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
236 // "5. Set serviceWorkerRegistration.activeWorker to activatingWorker."
237 // "6. Set serviceWorkerRegistration.waitingWorker to null."
238 SetActiveVersion(activating_version.get());
240 // "7. Run the [[UpdateState]] algorithm passing registration.activeWorker and
241 // "activating" as arguments."
242 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
244 // TODO(nhiroki): "8. Fire a simple event named controllerchange..."
246 // "9. Queue a task to fire an event named activate..."
247 activating_version->DispatchActivateEvent(
248 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
249 this, activating_version));
252 void ServiceWorkerRegistration::OnActivateEventFinished(
253 ServiceWorkerVersion* activating_version,
254 ServiceWorkerStatusCode status) {
255 if (!context_ || activating_version != active_version())
256 return;
257 // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
258 // unexpectedly terminated) we may want to retry sending the event again.
259 if (status != SERVICE_WORKER_OK) {
260 // "11. If activateFailed is true, then:..."
261 UnsetVersion(activating_version);
262 activating_version->Doom();
263 if (!waiting_version()) {
264 // Delete the records from the db.
265 context_->storage()->DeleteRegistration(
266 id(), pattern().GetOrigin(),
267 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
268 // But not from memory if there is a version in the pipeline.
269 if (installing_version())
270 is_deleted_ = false;
272 return;
275 // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
276 // and "activated" as the arguments."
277 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
278 if (context_) {
279 context_->storage()->UpdateToActiveState(
280 this,
281 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
285 void ServiceWorkerRegistration::OnDeleteFinished(
286 ServiceWorkerStatusCode status) {
287 // Intentionally empty completion callback, used to prevent
288 // |this| from being deleted until the storage method completes.
291 void ServiceWorkerRegistration::Clear() {
292 is_uninstalling_ = false;
293 is_uninstalled_ = true;
294 if (context_)
295 context_->storage()->NotifyDoneUninstallingRegistration(this);
297 ChangedVersionAttributesMask mask;
298 if (installing_version_.get()) {
299 installing_version_->Doom();
300 installing_version_ = NULL;
301 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
303 if (waiting_version_.get()) {
304 waiting_version_->Doom();
305 waiting_version_ = NULL;
306 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
308 if (active_version_.get()) {
309 active_version_->Doom();
310 active_version_->RemoveListener(this);
311 active_version_ = NULL;
312 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
314 if (mask.changed()) {
315 ServiceWorkerRegistrationInfo info = GetInfo();
316 FOR_EACH_OBSERVER(Listener, listeners_,
317 OnVersionAttributesChanged(this, mask, info));
320 FOR_EACH_OBSERVER(
321 Listener, listeners_, OnRegistrationFinishedUninstalling(this));
324 void ServiceWorkerRegistration::OnRestoreFinished(
325 const StatusCallback& callback,
326 scoped_refptr<ServiceWorkerVersion> version,
327 ServiceWorkerStatusCode status) {
328 if (!context_) {
329 callback.Run(SERVICE_WORKER_ERROR_ABORT);
330 return;
332 context_->storage()->NotifyDoneInstallingRegistration(
333 this, version.get(), status);
334 callback.Run(status);
337 } // namespace content