Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(925)

Side by Side Diff: content/browser/service_worker/service_worker_registration.cc

Issue 2027583002: service worker: Avoid starting up for activation during shutdown (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add unittest Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/service_worker/service_worker_registration.h" 5 #include "content/browser/service_worker/service_worker_registration.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "content/browser/service_worker/service_worker_context_core.h" 9 #include "content/browser/service_worker/service_worker_context_core.h"
10 #include "content/browser/service_worker/service_worker_context_wrapper.h"
10 #include "content/browser/service_worker/service_worker_info.h" 11 #include "content/browser/service_worker/service_worker_info.h"
11 #include "content/browser/service_worker/service_worker_metrics.h" 12 #include "content/browser/service_worker/service_worker_metrics.h"
12 #include "content/browser/service_worker/service_worker_register_job.h" 13 #include "content/browser/service_worker/service_worker_register_job.h"
13 #include "content/common/service_worker/service_worker_messages.h" 14 #include "content/common/service_worker/service_worker_messages.h"
14 #include "content/common/service_worker/service_worker_utils.h" 15 #include "content/common/service_worker/service_worker_utils.h"
15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
16 17
17 namespace content { 18 namespace content {
18 19
19 namespace { 20 namespace {
(...skipping 10 matching lines...) Expand all
30 const GURL& pattern, 31 const GURL& pattern,
31 int64_t registration_id, 32 int64_t registration_id,
32 base::WeakPtr<ServiceWorkerContextCore> context) 33 base::WeakPtr<ServiceWorkerContextCore> context)
33 : pattern_(pattern), 34 : pattern_(pattern),
34 registration_id_(registration_id), 35 registration_id_(registration_id),
35 is_deleted_(false), 36 is_deleted_(false),
36 is_uninstalling_(false), 37 is_uninstalling_(false),
37 is_uninstalled_(false), 38 is_uninstalled_(false),
38 should_activate_when_ready_(false), 39 should_activate_when_ready_(false),
39 resources_total_size_bytes_(0), 40 resources_total_size_bytes_(0),
40 context_(context) { 41 context_(context),
42 task_runner_(base::ThreadTaskRunnerHandle::Get()) {
41 DCHECK_CURRENTLY_ON(BrowserThread::IO); 43 DCHECK_CURRENTLY_ON(BrowserThread::IO);
42 DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id); 44 DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id);
43 DCHECK(context_); 45 DCHECK(context_);
44 context_->AddLiveRegistration(this); 46 context_->AddLiveRegistration(this);
45 } 47 }
46 48
47 ServiceWorkerRegistration::~ServiceWorkerRegistration() { 49 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
50 // Can be false during shutdown, in which case the DCHECK_CURRENTLY_ON below
51 // would cry.
52 if (!BrowserThread::IsThreadInitialized(BrowserThread::IO))
53 return;
54
48 DCHECK_CURRENTLY_ON(BrowserThread::IO); 55 DCHECK_CURRENTLY_ON(BrowserThread::IO);
49 DCHECK(!listeners_.might_have_observers()); 56 DCHECK(!listeners_.might_have_observers());
50 if (context_) 57 if (context_)
51 context_->RemoveLiveRegistration(registration_id_); 58 context_->RemoveLiveRegistration(registration_id_);
52 if (active_version()) 59 if (active_version())
53 active_version()->RemoveListener(this); 60 active_version()->RemoveListener(this);
54 } 61 }
55 62
56 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const { 63 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
57 if (installing_version()) 64 if (installing_version())
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 active_version_ = NULL; 176 active_version_ = NULL;
170 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION); 177 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
171 } 178 }
172 } 179 }
173 180
174 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() { 181 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
175 DCHECK(waiting_version()); 182 DCHECK(waiting_version());
176 should_activate_when_ready_ = true; 183 should_activate_when_ready_ = true;
177 184
178 if (!active_version() || !active_version()->HasControllee() || 185 if (!active_version() || !active_version()->HasControllee() ||
179 waiting_version()->skip_waiting()) 186 waiting_version()->skip_waiting()) {
180 ActivateWaitingVersion(); 187 ActivateWaitingVersion(false);
188 }
181 } 189 }
182 190
183 void ServiceWorkerRegistration::ClaimClients() { 191 void ServiceWorkerRegistration::ClaimClients() {
184 DCHECK(context_); 192 DCHECK(context_);
185 DCHECK(active_version()); 193 DCHECK(active_version());
186 194
187 for (std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator> it = 195 for (std::unique_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
188 context_->GetProviderHostIterator(); 196 context_->GetProviderHostIterator();
189 !it->IsAtEnd(); it->Advance()) { 197 !it->IsAtEnd(); it->Advance()) {
190 ServiceWorkerProviderHost* host = it->GetProviderHost(); 198 ServiceWorkerProviderHost* host = it->GetProviderHost();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 most_recent_version)); 244 most_recent_version));
237 } 245 }
238 246
239 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) { 247 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
240 if (!context_) 248 if (!context_)
241 return; 249 return;
242 DCHECK_EQ(active_version(), version); 250 DCHECK_EQ(active_version(), version);
243 if (is_uninstalling_) 251 if (is_uninstalling_)
244 Clear(); 252 Clear();
245 else if (should_activate_when_ready_) 253 else if (should_activate_when_ready_)
246 ActivateWaitingVersion(); 254 ActivateWaitingVersion(true);
247 is_uninstalling_ = false; 255 is_uninstalling_ = false;
248 should_activate_when_ready_ = false; 256 should_activate_when_ready_ = false;
249 } 257 }
250 258
251 void ServiceWorkerRegistration::ActivateWaitingVersion() { 259 void ServiceWorkerRegistration::ActivateWaitingVersion(bool delay) {
260 DCHECK_CURRENTLY_ON(BrowserThread::IO);
252 DCHECK(context_); 261 DCHECK(context_);
253 DCHECK(waiting_version()); 262 DCHECK(waiting_version());
254 DCHECK(should_activate_when_ready_); 263 DCHECK(should_activate_when_ready_);
255 should_activate_when_ready_ = false; 264 should_activate_when_ready_ = false;
256 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version(); 265 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
257 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version(); 266 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
258 267
259 if (activating_version->is_redundant()) 268 if (activating_version->is_redundant())
260 return; // Activation is no longer relevant. 269 return; // Activation is no longer relevant.
261 270
(...skipping 14 matching lines...) Expand all
276 SetActiveVersion(activating_version); 285 SetActiveVersion(activating_version);
277 286
278 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and 287 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
279 // "activating" as arguments." 288 // "activating" as arguments."
280 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING); 289 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
281 // "9. Fire a simple event named controllerchange..." 290 // "9. Fire a simple event named controllerchange..."
282 if (activating_version->skip_waiting()) 291 if (activating_version->skip_waiting())
283 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this)); 292 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
284 293
285 // "10. Queue a task to fire an event named activate..." 294 // "10. Queue a task to fire an event named activate..."
295 // The browser could be shutting down. To avoid spurious start worker
296 // failures, wait a bit before continuing.
297 if (delay) {
298 task_runner_->PostDelayedTask(
299 FROM_HERE, base::Bind(&ServiceWorkerRegistration::ContinueActivation,
300 this, activating_version),
301 base::TimeDelta::FromSeconds(1));
302 } else {
303 ContinueActivation(std::move(activating_version));
304 }
305 }
306
307 void ServiceWorkerRegistration::ContinueActivation(
308 scoped_refptr<ServiceWorkerVersion> activating_version) {
309 if (!context_)
310 return;
311 if (active_version() != activating_version.get())
312 return;
313 DCHECK_EQ(ServiceWorkerVersion::ACTIVATING, activating_version->status());
286 activating_version->RunAfterStartWorker( 314 activating_version->RunAfterStartWorker(
287 ServiceWorkerMetrics::EventType::ACTIVATE, 315 ServiceWorkerMetrics::EventType::ACTIVATE,
288 base::Bind(&ServiceWorkerRegistration::DispatchActivateEvent, this, 316 base::Bind(&ServiceWorkerRegistration::DispatchActivateEvent, this,
289 activating_version), 317 activating_version),
290 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished, this, 318 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished, this,
291 activating_version)); 319 activating_version));
292 } 320 }
293 321
294 void ServiceWorkerRegistration::DeleteVersion( 322 void ServiceWorkerRegistration::DeleteVersion(
295 const scoped_refptr<ServiceWorkerVersion>& version) { 323 const scoped_refptr<ServiceWorkerVersion>& version) {
(...skipping 28 matching lines...) Expand all
324 } 352 }
325 } 353 }
326 354
327 void ServiceWorkerRegistration::NotifyRegistrationFinished() { 355 void ServiceWorkerRegistration::NotifyRegistrationFinished() {
328 std::vector<base::Closure> callbacks; 356 std::vector<base::Closure> callbacks;
329 callbacks.swap(registration_finished_callbacks_); 357 callbacks.swap(registration_finished_callbacks_);
330 for (const auto& callback : callbacks) 358 for (const auto& callback : callbacks)
331 callback.Run(); 359 callback.Run();
332 } 360 }
333 361
362 void ServiceWorkerRegistration::SetTaskRunnerForTest(
363 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
364 task_runner_ = task_runner;
365 }
366
334 void ServiceWorkerRegistration::RegisterRegistrationFinishedCallback( 367 void ServiceWorkerRegistration::RegisterRegistrationFinishedCallback(
335 const base::Closure& callback) { 368 const base::Closure& callback) {
336 // This should only be called if the registration is in progress. 369 // This should only be called if the registration is in progress.
337 DCHECK(!active_version() && !waiting_version() && !is_uninstalled() && 370 DCHECK(!active_version() && !waiting_version() && !is_uninstalled() &&
338 !is_uninstalling()); 371 !is_uninstalling());
339 registration_finished_callbacks_.push_back(callback); 372 registration_finished_callbacks_.push_back(callback);
340 } 373 }
341 374
342 void ServiceWorkerRegistration::DispatchActivateEvent( 375 void ServiceWorkerRegistration::DispatchActivateEvent(
343 const scoped_refptr<ServiceWorkerVersion>& activating_version) { 376 scoped_refptr<ServiceWorkerVersion> activating_version) {
344 if (activating_version != active_version()) { 377 if (activating_version != active_version()) {
345 OnActivateEventFinished(activating_version, SERVICE_WORKER_ERROR_FAILED); 378 OnActivateEventFinished(activating_version, SERVICE_WORKER_ERROR_FAILED);
346 return; 379 return;
347 } 380 }
348 381
349 DCHECK_EQ(ServiceWorkerVersion::ACTIVATING, activating_version->status()); 382 DCHECK_EQ(ServiceWorkerVersion::ACTIVATING, activating_version->status());
350 DCHECK_EQ(ServiceWorkerVersion::RUNNING, activating_version->running_status()) 383 DCHECK_EQ(ServiceWorkerVersion::RUNNING, activating_version->running_status())
351 << "Worker stopped too soon after it was started."; 384 << "Worker stopped too soon after it was started.";
352 int request_id = activating_version->StartRequest( 385 int request_id = activating_version->StartRequest(
353 ServiceWorkerMetrics::EventType::ACTIVATE, 386 ServiceWorkerMetrics::EventType::ACTIVATE,
354 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished, this, 387 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished, this,
355 activating_version)); 388 activating_version));
356 activating_version 389 activating_version
357 ->DispatchSimpleEvent<ServiceWorkerHostMsg_ActivateEventFinished>( 390 ->DispatchSimpleEvent<ServiceWorkerHostMsg_ActivateEventFinished>(
358 request_id, ServiceWorkerMsg_ActivateEvent(request_id)); 391 request_id, ServiceWorkerMsg_ActivateEvent(request_id));
359 } 392 }
360 393
361 void ServiceWorkerRegistration::OnActivateEventFinished( 394 void ServiceWorkerRegistration::OnActivateEventFinished(
362 const scoped_refptr<ServiceWorkerVersion>& activating_version, 395 scoped_refptr<ServiceWorkerVersion> activating_version,
363 ServiceWorkerStatusCode status) { 396 ServiceWorkerStatusCode status) {
397 // Activate is prone to failing due to shutdown, because it's triggered when
398 // tabs close.
399 bool is_shutdown =
400 !context_ || context_->wrapper()->process_manager()->IsShutdown();
401 ServiceWorkerMetrics::RecordActivateEventStatus(status, is_shutdown);
402
364 if (!context_ || activating_version != active_version() || 403 if (!context_ || activating_version != active_version() ||
365 activating_version->status() != ServiceWorkerVersion::ACTIVATING) 404 activating_version->status() != ServiceWorkerVersion::ACTIVATING) {
366 return; 405 return;
406 }
367 407
368 // |status| is just for UMA. Once we've attempted to dispatch the activate 408 // Normally, the worker is committed to become activated once we get here, per
369 // event to an installed worker, it's committed to becoming active. 409 // spec. E.g., if the script rejected waitUntil or had an unhandled exception,
370 ServiceWorkerMetrics::RecordActivateEventStatus(status); 410 // it should still be activated. However, if the failure occurred during
411 // shutdown, ignore it to give the worker another chance the next time the
412 // browser starts up.
413 if (is_shutdown && status != SERVICE_WORKER_OK)
414 return;
371 415
372 // "Run the Update State algorithm passing registration's active worker and 416 // "Run the Update State algorithm passing registration's active worker and
373 // 'activated' as the arguments." 417 // 'activated' as the arguments."
374 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED); 418 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
375 context_->storage()->UpdateToActiveState( 419 context_->storage()->UpdateToActiveState(
376 this, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback)); 420 this, base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
377 } 421 }
378 422
379 void ServiceWorkerRegistration::OnDeleteFinished( 423 void ServiceWorkerRegistration::OnDeleteFinished(
380 ServiceWorkerStatusCode status) { 424 ServiceWorkerStatusCode status) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 if (!context_) { 472 if (!context_) {
429 callback.Run(SERVICE_WORKER_ERROR_ABORT); 473 callback.Run(SERVICE_WORKER_ERROR_ABORT);
430 return; 474 return;
431 } 475 }
432 context_->storage()->NotifyDoneInstallingRegistration( 476 context_->storage()->NotifyDoneInstallingRegistration(
433 this, version.get(), status); 477 this, version.get(), status);
434 callback.Run(status); 478 callback.Run(status);
435 } 479 }
436 480
437 } // namespace content 481 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/service_worker/service_worker_registration.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698