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 4fd441b8058715f9586bf91b372e1d6f08006a12..3c7f105dd70b767fe2139bed41f93dc253fdf186 100644 |
--- a/content/browser/service_worker/service_worker_version.cc |
+++ b/content/browser/service_worker/service_worker_version.cc |
@@ -329,6 +329,12 @@ void RestartTick(base::TimeTicks* time) { |
*time = base::TimeTicks().Now(); |
} |
+bool RequestExpired(const base::TimeTicks& expiration) { |
+ if (expiration.is_null()) |
+ return false; |
+ return base::TimeTicks().Now() >= expiration; |
+} |
+ |
base::TimeDelta GetTickDuration(const base::TimeTicks& time) { |
if (time.is_null()) |
return base::TimeDelta(); |
@@ -803,6 +809,7 @@ void ServiceWorkerVersion::DispatchFetchEvent( |
void ServiceWorkerVersion::DispatchSyncEvent( |
BackgroundSyncRegistrationHandle::HandleId handle_id, |
BackgroundSyncEventLastChance last_chance, |
+ base::TimeDelta max_duration, |
const StatusCallback& callback) { |
OnBeginEvent(); |
DCHECK_EQ(ACTIVATED, status()) << status(); |
@@ -811,11 +818,13 @@ void ServiceWorkerVersion::DispatchSyncEvent( |
StartWorker(base::Bind( |
&RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(), callback, |
base::Bind(&self::DispatchSyncEvent, weak_factory_.GetWeakPtr(), |
- handle_id, last_chance, callback))); |
+ handle_id, last_chance, max_duration, callback))); |
return; |
} |
- int request_id = AddRequest(callback, &sync_requests_, REQUEST_SYNC); |
+ int request_id = |
+ AddRequestWithExpiration(callback, &sync_requests_, REQUEST_SYNC, |
+ base::TimeTicks::Now() + max_duration); |
if (!background_sync_dispatcher_) { |
embedded_worker_->GetServiceRegistry()->ConnectToRemoteService( |
mojo::GetProxy(&background_sync_dispatcher_)); |
@@ -1079,7 +1088,7 @@ void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
skip_recording_startup_time_ = true; |
// Cancel request timeouts. |
- SetAllRequestTimes(base::TimeTicks()); |
+ SetAllRequestExpirations(base::TimeTicks()); |
return; |
} |
if (!start_callbacks_.empty()) { |
@@ -1090,8 +1099,10 @@ void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
RestartTick(&start_time_); |
} |
- // Reactivate request timeouts. |
- SetAllRequestTimes(base::TimeTicks::Now()); |
+ // Reactivate request timeouts, setting them all to the same expiration time. |
+ SetAllRequestExpirations( |
+ base::TimeTicks::Now() + |
+ base::TimeDelta::FromMinutes(kRequestTimeoutMinutes)); |
} |
void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
@@ -1110,15 +1121,20 @@ ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
return main_script_http_info_.get(); |
} |
-ServiceWorkerVersion::RequestInfo::RequestInfo(int id, |
- RequestType type, |
- const base::TimeTicks& now) |
- : id(id), type(type), time(now) { |
-} |
+ServiceWorkerVersion::RequestInfo::RequestInfo( |
+ int id, |
+ RequestType type, |
+ const base::TimeTicks& expiration) |
+ : id(id), type(type), expiration(expiration) {} |
ServiceWorkerVersion::RequestInfo::~RequestInfo() { |
} |
+bool ServiceWorkerVersion::RequestInfo::operator>( |
+ const RequestInfo& other) const { |
+ return expiration > other.expiration; |
+} |
+ |
template <typename CallbackType> |
ServiceWorkerVersion::PendingRequest<CallbackType>::PendingRequest( |
const CallbackType& callback, |
@@ -1433,10 +1449,13 @@ void ServiceWorkerVersion::OnSyncEventFinished( |
"Request id", request_id); |
PendingRequest<StatusCallback>* request = sync_requests_.Lookup(request_id); |
if (!request) { |
- NOTREACHED() << "Got unexpected message: " << request_id; |
+ // Assume the request timed out. |
return; |
} |
+ UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.BackgroundSyncEvent.Time", |
+ base::TimeTicks::Now() - request->start_time); |
+ |
scoped_refptr<ServiceWorkerVersion> protect(this); |
request->callback.Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status)); |
RemoveCallbackAndStopIfRedundant(&sync_requests_, request_id); |
@@ -2119,21 +2138,20 @@ void ServiceWorkerVersion::OnTimeoutTimer() { |
return; |
} |
- // Requests have not finished within a certain period. |
- bool request_timed_out = false; |
+ // Requests have not finished before their expiration. |
+ bool stop_for_timeout = false; |
while (!requests_.empty()) { |
- RequestInfo info = requests_.front(); |
- if (GetTickDuration(info.time) < |
- base::TimeDelta::FromMinutes(kRequestTimeoutMinutes)) |
+ RequestInfo info = requests_.top(); |
+ if (!RequestExpired(info.expiration)) |
break; |
if (MaybeTimeOutRequest(info)) { |
- request_timed_out = true; |
+ stop_for_timeout = stop_for_timeout || ShouldStopIfRequestTimesOut(info); |
UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RequestTimeouts.Count", |
info.type, NUM_REQUEST_TYPES); |
} |
requests_.pop(); |
} |
- if (request_timed_out && running_status() != STOPPING) |
+ if (stop_for_timeout && running_status() != STOPPING) |
embedded_worker_->Stop(); |
// For the timeouts below, there are no callbacks to timeout so there is |
@@ -2240,10 +2258,22 @@ int ServiceWorkerVersion::AddRequest( |
const CallbackType& callback, |
IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, |
RequestType request_type) { |
- base::TimeTicks now = base::TimeTicks::Now(); |
- int request_id = |
- callback_map->Add(new PendingRequest<CallbackType>(callback, now)); |
- requests_.push(RequestInfo(request_id, request_type, now)); |
+ base::TimeTicks expiration_time = |
+ base::TimeTicks::Now() + |
+ base::TimeDelta::FromMinutes(kRequestTimeoutMinutes); |
+ return AddRequestWithExpiration(callback, callback_map, request_type, |
+ expiration_time); |
+} |
+ |
+template <typename CallbackType> |
+int ServiceWorkerVersion::AddRequestWithExpiration( |
+ const CallbackType& callback, |
+ IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, |
+ RequestType request_type, |
+ base::TimeTicks expiration) { |
+ int request_id = callback_map->Add( |
+ new PendingRequest<CallbackType>(callback, base::TimeTicks::Now())); |
+ requests_.push(RequestInfo(request_id, request_type, expiration)); |
return request_id; |
} |
@@ -2284,11 +2314,35 @@ bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo& info) { |
return false; |
} |
-void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) { |
- std::queue<RequestInfo> new_requests; |
+bool ServiceWorkerVersion::ShouldStopIfRequestTimesOut( |
+ const RequestInfo& info) { |
+ // Note, returning false for a type means that the On*EventFinished should not |
+ // call NOTREACHED if it can't find the matching request, it may have simply |
+ // timed out. |
+ switch (info.type) { |
+ case REQUEST_SYNC: |
+ return false; |
+ case REQUEST_ACTIVATE: |
+ case REQUEST_INSTALL: |
+ case REQUEST_FETCH: |
+ case REQUEST_NOTIFICATION_CLICK: |
+ case REQUEST_PUSH: |
+ case REQUEST_GEOFENCING: |
+ case REQUEST_SERVICE_PORT_CONNECT: |
+ return true; |
+ case NUM_REQUEST_TYPES: |
+ NOTREACHED() << "Got unexpected request type: " << info.type; |
+ } |
+ NOTREACHED() << "Got unexpected request type: " << info.type; |
+ return false; |
+} |
+ |
+void ServiceWorkerVersion::SetAllRequestExpirations( |
+ const base::TimeTicks& expiration) { |
+ RequestInfoPriorityQueue new_requests; |
while (!requests_.empty()) { |
- RequestInfo info = requests_.front(); |
- info.time = ticks; |
+ RequestInfo info = requests_.top(); |
+ info.expiration = expiration; |
new_requests.push(info); |
requests_.pop(); |
} |