Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blob51bd701c358ca9ba5b8de9dac19d53e6da8da919
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 should_activate_when_ready_(false),
34 context_(context) {
35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
36 DCHECK(context_);
37 context_->AddLiveRegistration(this);
40 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
42 DCHECK(!listeners_.might_have_observers());
43 if (context_)
44 context_->RemoveLiveRegistration(registration_id_);
45 if (active_version())
46 active_version()->RemoveListener(this);
49 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
50 if (installing_version())
51 return installing_version();
52 if (waiting_version())
53 return waiting_version();
54 return active_version();
57 void ServiceWorkerRegistration::AddListener(Listener* listener) {
58 listeners_.AddObserver(listener);
61 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
62 listeners_.RemoveObserver(listener);
65 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
66 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
69 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71 return ServiceWorkerRegistrationInfo(
72 pattern(),
73 registration_id_,
74 GetVersionInfo(active_version_.get()),
75 GetVersionInfo(waiting_version_.get()),
76 GetVersionInfo(installing_version_.get()));
79 void ServiceWorkerRegistration::SetActiveVersion(
80 ServiceWorkerVersion* version) {
81 should_activate_when_ready_ = false;
82 SetVersionInternal(version, &active_version_,
83 ChangedVersionAttributesMask::ACTIVE_VERSION);
86 void ServiceWorkerRegistration::SetWaitingVersion(
87 ServiceWorkerVersion* version) {
88 should_activate_when_ready_ = false;
89 SetVersionInternal(version, &waiting_version_,
90 ChangedVersionAttributesMask::WAITING_VERSION);
93 void ServiceWorkerRegistration::SetInstallingVersion(
94 ServiceWorkerVersion* version) {
95 SetVersionInternal(version, &installing_version_,
96 ChangedVersionAttributesMask::INSTALLING_VERSION);
99 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
100 if (!version)
101 return;
102 ChangedVersionAttributesMask mask;
103 UnsetVersionInternal(version, &mask);
104 if (mask.changed()) {
105 ServiceWorkerRegistrationInfo info = GetInfo();
106 FOR_EACH_OBSERVER(Listener, listeners_,
107 OnVersionAttributesChanged(this, mask, info));
111 void ServiceWorkerRegistration::SetVersionInternal(
112 ServiceWorkerVersion* version,
113 scoped_refptr<ServiceWorkerVersion>* data_member,
114 int change_flag) {
115 if (version == data_member->get())
116 return;
117 scoped_refptr<ServiceWorkerVersion> protect(version);
118 ChangedVersionAttributesMask mask;
119 if (version)
120 UnsetVersionInternal(version, &mask);
121 *data_member = version;
122 if (active_version_.get() && active_version_.get() == version)
123 active_version_->AddListener(this);
124 mask.add(change_flag);
125 ServiceWorkerRegistrationInfo info = GetInfo();
126 FOR_EACH_OBSERVER(Listener, listeners_,
127 OnVersionAttributesChanged(this, mask, info));
130 void ServiceWorkerRegistration::UnsetVersionInternal(
131 ServiceWorkerVersion* version,
132 ChangedVersionAttributesMask* mask) {
133 DCHECK(version);
134 if (installing_version_.get() == version) {
135 installing_version_ = NULL;
136 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
137 } else if (waiting_version_.get() == version) {
138 waiting_version_ = NULL;
139 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
140 } else if (active_version_.get() == version) {
141 active_version_->RemoveListener(this);
142 active_version_ = NULL;
143 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
147 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
148 DCHECK(waiting_version());
149 should_activate_when_ready_ = true;
150 if (!active_version() || !active_version()->HasControllee())
151 ActivateWaitingVersion();
154 void ServiceWorkerRegistration::ClearWhenReady() {
155 DCHECK(context_);
156 if (is_uninstalling_)
157 return;
158 is_uninstalling_ = true;
160 context_->storage()->NotifyUninstallingRegistration(this);
161 context_->storage()->DeleteRegistration(
162 id(),
163 pattern().GetOrigin(),
164 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
166 if (!active_version() || !active_version()->HasControllee())
167 Clear();
170 void ServiceWorkerRegistration::AbortPendingClear(
171 const StatusCallback& callback) {
172 DCHECK(context_);
173 if (!is_uninstalling()) {
174 callback.Run(SERVICE_WORKER_OK);
175 return;
177 is_uninstalling_ = false;
178 context_->storage()->NotifyDoneUninstallingRegistration(this);
180 scoped_refptr<ServiceWorkerVersion> most_recent_version =
181 waiting_version() ? waiting_version() : active_version();
182 DCHECK(most_recent_version.get());
183 context_->storage()->NotifyInstallingRegistration(this);
184 context_->storage()->StoreRegistration(
185 this,
186 most_recent_version.get(),
187 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
188 this,
189 callback,
190 most_recent_version));
193 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
194 DCHECK_EQ(active_version(), version);
195 if (is_uninstalling_)
196 Clear();
197 else if (should_activate_when_ready_)
198 ActivateWaitingVersion();
199 is_uninstalling_ = false;
200 should_activate_when_ready_ = false;
203 void ServiceWorkerRegistration::ActivateWaitingVersion() {
204 DCHECK(context_);
205 DCHECK(waiting_version());
206 DCHECK(should_activate_when_ready_);
207 should_activate_when_ready_ = false;
208 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
209 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
211 if (activating_version->is_doomed() ||
212 activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
213 return; // Activation is no longer relevant.
216 // "4. If exitingWorker is not null,
217 if (exiting_version.get()) {
218 DCHECK(!exiting_version->HasControllee());
219 // TODO(michaeln): should wait for events to be complete
220 // "1. Wait for exitingWorker to finish handling any in-progress requests."
221 // "2. Terminate exitingWorker."
222 exiting_version->StopWorker(
223 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
224 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
225 // "redundant" as the arguments."
226 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
229 // "5. Set serviceWorkerRegistration.activeWorker to activatingWorker."
230 // "6. Set serviceWorkerRegistration.waitingWorker to null."
231 SetActiveVersion(activating_version.get());
233 // "7. Run the [[UpdateState]] algorithm passing registration.activeWorker and
234 // "activating" as arguments."
235 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
237 // TODO(nhiroki): "8. Fire a simple event named controllerchange..."
239 // "9. Queue a task to fire an event named activate..."
240 activating_version->DispatchActivateEvent(
241 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
242 this, activating_version));
245 void ServiceWorkerRegistration::OnActivateEventFinished(
246 ServiceWorkerVersion* activating_version,
247 ServiceWorkerStatusCode status) {
248 if (!context_ || activating_version != active_version())
249 return;
250 // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
251 // unexpectedly terminated) we may want to retry sending the event again.
252 if (status != SERVICE_WORKER_OK) {
253 // "11. If activateFailed is true, then:..."
254 UnsetVersion(activating_version);
255 activating_version->Doom();
256 if (!waiting_version()) {
257 // Delete the records from the db.
258 context_->storage()->DeleteRegistration(
259 id(), pattern().GetOrigin(),
260 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
261 // But not from memory if there is a version in the pipeline.
262 if (installing_version())
263 is_deleted_ = false;
265 return;
268 // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
269 // and "activated" as the arguments."
270 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
271 if (context_) {
272 context_->storage()->UpdateToActiveState(
273 this,
274 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
278 void ServiceWorkerRegistration::OnDeleteFinished(
279 ServiceWorkerStatusCode status) {
280 // Intentionally empty completion callback, used to prevent
281 // |this| from being deleted until the storage method completes.
284 void ServiceWorkerRegistration::Clear() {
285 is_uninstalling_ = false;
286 if (context_)
287 context_->storage()->NotifyDoneUninstallingRegistration(this);
289 ChangedVersionAttributesMask mask;
290 if (installing_version_.get()) {
291 installing_version_->Doom();
292 installing_version_ = NULL;
293 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
295 if (waiting_version_.get()) {
296 waiting_version_->Doom();
297 waiting_version_ = NULL;
298 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
300 if (active_version_.get()) {
301 active_version_->Doom();
302 active_version_->RemoveListener(this);
303 active_version_ = NULL;
304 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
306 if (mask.changed()) {
307 ServiceWorkerRegistrationInfo info = GetInfo();
308 FOR_EACH_OBSERVER(Listener, listeners_,
309 OnVersionAttributesChanged(this, mask, info));
312 FOR_EACH_OBSERVER(
313 Listener, listeners_, OnRegistrationFinishedUninstalling(this));
316 void ServiceWorkerRegistration::OnRestoreFinished(
317 const StatusCallback& callback,
318 scoped_refptr<ServiceWorkerVersion> version,
319 ServiceWorkerStatusCode status) {
320 if (!context_) {
321 callback.Run(ServiceWorkerStatusCode::SERVICE_WORKER_ERROR_ABORT);
322 return;
324 context_->storage()->NotifyDoneInstallingRegistration(
325 this, version.get(), status);
326 callback.Run(status);
329 } // namespace content