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

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: review comments 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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 if (registration) { 303 if (registration) {
301 registration_id_ = registration->id(); 304 registration_id_ = registration->id();
302 scope_ = registration->pattern(); 305 scope_ = registration->pattern();
303 } 306 }
304 context_->AddLiveVersion(this); 307 context_->AddLiveVersion(this);
305 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker(); 308 embedded_worker_ = context_->embedded_worker_registry()->CreateWorker();
306 embedded_worker_->AddListener(this); 309 embedded_worker_->AddListener(this);
307 } 310 }
308 311
309 ServiceWorkerVersion::~ServiceWorkerVersion() { 312 ServiceWorkerVersion::~ServiceWorkerVersion() {
313 // The user may have closed the tab waiting for SW to start up.
314 if (start_worker_timeout_timer_.IsRunning() && !start_timing_.is_null() &&
315 (base::TimeTicks::Now() - start_timing_) >
316 base::TimeDelta::FromSeconds(5)) {
kinuko 2015/03/02 06:13:19 nit: use constant here?
falken 2015/03/02 06:33:16 Done.
317 RecordStartWorkerResult(SERVICE_WORKER_ERROR_TIMEOUT);
318 }
319
310 embedded_worker_->RemoveListener(this); 320 embedded_worker_->RemoveListener(this);
311 if (context_) 321 if (context_)
312 context_->RemoveLiveVersion(version_id_); 322 context_->RemoveLiveVersion(version_id_);
313 // EmbeddedWorker's dtor sends StopWorker if it's still running. 323 // EmbeddedWorker's dtor sends StopWorker if it's still running.
314 } 324 }
315 325
316 void ServiceWorkerVersion::SetStatus(Status status) { 326 void ServiceWorkerVersion::SetStatus(Status status) {
317 if (status_ == status) 327 if (status_ == status)
318 return; 328 return;
319 329
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED)); 371 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED));
362 return; 372 return;
363 } 373 }
364 switch (running_status()) { 374 switch (running_status()) {
365 case RUNNING: 375 case RUNNING:
366 RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); 376 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
367 return; 377 return;
368 case STOPPING: 378 case STOPPING:
369 case STOPPED: 379 case STOPPED:
370 case STARTING: 380 case STARTING:
381 if (!start_worker_timeout_timer_.IsRunning())
382 ScheduleStartWorkerTimeout();
371 start_callbacks_.push_back(callback); 383 start_callbacks_.push_back(callback);
372 if (running_status() == STOPPED) { 384 if (running_status() == STOPPED) {
373 DCHECK(!cache_listener_.get()); 385 DCHECK(!cache_listener_.get());
374 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); 386 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
375 embedded_worker_->Start( 387 embedded_worker_->Start(
376 version_id_, 388 version_id_, scope_, script_url_, pause_after_download,
377 scope_, 389 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
378 script_url_,
379 pause_after_download,
380 base::Bind(&ServiceWorkerVersion::OnStartMessageSent,
381 weak_factory_.GetWeakPtr())); 390 weak_factory_.GetWeakPtr()));
382 } 391 }
383 return; 392 return;
384 } 393 }
385 } 394 }
386 395
387 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) { 396 void ServiceWorkerVersion::StopWorker(const StatusCallback& callback) {
388 if (running_status() == STOPPED) { 397 if (running_status() == STOPPED) {
389 RunSoon(base::Bind(callback, SERVICE_WORKER_OK)); 398 RunSoon(base::Bind(callback, SERVICE_WORKER_OK));
390 return; 399 return;
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
779 void ServiceWorkerVersion::Doom() { 788 void ServiceWorkerVersion::Doom() {
780 if (is_doomed_) 789 if (is_doomed_)
781 return; 790 return;
782 is_doomed_ = true; 791 is_doomed_ = true;
783 if (!HasControllee()) 792 if (!HasControllee())
784 DoomInternal(); 793 DoomInternal();
785 } 794 }
786 795
787 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) { 796 void ServiceWorkerVersion::SetDevToolsAttached(bool attached) {
788 embedded_worker()->set_devtools_attached(attached); 797 embedded_worker()->set_devtools_attached(attached);
789 if (attached) 798 if (attached) {
799 // Set to null time so we don't record the startup time metric.
800 start_timing_ = base::TimeTicks();
790 return; 801 return;
802 }
791 // If devtools is detached try scheduling the timers for stopping the worker 803 // If devtools is detached try scheduling the timers for stopping the worker
792 // now. 804 // now.
793 if (!stop_worker_timer_.IsRunning()) 805 if (!stop_worker_timer_.IsRunning())
794 ScheduleStopWorker(); 806 ScheduleStopWorker();
795 if (!ping_worker_timer_.IsRunning()) 807 if (!ping_worker_timer_.IsRunning())
796 StartPingWorker(); 808 StartPingWorker();
809 if (!start_worker_timeout_timer_.IsRunning() && !start_callbacks_.empty())
810 ScheduleStartWorkerTimeout();
797 } 811 }
798 812
799 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo( 813 void ServiceWorkerVersion::SetMainScriptHttpResponseInfo(
800 const net::HttpResponseInfo& http_info) { 814 const net::HttpResponseInfo& http_info) {
801 main_script_http_info_.reset(new net::HttpResponseInfo(http_info)); 815 main_script_http_info_.reset(new net::HttpResponseInfo(http_info));
802 } 816 }
803 817
804 const net::HttpResponseInfo* 818 const net::HttpResponseInfo*
805 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() { 819 ServiceWorkerVersion::GetMainScriptHttpResponseInfo() {
806 return main_script_http_info_.get(); 820 return main_script_http_info_.get();
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
870 884
871 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this)); 885 FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
872 886
873 // There should be no more communication from/to a stopped worker. Deleting 887 // There should be no more communication from/to a stopped worker. Deleting
874 // the listener prevents any pending completion callbacks from causing 888 // the listener prevents any pending completion callbacks from causing
875 // messages to be sent to the stopped worker. 889 // messages to be sent to the stopped worker.
876 cache_listener_.reset(); 890 cache_listener_.reset();
877 891
878 // Restart worker if we have any start callbacks and the worker isn't doomed. 892 // Restart worker if we have any start callbacks and the worker isn't doomed.
879 if (should_restart) { 893 if (should_restart) {
894 start_worker_timeout_timer_.Reset();
880 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_)); 895 cache_listener_.reset(new ServiceWorkerCacheListener(this, context_));
881 embedded_worker_->Start( 896 embedded_worker_->Start(
882 version_id_, scope_, script_url_, false /* pause_after_download */, 897 version_id_, scope_, script_url_, false /* pause_after_download */,
883 base::Bind(&ServiceWorkerVersion::OnStartMessageSent, 898 base::Bind(&ServiceWorkerVersion::OnStartSentAndScriptEvaluated,
884 weak_factory_.GetWeakPtr())); 899 weak_factory_.GetWeakPtr()));
885 } 900 }
886 } 901 }
887 902
888 void ServiceWorkerVersion::OnReportException( 903 void ServiceWorkerVersion::OnReportException(
889 const base::string16& error_message, 904 const base::string16& error_message,
890 int line_number, 905 int line_number,
891 int column_number, 906 int column_number,
892 const GURL& source_url) { 907 const GURL& source_url) {
893 FOR_EACH_OBSERVER( 908 FOR_EACH_OBSERVER(
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
946 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting, 961 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_SkipWaiting,
947 OnSkipWaiting) 962 OnSkipWaiting)
948 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients, 963 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_ClaimClients,
949 OnClaimClients) 964 OnClaimClients)
950 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker) 965 IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_Pong, OnPongFromWorker)
951 IPC_MESSAGE_UNHANDLED(handled = false) 966 IPC_MESSAGE_UNHANDLED(handled = false)
952 IPC_END_MESSAGE_MAP() 967 IPC_END_MESSAGE_MAP()
953 return handled; 968 return handled;
954 } 969 }
955 970
956 void ServiceWorkerVersion::OnStartMessageSent( 971 void ServiceWorkerVersion::OnStartSentAndScriptEvaluated(
957 ServiceWorkerStatusCode status) { 972 ServiceWorkerStatusCode status) {
958 if (status != SERVICE_WORKER_OK) 973 if (status != SERVICE_WORKER_OK)
959 RunCallbacks(this, &start_callbacks_, status); 974 RunCallbacks(this, &start_callbacks_, status);
960 } 975 }
961 976
962 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker( 977 void ServiceWorkerVersion::DispatchInstallEventAfterStartWorker(
963 int active_version_id, 978 int active_version_id,
964 const StatusCallback& callback) { 979 const StatusCallback& callback) {
965 DCHECK_EQ(RUNNING, running_status()) 980 DCHECK_EQ(RUNNING, running_status())
966 << "Worker stopped too soon after it was started."; 981 << "Worker stopped too soon after it was started.";
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after
1448 base::TimeDelta::FromSeconds(kPingIntervalTime), 1463 base::TimeDelta::FromSeconds(kPingIntervalTime),
1449 base::Bind(&ServiceWorkerVersion::PingWorker, 1464 base::Bind(&ServiceWorkerVersion::PingWorker,
1450 weak_factory_.GetWeakPtr())); 1465 weak_factory_.GetWeakPtr()));
1451 } 1466 }
1452 1467
1453 void ServiceWorkerVersion::OnPingTimeout() { 1468 void ServiceWorkerVersion::OnPingTimeout() {
1454 if (running_status() != STARTING && running_status() != RUNNING) 1469 if (running_status() != STARTING && running_status() != RUNNING)
1455 return; 1470 return;
1456 ping_timed_out_ = true; 1471 ping_timed_out_ = true;
1457 // TODO(falken): Show a message to the developer that the SW was stopped due 1472 // TODO(falken): Show a message to the developer that the SW was stopped due
1458 // to timeout (crbug.com/457968). 1473 // to timeout (crbug.com/457968). Also, change the error code to
1474 // SERVICE_WORKER_ERROR_TIMEOUT.
1459 StopWorkerIfIdle(); 1475 StopWorkerIfIdle();
1460 } 1476 }
1461 1477
1462 void ServiceWorkerVersion::ScheduleStopWorker() { 1478 void ServiceWorkerVersion::ScheduleStopWorker() {
1463 if (running_status() != RUNNING) 1479 if (running_status() != RUNNING)
1464 return; 1480 return;
1465 stop_worker_timer_.Stop(); 1481 stop_worker_timer_.Stop();
1466 stop_worker_timer_.Start( 1482 stop_worker_timer_.Start(
1467 FROM_HERE, base::TimeDelta::FromSeconds( 1483 FROM_HERE, base::TimeDelta::FromSeconds(
1468 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay), 1484 is_doomed_ ? kStopDoomedWorkerDelay : kStopWorkerDelay),
(...skipping 23 matching lines...) Expand all
1492 !install_callbacks_.IsEmpty() || 1508 !install_callbacks_.IsEmpty() ||
1493 !fetch_callbacks_.IsEmpty() || 1509 !fetch_callbacks_.IsEmpty() ||
1494 !sync_callbacks_.IsEmpty() || 1510 !sync_callbacks_.IsEmpty() ||
1495 !notification_click_callbacks_.IsEmpty() || 1511 !notification_click_callbacks_.IsEmpty() ||
1496 !push_callbacks_.IsEmpty() || 1512 !push_callbacks_.IsEmpty() ||
1497 !geofencing_callbacks_.IsEmpty() || 1513 !geofencing_callbacks_.IsEmpty() ||
1498 !cross_origin_connect_callbacks_.IsEmpty() || 1514 !cross_origin_connect_callbacks_.IsEmpty() ||
1499 !streaming_url_request_jobs_.empty(); 1515 !streaming_url_request_jobs_.empty();
1500 } 1516 }
1501 1517
1518 void ServiceWorkerVersion::ScheduleStartWorkerTimeout() {
1519 DCHECK(!start_worker_timeout_timer_.IsRunning());
1520 start_timing_ = embedded_worker_->devtools_attached()
1521 ? base::TimeTicks()
1522 : base::TimeTicks::Now();
1523 start_callbacks_.push_back(
1524 base::Bind(&ServiceWorkerVersion::RecordStartWorkerResult,
1525 weak_factory_.GetWeakPtr()));
1526 start_worker_timeout_timer_.Start(
1527 FROM_HERE, base::TimeDelta::FromMinutes(kStartWorkerTimeoutMinutes),
1528 base::Bind(&ServiceWorkerVersion::OnStartWorkerTimeout,
1529 weak_factory_.GetWeakPtr()));
1530 }
1531
1532 void ServiceWorkerVersion::OnStartWorkerTimeout() {
1533 DCHECK(running_status() == STARTING || running_status() == STOPPING)
1534 << running_status();
1535
1536 if (embedded_worker_->devtools_attached()) {
1537 start_worker_timeout_timer_.Stop();
1538 return;
1539 }
1540
1541 scoped_refptr<ServiceWorkerVersion> protect(this);
1542 RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_ERROR_TIMEOUT);
1543 if (running_status() == STARTING)
1544 embedded_worker_->Stop();
1545 }
1546
1547 void ServiceWorkerVersion::RecordStartWorkerResult(
1548 ServiceWorkerStatusCode status) {
1549 start_worker_timeout_timer_.Stop();
1550
1551 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerVersion.StartWorkerStatus", status,
1552 SERVICE_WORKER_ERROR_MAX_VALUE);
1553 if (status == SERVICE_WORKER_OK && !start_timing_.is_null()) {
1554 UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorkerVersion.StartWorkerTime",
1555 base::TimeTicks::Now() - start_timing_);
1556 }
1557
1558 if (status != SERVICE_WORKER_ERROR_TIMEOUT)
1559 return;
1560 EmbeddedWorkerInstance::StartingPhase phase =
1561 EmbeddedWorkerInstance::NOT_STARTING;
1562 EmbeddedWorkerInstance::Status running_status = embedded_worker_->status();
1563 std::string message = "ServiceWorker startup timed out. ";
1564 if (running_status != EmbeddedWorkerInstance::STARTING) {
1565 message.append("The worker had unexpected status: ");
1566 message.append(EmbeddedWorkerInstance::StatusToString(running_status));
1567 } else {
1568 phase = embedded_worker_->starting_phase();
1569 message.append("The worker was in startup phase: ");
1570 message.append(EmbeddedWorkerInstance::StartingPhaseToString(phase));
1571 }
1572 message.append(".");
1573 OnReportException(base::UTF8ToUTF16(message), -1, -1, GURL());
1574 DVLOG(1) << message;
1575 UMA_HISTOGRAM_ENUMERATION("ServiceWorkerVersion.StartWorkerTimeoutPhase",
1576 phase,
1577 EmbeddedWorkerInstance::STARTING_PHASE_MAX_VALUE);
1578 }
1579
1502 void ServiceWorkerVersion::DoomInternal() { 1580 void ServiceWorkerVersion::DoomInternal() {
1503 DCHECK(is_doomed_); 1581 DCHECK(is_doomed_);
1504 DCHECK(!HasControllee()); 1582 DCHECK(!HasControllee());
1505 SetStatus(REDUNDANT); 1583 SetStatus(REDUNDANT);
1506 StopWorkerIfIdle(); 1584 StopWorkerIfIdle();
1507 if (!context_) 1585 if (!context_)
1508 return; 1586 return;
1509 std::vector<ServiceWorkerDatabase::ResourceRecord> resources; 1587 std::vector<ServiceWorkerDatabase::ResourceRecord> resources;
1510 script_cache_map_.GetResources(&resources); 1588 script_cache_map_.GetResources(&resources);
1511 context_->storage()->PurgeResources(resources); 1589 context_->storage()->PurgeResources(resources);
1512 } 1590 }
1513 1591
1514 template <typename IDMAP> 1592 template <typename IDMAP>
1515 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed( 1593 void ServiceWorkerVersion::RemoveCallbackAndStopIfDoomed(
1516 IDMAP* callbacks, 1594 IDMAP* callbacks,
1517 int request_id) { 1595 int request_id) {
1518 callbacks->Remove(request_id); 1596 callbacks->Remove(request_id);
1519 if (is_doomed_) { 1597 if (is_doomed_) {
1520 // The stop should be already scheduled, but try to stop immediately, in 1598 // The stop should be already scheduled, but try to stop immediately, in
1521 // order to release worker resources soon. 1599 // order to release worker resources soon.
1522 StopWorkerIfIdle(); 1600 StopWorkerIfIdle();
1523 } 1601 }
1524 } 1602 }
1525 1603
1526 } // namespace content 1604 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698