Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(487)

Side by Side Diff: content/browser/service_worker/service_worker_version.cc

Issue 962543005: Service Worker: Add metrics and timeout for starting a Service Worker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: self-review Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.h"
9 #include "base/stl_util.h" 10 #include "base/stl_util.h"
10 #include "base/strings/string16.h" 11 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h" 13 #include "base/time/time.h"
13 #include "content/browser/message_port_message_filter.h" 14 #include "content/browser/message_port_message_filter.h"
14 #include "content/browser/message_port_service.h" 15 #include "content/browser/message_port_service.h"
15 #include "content/browser/service_worker/embedded_worker_instance.h" 16 #include "content/browser/service_worker/embedded_worker_instance.h"
16 #include "content/browser/service_worker/embedded_worker_registry.h" 17 #include "content/browser/service_worker/embedded_worker_registry.h"
17 #include "content/browser/service_worker/service_worker_context_core.h" 18 #include "content/browser/service_worker/service_worker_context_core.h"
18 #include "content/browser/service_worker/service_worker_context_wrapper.h" 19 #include "content/browser/service_worker/service_worker_context_wrapper.h"
(...skipping 10 matching lines...) Expand all
29 #include "content/public/browser/web_contents_observer.h" 30 #include "content/public/browser/web_contents_observer.h"
30 #include "content/public/common/child_process_host.h" 31 #include "content/public/common/child_process_host.h"
31 #include "content/public/common/content_client.h" 32 #include "content/public/common/content_client.h"
32 #include "content/public/common/content_switches.h" 33 #include "content/public/common/content_switches.h"
33 #include "content/public/common/result_codes.h" 34 #include "content/public/common/result_codes.h"
34 #include "net/http/http_response_info.h" 35 #include "net/http/http_response_info.h"
35 36
36 namespace content { 37 namespace content {
37 38
38 typedef ServiceWorkerVersion::StatusCallback StatusCallback; 39 typedef ServiceWorkerVersion::StatusCallback StatusCallback;
39 typedef ServiceWorkerVersion::MessageCallback MessageCallback;
40 40
41 class ServiceWorkerVersion::GetClientDocumentsCallback 41 class ServiceWorkerVersion::GetClientDocumentsCallback
42 : public base::RefCounted<GetClientDocumentsCallback> { 42 : public base::RefCounted<GetClientDocumentsCallback> {
43 public: 43 public:
44 GetClientDocumentsCallback(int request_id, 44 GetClientDocumentsCallback(int request_id,
45 ServiceWorkerVersion* version) 45 ServiceWorkerVersion* version)
46 : request_id_(request_id), 46 : request_id_(request_id),
47 version_(version) { 47 version_(version) {
48 DCHECK(version_); 48 DCHECK(version_);
49 } 49 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
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. 88 // Delay between sending pings to the worker.
89 const int kPingIntervalTime = 10; // 10 secs. 89 const int kPingIntervalTime = 10; // 10 secs.
90 90
91 // Timeout for waiting for a response to a ping. 91 // Timeout for waiting for a response to a ping.
92 const int kPingTimeoutTime = 30; // 30 secs. 92 const int kPingTimeoutTime = 30; // 30 secs.
93 93
94 // Timeout for the worker to start.
95 const int kStartWorkerTimeoutMinutes = 5;
96
94 const char kClaimClientsStateErrorMesage[] = 97 const char kClaimClientsStateErrorMesage[] =
95 "Only the active worker can claim clients."; 98 "Only the active worker can claim clients.";
96 99
97 const char kClaimClientsShutdownErrorMesage[] = 100 const char kClaimClientsShutdownErrorMesage[] =
98 "Failed to claim clients due to Service Worker system shutdown."; 101 "Failed to claim clients due to Service Worker system shutdown.";
99 102
100 void RunSoon(const base::Closure& callback) { 103 void RunSoon(const base::Closure& callback) {
101 if (!callback.is_null()) 104 if (!callback.is_null())
102 base::MessageLoop::current()->PostTask(FROM_HERE, callback); 105 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
103 } 106 }
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 if (registration) { 315 if (registration) {
313 registration_id_ = registration->id(); 316 registration_id_ = registration->id();
314 scope_ = registration->pattern(); 317 scope_ = registration->pattern();
315 } 318 }
316 context_->AddLiveVersion(this); 319 context_->AddLiveVersion(this);
317 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker(); 320 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
318 embedded_worker_->AddListener(this); 321 embedded_worker_->AddListener(this);
319 } 322 }
320 323
321 ServiceWorkerVersion::~ServiceWorkerVersion() { 324 ServiceWorkerVersion::~ServiceWorkerVersion() {
325 // The user may have closed the tab waiting for SW to start up.
326 if (start_worker_timeout_timer_.IsRunning() && !start_timing_.is_null() &&
327 (base::TimeTicks::Now() - start_timing_) >
328 base::TimeDelta::FromSeconds(5)) {
329 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT);
330 }
331
322 embedded_worker_->RemoveListener(this); 332 embedded_worker_->RemoveListener(this);
323 if (context_) 333 if (context_)
324 context_->RemoveLiveVersion(version_id_); 334 context_->RemoveLiveVersion(version_id_);
325 // EmbeddedWorker's dtor sends StopWorker if it's still running. 335 // EmbeddedWorker's dtor sends StopWorker if it's still running.
326 } 336 }
327 337
328 void ServiceWorkerVersion::SetStatus(Status status) { 338 void ServiceWorkerVersion::SetStatus(Status status) {
329 if (status_ == status) 339 if (status_ == status)
330 return; 340 return;
331 341
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED)); 383 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
374 return; 384 return;
375 } 385 }
376 switch (running_status()) { 386 switch (running_status()) {
377 case RUNNING: 387 case RUNNING:
378 RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); 388 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
379 return; 389 return;
380 case STOPPING: 390 case STOPPING:
381 case STOPPED: 391 case STOPPED:
382 case STARTING: 392 case STARTING:
393 if (!start_worker_timeout_timer_.IsRunning())
394 ScheduleStartWorkerTimeout();
kinuko 2015/03/02 03:19:33 when we come here running_status() == STOPPED shou
falken 2015/03/02 04:19:17 Not necessarily, you could call StopWorker(); Star
383 start_callbacks_.push_back(callback); 395 start_callbacks_.push_back(callback);
384 if (running_status() == STOPPED) { 396 if (running_status() == STOPPED) {
385 DCHECK(!cache_listener_.get()); 397 DCHECK(!cache_listener_.get());
386 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); 398 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
387 embedded_worker_->Start( 399 embedded_worker_->Start(
388 version_id_, 400 version_id_, scope_, script_url_, pause_after_download,
389 scope_, 401 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
390 script_url_,
391 pause_after_download,
392 base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
393 weak_factory_.GetWeakPtr())); 402 weak_factory_.GetWeakPtr()));
394 } 403 }
395 return; 404 return;
396 } 405 }
397 } 406 }
398 407
399 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) { 408 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
400 if (running_status() == STOPPED) { 409 if (running_status() == STOPPED) {
401 RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); 410 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
402 return; 411 return;
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 void ServiceWorkerVersion::Doom() { 800 void ServiceWorkerVersion::Doom() {
792 if (is_doomed_) 801 if (is_doomed_)
793 return; 802 return;
794 is_doomed_ = true; 803 is_doomed_ = true;
795 if (!HasControllee()) 804 if (!HasControllee())
796 DoomInternal(); 805 DoomInternal();
797 } 806 }
798 807
799 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { 808 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
800 embedded_worker()->set_devtools_attached(attached); 809 embedded_worker()->set_devtools_attached(attached);
801 if (attached) 810 if (attached) {
811 // Set to null time so we don't record the startup time metric.
812 start_timing_ = base::TimeTicks();
802 return; 813 return;
814 }
803 // If devtools is detached try scheduling the timers for stopping the worker 815 // If devtools is detached try scheduling the timers for stopping the worker
804 // now. 816 // now.
805 if (!stop_worker_timer_.IsRunning()) 817 if (!stop_worker_timer_.IsRunning())
806 ScheduleStopWorker(); 818 ScheduleStopWorker();
807 if (!ping_worker_timer_.IsRunning()) 819 if (!ping_worker_timer_.IsRunning())
808 StartPingWorker(); 820 StartPingWorker();
809 } 821 }
810 822
811 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( 823 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
812 const net::HttpResponseInfo& http_info) { 824 const net::HttpResponseInfo& http_info) {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
882 894
883 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this)); 895 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
884 896
885 // There should be no more communication from/to a stopped worker. Deleting 897 // There should be no more communication from/to a stopped worker. Deleting
886 // the listener prevents any pending completion callbacks from causing 898 // the listener prevents any pending completion callbacks from causing
887 // messages to be sent to the stopped worker. 899 // messages to be sent to the stopped worker.
888 cache_listener_.reset(); 900 cache_listener_.reset();
889 901
890 // Restart worker if we have any start callbacks and the worker isn't doomed. 902 // Restart worker if we have any start callbacks and the worker isn't doomed.
891 if (should_restart) { 903 if (should_restart) {
904 start_worker_timeout_timer_.Reset();
892 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); 905 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
893 embedded_worker_->Start( 906 embedded_worker_->Start(
894 version_id_, scope_, script_url_, false /* pause_after_download */, 907 version_id_, scope_, script_url_, false /* pause_after_download */,
895 base::Bind(&ServiceWorkerVersion::OnStartMessageSent, 908 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
896 weak_factory_.GetWeakPtr())); 909 weak_factory_.GetWeakPtr()));
897 } 910 }
898 } 911 }
899 912
900 void ServiceWorkerVersion::OnReportException( 913 void ServiceWorkerVersion::OnReportException(
901 const base::string16& error_message, 914 const base::string16& error_message,
902 int line_number, 915 int line_number,
903 int column_number, 916 int column_number,
904 const GURL& source_url) { 917 const GURL& source_url) {
905 FOR_EACH_OBSERVER( 918 FOR_EACH_OBSERVER(
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, 971 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
959 OnSkipWaiting) 972 OnSkipWaiting)
960 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, 973 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
961 OnClaimClients) 974 OnClaimClients)
962 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker) 975 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
963 IPC_MESSAGE_UNHANDLED(handled = false) 976 IPC_MESSAGE_UNHANDLED(handled = false)
964 IPC_END_MESSAGE_MAP() 977 IPC_END_MESSAGE_MAP()
965 return handled; 978 return handled;
966 } 979 }
967 980
968 void ServiceWorkerVersion::OnStartMessageSent( 981 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
969 ServiceWorkerStatusCode status) { 982 ServiceWorkerStatusCode status) {
970 if (status != SERVICE_WORKER_OK) 983 if (status != SERVICE_WORKER_OK)
971 RunCallbacks(this, &start_callbacks_, status); 984 RunCallbacks(this, &start_callbacks_, status);
972 } 985 }
973 986
974 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker( 987 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
975 int active_version_id, 988 int active_version_id,
976 const StatusCallback& callback) { 989 const StatusCallback& callback) {
977 DCHECK_EQ(RUNNING, running_status()) 990 DCHECK_EQ(RUNNING, running_status())
978 << "Worker stopped too soon after it was started."; 991 << "Worker stopped too soon after it was started.";
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
1442 base::TimeDelta::FromSeconds(kPingIntervalTime), 1455 base::TimeDelta::FromSeconds(kPingIntervalTime),
1443 base::Bind(&ServiceWorkerVersion::PingWorker, 1456 base::Bind(&ServiceWorkerVersion::PingWorker,
1444 weak_factory_.GetWeakPtr())); 1457 weak_factory_.GetWeakPtr()));
1445 } 1458 }
1446 1459
1447 void ServiceWorkerVersion::OnPingTimeout() { 1460 void ServiceWorkerVersion::OnPingTimeout() {
1448 if (running_status() != STARTING && running_status() != RUNNING) 1461 if (running_status() != STARTING && running_status() != RUNNING)
1449 return; 1462 return;
1450 ping_timed_out_ = true; 1463 ping_timed_out_ = true;
1451 // TODO(falken): Show a message to the developer that the SW was stopped due 1464 // TODO(falken): Show a message to the developer that the SW was stopped due
1452 // to timeout (crbug.com/457968). 1465 // to timeout (crbug.com/457968). Also, change the error code to
1466 // SERVICE_WORKER_ERROR_TIMEOUT.
1453 StopWorkerIfIdle(); 1467 StopWorkerIfIdle();
1454 } 1468 }
1455 1469
1456 void ServiceWorkerVersion::ScheduleStopWorker() { 1470 void ServiceWorkerVersion::ScheduleStopWorker() {
1457 if (running_status() != RUNNING) 1471 if (running_status() != RUNNING)
1458 return; 1472 return;
1459 stop_worker_timer_.Stop(); 1473 stop_worker_timer_.Stop();
1460 stop_worker_timer_.Start( 1474 stop_worker_timer_.Start(
1461 FROM_HERE, base::TimeDelta::FromSeconds( 1475 FROM_HERE, base::TimeDelta::FromSeconds(
1462 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), 1476 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay),
(...skipping 23 matching lines...) Expand all
1486 !install_callbacks_.IsEmpty() || 1500 !install_callbacks_.IsEmpty() ||
1487 !fetch_callbacks_.IsEmpty() || 1501 !fetch_callbacks_.IsEmpty() ||
1488 !sync_callbacks_.IsEmpty() || 1502 !sync_callbacks_.IsEmpty() ||
1489 !notification_click_callbacks_.IsEmpty() || 1503 !notification_click_callbacks_.IsEmpty() ||
1490 !push_callbacks_.IsEmpty() || 1504 !push_callbacks_.IsEmpty() ||
1491 !geofencing_callbacks_.IsEmpty() || 1505 !geofencing_callbacks_.IsEmpty() ||
1492 !cross_origin_connect_callbacks_.IsEmpty() || 1506 !cross_origin_connect_callbacks_.IsEmpty() ||
1493 !streaming_url_request_jobs_.empty(); 1507 !streaming_url_request_jobs_.empty();
1494 } 1508 }
1495 1509
1510 void ServiceWorkerVersion::ScheduleStartWorkerTimeout() {
1511 DCHECK(!start_worker_timeout_timer_.IsRunning());
1512 start_timing_ = embedded_worker_->devtools_attached()
1513 ? base::TimeTicks()
1514 : base::TimeTicks::Now();
1515 start_callbacks_.push_back(
1516 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
1517 weak_factory_.GetWeakPtr()));
1518 start_worker_timeout_timer_.Start(
1519 FROM_HERE, base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes),
1520 base::Bind(&ServiceWorkerVersion::OnStartWorkerTimeout,
1521 weak_factory_.GetWeakPtr()));
1522 }
1523
1524 void ServiceWorkerVersion::OnStartWorkerTimeout() {
1525 DCHECK(running_status() == STARTING || running_status() == STOPPING)
1526 << running_status();
1527
1528 if (embedded_worker_->devtools_attached()) {
1529 start_worker_timeout_timer_.Reset();
kinuko 2015/03/02 03:19:33 Hm, why do we reset but not stop the timer here?
falken 2015/03/02 04:19:16 Changed to stop here and restart the timer in SetD
1530 return;
1531 }
1532
1533 scoped_refptr<ServiceWorkerVersion> protect(this);
1534 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT);
1535 if (running_status() == STARTING)
1536 embedded_worker_->Stop();
1537 }
1538
1539 void ServiceWorkerVersion::RecordStartWorkerResult(
1540 ServiceWorkerStatusCode status) {
1541 start_worker_timeout_timer_.Stop();
1542
1543 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerVersion.StartWorkerStatus", status,
1544 SERVICE_WORKER_ERROR_MAX_VALUE);
1545 if (status == SERVICE_WORKER_OK && !start_timing_.is_null()) {
1546 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorkerVersion.StartWorkerTime",
1547 base::TimeTicks::Now() - start_timing_);
1548 }
1549
1550 if (status != SERVICE_WORKER_ERROR_TIMEOUT)
1551 return;
1552 EmbeddedWorkerInstance::StartingPhase phase =
1553 EmbeddedWorkerInstance::NOT_STARTING;
1554 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status();
1555 std::string message = "ServiceWorker startup timed out. ";
1556 if (running_status != EmbeddedWorkerInstance::STARTING) {
1557 message.append("The worker had unexpected status: ");
1558 message.append(EmbeddedWorkerInstance::StatusToString(running_status));
1559 } else {
1560 phase = embedded_worker_->starting_phase();
1561 message.append("The worker was in startup phase: ");
1562 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
1563 }
1564 message.append(".");
1565 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
1566 DVLOG(1) << message;
1567 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerVersion.StartWorkerTimeoutPhase",
1568 phase,
1569 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
1570 }
1571
1496 void ServiceWorkerVersion::DoomInternal() { 1572 void ServiceWorkerVersion::DoomInternal() {
1497 DCHECK(is_doomed_); 1573 DCHECK(is_doomed_);
1498 DCHECK(!HasControllee()); 1574 DCHECK(!HasControllee());
1499 SetStatus(REDUNDANT); 1575 SetStatus(REDUNDANT);
1500 StopWorkerIfIdle(); 1576 StopWorkerIfIdle();
1501 if (!context_) 1577 if (!context_)
1502 return; 1578 return;
1503 std::vector<ServiceWorkerDatabase::ResourceRecord> resources; 1579 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
1504 script_cache_map_.GetResources(&resources); 1580 script_cache_map_.GetResources(&resources);
1505 context_->storage()->PurgeResources(resources); 1581 context_->storage()->PurgeResources(resources);
1506 } 1582 }
1507 1583
1508 template <typename IDMAP> 1584 template <typename IDMAP>
1509 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed( 1585 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1510 IDMAP* callbacks, 1586 IDMAP* callbacks,
1511 int request_id) { 1587 int request_id) {
1512 callbacks->Remove(request_id); 1588 callbacks->Remove(request_id);
1513 if (is_doomed_) { 1589 if (is_doomed_) {
1514 // The stop should be already scheduled, but try to stop immediately, in 1590 // The stop should be already scheduled, but try to stop immediately, in
1515 // order to release worker resources soon. 1591 // order to release worker resources soon.
1516 StopWorkerIfIdle(); 1592 StopWorkerIfIdle();
1517 } 1593 }
1518 } 1594 }
1519 1595
1520 } // namespace content 1596 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698