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 <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 } | 322 } |
323 | 323 |
324 void ClearTick(base::TimeTicks* time) { | 324 void ClearTick(base::TimeTicks* time) { |
325 *time = base::TimeTicks(); | 325 *time = base::TimeTicks(); |
326 } | 326 } |
327 | 327 |
328 void RestartTick(base::TimeTicks* time) { | 328 void RestartTick(base::TimeTicks* time) { |
329 *time = base::TimeTicks().Now(); | 329 *time = base::TimeTicks().Now(); |
330 } | 330 } |
331 | 331 |
| 332 bool RequestExpired(const base::TimeTicks& expiration) { |
| 333 if (expiration.is_null()) |
| 334 return false; |
| 335 return base::TimeTicks().Now() >= expiration; |
| 336 } |
| 337 |
332 base::TimeDelta GetTickDuration(const base::TimeTicks& time) { | 338 base::TimeDelta GetTickDuration(const base::TimeTicks& time) { |
333 if (time.is_null()) | 339 if (time.is_null()) |
334 return base::TimeDelta(); | 340 return base::TimeDelta(); |
335 return base::TimeTicks().Now() - time; | 341 return base::TimeTicks().Now() - time; |
336 } | 342 } |
337 | 343 |
338 void OnGetWindowClientsFromUI( | 344 void OnGetWindowClientsFromUI( |
339 // The tuple contains process_id, frame_id, client_uuid. | 345 // The tuple contains process_id, frame_id, client_uuid. |
340 const std::vector<base::Tuple<int, int, std::string>>& clients_info, | 346 const std::vector<base::Tuple<int, int, std::string>>& clients_info, |
341 const GURL& script_url, | 347 const GURL& script_url, |
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 fetch_requests_.Remove(request_id); | 802 fetch_requests_.Remove(request_id); |
797 RunSoon(base::Bind(&RunErrorFetchCallback, | 803 RunSoon(base::Bind(&RunErrorFetchCallback, |
798 fetch_callback, | 804 fetch_callback, |
799 SERVICE_WORKER_ERROR_FAILED)); | 805 SERVICE_WORKER_ERROR_FAILED)); |
800 } | 806 } |
801 } | 807 } |
802 | 808 |
803 void ServiceWorkerVersion::DispatchSyncEvent( | 809 void ServiceWorkerVersion::DispatchSyncEvent( |
804 BackgroundSyncRegistrationHandle::HandleId handle_id, | 810 BackgroundSyncRegistrationHandle::HandleId handle_id, |
805 BackgroundSyncEventLastChance last_chance, | 811 BackgroundSyncEventLastChance last_chance, |
| 812 base::TimeDelta max_duration, |
806 const StatusCallback& callback) { | 813 const StatusCallback& callback) { |
807 OnBeginEvent(); | 814 OnBeginEvent(); |
808 DCHECK_EQ(ACTIVATED, status()) << status(); | 815 DCHECK_EQ(ACTIVATED, status()) << status(); |
809 if (running_status() != RUNNING) { | 816 if (running_status() != RUNNING) { |
810 // Schedule calling this method after starting the worker. | 817 // Schedule calling this method after starting the worker. |
811 StartWorker(base::Bind( | 818 StartWorker(base::Bind( |
812 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(), callback, | 819 &RunTaskAfterStartWorker, weak_factory_.GetWeakPtr(), callback, |
813 base::Bind(&self::DispatchSyncEvent, weak_factory_.GetWeakPtr(), | 820 base::Bind(&self::DispatchSyncEvent, weak_factory_.GetWeakPtr(), |
814 handle_id, last_chance, callback))); | 821 handle_id, last_chance, max_duration, callback))); |
815 return; | 822 return; |
816 } | 823 } |
817 | 824 |
818 int request_id = AddRequest(callback, &sync_requests_, REQUEST_SYNC); | 825 int request_id = |
| 826 AddRequestWithExpiration(callback, &sync_requests_, REQUEST_SYNC, |
| 827 base::TimeTicks::Now() + max_duration); |
819 if (!background_sync_dispatcher_) { | 828 if (!background_sync_dispatcher_) { |
820 embedded_worker_->GetServiceRegistry()->ConnectToRemoteService( | 829 embedded_worker_->GetServiceRegistry()->ConnectToRemoteService( |
821 mojo::GetProxy(&background_sync_dispatcher_)); | 830 mojo::GetProxy(&background_sync_dispatcher_)); |
822 background_sync_dispatcher_.set_connection_error_handler(base::Bind( | 831 background_sync_dispatcher_.set_connection_error_handler(base::Bind( |
823 &ServiceWorkerVersion::OnBackgroundSyncDispatcherConnectionError, | 832 &ServiceWorkerVersion::OnBackgroundSyncDispatcherConnectionError, |
824 weak_factory_.GetWeakPtr())); | 833 weak_factory_.GetWeakPtr())); |
825 } | 834 } |
826 | 835 |
827 background_sync_dispatcher_->Sync( | 836 background_sync_dispatcher_->Sync( |
828 handle_id, last_chance, | 837 handle_id, last_chance, |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1072 if (attached) { | 1081 if (attached) { |
1073 // TODO(falken): Canceling the timeouts when debugging could cause | 1082 // TODO(falken): Canceling the timeouts when debugging could cause |
1074 // heisenbugs; we should instead run them as normal show an educational | 1083 // heisenbugs; we should instead run them as normal show an educational |
1075 // message in DevTools when they occur. crbug.com/470419 | 1084 // message in DevTools when they occur. crbug.com/470419 |
1076 | 1085 |
1077 // Don't record the startup time metric once DevTools is attached. | 1086 // Don't record the startup time metric once DevTools is attached. |
1078 ClearTick(&start_time_); | 1087 ClearTick(&start_time_); |
1079 skip_recording_startup_time_ = true; | 1088 skip_recording_startup_time_ = true; |
1080 | 1089 |
1081 // Cancel request timeouts. | 1090 // Cancel request timeouts. |
1082 SetAllRequestTimes(base::TimeTicks()); | 1091 SetAllRequestExpirations(base::TimeTicks()); |
1083 return; | 1092 return; |
1084 } | 1093 } |
1085 if (!start_callbacks_.empty()) { | 1094 if (!start_callbacks_.empty()) { |
1086 // Reactivate the timer for start timeout. | 1095 // Reactivate the timer for start timeout. |
1087 DCHECK(timeout_timer_.IsRunning()); | 1096 DCHECK(timeout_timer_.IsRunning()); |
1088 DCHECK(running_status() == STARTING || running_status() == STOPPING) | 1097 DCHECK(running_status() == STARTING || running_status() == STOPPING) |
1089 << running_status(); | 1098 << running_status(); |
1090 RestartTick(&start_time_); | 1099 RestartTick(&start_time_); |
1091 } | 1100 } |
1092 | 1101 |
1093 // Reactivate request timeouts. | 1102 // Reactivate request timeouts, setting them all to the same expiration time. |
1094 SetAllRequestTimes(base::TimeTicks::Now()); | 1103 SetAllRequestExpirations( |
| 1104 base::TimeTicks::Now() + |
| 1105 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes)); |
1095 } | 1106 } |
1096 | 1107 |
1097 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( | 1108 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
1098 const net::HttpResponseInfo& http_info) { | 1109 const net::HttpResponseInfo& http_info) { |
1099 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); | 1110 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); |
1100 FOR_EACH_OBSERVER(Listener, listeners_, | 1111 FOR_EACH_OBSERVER(Listener, listeners_, |
1101 OnMainScriptHttpResponseInfoSet(this)); | 1112 OnMainScriptHttpResponseInfoSet(this)); |
1102 } | 1113 } |
1103 | 1114 |
1104 void ServiceWorkerVersion::SimulatePingTimeoutForTesting() { | 1115 void ServiceWorkerVersion::SimulatePingTimeoutForTesting() { |
1105 ping_controller_->SimulateTimeoutForTesting(); | 1116 ping_controller_->SimulateTimeoutForTesting(); |
1106 } | 1117 } |
1107 | 1118 |
1108 const net::HttpResponseInfo* | 1119 const net::HttpResponseInfo* |
1109 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { | 1120 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
1110 return main_script_http_info_.get(); | 1121 return main_script_http_info_.get(); |
1111 } | 1122 } |
1112 | 1123 |
1113 ServiceWorkerVersion::RequestInfo::RequestInfo(int id, | 1124 ServiceWorkerVersion::RequestInfo::RequestInfo( |
1114 RequestType type, | 1125 int id, |
1115 const base::TimeTicks& now) | 1126 RequestType type, |
1116 : id(id), type(type), time(now) { | 1127 const base::TimeTicks& expiration) |
| 1128 : id(id), type(type), expiration(expiration) {} |
| 1129 |
| 1130 ServiceWorkerVersion::RequestInfo::~RequestInfo() { |
1117 } | 1131 } |
1118 | 1132 |
1119 ServiceWorkerVersion::RequestInfo::~RequestInfo() { | 1133 bool ServiceWorkerVersion::RequestInfo::operator>( |
| 1134 const RequestInfo& other) const { |
| 1135 return expiration > other.expiration; |
1120 } | 1136 } |
1121 | 1137 |
1122 template <typename CallbackType> | 1138 template <typename CallbackType> |
1123 ServiceWorkerVersion::PendingRequest<CallbackType>::PendingRequest( | 1139 ServiceWorkerVersion::PendingRequest<CallbackType>::PendingRequest( |
1124 const CallbackType& callback, | 1140 const CallbackType& callback, |
1125 const base::TimeTicks& time) | 1141 const base::TimeTicks& time) |
1126 : callback(callback), start_time(time) { | 1142 : callback(callback), start_time(time) { |
1127 } | 1143 } |
1128 | 1144 |
1129 template <typename CallbackType> | 1145 template <typename CallbackType> |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1426 } | 1442 } |
1427 | 1443 |
1428 void ServiceWorkerVersion::OnSyncEventFinished( | 1444 void ServiceWorkerVersion::OnSyncEventFinished( |
1429 int request_id, | 1445 int request_id, |
1430 ServiceWorkerEventStatus status) { | 1446 ServiceWorkerEventStatus status) { |
1431 TRACE_EVENT1("ServiceWorker", | 1447 TRACE_EVENT1("ServiceWorker", |
1432 "ServiceWorkerVersion::OnSyncEventFinished", | 1448 "ServiceWorkerVersion::OnSyncEventFinished", |
1433 "Request id", request_id); | 1449 "Request id", request_id); |
1434 PendingRequest<StatusCallback>* request = sync_requests_.Lookup(request_id); | 1450 PendingRequest<StatusCallback>* request = sync_requests_.Lookup(request_id); |
1435 if (!request) { | 1451 if (!request) { |
1436 NOTREACHED() << "Got unexpected message: " << request_id; | 1452 // Assume the request timed out. |
1437 return; | 1453 return; |
1438 } | 1454 } |
1439 | 1455 |
| 1456 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.BackgroundSyncEvent.Time", |
| 1457 base::TimeTicks::Now() - request->start_time); |
| 1458 |
1440 scoped_refptr<ServiceWorkerVersion> protect(this); | 1459 scoped_refptr<ServiceWorkerVersion> protect(this); |
1441 request->callback.Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status)); | 1460 request->callback.Run(mojo::ConvertTo<ServiceWorkerStatusCode>(status)); |
1442 RemoveCallbackAndStopIfRedundant(&sync_requests_, request_id); | 1461 RemoveCallbackAndStopIfRedundant(&sync_requests_, request_id); |
1443 } | 1462 } |
1444 | 1463 |
1445 void ServiceWorkerVersion::OnNotificationClickEventFinished( | 1464 void ServiceWorkerVersion::OnNotificationClickEventFinished( |
1446 int request_id) { | 1465 int request_id) { |
1447 TRACE_EVENT1("ServiceWorker", | 1466 TRACE_EVENT1("ServiceWorker", |
1448 "ServiceWorkerVersion::OnNotificationClickEventFinished", | 1467 "ServiceWorkerVersion::OnNotificationClickEventFinished", |
1449 "Request id", request_id); | 1468 "Request id", request_id); |
(...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2112 if (GetTickDuration(start_time_) > start_limit) { | 2131 if (GetTickDuration(start_time_) > start_limit) { |
2113 DCHECK(running_status() == STARTING || running_status() == STOPPING) | 2132 DCHECK(running_status() == STARTING || running_status() == STOPPING) |
2114 << running_status(); | 2133 << running_status(); |
2115 scoped_refptr<ServiceWorkerVersion> protect(this); | 2134 scoped_refptr<ServiceWorkerVersion> protect(this); |
2116 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT); | 2135 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT); |
2117 if (running_status() == STARTING) | 2136 if (running_status() == STARTING) |
2118 embedded_worker_->Stop(); | 2137 embedded_worker_->Stop(); |
2119 return; | 2138 return; |
2120 } | 2139 } |
2121 | 2140 |
2122 // Requests have not finished within a certain period. | 2141 // Requests have not finished before their expiration. |
2123 bool request_timed_out = false; | 2142 bool stop_for_timeout = false; |
2124 while (!requests_.empty()) { | 2143 while (!requests_.empty()) { |
2125 RequestInfo info = requests_.front(); | 2144 RequestInfo info = requests_.top(); |
2126 if (GetTickDuration(info.time) < | 2145 if (!RequestExpired(info.expiration)) |
2127 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes)) | |
2128 break; | 2146 break; |
2129 if (MaybeTimeOutRequest(info)) { | 2147 if (MaybeTimeOutRequest(info)) { |
2130 request_timed_out = true; | 2148 stop_for_timeout = stop_for_timeout || ShouldStopIfRequestTimesOut(info); |
2131 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RequestTimeouts.Count", | 2149 UMA_HISTOGRAM_ENUMERATION("ServiceWorker.RequestTimeouts.Count", |
2132 info.type, NUM_REQUEST_TYPES); | 2150 info.type, NUM_REQUEST_TYPES); |
2133 } | 2151 } |
2134 requests_.pop(); | 2152 requests_.pop(); |
2135 } | 2153 } |
2136 if (request_timed_out && running_status() != STOPPING) | 2154 if (stop_for_timeout && running_status() != STOPPING) |
2137 embedded_worker_->Stop(); | 2155 embedded_worker_->Stop(); |
2138 | 2156 |
2139 // For the timeouts below, there are no callbacks to timeout so there is | 2157 // For the timeouts below, there are no callbacks to timeout so there is |
2140 // nothing more to do if the worker is already stopping. | 2158 // nothing more to do if the worker is already stopping. |
2141 if (running_status() == STOPPING) | 2159 if (running_status() == STOPPING) |
2142 return; | 2160 return; |
2143 | 2161 |
2144 // The worker has been idle for longer than a certain period. | 2162 // The worker has been idle for longer than a certain period. |
2145 if (GetTickDuration(idle_time_) > | 2163 if (GetTickDuration(idle_time_) > |
2146 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) { | 2164 base::TimeDelta::FromSeconds(kIdleWorkerTimeoutSeconds)) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2233 // order to release worker resources soon. | 2251 // order to release worker resources soon. |
2234 StopWorkerIfIdle(); | 2252 StopWorkerIfIdle(); |
2235 } | 2253 } |
2236 } | 2254 } |
2237 | 2255 |
2238 template <typename CallbackType> | 2256 template <typename CallbackType> |
2239 int ServiceWorkerVersion::AddRequest( | 2257 int ServiceWorkerVersion::AddRequest( |
2240 const CallbackType& callback, | 2258 const CallbackType& callback, |
2241 IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, | 2259 IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, |
2242 RequestType request_type) { | 2260 RequestType request_type) { |
2243 base::TimeTicks now = base::TimeTicks::Now(); | 2261 base::TimeTicks expiration_time = |
2244 int request_id = | 2262 base::TimeTicks::Now() + |
2245 callback_map->Add(new PendingRequest<CallbackType>(callback, now)); | 2263 base::TimeDelta::FromMinutes(kRequestTimeoutMinutes); |
2246 requests_.push(RequestInfo(request_id, request_type, now)); | 2264 return AddRequestWithExpiration(callback, callback_map, request_type, |
| 2265 expiration_time); |
| 2266 } |
| 2267 |
| 2268 template <typename CallbackType> |
| 2269 int ServiceWorkerVersion::AddRequestWithExpiration( |
| 2270 const CallbackType& callback, |
| 2271 IDMap<PendingRequest<CallbackType>, IDMapOwnPointer>* callback_map, |
| 2272 RequestType request_type, |
| 2273 base::TimeTicks expiration) { |
| 2274 int request_id = callback_map->Add( |
| 2275 new PendingRequest<CallbackType>(callback, base::TimeTicks::Now())); |
| 2276 requests_.push(RequestInfo(request_id, request_type, expiration)); |
2247 return request_id; | 2277 return request_id; |
2248 } | 2278 } |
2249 | 2279 |
2250 bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo& info) { | 2280 bool ServiceWorkerVersion::MaybeTimeOutRequest(const RequestInfo& info) { |
2251 switch (info.type) { | 2281 switch (info.type) { |
2252 case REQUEST_ACTIVATE: | 2282 case REQUEST_ACTIVATE: |
2253 return RunIDMapCallback(&activate_requests_, info.id, | 2283 return RunIDMapCallback(&activate_requests_, info.id, |
2254 SERVICE_WORKER_ERROR_TIMEOUT); | 2284 SERVICE_WORKER_ERROR_TIMEOUT); |
2255 case REQUEST_INSTALL: | 2285 case REQUEST_INSTALL: |
2256 return RunIDMapCallback(&install_requests_, info.id, | 2286 return RunIDMapCallback(&install_requests_, info.id, |
(...skipping 20 matching lines...) Expand all Loading... |
2277 SERVICE_WORKER_ERROR_TIMEOUT, | 2307 SERVICE_WORKER_ERROR_TIMEOUT, |
2278 false /* accept_connection */, base::string16(), | 2308 false /* accept_connection */, base::string16(), |
2279 base::string16()); | 2309 base::string16()); |
2280 case NUM_REQUEST_TYPES: | 2310 case NUM_REQUEST_TYPES: |
2281 break; | 2311 break; |
2282 } | 2312 } |
2283 NOTREACHED() << "Got unexpected request type: " << info.type; | 2313 NOTREACHED() << "Got unexpected request type: " << info.type; |
2284 return false; | 2314 return false; |
2285 } | 2315 } |
2286 | 2316 |
2287 void ServiceWorkerVersion::SetAllRequestTimes(const base::TimeTicks& ticks) { | 2317 bool ServiceWorkerVersion::ShouldStopIfRequestTimesOut( |
2288 std::queue<RequestInfo> new_requests; | 2318 const RequestInfo& info) { |
| 2319 // Note, returning false for a type means that the On*EventFinished should not |
| 2320 // call NOTREACHED if it can't find the matching request, it may have simply |
| 2321 // timed out. |
| 2322 switch (info.type) { |
| 2323 case REQUEST_SYNC: |
| 2324 return false; |
| 2325 case REQUEST_ACTIVATE: |
| 2326 case REQUEST_INSTALL: |
| 2327 case REQUEST_FETCH: |
| 2328 case REQUEST_NOTIFICATION_CLICK: |
| 2329 case REQUEST_PUSH: |
| 2330 case REQUEST_GEOFENCING: |
| 2331 case REQUEST_SERVICE_PORT_CONNECT: |
| 2332 return true; |
| 2333 case NUM_REQUEST_TYPES: |
| 2334 NOTREACHED() << "Got unexpected request type: " << info.type; |
| 2335 } |
| 2336 NOTREACHED() << "Got unexpected request type: " << info.type; |
| 2337 return false; |
| 2338 } |
| 2339 |
| 2340 void ServiceWorkerVersion::SetAllRequestExpirations( |
| 2341 const base::TimeTicks& expiration) { |
| 2342 RequestInfoPriorityQueue new_requests; |
2289 while (!requests_.empty()) { | 2343 while (!requests_.empty()) { |
2290 RequestInfo info = requests_.front(); | 2344 RequestInfo info = requests_.top(); |
2291 info.time = ticks; | 2345 info.expiration = expiration; |
2292 new_requests.push(info); | 2346 new_requests.push(info); |
2293 requests_.pop(); | 2347 requests_.pop(); |
2294 } | 2348 } |
2295 requests_ = new_requests; | 2349 requests_ = new_requests; |
2296 } | 2350 } |
2297 | 2351 |
2298 ServiceWorkerStatusCode ServiceWorkerVersion::DeduceStartWorkerFailureReason( | 2352 ServiceWorkerStatusCode ServiceWorkerVersion::DeduceStartWorkerFailureReason( |
2299 ServiceWorkerStatusCode default_code) { | 2353 ServiceWorkerStatusCode default_code) { |
2300 if (ping_controller_->IsTimedOut()) | 2354 if (ping_controller_->IsTimedOut()) |
2301 return SERVICE_WORKER_ERROR_TIMEOUT; | 2355 return SERVICE_WORKER_ERROR_TIMEOUT; |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2426 void ServiceWorkerVersion::OnBeginEvent() { | 2480 void ServiceWorkerVersion::OnBeginEvent() { |
2427 if (should_exclude_from_uma_ || running_status() != RUNNING || | 2481 if (should_exclude_from_uma_ || running_status() != RUNNING || |
2428 idle_time_.is_null()) { | 2482 idle_time_.is_null()) { |
2429 return; | 2483 return; |
2430 } | 2484 } |
2431 ServiceWorkerMetrics::RecordTimeBetweenEvents(base::TimeTicks::Now() - | 2485 ServiceWorkerMetrics::RecordTimeBetweenEvents(base::TimeTicks::Now() - |
2432 idle_time_); | 2486 idle_time_); |
2433 } | 2487 } |
2434 | 2488 |
2435 } // namespace content | 2489 } // namespace content |
OLD | NEW |