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"
17 ServiceWorkerVersionInfo
GetVersionInfo(ServiceWorkerVersion
* version
) {
19 return ServiceWorkerVersionInfo();
20 return version
->GetInfo();
25 ServiceWorkerRegistration::ServiceWorkerRegistration(
27 int64 registration_id
,
28 base::WeakPtr
<ServiceWorkerContextCore
> context
)
30 registration_id_(registration_id
),
32 is_uninstalling_(false),
33 is_uninstalled_(false),
34 should_activate_when_ready_(false),
35 resources_total_size_bytes_(0),
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
39 context_
->AddLiveRegistration(this);
42 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
44 DCHECK(!listeners_
.might_have_observers());
46 context_
->RemoveLiveRegistration(registration_id_
);
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(
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
) {
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
,
122 if (version
== data_member
->get())
124 scoped_refptr
<ServiceWorkerVersion
> protect(version
);
125 ChangedVersionAttributesMask mask
;
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
) {
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;
159 if (!active_version() || !active_version()->HasControllee() ||
160 waiting_version()->skip_waiting())
161 ActivateWaitingVersion();
164 void ServiceWorkerRegistration::ClearWhenReady() {
166 if (is_uninstalling_
)
168 is_uninstalling_
= true;
170 context_
->storage()->NotifyUninstallingRegistration(this);
171 context_
->storage()->DeleteRegistration(
173 pattern().GetOrigin(),
174 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
176 if (!active_version() || !active_version()->HasControllee())
180 void ServiceWorkerRegistration::AbortPendingClear(
181 const StatusCallback
& callback
) {
183 if (!is_uninstalling()) {
184 callback
.Run(SERVICE_WORKER_OK
);
187 is_uninstalling_
= false;
188 context_
->storage()->NotifyDoneUninstallingRegistration(this);
190 scoped_refptr
<ServiceWorkerVersion
> most_recent_version
=
191 waiting_version() ? waiting_version() : active_version();
192 DCHECK(most_recent_version
.get());
193 context_
->storage()->NotifyInstallingRegistration(this);
194 context_
->storage()->StoreRegistration(
196 most_recent_version
.get(),
197 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished
,
200 most_recent_version
));
203 void ServiceWorkerRegistration::GetUserData(
204 const std::string
& key
,
205 const GetUserDataCallback
& callback
) {
207 context_
->storage()->GetUserData(registration_id_
, key
, callback
);
210 void ServiceWorkerRegistration::StoreUserData(
211 const std::string
& key
,
212 const std::string
& data
,
213 const StatusCallback
& callback
) {
215 context_
->storage()->StoreUserData(
216 registration_id_
, pattern().GetOrigin(), key
, data
, callback
);
219 void ServiceWorkerRegistration::ClearUserData(
220 const std::string
& key
,
221 const StatusCallback
& callback
) {
223 context_
->storage()->ClearUserData(registration_id_
, key
, callback
);
226 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion
* version
) {
227 DCHECK_EQ(active_version(), version
);
228 if (is_uninstalling_
)
230 else if (should_activate_when_ready_
)
231 ActivateWaitingVersion();
232 is_uninstalling_
= false;
233 should_activate_when_ready_
= false;
236 void ServiceWorkerRegistration::ActivateWaitingVersion() {
238 DCHECK(waiting_version());
239 DCHECK(should_activate_when_ready_
);
240 should_activate_when_ready_
= false;
241 scoped_refptr
<ServiceWorkerVersion
> activating_version
= waiting_version();
242 scoped_refptr
<ServiceWorkerVersion
> exiting_version
= active_version();
244 if (activating_version
->is_doomed() ||
245 activating_version
->status() == ServiceWorkerVersion::REDUNDANT
) {
246 return; // Activation is no longer relevant.
249 // "5. If exitingWorker is not null,
250 if (exiting_version
.get()) {
251 // TODO(michaeln): should wait for events to be complete
252 // "1. Wait for exitingWorker to finish handling any in-progress requests."
253 // "2. Terminate exitingWorker."
254 exiting_version
->StopWorker(
255 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
256 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
257 // "redundant" as the arguments."
258 exiting_version
->SetStatus(ServiceWorkerVersion::REDUNDANT
);
261 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
262 // "7. Set serviceWorkerRegistration.waitingWorker to null."
263 SetActiveVersion(activating_version
.get());
265 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
266 // "activating" as arguments."
267 activating_version
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
268 // "9. Fire a simple event named controllerchange..."
269 if (activating_version
->skip_waiting())
270 FOR_EACH_OBSERVER(Listener
, listeners_
, OnSkippedWaiting(this));
272 // "10. Queue a task to fire an event named activate..."
273 activating_version
->DispatchActivateEvent(
274 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished
,
275 this, activating_version
));
278 void ServiceWorkerRegistration::OnActivateEventFinished(
279 ServiceWorkerVersion
* activating_version
,
280 ServiceWorkerStatusCode status
) {
281 if (!context_
|| activating_version
!= active_version())
283 // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
284 // unexpectedly terminated) we may want to retry sending the event again.
285 if (status
!= SERVICE_WORKER_OK
) {
286 // "11. If activateFailed is true, then:..."
287 UnsetVersion(activating_version
);
288 activating_version
->Doom();
289 if (!waiting_version()) {
290 // Delete the records from the db.
291 context_
->storage()->DeleteRegistration(
292 id(), pattern().GetOrigin(),
293 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished
, this));
294 // But not from memory if there is a version in the pipeline.
295 if (installing_version())
301 // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
302 // and "activated" as the arguments."
303 activating_version
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
305 context_
->storage()->UpdateToActiveState(
307 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
311 void ServiceWorkerRegistration::OnDeleteFinished(
312 ServiceWorkerStatusCode status
) {
313 // Intentionally empty completion callback, used to prevent
314 // |this| from being deleted until the storage method completes.
317 void ServiceWorkerRegistration::Clear() {
318 is_uninstalling_
= false;
319 is_uninstalled_
= true;
321 context_
->storage()->NotifyDoneUninstallingRegistration(this);
323 ChangedVersionAttributesMask mask
;
324 if (installing_version_
.get()) {
325 installing_version_
->Doom();
326 installing_version_
= NULL
;
327 mask
.add(ChangedVersionAttributesMask::INSTALLING_VERSION
);
329 if (waiting_version_
.get()) {
330 waiting_version_
->Doom();
331 waiting_version_
= NULL
;
332 mask
.add(ChangedVersionAttributesMask::WAITING_VERSION
);
334 if (active_version_
.get()) {
335 active_version_
->Doom();
336 active_version_
->RemoveListener(this);
337 active_version_
= NULL
;
338 mask
.add(ChangedVersionAttributesMask::ACTIVE_VERSION
);
340 if (mask
.changed()) {
341 ServiceWorkerRegistrationInfo info
= GetInfo();
342 FOR_EACH_OBSERVER(Listener
, listeners_
,
343 OnVersionAttributesChanged(this, mask
, info
));
347 Listener
, listeners_
, OnRegistrationFinishedUninstalling(this));
350 void ServiceWorkerRegistration::OnRestoreFinished(
351 const StatusCallback
& callback
,
352 scoped_refptr
<ServiceWorkerVersion
> version
,
353 ServiceWorkerStatusCode status
) {
355 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
358 context_
->storage()->NotifyDoneInstallingRegistration(
359 this, version
.get(), status
);
360 callback
.Run(status
);
363 } // namespace content