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_CURRENTLY_ON(BrowserThread::IO
);
39 context_
->AddLiveRegistration(this);
42 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
43 DCHECK_CURRENTLY_ON(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_CURRENTLY_ON(BrowserThread::IO
);
77 return ServiceWorkerRegistrationInfo(
78 pattern(), registration_id_
,
79 is_deleted_
? ServiceWorkerRegistrationInfo::IS_DELETED
80 : ServiceWorkerRegistrationInfo::IS_NOT_DELETED
,
81 GetVersionInfo(active_version_
.get()),
82 GetVersionInfo(waiting_version_
.get()),
83 GetVersionInfo(installing_version_
.get()), 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;
160 if (!active_version() || !active_version()->HasControllee() ||
161 waiting_version()->skip_waiting())
162 ActivateWaitingVersion();
165 void ServiceWorkerRegistration::ClaimClients() {
167 DCHECK(active_version());
169 for (scoped_ptr
<ServiceWorkerContextCore::ProviderHostIterator
> it
=
170 context_
->GetProviderHostIterator();
171 !it
->IsAtEnd(); it
->Advance()) {
172 ServiceWorkerProviderHost
* host
= it
->GetProviderHost();
173 if (host
->IsHostToRunningServiceWorker())
175 if (host
->controlling_version() == active_version())
177 if (host
->MatchRegistration() == this)
178 host
->ClaimedByRegistration(this);
182 void ServiceWorkerRegistration::ClearWhenReady() {
184 if (is_uninstalling_
)
186 is_uninstalling_
= true;
188 context_
->storage()->NotifyUninstallingRegistration(this);
189 context_
->storage()->DeleteRegistration(
191 pattern().GetOrigin(),
192 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
194 if (!active_version() || !active_version()->HasControllee())
198 void ServiceWorkerRegistration::AbortPendingClear(
199 const StatusCallback
& callback
) {
201 if (!is_uninstalling()) {
202 callback
.Run(SERVICE_WORKER_OK
);
205 is_uninstalling_
= false;
206 context_
->storage()->NotifyDoneUninstallingRegistration(this);
208 scoped_refptr
<ServiceWorkerVersion
> most_recent_version
=
209 waiting_version() ? waiting_version() : active_version();
210 DCHECK(most_recent_version
.get());
211 context_
->storage()->NotifyInstallingRegistration(this);
212 context_
->storage()->StoreRegistration(
214 most_recent_version
.get(),
215 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished
,
218 most_recent_version
));
221 void ServiceWorkerRegistration::GetUserData(
222 const std::string
& key
,
223 const GetUserDataCallback
& callback
) {
225 context_
->storage()->GetUserData(registration_id_
, key
, callback
);
228 void ServiceWorkerRegistration::StoreUserData(
229 const std::string
& key
,
230 const std::string
& data
,
231 const StatusCallback
& callback
) {
233 context_
->storage()->StoreUserData(
234 registration_id_
, pattern().GetOrigin(), key
, data
, callback
);
237 void ServiceWorkerRegistration::ClearUserData(
238 const std::string
& key
,
239 const StatusCallback
& callback
) {
241 context_
->storage()->ClearUserData(registration_id_
, key
, callback
);
244 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion
* version
) {
245 DCHECK_EQ(active_version(), version
);
246 if (is_uninstalling_
)
248 else if (should_activate_when_ready_
)
249 ActivateWaitingVersion();
250 is_uninstalling_
= false;
251 should_activate_when_ready_
= false;
254 void ServiceWorkerRegistration::ActivateWaitingVersion() {
256 DCHECK(waiting_version());
257 DCHECK(should_activate_when_ready_
);
258 should_activate_when_ready_
= false;
259 scoped_refptr
<ServiceWorkerVersion
> activating_version
= waiting_version();
260 scoped_refptr
<ServiceWorkerVersion
> exiting_version
= active_version();
262 if (activating_version
->is_doomed() ||
263 activating_version
->status() == ServiceWorkerVersion::REDUNDANT
) {
264 return; // Activation is no longer relevant.
267 // "5. If exitingWorker is not null,
268 if (exiting_version
.get()) {
269 // TODO(michaeln): should wait for events to be complete
270 // "1. Wait for exitingWorker to finish handling any in-progress requests."
271 // "2. Terminate exitingWorker."
272 exiting_version
->StopWorker(
273 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
274 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
275 // "redundant" as the arguments."
276 exiting_version
->SetStatus(ServiceWorkerVersion::REDUNDANT
);
279 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
280 // "7. Set serviceWorkerRegistration.waitingWorker to null."
281 SetActiveVersion(activating_version
.get());
283 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
284 // "activating" as arguments."
285 activating_version
->SetStatus(ServiceWorkerVersion::ACTIVATING
);
286 // "9. Fire a simple event named controllerchange..."
287 if (activating_version
->skip_waiting())
288 FOR_EACH_OBSERVER(Listener
, listeners_
, OnSkippedWaiting(this));
290 // "10. Queue a task to fire an event named activate..."
291 activating_version
->DispatchActivateEvent(
292 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished
,
293 this, activating_version
));
296 void ServiceWorkerRegistration::OnActivateEventFinished(
297 ServiceWorkerVersion
* activating_version
,
298 ServiceWorkerStatusCode status
) {
299 if (!context_
|| activating_version
!= active_version())
301 // "If activateFailed is true, then:..."
302 if (status
!= SERVICE_WORKER_OK
) {
303 // "Set registration's active worker to null." (The spec's step order may
304 // differ. It's OK because the other steps queue a task.)
305 UnsetVersion(activating_version
);
307 // "Run the Update State algorithm passing registration's active worker and
308 // 'redundant' as the arguments."
309 activating_version
->SetStatus(ServiceWorkerVersion::REDUNDANT
);
311 // "For each service worker client client whose active worker is
312 // registration's active worker..." set the active worker to null.
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() == activating_version
)
318 host
->NotifyControllerActivationFailed();
321 activating_version
->Doom();
322 if (!waiting_version()) {
323 // Delete the records from the db.
324 context_
->storage()->DeleteRegistration(
325 id(), pattern().GetOrigin(),
326 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished
, this));
327 // But not from memory if there is a version in the pipeline.
328 if (installing_version()) {
331 is_uninstalled_
= true;
332 FOR_EACH_OBSERVER(Listener
, listeners_
, OnRegistrationFailed(this));
338 // "Run the Update State algorithm passing registration's active worker and
339 // 'activated' as the arguments."
340 activating_version
->SetStatus(ServiceWorkerVersion::ACTIVATED
);
342 context_
->storage()->UpdateToActiveState(
344 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback
));
348 void ServiceWorkerRegistration::OnDeleteFinished(
349 ServiceWorkerStatusCode status
) {
350 // Intentionally empty completion callback, used to prevent
351 // |this| from being deleted until the storage method completes.
354 void ServiceWorkerRegistration::Clear() {
355 is_uninstalling_
= false;
356 is_uninstalled_
= true;
358 context_
->storage()->NotifyDoneUninstallingRegistration(this);
360 ChangedVersionAttributesMask mask
;
361 if (installing_version_
.get()) {
362 installing_version_
->Doom();
363 installing_version_
= NULL
;
364 mask
.add(ChangedVersionAttributesMask::INSTALLING_VERSION
);
366 if (waiting_version_
.get()) {
367 waiting_version_
->Doom();
368 waiting_version_
= NULL
;
369 mask
.add(ChangedVersionAttributesMask::WAITING_VERSION
);
371 if (active_version_
.get()) {
372 active_version_
->Doom();
373 active_version_
->RemoveListener(this);
374 active_version_
= NULL
;
375 mask
.add(ChangedVersionAttributesMask::ACTIVE_VERSION
);
377 if (mask
.changed()) {
378 ServiceWorkerRegistrationInfo info
= GetInfo();
379 FOR_EACH_OBSERVER(Listener
, listeners_
,
380 OnVersionAttributesChanged(this, mask
, info
));
384 Listener
, listeners_
, OnRegistrationFinishedUninstalling(this));
387 void ServiceWorkerRegistration::OnRestoreFinished(
388 const StatusCallback
& callback
,
389 scoped_refptr
<ServiceWorkerVersion
> version
,
390 ServiceWorkerStatusCode status
) {
392 callback
.Run(SERVICE_WORKER_ERROR_ABORT
);
395 context_
->storage()->NotifyDoneInstallingRegistration(
396 this, version
.get(), status
);
397 callback
.Run(status
);
400 } // namespace content