| Index: chrome/browser/sync/profile_sync_service.cc
|
| diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
|
| index ead0cf5aed34d91b3096d36b6c71d9d71e23f849..283a9ba0fa43aa7afe837f08f8af595c0161d262 100644
|
| --- a/chrome/browser/sync/profile_sync_service.cc
|
| +++ b/chrome/browser/sync/profile_sync_service.cc
|
| @@ -643,8 +643,6 @@ void ProfileSyncService::OnGetTokenSuccess(
|
| const base::Time& expiration_time) {
|
| DCHECK_EQ(access_token_request_, request);
|
| access_token_request_.reset();
|
| - // Reset backoff time after successful response.
|
| - request_access_token_backoff_.Reset();
|
| access_token_ = access_token;
|
| if (backend_)
|
| backend_->UpdateCredentials(GetCredentials());
|
| @@ -1111,9 +1109,51 @@ void ProfileSyncService::OnConnectionStatusChange(
|
| // Sync server returned error indicating that access token is invalid. It
|
| // could be either expired or access is revoked. Let's request another
|
| // access token and if access is revoked then request for token will fail
|
| - // with corresponding error.
|
| - RequestAccessToken();
|
| + // with corresponding error. If access token is repeatedly reported
|
| + // invalid, there may be some issues with token server, e.g. authentication
|
| + // server is inconsistent with token issue server. In that case, we
|
| + // backoff token requests exponentially to avoid hammering token server
|
| + // too much and to avoid getting same token due to token server's caching
|
| + // policy. |request_access_token_retry_timer_| is used to backoff request
|
| + // triggered by both auth error and failure talking to GAIA server.
|
| + // Therefore, we're likely to reach the backoff ceiling more quickly than
|
| + // you would expect from looking at the BackoffPolicy if both types of
|
| + // errors happen. We shouldn't receive two errors back-to-back without
|
| + // attempting a token/sync request in between, thus crank up request delay
|
| + // unnecessary. This is because we won't make a sync request if we hit an
|
| + // error until GAIA succeeds at sending a new token, and we won't request
|
| + // a new token unless sync reports a token failure. But to be safe, don't
|
| + // schedule request if this happens.
|
| + if (request_access_token_retry_timer_.IsRunning()) {
|
| + NOTREACHED();
|
| + } else if (request_access_token_backoff_.failure_count() == 0) {
|
| + // First time request without delay. Currently invalid token is used
|
| + // to initialize sync backend and we'll always end up here. We don't
|
| + // want to delay initialization.
|
| + request_access_token_backoff_.InformOfRequest(false);
|
| + RequestAccessToken();
|
| + } else {
|
| + request_access_token_backoff_.InformOfRequest(false);
|
| + request_access_token_retry_timer_.Start(
|
| + FROM_HERE,
|
| + request_access_token_backoff_.GetTimeUntilRelease(),
|
| + base::Bind(&ProfileSyncService::RequestAccessToken,
|
| + weak_factory_.GetWeakPtr()));
|
| + }
|
| } else {
|
| + // Reset backoff time after successful connection.
|
| + if (status == syncer::CONNECTION_OK) {
|
| + // Request shouldn't be scheduled at this time. But if it is, it's
|
| + // possible that sync flips between OK and auth error states rapidly,
|
| + // thus hammers token server. To be safe, only reset backoff delay when
|
| + // no scheduled request.
|
| + if (request_access_token_retry_timer_.IsRunning()) {
|
| + NOTREACHED();
|
| + } else {
|
| + request_access_token_backoff_.Reset();
|
| + }
|
| + }
|
| +
|
| const GoogleServiceAuthError auth_error =
|
| ConnectionStatusToAuthError(status);
|
| DVLOG(1) << "Connection status change: " << auth_error.ToString();
|
|
|