Index: content/browser/service_worker/service_worker_version.cc |
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc |
index 4857ff945871867b0ed6c703669c1ad678b28c18..51eb072ff933c4a2b34dc3f24aaed5d8c7fdee91 100644 |
--- a/content/browser/service_worker/service_worker_version.cc |
+++ b/content/browser/service_worker/service_worker_version.cc |
@@ -54,12 +54,9 @@ const int kUpdateDelaySeconds = 1; |
// Timeout for waiting for a response to a ping. |
const int kPingTimeoutSeconds = 30; |
-// Timeout for the worker to start. |
-const int kStartWorkerTimeoutMinutes = 5; |
- |
// If the SW was destructed while starting up, how many seconds it |
// had to start up for this to be considered a timeout occurrence. |
-const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5; // 5 secs. |
+const int kDestructedStartingWorkerTimeoutThresholdSeconds = 5; |
const char kClaimClientsStateErrorMesage[] = |
"Only the active worker can claim clients."; |
@@ -296,6 +293,8 @@ void OnGetClientsFromUI( |
} // namespace |
+const int ServiceWorkerVersion::kStartWorkerTimeoutMinutes = 5; |
+ |
ServiceWorkerVersion::ServiceWorkerVersion( |
ServiceWorkerRegistration* registration, |
const GURL& script_url, |
@@ -307,7 +306,7 @@ ServiceWorkerVersion::ServiceWorkerVersion( |
status_(NEW), |
context_(context), |
script_cache_map_(this, context), |
- ping_timed_out_(false), |
+ ping_state_(NOT_PINGING), |
is_doomed_(false), |
skip_waiting_(false), |
weak_factory_(this) { |
@@ -324,10 +323,11 @@ ServiceWorkerVersion::ServiceWorkerVersion( |
ServiceWorkerVersion::~ServiceWorkerVersion() { |
// The user may have closed the tab waiting for SW to start up. |
- if (start_worker_timeout_timer_.IsRunning() && |
- GetTickDuration(start_timing_) > |
- base::TimeDelta::FromSeconds( |
- kDestructedStartingWorkerTimeoutThresholdSeconds)) { |
+ if (GetTickDuration(start_time_) > |
+ base::TimeDelta::FromSeconds( |
+ kDestructedStartingWorkerTimeoutThresholdSeconds)) { |
+ DCHECK(timeout_timer_.IsRunning()); |
+ DCHECK(!embedded_worker_->devtools_attached()); |
RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT); |
} |
@@ -392,8 +392,8 @@ void ServiceWorkerVersion::StartWorker( |
case STOPPING: |
case STOPPED: |
case STARTING: |
- if (!start_worker_timeout_timer_.IsRunning()) |
- ScheduleStartWorkerTimeout(); |
+ if (!timeout_timer_.IsRunning()) |
+ StartTimeoutTimer(); |
start_callbacks_.push_back(callback); |
if (running_status() == STOPPED) { |
DCHECK(!cache_listener_.get()); |
@@ -789,15 +789,11 @@ void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
embedded_worker()->set_devtools_attached(attached); |
if (attached) { |
// Set to null time so we don't record the startup time metric. |
- ClearTick(&start_timing_); |
+ ClearTick(&start_time_); |
return; |
} |
- // If devtools is detached try scheduling the timers for stopping the worker |
- // now. |
if (!timeout_timer_.IsRunning()) |
StartTimeoutTimer(); |
- if (!start_worker_timeout_timer_.IsRunning() && !start_callbacks_.empty()) |
- ScheduleStartWorkerTimeout(); |
} |
void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
@@ -812,7 +808,8 @@ ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
void ServiceWorkerVersion::OnScriptLoaded() { |
DCHECK_EQ(STARTING, running_status()); |
- StartTimeoutTimer(); |
+ // Activate ping/pong now that JavaScript execution will start. |
+ ping_state_ = PINGING; |
} |
void ServiceWorkerVersion::OnStarted() { |
@@ -835,7 +832,7 @@ void ServiceWorkerVersion::OnStopped( |
(old_status != EmbeddedWorkerInstance::STARTING); |
StopTimeoutTimer(); |
- if (ping_timed_out_) |
+ if (ping_state_ == PING_TIMED_OUT) |
should_restart = false; |
// Fire all stop callbacks. |
@@ -881,7 +878,10 @@ void ServiceWorkerVersion::OnStopped( |
// Restart worker if we have any start callbacks and the worker isn't doomed. |
if (should_restart) { |
- start_worker_timeout_timer_.Reset(); |
+ if (embedded_worker_->devtools_attached()) |
+ ClearTick(&start_time_); |
+ else |
+ RestartTick(&start_time_); |
cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); |
embedded_worker_->Start( |
version_id_, scope_, script_url_, false /* pause_after_download */, |
@@ -1426,9 +1426,19 @@ void ServiceWorkerVersion::DidGetClients( |
void ServiceWorkerVersion::StartTimeoutTimer() { |
DCHECK(!timeout_timer_.IsRunning()); |
+ |
+ if (embedded_worker_->devtools_attached()) |
+ ClearTick(&start_time_); |
+ else |
+ RestartTick(&start_time_); |
+ start_callbacks_.push_back( |
+ base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult, |
+ weak_factory_.GetWeakPtr())); |
+ |
ClearTick(&idle_time_); |
ClearTick(&ping_time_); |
- ping_timed_out_ = false; |
+ ping_state_ = NOT_PINGING; |
+ |
timeout_timer_.Start(FROM_HERE, |
base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds), |
this, &ServiceWorkerVersion::OnTimeoutTimer); |
@@ -1439,33 +1449,53 @@ void ServiceWorkerVersion::StopTimeoutTimer() { |
} |
void ServiceWorkerVersion::OnTimeoutTimer() { |
+ DCHECK(running_status() == STARTING || running_status() == RUNNING || |
+ running_status() == STOPPING) |
+ << running_status(); |
+ |
+ // Starting a worker hasn't finished within a certain period. |
+ if (GetTickDuration(start_time_) > |
+ base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes)) { |
+ DCHECK_NE(RUNNING, running_status()); |
+ scoped_refptr<ServiceWorkerVersion> protect(this); |
+ RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT); |
+ if (running_status() == STARTING) |
+ embedded_worker_->Stop(); |
+ return; |
+ } |
+ |
+ // This check occurs after the start_time_ timeout check, since in that case |
+ // the start callbacks should fail with ERROR_TIMEOUT. In the other timeout |
+ // checks, there's nothing more to do as the worker is already stopping. |
if (running_status() == STOPPING) |
return; |
- DCHECK(running_status() == STARTING || running_status() == RUNNING); |
+ |
+ // The worker has been idle for longer than a certain period. |
if (GetTickDuration(idle_time_) > |
base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) { |
StopWorkerIfIdle(); |
- StopTimeoutTimer(); |
return; |
} |
+ |
+ // The worker hasn't responded to ping within a certain period. |
if (GetTickDuration(ping_time_) > |
base::TimeDelta::FromSeconds(kPingTimeoutSeconds)) { |
OnPingTimeout(); |
- StopTimeoutTimer(); |
return; |
} |
- if (ping_time_.is_null()) |
+ if (ping_state_ == PINGING && ping_time_.is_null()) |
PingWorker(); |
} |
void ServiceWorkerVersion::PingWorker() { |
DCHECK(running_status() == STARTING || running_status() == RUNNING); |
+ DCHECK_EQ(PINGING, ping_state_); |
ServiceWorkerStatusCode status = |
embedded_worker_->SendMessage(ServiceWorkerMsg_Ping()); |
if (status != SERVICE_WORKER_OK) { |
// TODO(falken): Maybe try resending Ping a few times first? |
- ping_timed_out_ = true; |
+ ping_state_ = PING_TIMED_OUT; |
StopWorkerIfIdle(); |
return; |
} |
@@ -1474,7 +1504,7 @@ void ServiceWorkerVersion::PingWorker() { |
void ServiceWorkerVersion::OnPingTimeout() { |
DCHECK(running_status() == STARTING || running_status() == RUNNING); |
- ping_timed_out_ = true; |
+ ping_state_ = PING_TIMED_OUT; |
// TODO(falken): Show a message to the developer that the SW was stopped due |
// to timeout (crbug.com/457968). Also, change the error code to |
// SERVICE_WORKER_ERROR_TIMEOUT. |
@@ -1482,7 +1512,7 @@ void ServiceWorkerVersion::OnPingTimeout() { |
} |
void ServiceWorkerVersion::StopWorkerIfIdle() { |
- if (HasInflightRequests() && !ping_timed_out_) |
+ if (HasInflightRequests() && ping_state_ != PING_TIMED_OUT) |
return; |
if (running_status() == STOPPED || running_status() == STOPPING || |
!stop_callbacks_.empty()) { |
@@ -1508,46 +1538,16 @@ bool ServiceWorkerVersion::HasInflightRequests() const { |
!streaming_url_request_jobs_.empty(); |
} |
-void ServiceWorkerVersion::ScheduleStartWorkerTimeout() { |
- DCHECK(!start_worker_timeout_timer_.IsRunning()); |
- start_timing_ = embedded_worker_->devtools_attached() |
- ? base::TimeTicks() |
- : base::TimeTicks::Now(); |
- start_callbacks_.push_back( |
- base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult, |
- weak_factory_.GetWeakPtr())); |
- start_worker_timeout_timer_.Start( |
- FROM_HERE, base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes), |
- base::Bind(&ServiceWorkerVersion::OnStartWorkerTimeout, |
- weak_factory_.GetWeakPtr())); |
-} |
- |
-void ServiceWorkerVersion::OnStartWorkerTimeout() { |
- DCHECK(running_status() == STARTING || running_status() == STOPPING) |
- << running_status(); |
- |
- if (embedded_worker_->devtools_attached()) { |
- start_worker_timeout_timer_.Stop(); |
- return; |
- } |
- |
- scoped_refptr<ServiceWorkerVersion> protect(this); |
- RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT); |
- if (running_status() == STARTING) |
- embedded_worker_->Stop(); |
-} |
- |
void ServiceWorkerVersion::RecordStartWorkerResult( |
ServiceWorkerStatusCode status) { |
- start_worker_timeout_timer_.Stop(); |
- |
UMA_HISTOGRAM_ENUMERATION("ServiceWorker.StartWorker.Status", status, |
SERVICE_WORKER_ERROR_MAX_VALUE); |
- if (status == SERVICE_WORKER_OK && !start_timing_.is_null()) { |
+ if (status == SERVICE_WORKER_OK && !start_time_.is_null()) { |
UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.StartWorker.Time", |
- GetTickDuration(start_timing_)); |
+ GetTickDuration(start_time_)); |
} |
+ ClearTick(&start_time_); |
if (status != SERVICE_WORKER_ERROR_TIMEOUT) |
return; |
EmbeddedWorkerInstance::StartingPhase phase = |