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

Unified Diff: google_apis/gcm/engine/connection_factory_impl.cc

Issue 160703002: [GCM] Track connection failures properly (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update comment Created 6 years, 10 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 side-by-side diff with in-line comments
Download patch
Index: google_apis/gcm/engine/connection_factory_impl.cc
diff --git a/google_apis/gcm/engine/connection_factory_impl.cc b/google_apis/gcm/engine/connection_factory_impl.cc
index fcab2c2de251689427705b6a9eaf8374f88e8161..3c2e412ce38922e0e39a9c1ad815f34e70f4969c 100644
--- a/google_apis/gcm/engine/connection_factory_impl.cc
+++ b/google_apis/gcm/engine/connection_factory_impl.cc
@@ -29,6 +29,15 @@ const int kReadTimeoutMs = 30000; // 30 seconds.
// as if it was transient).
const int kConnectionResetWindowSecs = 10; // 10 seconds.
+// Decides whether the last login was within kConnectionResetWindowSecs of now
+// or not.
+bool ShouldRestorePreviousBackoff(const base::TimeTicks& login_time,
+ const base::TimeTicks& now_ticks) {
+ return !login_time.is_null() &&
+ now_ticks - login_time <=
+ base::TimeDelta::FromSeconds(kConnectionResetWindowSecs);
+}
+
} // namespace
ConnectionFactoryImpl::ConnectionFactoryImpl(
@@ -41,6 +50,7 @@ ConnectionFactoryImpl::ConnectionFactoryImpl(
network_session_(network_session),
net_log_(net_log),
connecting_(false),
+ logging_in_(false),
weak_ptr_factory_(this) {
}
@@ -98,21 +108,52 @@ bool ConnectionFactoryImpl::IsEndpointReachable() const {
!connecting_;
}
-void ConnectionFactoryImpl::SignalConnectionReset() {
+void ConnectionFactoryImpl::SignalConnectionReset(
+ ConnectionResetReason reason) {
+ // A failure can trigger multiple resets, so no need to do anything if a
+ // connection is already in progress.
if (connecting_)
- return; // Already attempting to reconnect.
+ return;
+
+ UMA_HISTOGRAM_ENUMERATION("GCM.ConnectionResetReason",
+ reason,
+ CONNECTION_RESET_COUNT);
+ if (!last_login_time_.is_null()) {
+ UMA_HISTOGRAM_CUSTOM_TIMES("GCM.ConnectionUpTime",
+ NowTicks() - last_login_time_,
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromHours(24),
+ 50);
+ // |last_login_time_| will be reset below, before attempting the new
+ // connection.
+ }
if (connection_handler_)
connection_handler_->Reset();
- if (!backoff_reset_time_.is_null() &&
- NowTicks() - backoff_reset_time_ <=
- base::TimeDelta::FromSeconds(kConnectionResetWindowSecs)) {
+ if (socket_handle_.socket() && socket_handle_.socket()->IsConnected())
+ socket_handle_.socket()->Disconnect();
+ socket_handle_.Reset();
+
+ if (logging_in_) {
+ // Failures prior to login completion just reuse the existing backoff entry.
+ logging_in_ = false;
+ backoff_entry_->InformOfRequest(false);
+ } else if (reason == LOGIN_FAILURE ||
+ ShouldRestorePreviousBackoff(last_login_time_, NowTicks())) {
+ // Failures due to login, or within the reset window of a login, restore
+ // the backoff entry that was saved off at login completion time.
backoff_entry_.swap(previous_backoff_);
backoff_entry_->InformOfRequest(false);
+ } else {
+ // We shouldn't be in backoff in thise case.
+ DCHECK(backoff_entry_->CanDiscard());
}
- backoff_reset_time_ = base::TimeTicks();
- previous_backoff_->Reset();
+
+ // At this point the last login time has been consumed or deemed irrelevant,
+ // reset it.
+ last_login_time_ = base::TimeTicks();
+
Connect();
}
@@ -143,10 +184,8 @@ void ConnectionFactoryImpl::OnIPAddressChanged() {
}
void ConnectionFactoryImpl::ConnectImpl() {
- DCHECK(!connection_handler_->CanSendMessage());
- if (socket_handle_.socket() && socket_handle_.socket()->IsConnected())
- socket_handle_.socket()->Disconnect();
- socket_handle_.Reset();
+ DCHECK(connecting_);
+ DCHECK(!socket_handle_.socket());
// TODO(zea): resolve proxies.
net::ProxyInfo proxy_info;
@@ -190,6 +229,8 @@ base::TimeTicks ConnectionFactoryImpl::NowTicks() {
}
void ConnectionFactoryImpl::OnConnectDone(int result) {
+ UMA_HISTOGRAM_BOOLEAN("GCM.ConnectionSuccessRate", (result == net::OK));
+
if (result != net::OK) {
LOG(ERROR) << "Failed to connect to MCS endpoint with error " << result;
backoff_entry_->InformOfRequest(false);
@@ -198,31 +239,29 @@ void ConnectionFactoryImpl::OnConnectDone(int result) {
return;
}
- DVLOG(1) << "MCS endpoint socket connection success, starting handshake.";
+ connecting_ = false;
+ logging_in_ = true;
+ DVLOG(1) << "MCS endpoint socket connection success, starting login.";
InitHandler();
}
void ConnectionFactoryImpl::ConnectionHandlerCallback(int result) {
- if (result == net::OK) {
- // Handshake succeeded, reset the backoff.
- connecting_ = false;
- backoff_reset_time_ = NowTicks();
- previous_backoff_.swap(backoff_entry_);
- backoff_entry_->Reset();
+ DCHECK(!connecting_);
+ if (result != net::OK) {
+ // TODO(zea): Consider how to handle errors that may require some sort of
+ // user intervention (login page, etc.).
+ UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionDisconnectErrorCode", result);
+ SignalConnectionReset(SOCKET_FAILURE);
return;
}
- if (!connecting_)
- UMA_HISTOGRAM_SPARSE_SLOWLY("GCM.ConnectionDisconnectErrorCode", result);
-
- if (connection_handler_)
- connection_handler_->Reset();
-
- // TODO(zea): Consider how to handle errors that may require some sort of
- // user intervention (login page, etc.).
- LOG(ERROR) << "Connection reset with error " << result;
- backoff_entry_->InformOfRequest(false);
- Connect();
+ // Handshake complete, reset backoff. If the login failed with an error,
+ // the client should invoke SignalConnectionReset(LOGIN_FAILURE), which will
+ // restore the previous backoff.
+ last_login_time_ = NowTicks();
+ previous_backoff_.swap(backoff_entry_);
+ backoff_entry_->Reset();
+ logging_in_ = false;
}
} // namespace gcm

Powered by Google App Engine
This is Rietveld 408576698