Chromium Code Reviews| OLD | NEW |
|---|---|
| 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_version.h" | 5 #include "content/browser/service_worker/service_worker_version.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
| 9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 const int kUpdateDelaySeconds = 1; | 52 const int kUpdateDelaySeconds = 1; |
| 53 | 53 |
| 54 // Timeout for waiting for a response to a ping. | 54 // Timeout for waiting for a response to a ping. |
| 55 const int kPingTimeoutSeconds = 30; | 55 const int kPingTimeoutSeconds = 30; |
| 56 | 56 |
| 57 // Timeout for the worker to start. | 57 // Timeout for the worker to start. |
| 58 const int kStartWorkerTimeoutMinutes = 5; | 58 const int kStartWorkerTimeoutMinutes = 5; |
| 59 | 59 |
| 60 // If the SW was destructed while starting up, how many seconds it | 60 // If the SW was destructed while starting up, how many seconds it |
| 61 // had to start up for this to be considered a timeout occurrence. | 61 // had to start up for this to be considered a timeout occurrence. |
| 62 const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5; // 5 secs. | 62 const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5; // 5 secs. |
|
nhiroki
2015/03/10 00:37:10
nit: This comment "// 5 secs." would be pointless
falken
2015/03/10 06:56:36
Done.
| |
| 63 | 63 |
| 64 const char kClaimClientsStateErrorMesage[] = | 64 const char kClaimClientsStateErrorMesage[] = |
| 65 "Only the active worker can claim clients."; | 65 "Only the active worker can claim clients."; |
| 66 | 66 |
| 67 const char kClaimClientsShutdownErrorMesage[] = | 67 const char kClaimClientsShutdownErrorMesage[] = |
| 68 "Failed to claim clients due to Service Worker system shutdown."; | 68 "Failed to claim clients due to Service Worker system shutdown."; |
| 69 | 69 |
| 70 void RunSoon(const base::Closure& callback) { | 70 void RunSoon(const base::Closure& callback) { |
| 71 if (!callback.is_null()) | 71 if (!callback.is_null()) |
| 72 base::MessageLoop::current()->PostTask(FROM_HERE, callback); | 72 base::MessageLoop::current()->PostTask(FROM_HERE, callback); |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 ServiceWorkerRegistration* registration, | 300 ServiceWorkerRegistration* registration, |
| 301 const GURL& script_url, | 301 const GURL& script_url, |
| 302 int64 version_id, | 302 int64 version_id, |
| 303 base::WeakPtr<ServiceWorkerContextCore> context) | 303 base::WeakPtr<ServiceWorkerContextCore> context) |
| 304 : version_id_(version_id), | 304 : version_id_(version_id), |
| 305 registration_id_(kInvalidServiceWorkerVersionId), | 305 registration_id_(kInvalidServiceWorkerVersionId), |
| 306 script_url_(script_url), | 306 script_url_(script_url), |
| 307 status_(NEW), | 307 status_(NEW), |
| 308 context_(context), | 308 context_(context), |
| 309 script_cache_map_(this, context), | 309 script_cache_map_(this, context), |
| 310 ping_timed_out_(false), | 310 ping_state_(PING_NOT_STARTED), |
| 311 is_doomed_(false), | 311 is_doomed_(false), |
| 312 skip_waiting_(false), | 312 skip_waiting_(false), |
| 313 weak_factory_(this) { | 313 weak_factory_(this) { |
| 314 DCHECK(context_); | 314 DCHECK(context_); |
| 315 DCHECK(registration); | 315 DCHECK(registration); |
| 316 if (registration) { | 316 if (registration) { |
| 317 registration_id_ = registration->id(); | 317 registration_id_ = registration->id(); |
| 318 scope_ = registration->pattern(); | 318 scope_ = registration->pattern(); |
| 319 } | 319 } |
| 320 context_->AddLiveVersion(this); | 320 context_->AddLiveVersion(this); |
| 321 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker(); | 321 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker(); |
| 322 embedded_worker_->AddListener(this); | 322 embedded_worker_->AddListener(this); |
| 323 } | 323 } |
| 324 | 324 |
| 325 ServiceWorkerVersion::~ServiceWorkerVersion() { | 325 ServiceWorkerVersion::~ServiceWorkerVersion() { |
| 326 // The user may have closed the tab waiting for SW to start up. | 326 // The user may have closed the tab waiting for SW to start up. |
| 327 if (start_worker_timeout_timer_.IsRunning() && | 327 if (GetTickDuration(start_time_) > |
| 328 GetTickDuration(start_timing_) > | 328 base::TimeDelta::FromSeconds( |
| 329 base::TimeDelta::FromSeconds( | 329 kDestructedStartingWorkerTimeoutThresholdSeconds)) { |
| 330 kDestructedStartingWorkerTimeoutThresholdSeconds)) { | 330 DCHECK(timeout_timer_.IsRunning()); |
| 331 DCHECK(!embedded_worker_->devtools_attached()); | |
| 331 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT); | 332 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT); |
| 332 } | 333 } |
| 333 | 334 |
| 334 embedded_worker_->RemoveListener(this); | 335 embedded_worker_->RemoveListener(this); |
| 335 if (context_) | 336 if (context_) |
| 336 context_->RemoveLiveVersion(version_id_); | 337 context_->RemoveLiveVersion(version_id_); |
| 337 // EmbeddedWorker's dtor sends StopWorker if it's still running. | 338 // EmbeddedWorker's dtor sends StopWorker if it's still running. |
| 338 } | 339 } |
| 339 | 340 |
| 340 void ServiceWorkerVersion::SetStatus(Status status) { | 341 void ServiceWorkerVersion::SetStatus(Status status) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED)); | 386 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED)); |
| 386 return; | 387 return; |
| 387 } | 388 } |
| 388 switch (running_status()) { | 389 switch (running_status()) { |
| 389 case RUNNING: | 390 case RUNNING: |
| 390 RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); | 391 RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); |
| 391 return; | 392 return; |
| 392 case STOPPING: | 393 case STOPPING: |
| 393 case STOPPED: | 394 case STOPPED: |
| 394 case STARTING: | 395 case STARTING: |
| 395 if (!start_worker_timeout_timer_.IsRunning()) | 396 if (!timeout_timer_.IsRunning()) |
| 396 ScheduleStartWorkerTimeout(); | 397 StartTimeoutTimer(); |
| 397 start_callbacks_.push_back(callback); | 398 start_callbacks_.push_back(callback); |
| 398 if (running_status() == STOPPED) { | 399 if (running_status() == STOPPED) { |
| 399 DCHECK(!cache_listener_.get()); | 400 DCHECK(!cache_listener_.get()); |
| 400 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); | 401 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); |
| 401 embedded_worker_->Start( | 402 embedded_worker_->Start( |
| 402 version_id_, scope_, script_url_, pause_after_download, | 403 version_id_, scope_, script_url_, pause_after_download, |
| 403 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated, | 404 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated, |
| 404 weak_factory_.GetWeakPtr())); | 405 weak_factory_.GetWeakPtr())); |
| 405 } | 406 } |
| 406 return; | 407 return; |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 782 return; | 783 return; |
| 783 is_doomed_ = true; | 784 is_doomed_ = true; |
| 784 if (!HasControllee()) | 785 if (!HasControllee()) |
| 785 DoomInternal(); | 786 DoomInternal(); |
| 786 } | 787 } |
| 787 | 788 |
| 788 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { | 789 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
| 789 embedded_worker()->set_devtools_attached(attached); | 790 embedded_worker()->set_devtools_attached(attached); |
| 790 if (attached) { | 791 if (attached) { |
| 791 // Set to null time so we don't record the startup time metric. | 792 // Set to null time so we don't record the startup time metric. |
| 792 ClearTick(&start_timing_); | 793 ClearTick(&start_time_); |
| 793 return; | 794 return; |
| 794 } | 795 } |
| 795 // If devtools is detached try scheduling the timers for stopping the worker | |
| 796 // now. | |
| 797 if (!timeout_timer_.IsRunning()) | 796 if (!timeout_timer_.IsRunning()) |
| 798 StartTimeoutTimer(); | 797 StartTimeoutTimer(); |
| 799 if (!start_worker_timeout_timer_.IsRunning() && !start_callbacks_.empty()) | |
| 800 ScheduleStartWorkerTimeout(); | |
| 801 } | 798 } |
| 802 | 799 |
| 803 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( | 800 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
| 804 const net::HttpResponseInfo& http_info) { | 801 const net::HttpResponseInfo& http_info) { |
| 805 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); | 802 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); |
| 806 } | 803 } |
| 807 | 804 |
| 808 const net::HttpResponseInfo* | 805 const net::HttpResponseInfo* |
| 809 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { | 806 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
| 810 return main_script_http_info_.get(); | 807 return main_script_http_info_.get(); |
| 811 } | 808 } |
| 812 | 809 |
| 813 void ServiceWorkerVersion::OnScriptLoaded() { | 810 void ServiceWorkerVersion::OnScriptLoaded() { |
| 814 DCHECK_EQ(STARTING, running_status()); | 811 DCHECK_EQ(STARTING, running_status()); |
| 815 StartTimeoutTimer(); | 812 ping_state_ = PING_STARTED; |
|
kinuko
2015/03/09 09:30:40
nit: This line (or enum name) may look a bit crypt
falken
2015/03/09 10:10:55
Agreed. I renamed the enums and added a comment.
| |
| 816 } | 813 } |
| 817 | 814 |
| 818 void ServiceWorkerVersion::OnStarted() { | 815 void ServiceWorkerVersion::OnStarted() { |
| 819 DCHECK_EQ(RUNNING, running_status()); | 816 DCHECK_EQ(RUNNING, running_status()); |
| 820 DCHECK(cache_listener_.get()); | 817 DCHECK(cache_listener_.get()); |
| 821 RestartTick(&idle_time_); | 818 RestartTick(&idle_time_); |
| 822 | 819 |
| 823 // Fire all start callbacks. | 820 // Fire all start callbacks. |
| 824 scoped_refptr<ServiceWorkerVersion> protect(this); | 821 scoped_refptr<ServiceWorkerVersion> protect(this); |
| 825 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); | 822 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); |
| 826 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); | 823 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); |
| 827 } | 824 } |
| 828 | 825 |
| 829 void ServiceWorkerVersion::OnStopped( | 826 void ServiceWorkerVersion::OnStopped( |
| 830 EmbeddedWorkerInstance::Status old_status) { | 827 EmbeddedWorkerInstance::Status old_status) { |
| 831 DCHECK_EQ(STOPPED, running_status()); | 828 DCHECK_EQ(STOPPED, running_status()); |
| 832 scoped_refptr<ServiceWorkerVersion> protect(this); | 829 scoped_refptr<ServiceWorkerVersion> protect(this); |
| 833 | 830 |
| 834 bool should_restart = !is_doomed() && !start_callbacks_.empty() && | 831 bool should_restart = !is_doomed() && !start_callbacks_.empty() && |
| 835 (old_status != EmbeddedWorkerInstance::STARTING); | 832 (old_status != EmbeddedWorkerInstance::STARTING); |
| 836 | 833 |
| 837 StopTimeoutTimer(); | 834 StopTimeoutTimer(); |
| 838 if (ping_timed_out_) | 835 if (ping_state_ == PING_TIMED_OUT) |
| 839 should_restart = false; | 836 should_restart = false; |
| 840 | 837 |
| 841 // Fire all stop callbacks. | 838 // Fire all stop callbacks. |
| 842 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); | 839 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); |
| 843 | 840 |
| 844 if (!should_restart) { | 841 if (!should_restart) { |
| 845 // Let all start callbacks fail. | 842 // Let all start callbacks fail. |
| 846 RunCallbacks(this, &start_callbacks_, | 843 RunCallbacks(this, &start_callbacks_, |
| 847 SERVICE_WORKER_ERROR_START_WORKER_FAILED); | 844 SERVICE_WORKER_ERROR_START_WORKER_FAILED); |
| 848 } | 845 } |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 874 | 871 |
| 875 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this)); | 872 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this)); |
| 876 | 873 |
| 877 // There should be no more communication from/to a stopped worker. Deleting | 874 // There should be no more communication from/to a stopped worker. Deleting |
| 878 // the listener prevents any pending completion callbacks from causing | 875 // the listener prevents any pending completion callbacks from causing |
| 879 // messages to be sent to the stopped worker. | 876 // messages to be sent to the stopped worker. |
| 880 cache_listener_.reset(); | 877 cache_listener_.reset(); |
| 881 | 878 |
| 882 // Restart worker if we have any start callbacks and the worker isn't doomed. | 879 // Restart worker if we have any start callbacks and the worker isn't doomed. |
| 883 if (should_restart) { | 880 if (should_restart) { |
| 884 start_worker_timeout_timer_.Reset(); | 881 if (embedded_worker_->devtools_attached()) |
| 882 ClearTick(&start_time_); | |
| 883 else | |
| 884 RestartTick(&start_time_); | |
| 885 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); | 885 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); |
| 886 embedded_worker_->Start( | 886 embedded_worker_->Start( |
| 887 version_id_, scope_, script_url_, false /* pause_after_download */, | 887 version_id_, scope_, script_url_, false /* pause_after_download */, |
| 888 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated, | 888 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated, |
| 889 weak_factory_.GetWeakPtr())); | 889 weak_factory_.GetWeakPtr())); |
| 890 } | 890 } |
| 891 } | 891 } |
| 892 | 892 |
| 893 void ServiceWorkerVersion::OnReportException( | 893 void ServiceWorkerVersion::OnReportException( |
| 894 const base::string16& error_message, | 894 const base::string16& error_message, |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1419 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 1419 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 1420 if (running_status() != RUNNING) | 1420 if (running_status() != RUNNING) |
| 1421 return; | 1421 return; |
| 1422 | 1422 |
| 1423 embedded_worker_->SendMessage( | 1423 embedded_worker_->SendMessage( |
| 1424 ServiceWorkerMsg_DidGetClients(request_id, clients)); | 1424 ServiceWorkerMsg_DidGetClients(request_id, clients)); |
| 1425 } | 1425 } |
| 1426 | 1426 |
| 1427 void ServiceWorkerVersion::StartTimeoutTimer() { | 1427 void ServiceWorkerVersion::StartTimeoutTimer() { |
| 1428 DCHECK(!timeout_timer_.IsRunning()); | 1428 DCHECK(!timeout_timer_.IsRunning()); |
| 1429 | |
| 1430 if (embedded_worker_->devtools_attached()) | |
| 1431 ClearTick(&start_time_); | |
| 1432 else | |
| 1433 RestartTick(&start_time_); | |
| 1434 start_callbacks_.push_back( | |
| 1435 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult, | |
| 1436 weak_factory_.GetWeakPtr())); | |
| 1437 | |
| 1429 ClearTick(&idle_time_); | 1438 ClearTick(&idle_time_); |
| 1430 ClearTick(&ping_time_); | 1439 ClearTick(&ping_time_); |
| 1431 ping_timed_out_ = false; | 1440 ping_state_ = PING_NOT_STARTED; |
| 1441 | |
| 1432 timeout_timer_.Start(FROM_HERE, | 1442 timeout_timer_.Start(FROM_HERE, |
| 1433 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds), | 1443 base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds), |
| 1434 this, &ServiceWorkerVersion::OnTimeoutTimer); | 1444 this, &ServiceWorkerVersion::OnTimeoutTimer); |
| 1435 } | 1445 } |
| 1436 | 1446 |
| 1437 void ServiceWorkerVersion::StopTimeoutTimer() { | 1447 void ServiceWorkerVersion::StopTimeoutTimer() { |
| 1438 timeout_timer_.Stop(); | 1448 timeout_timer_.Stop(); |
| 1439 } | 1449 } |
| 1440 | 1450 |
| 1441 void ServiceWorkerVersion::OnTimeoutTimer() { | 1451 void ServiceWorkerVersion::OnTimeoutTimer() { |
| 1452 DCHECK(running_status() == STARTING || running_status() == RUNNING || | |
| 1453 running_status() == STOPPING) | |
| 1454 << running_status(); | |
| 1455 | |
| 1456 if (GetTickDuration(start_time_) > | |
|
kinuko
2015/03/09 09:30:40
nit: Could we have one-line comments for each of t
falken
2015/03/09 10:10:55
Done.
| |
| 1457 base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) { | |
| 1458 DCHECK_NE(RUNNING, running_status()); | |
| 1459 scoped_refptr<ServiceWorkerVersion> protect(this); | |
| 1460 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT); | |
| 1461 if (running_status() == STARTING) | |
| 1462 embedded_worker_->Stop(); | |
| 1463 StopTimeoutTimer(); | |
| 1464 return; | |
| 1465 } | |
| 1466 | |
| 1442 if (running_status() == STOPPING) | 1467 if (running_status() == STOPPING) |
| 1443 return; | 1468 return; |
|
kinuko
2015/03/09 09:30:40
nit: could this check be done before we check star
falken
2015/03/09 10:10:55
Thanks for pointing this out. The start_time timeo
falken
2015/03/10 06:56:36
Updated this... the timeout timer now continues un
| |
| 1444 DCHECK(running_status() == STARTING || running_status() == RUNNING); | 1469 |
| 1445 if (GetTickDuration(idle_time_) > | 1470 if (GetTickDuration(idle_time_) > |
| 1446 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) { | 1471 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) { |
| 1447 StopWorkerIfIdle(); | 1472 StopWorkerIfIdle(); |
| 1448 StopTimeoutTimer(); | 1473 StopTimeoutTimer(); |
| 1449 return; | 1474 return; |
| 1450 } | 1475 } |
| 1451 if (GetTickDuration(ping_time_) > | 1476 if (GetTickDuration(ping_time_) > |
| 1452 base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) { | 1477 base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) { |
| 1453 OnPingTimeout(); | 1478 OnPingTimeout(); |
| 1454 StopTimeoutTimer(); | 1479 StopTimeoutTimer(); |
| 1455 return; | 1480 return; |
| 1456 } | 1481 } |
| 1457 | 1482 |
| 1458 if (ping_time_.is_null()) | 1483 if (ping_state_ == PING_STARTED && ping_time_.is_null()) |
| 1459 PingWorker(); | 1484 PingWorker(); |
| 1460 } | 1485 } |
| 1461 | 1486 |
| 1462 void ServiceWorkerVersion::PingWorker() { | 1487 void ServiceWorkerVersion::PingWorker() { |
| 1463 DCHECK(running_status() == STARTING || running_status() == RUNNING); | 1488 DCHECK(running_status() == STARTING || running_status() == RUNNING); |
| 1489 DCHECK_EQ(PING_STARTED, ping_state_); | |
| 1464 ServiceWorkerStatusCode status = | 1490 ServiceWorkerStatusCode status = |
| 1465 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping()); | 1491 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping()); |
| 1466 if (status != SERVICE_WORKER_OK) { | 1492 if (status != SERVICE_WORKER_OK) { |
| 1467 // TODO(falken): Maybe try resending Ping a few times first? | 1493 // TODO(falken): Maybe try resending Ping a few times first? |
| 1468 ping_timed_out_ = true; | 1494 ping_state_ = PING_TIMED_OUT; |
| 1469 StopWorkerIfIdle(); | 1495 StopWorkerIfIdle(); |
| 1470 return; | 1496 return; |
| 1471 } | 1497 } |
| 1472 RestartTick(&ping_time_); | 1498 RestartTick(&ping_time_); |
| 1473 } | 1499 } |
| 1474 | 1500 |
| 1475 void ServiceWorkerVersion::OnPingTimeout() { | 1501 void ServiceWorkerVersion::OnPingTimeout() { |
| 1476 DCHECK(running_status() == STARTING || running_status() == RUNNING); | 1502 DCHECK(running_status() == STARTING || running_status() == RUNNING); |
| 1477 ping_timed_out_ = true; | 1503 ping_state_ = PING_TIMED_OUT; |
| 1478 // TODO(falken): Show a message to the developer that the SW was stopped due | 1504 // TODO(falken): Show a message to the developer that the SW was stopped due |
| 1479 // to timeout (crbug.com/457968). Also, change the error code to | 1505 // to timeout (crbug.com/457968). Also, change the error code to |
| 1480 // SERVICE_WORKER_ERROR_TIMEOUT. | 1506 // SERVICE_WORKER_ERROR_TIMEOUT. |
| 1481 StopWorkerIfIdle(); | 1507 StopWorkerIfIdle(); |
| 1482 } | 1508 } |
| 1483 | 1509 |
| 1484 void ServiceWorkerVersion::StopWorkerIfIdle() { | 1510 void ServiceWorkerVersion::StopWorkerIfIdle() { |
| 1485 if (HasInflightRequests() && !ping_timed_out_) | 1511 if (HasInflightRequests() && ping_state_ != PING_TIMED_OUT) |
| 1486 return; | 1512 return; |
| 1487 if (running_status() == STOPPED || running_status() == STOPPING || | 1513 if (running_status() == STOPPED || running_status() == STOPPING || |
| 1488 !stop_callbacks_.empty()) { | 1514 !stop_callbacks_.empty()) { |
| 1489 return; | 1515 return; |
| 1490 } | 1516 } |
| 1491 | 1517 |
| 1492 // TODO(falken): We may need to handle StopIfIdle failure and | 1518 // TODO(falken): We may need to handle StopIfIdle failure and |
| 1493 // forcibly fail pending callbacks so no one is stuck waiting | 1519 // forcibly fail pending callbacks so no one is stuck waiting |
| 1494 // for the worker. | 1520 // for the worker. |
| 1495 embedded_worker_->StopIfIdle(); | 1521 embedded_worker_->StopIfIdle(); |
| 1496 } | 1522 } |
| 1497 | 1523 |
| 1498 bool ServiceWorkerVersion::HasInflightRequests() const { | 1524 bool ServiceWorkerVersion::HasInflightRequests() const { |
| 1499 return | 1525 return |
| 1500 !activate_callbacks_.IsEmpty() || | 1526 !activate_callbacks_.IsEmpty() || |
| 1501 !install_callbacks_.IsEmpty() || | 1527 !install_callbacks_.IsEmpty() || |
| 1502 !fetch_callbacks_.IsEmpty() || | 1528 !fetch_callbacks_.IsEmpty() || |
| 1503 !sync_callbacks_.IsEmpty() || | 1529 !sync_callbacks_.IsEmpty() || |
| 1504 !notification_click_callbacks_.IsEmpty() || | 1530 !notification_click_callbacks_.IsEmpty() || |
| 1505 !push_callbacks_.IsEmpty() || | 1531 !push_callbacks_.IsEmpty() || |
| 1506 !geofencing_callbacks_.IsEmpty() || | 1532 !geofencing_callbacks_.IsEmpty() || |
| 1507 !cross_origin_connect_callbacks_.IsEmpty() || | 1533 !cross_origin_connect_callbacks_.IsEmpty() || |
| 1508 !streaming_url_request_jobs_.empty(); | 1534 !streaming_url_request_jobs_.empty(); |
| 1509 } | 1535 } |
| 1510 | 1536 |
| 1511 void ServiceWorkerVersion::ScheduleStartWorkerTimeout() { | |
| 1512 DCHECK(!start_worker_timeout_timer_.IsRunning()); | |
| 1513 start_timing_ = embedded_worker_->devtools_attached() | |
| 1514 ? base::TimeTicks() | |
| 1515 : base::TimeTicks::Now(); | |
| 1516 start_callbacks_.push_back( | |
| 1517 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult, | |
| 1518 weak_factory_.GetWeakPtr())); | |
| 1519 start_worker_timeout_timer_.Start( | |
| 1520 FROM_HERE, base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes), | |
| 1521 base::Bind(&ServiceWorkerVersion::OnStartWorkerTimeout, | |
| 1522 weak_factory_.GetWeakPtr())); | |
| 1523 } | |
| 1524 | |
| 1525 void ServiceWorkerVersion::OnStartWorkerTimeout() { | |
| 1526 DCHECK(running_status() == STARTING || running_status() == STOPPING) | |
| 1527 << running_status(); | |
| 1528 | |
| 1529 if (embedded_worker_->devtools_attached()) { | |
| 1530 start_worker_timeout_timer_.Stop(); | |
| 1531 return; | |
| 1532 } | |
| 1533 | |
| 1534 scoped_refptr<ServiceWorkerVersion> protect(this); | |
| 1535 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT); | |
| 1536 if (running_status() == STARTING) | |
| 1537 embedded_worker_->Stop(); | |
| 1538 } | |
| 1539 | |
| 1540 void ServiceWorkerVersion::RecordStartWorkerResult( | 1537 void ServiceWorkerVersion::RecordStartWorkerResult( |
| 1541 ServiceWorkerStatusCode status) { | 1538 ServiceWorkerStatusCode status) { |
| 1542 start_worker_timeout_timer_.Stop(); | |
| 1543 | |
| 1544 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status, | 1539 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status, |
| 1545 SERVICE_WORKER_ERROR_MAX_VALUE); | 1540 SERVICE_WORKER_ERROR_MAX_VALUE); |
| 1546 if (status == SERVICE_WORKER_OK && !start_timing_.is_null()) { | 1541 if (status == SERVICE_WORKER_OK && !start_time_.is_null()) { |
| 1547 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", | 1542 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", |
| 1548 GetTickDuration(start_timing_)); | 1543 GetTickDuration(start_time_)); |
| 1549 } | 1544 } |
| 1550 | 1545 |
| 1546 ClearTick(&start_time_); | |
| 1551 if (status != SERVICE_WORKER_ERROR_TIMEOUT) | 1547 if (status != SERVICE_WORKER_ERROR_TIMEOUT) |
| 1552 return; | 1548 return; |
| 1553 EmbeddedWorkerInstance::StartingPhase phase = | 1549 EmbeddedWorkerInstance::StartingPhase phase = |
| 1554 EmbeddedWorkerInstance::NOT_STARTING; | 1550 EmbeddedWorkerInstance::NOT_STARTING; |
| 1555 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status(); | 1551 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status(); |
| 1556 // Build an artifical JavaScript exception to show in the ServiceWorker | 1552 // Build an artifical JavaScript exception to show in the ServiceWorker |
| 1557 // log for developers; it's not user-facing so it's not a localized resource. | 1553 // log for developers; it's not user-facing so it's not a localized resource. |
| 1558 std::string message = "ServiceWorker startup timed out. "; | 1554 std::string message = "ServiceWorker startup timed out. "; |
| 1559 if (running_status != EmbeddedWorkerInstance::STARTING) { | 1555 if (running_status != EmbeddedWorkerInstance::STARTING) { |
| 1560 message.append("The worker had unexpected status: "); | 1556 message.append("The worker had unexpected status: "); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1590 int request_id) { | 1586 int request_id) { |
| 1591 callbacks->Remove(request_id); | 1587 callbacks->Remove(request_id); |
| 1592 if (is_doomed_) { | 1588 if (is_doomed_) { |
| 1593 // The stop should be already scheduled, but try to stop immediately, in | 1589 // The stop should be already scheduled, but try to stop immediately, in |
| 1594 // order to release worker resources soon. | 1590 // order to release worker resources soon. |
| 1595 StopWorkerIfIdle(); | 1591 StopWorkerIfIdle(); |
| 1596 } | 1592 } |
| 1597 } | 1593 } |
| 1598 | 1594 |
| 1599 } // namespace content | 1595 } // namespace content |
| OLD | NEW |