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/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 // (Note that if all references to the version is dropped the worker | 78 // (Note that if all references to the version is dropped the worker |
79 // is also stopped without delay) | 79 // is also stopped without delay) |
80 const int64 kStopWorkerDelay = 30; // 30 secs. | 80 const int64 kStopWorkerDelay = 30; // 30 secs. |
81 | 81 |
82 // Delay for attempting to stop a doomed worker with in-flight requests. | 82 // Delay for attempting to stop a doomed worker with in-flight requests. |
83 const int64 kStopDoomedWorkerDelay = 5; // 5 secs. | 83 const int64 kStopDoomedWorkerDelay = 5; // 5 secs. |
84 | 84 |
85 // Default delay for scheduled update. | 85 // Default delay for scheduled update. |
86 const int kUpdateDelaySeconds = 1; | 86 const int kUpdateDelaySeconds = 1; |
87 | 87 |
| 88 // Delay between sending pings to the worker. |
| 89 const int kPingIntervalTime = 10; // 10 secs. |
| 90 |
| 91 // Timeout for waiting for a response to a ping. |
| 92 const int kPingTimeoutTime = 30; // 30 secs. |
| 93 |
88 const char kClaimClientsStateErrorMesage[] = | 94 const char kClaimClientsStateErrorMesage[] = |
89 "Only the active worker can claim clients."; | 95 "Only the active worker can claim clients."; |
90 | 96 |
91 const char kClaimClientsShutdownErrorMesage[] = | 97 const char kClaimClientsShutdownErrorMesage[] = |
92 "Failed to claim clients due to Service Worker system shutdown."; | 98 "Failed to claim clients due to Service Worker system shutdown."; |
93 | 99 |
94 void RunSoon(const base::Closure& callback) { | 100 void RunSoon(const base::Closure& callback) { |
95 if (!callback.is_null()) | 101 if (!callback.is_null()) |
96 base::MessageLoop::current()->PostTask(FROM_HERE, callback); | 102 base::MessageLoop::current()->PostTask(FROM_HERE, callback); |
97 } | 103 } |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 ServiceWorkerRegistration* registration, | 296 ServiceWorkerRegistration* registration, |
291 const GURL& script_url, | 297 const GURL& script_url, |
292 int64 version_id, | 298 int64 version_id, |
293 base::WeakPtr<ServiceWorkerContextCore> context) | 299 base::WeakPtr<ServiceWorkerContextCore> context) |
294 : version_id_(version_id), | 300 : version_id_(version_id), |
295 registration_id_(kInvalidServiceWorkerVersionId), | 301 registration_id_(kInvalidServiceWorkerVersionId), |
296 script_url_(script_url), | 302 script_url_(script_url), |
297 status_(NEW), | 303 status_(NEW), |
298 context_(context), | 304 context_(context), |
299 script_cache_map_(this, context), | 305 script_cache_map_(this, context), |
| 306 ping_timed_out_(false), |
300 is_doomed_(false), | 307 is_doomed_(false), |
301 skip_waiting_(false), | 308 skip_waiting_(false), |
302 weak_factory_(this) { | 309 weak_factory_(this) { |
303 DCHECK(context_); | 310 DCHECK(context_); |
304 DCHECK(registration); | 311 DCHECK(registration); |
305 if (registration) { | 312 if (registration) { |
306 registration_id_ = registration->id(); | 313 registration_id_ = registration->id(); |
307 scope_ = registration->pattern(); | 314 scope_ = registration->pattern(); |
308 } | 315 } |
309 context_->AddLiveVersion(this); | 316 context_->AddLiveVersion(this); |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
784 void ServiceWorkerVersion::Doom() { | 791 void ServiceWorkerVersion::Doom() { |
785 if (is_doomed_) | 792 if (is_doomed_) |
786 return; | 793 return; |
787 is_doomed_ = true; | 794 is_doomed_ = true; |
788 if (!HasControllee()) | 795 if (!HasControllee()) |
789 DoomInternal(); | 796 DoomInternal(); |
790 } | 797 } |
791 | 798 |
792 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { | 799 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { |
793 embedded_worker()->set_devtools_attached(attached); | 800 embedded_worker()->set_devtools_attached(attached); |
794 if (!attached && !stop_worker_timer_.IsRunning()) { | 801 if (attached) |
795 // If devtools is detached from this version and stop-worker-timer is not | 802 return; |
796 // running, try scheduling stop-worker-timer now. | 803 // If devtools is detached try scheduling the timers for stopping the worker |
| 804 // now. |
| 805 if (!stop_worker_timer_.IsRunning()) |
797 ScheduleStopWorker(); | 806 ScheduleStopWorker(); |
798 } | 807 if (!ping_worker_timer_.IsRunning()) |
| 808 StartPingWorker(); |
799 } | 809 } |
800 | 810 |
801 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( | 811 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( |
802 const net::HttpResponseInfo& http_info) { | 812 const net::HttpResponseInfo& http_info) { |
803 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); | 813 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); |
804 } | 814 } |
805 | 815 |
806 const net::HttpResponseInfo* | 816 const net::HttpResponseInfo* |
807 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { | 817 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { |
808 return main_script_http_info_.get(); | 818 return main_script_http_info_.get(); |
809 } | 819 } |
810 | 820 |
| 821 void ServiceWorkerVersion::OnScriptLoaded() { |
| 822 DCHECK_EQ(STARTING, running_status()); |
| 823 StartPingWorker(); |
| 824 } |
| 825 |
811 void ServiceWorkerVersion::OnStarted() { | 826 void ServiceWorkerVersion::OnStarted() { |
812 DCHECK_EQ(RUNNING, running_status()); | 827 DCHECK_EQ(RUNNING, running_status()); |
813 DCHECK(cache_listener_.get()); | 828 DCHECK(cache_listener_.get()); |
814 ScheduleStopWorker(); | 829 ScheduleStopWorker(); |
815 | 830 |
816 // Fire all start callbacks. | 831 // Fire all start callbacks. |
817 scoped_refptr<ServiceWorkerVersion> protect(this); | 832 scoped_refptr<ServiceWorkerVersion> protect(this); |
818 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); | 833 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK); |
819 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); | 834 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStarted(this)); |
820 } | 835 } |
821 | 836 |
822 void ServiceWorkerVersion::OnStopped( | 837 void ServiceWorkerVersion::OnStopped( |
823 EmbeddedWorkerInstance::Status old_status) { | 838 EmbeddedWorkerInstance::Status old_status) { |
824 DCHECK_EQ(STOPPED, running_status()); | 839 DCHECK_EQ(STOPPED, running_status()); |
825 scoped_refptr<ServiceWorkerVersion> protect(this); | 840 scoped_refptr<ServiceWorkerVersion> protect(this); |
826 | 841 |
827 bool should_restart = !is_doomed() && !start_callbacks_.empty() && | 842 bool should_restart = !is_doomed() && !start_callbacks_.empty() && |
828 (old_status != EmbeddedWorkerInstance::STARTING); | 843 (old_status != EmbeddedWorkerInstance::STARTING); |
829 | 844 |
| 845 ping_worker_timer_.Stop(); |
| 846 if (ping_timed_out_) |
| 847 should_restart = false; |
| 848 |
830 // Fire all stop callbacks. | 849 // Fire all stop callbacks. |
831 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); | 850 RunCallbacks(this, &stop_callbacks_, SERVICE_WORKER_OK); |
832 | 851 |
833 if (!should_restart) { | 852 if (!should_restart) { |
834 // Let all start callbacks fail. | 853 // Let all start callbacks fail. |
835 RunCallbacks(this, &start_callbacks_, | 854 RunCallbacks(this, &start_callbacks_, |
836 SERVICE_WORKER_ERROR_START_WORKER_FAILED); | 855 SERVICE_WORKER_ERROR_START_WORKER_FAILED); |
837 } | 856 } |
838 | 857 |
839 // Let all message callbacks fail (this will also fire and clear all | 858 // Let all message callbacks fail (this will also fire and clear all |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata, | 952 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClearCachedMetadata, |
934 OnClearCachedMetadata) | 953 OnClearCachedMetadata) |
935 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument, | 954 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument, |
936 OnPostMessageToDocument) | 955 OnPostMessageToDocument) |
937 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, | 956 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_FocusClient, |
938 OnFocusClient) | 957 OnFocusClient) |
939 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, | 958 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, |
940 OnSkipWaiting) | 959 OnSkipWaiting) |
941 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, | 960 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, |
942 OnClaimClients) | 961 OnClaimClients) |
| 962 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker) |
943 IPC_MESSAGE_UNHANDLED(handled = false) | 963 IPC_MESSAGE_UNHANDLED(handled = false) |
944 IPC_END_MESSAGE_MAP() | 964 IPC_END_MESSAGE_MAP() |
945 return handled; | 965 return handled; |
946 } | 966 } |
947 | 967 |
948 void ServiceWorkerVersion::OnStartMessageSent( | 968 void ServiceWorkerVersion::OnStartMessageSent( |
949 ServiceWorkerStatusCode status) { | 969 ServiceWorkerStatusCode status) { |
950 if (status != SERVICE_WORKER_OK) | 970 if (status != SERVICE_WORKER_OK) |
951 RunCallbacks(this, &start_callbacks_, status); | 971 RunCallbacks(this, &start_callbacks_, status); |
952 } | 972 } |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1342 | 1362 |
1343 ServiceWorkerRegistration* registration = | 1363 ServiceWorkerRegistration* registration = |
1344 context_->GetLiveRegistration(registration_id_); | 1364 context_->GetLiveRegistration(registration_id_); |
1345 if (!registration) { | 1365 if (!registration) { |
1346 callback.Run(SERVICE_WORKER_ERROR_ABORT); | 1366 callback.Run(SERVICE_WORKER_ERROR_ABORT); |
1347 return; | 1367 return; |
1348 } | 1368 } |
1349 registration->ClaimClients(callback); | 1369 registration->ClaimClients(callback); |
1350 } | 1370 } |
1351 | 1371 |
| 1372 void ServiceWorkerVersion::OnPongFromWorker() { |
| 1373 if (ping_timed_out_) |
| 1374 return; |
| 1375 SchedulePingWorker(); |
| 1376 } |
| 1377 |
1352 void ServiceWorkerVersion::DidClaimClients( | 1378 void ServiceWorkerVersion::DidClaimClients( |
1353 int request_id, ServiceWorkerStatusCode status) { | 1379 int request_id, ServiceWorkerStatusCode status) { |
1354 if (status == SERVICE_WORKER_ERROR_STATE) { | 1380 if (status == SERVICE_WORKER_ERROR_STATE) { |
1355 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( | 1381 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( |
1356 request_id, blink::WebServiceWorkerError::ErrorTypeState, | 1382 request_id, blink::WebServiceWorkerError::ErrorTypeState, |
1357 base::ASCIIToUTF16(kClaimClientsStateErrorMesage))); | 1383 base::ASCIIToUTF16(kClaimClientsStateErrorMesage))); |
1358 return; | 1384 return; |
1359 } | 1385 } |
1360 if (status == SERVICE_WORKER_ERROR_ABORT) { | 1386 if (status == SERVICE_WORKER_ERROR_ABORT) { |
1361 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( | 1387 embedded_worker_->SendMessage(ServiceWorkerMsg_ClaimClientsError( |
(...skipping 18 matching lines...) Expand all Loading... |
1380 | 1406 |
1381 // We can get info for a frame that was navigating end ended up with a | 1407 // We can get info for a frame that was navigating end ended up with a |
1382 // different URL than expected. In such case, we should make sure to not | 1408 // different URL than expected. In such case, we should make sure to not |
1383 // expose cross-origin WindowClient. | 1409 // expose cross-origin WindowClient. |
1384 if (info.url.GetOrigin() != script_url_.GetOrigin()) | 1410 if (info.url.GetOrigin() != script_url_.GetOrigin()) |
1385 return; | 1411 return; |
1386 | 1412 |
1387 callback->AddClientInfo(client_id, info); | 1413 callback->AddClientInfo(client_id, info); |
1388 } | 1414 } |
1389 | 1415 |
| 1416 void ServiceWorkerVersion::PingWorker() { |
| 1417 if (running_status() != STARTING && running_status() != RUNNING) |
| 1418 return; |
| 1419 ServiceWorkerStatusCode status = |
| 1420 embedded_worker_->SendMessage(ServiceWorkerMsg_Ping()); |
| 1421 if (status != SERVICE_WORKER_OK) { |
| 1422 // TODO(falken): Maybe try resending Ping a few times first? |
| 1423 ping_timed_out_ = true; |
| 1424 StopWorkerIfIdle(); |
| 1425 return; |
| 1426 } |
| 1427 ping_worker_timer_.Start(FROM_HERE, |
| 1428 base::TimeDelta::FromSeconds(kPingTimeoutTime), |
| 1429 base::Bind(&ServiceWorkerVersion::OnPingTimeout, |
| 1430 weak_factory_.GetWeakPtr())); |
| 1431 } |
| 1432 |
| 1433 void ServiceWorkerVersion::StartPingWorker() { |
| 1434 ping_timed_out_ = false; |
| 1435 SchedulePingWorker(); |
| 1436 } |
| 1437 |
| 1438 void ServiceWorkerVersion::SchedulePingWorker() { |
| 1439 DCHECK(!ping_timed_out_); |
| 1440 ping_worker_timer_.Stop(); |
| 1441 ping_worker_timer_.Start(FROM_HERE, |
| 1442 base::TimeDelta::FromSeconds(kPingIntervalTime), |
| 1443 base::Bind(&ServiceWorkerVersion::PingWorker, |
| 1444 weak_factory_.GetWeakPtr())); |
| 1445 } |
| 1446 |
| 1447 void ServiceWorkerVersion::OnPingTimeout() { |
| 1448 if (running_status() != STARTING && running_status() != RUNNING) |
| 1449 return; |
| 1450 ping_timed_out_ = true; |
| 1451 // TODO(falken): Show a message to the developer that the SW was stopped due |
| 1452 // to timeout (crbug.com/457968). |
| 1453 StopWorkerIfIdle(); |
| 1454 } |
| 1455 |
1390 void ServiceWorkerVersion::ScheduleStopWorker() { | 1456 void ServiceWorkerVersion::ScheduleStopWorker() { |
1391 if (running_status() != RUNNING) | 1457 if (running_status() != RUNNING) |
1392 return; | 1458 return; |
1393 stop_worker_timer_.Stop(); | 1459 stop_worker_timer_.Stop(); |
1394 stop_worker_timer_.Start( | 1460 stop_worker_timer_.Start( |
1395 FROM_HERE, base::TimeDelta::FromSeconds( | 1461 FROM_HERE, base::TimeDelta::FromSeconds( |
1396 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), | 1462 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), |
1397 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle, | 1463 base::Bind(&ServiceWorkerVersion::StopWorkerIfIdle, |
1398 weak_factory_.GetWeakPtr())); | 1464 weak_factory_.GetWeakPtr())); |
1399 } | 1465 } |
1400 | 1466 |
1401 void ServiceWorkerVersion::StopWorkerIfIdle() { | 1467 void ServiceWorkerVersion::StopWorkerIfIdle() { |
1402 // Reschedule the stop the worker while there're inflight requests. | 1468 if (HasInflightRequests() && !ping_timed_out_) { |
1403 // (Note: we'll probably need to revisit this so that we can kill 'bad' SW. | |
1404 // See https://github.com/slightlyoff/ServiceWorker/issues/527) | |
1405 if (HasInflightRequests()) { | |
1406 ScheduleStopWorker(); | 1469 ScheduleStopWorker(); |
1407 return; | 1470 return; |
1408 } | 1471 } |
1409 if (running_status() == STOPPED || running_status() == STOPPING || | 1472 if (running_status() == STOPPED || running_status() == STOPPING || |
1410 !stop_callbacks_.empty()) { | 1473 !stop_callbacks_.empty()) { |
1411 return; | 1474 return; |
1412 } | 1475 } |
| 1476 |
| 1477 // TODO(falken): We may need to handle StopIfIdle failure and |
| 1478 // forcibly fail pending callbacks so no one is stuck waiting |
| 1479 // for the worker. |
1413 embedded_worker_->StopIfIdle(); | 1480 embedded_worker_->StopIfIdle(); |
1414 } | 1481 } |
1415 | 1482 |
1416 bool ServiceWorkerVersion::HasInflightRequests() const { | 1483 bool ServiceWorkerVersion::HasInflightRequests() const { |
1417 return | 1484 return |
1418 !activate_callbacks_.IsEmpty() || | 1485 !activate_callbacks_.IsEmpty() || |
1419 !install_callbacks_.IsEmpty() || | 1486 !install_callbacks_.IsEmpty() || |
1420 !fetch_callbacks_.IsEmpty() || | 1487 !fetch_callbacks_.IsEmpty() || |
1421 !sync_callbacks_.IsEmpty() || | 1488 !sync_callbacks_.IsEmpty() || |
1422 !notification_click_callbacks_.IsEmpty() || | 1489 !notification_click_callbacks_.IsEmpty() || |
(...skipping 21 matching lines...) Expand all Loading... |
1444 int request_id) { | 1511 int request_id) { |
1445 callbacks->Remove(request_id); | 1512 callbacks->Remove(request_id); |
1446 if (is_doomed_) { | 1513 if (is_doomed_) { |
1447 // The stop should be already scheduled, but try to stop immediately, in | 1514 // The stop should be already scheduled, but try to stop immediately, in |
1448 // order to release worker resources soon. | 1515 // order to release worker resources soon. |
1449 StopWorkerIfIdle(); | 1516 StopWorkerIfIdle(); |
1450 } | 1517 } |
1451 } | 1518 } |
1452 | 1519 |
1453 } // namespace content | 1520 } // namespace content |
OLD | NEW |