diff options
Diffstat (limited to 'chrome/browser/invalidation/ticl_invalidation_service.cc')
-rw-r--r-- | chrome/browser/invalidation/ticl_invalidation_service.cc | 193 |
1 files changed, 156 insertions, 37 deletions
diff --git a/chrome/browser/invalidation/ticl_invalidation_service.cc b/chrome/browser/invalidation/ticl_invalidation_service.cc index bfee8f0..4d724f5 100644 --- a/chrome/browser/invalidation/ticl_invalidation_service.cc +++ b/chrome/browser/invalidation/ticl_invalidation_service.cc @@ -6,9 +6,11 @@ #include "base/command_line.h" #include "chrome/browser/invalidation/invalidation_service_util.h" +#include "chrome/browser/managed_mode/managed_user_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/profile_oauth2_token_service.h" +#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager.h" -#include "chrome/browser/signin/token_service.h" #include "chrome/common/chrome_notification_types.h" #include "content/public/browser/notification_service.h" #include "google_apis/gaia/gaia_constants.h" @@ -16,15 +18,52 @@ #include "sync/notifier/invalidator_state.h" #include "sync/notifier/non_blocking_invalidator.h" +static const char* kOAuth2Scopes[] = { + GaiaConstants::kGoogleTalkOAuth2Scope +}; + +static const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = { + // Number of initial errors (in sequence) to ignore before applying + // exponential back-off rules. + 0, + + // Initial delay for exponential back-off in ms. + 2000, + + // Factor by which the waiting time will be multiplied. + 2, + + // Fuzzing percentage. ex: 10% will spread requests randomly + // between 90%-100% of the calculated time. + 0.2, // 20% + + // Maximum amount of time we are willing to delay our request in ms. + // TODO(pavely): crbug.com/246686 ProfileSyncService should retry + // RequestAccessToken on connection state change after backoff + 1000 * 3600 * 4, // 4 hours. + + // Time to keep an entry from being discarded even when it + // has no significant state, -1 to never discard. + -1, + + // Don't use initial delay unless the last request was an error. + false, +}; + namespace invalidation { -TiclInvalidationService::TiclInvalidationService(SigninManagerBase* signin, - TokenService* token_service, - Profile* profile) - : profile_(profile), - signin_manager_(signin), - token_service_(token_service), - invalidator_registrar_(new syncer::InvalidatorRegistrar()) { } +TiclInvalidationService::TiclInvalidationService( + SigninManagerBase* signin, + TokenService* token_service, + OAuth2TokenService* oauth2_token_service, + Profile* profile) + : profile_(profile), + signin_manager_(signin), + token_service_(token_service), + oauth2_token_service_(oauth2_token_service), + invalidator_registrar_(new syncer::InvalidatorRegistrar()), + request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) { +} TiclInvalidationService::~TiclInvalidationService() { DCHECK(CalledOnValidThread()); @@ -41,20 +80,24 @@ void TiclInvalidationService::Init() { } if (IsReadyToStart()) { - Start(); + StartInvalidator(); } notification_registrar_.Add(this, - chrome::NOTIFICATION_TOKEN_AVAILABLE, - content::Source<TokenService>(token_service_)); - notification_registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, content::Source<Profile>(profile_)); + notification_registrar_.Add(this, + chrome::NOTIFICATION_TOKEN_LOADING_FINISHED, + content::Source<TokenService>(token_service_)); + notification_registrar_.Add(this, + chrome::NOTIFICATION_TOKENS_CLEARED, + content::Source<TokenService>(token_service_)); } void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) { - // Here we perform the equivalent of Init() and Start(), but with some minor - // changes to account for the fact that we're injecting the invalidator. + // Here we perform the equivalent of Init() and StartInvalidator(), but with + // some minor changes to account for the fact that we're injecting the + // invalidator. invalidator_.reset(invalidator); invalidator_->RegisterHandler(this); @@ -128,17 +171,16 @@ void TiclInvalidationService::Observe( DCHECK(CalledOnValidThread()); switch (type) { - case chrome::NOTIFICATION_TOKEN_AVAILABLE: { - const TokenService::TokenAvailableDetails& token_details = - *(content::Details<const TokenService::TokenAvailableDetails>( - details).ptr()); - if (token_details.service() == GaiaConstants::kSyncService) { - DCHECK(IsReadyToStart()); - if (!IsStarted()) { - Start(); - } else { - UpdateToken(); - } + case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: { + if (!IsStarted() && IsReadyToStart()) { + StartInvalidator(); + } + break; + } + case chrome::NOTIFICATION_TOKENS_CLEARED: { + access_token_.clear(); + if (IsStarted()) { + UpdateInvalidatorCredentials(); } break; } @@ -152,6 +194,68 @@ void TiclInvalidationService::Observe( } } +void TiclInvalidationService::RequestAccessToken() { + // Only one active request at a time. + if (access_token_request_ != NULL) + return; + request_access_token_retry_timer_.Stop(); + OAuth2TokenService::ScopeSet oauth2_scopes; + for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++) + oauth2_scopes.insert(kOAuth2Scopes[i]); + // Invalidate previous token, otherwise token service will return the same + // token again. + oauth2_token_service_->InvalidateToken(oauth2_scopes, access_token_); + access_token_.clear(); + access_token_request_ = + oauth2_token_service_->StartRequest(oauth2_scopes, this); +} + +void TiclInvalidationService::OnGetTokenSuccess( + const OAuth2TokenService::Request* request, + const std::string& access_token, + 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 (!IsStarted() && IsReadyToStart()) { + StartInvalidator(); + } else { + UpdateInvalidatorCredentials(); + } +} + +void TiclInvalidationService::OnGetTokenFailure( + const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) { + DCHECK_EQ(access_token_request_, request); + DCHECK_NE(error.state(), GoogleServiceAuthError::NONE); + access_token_request_.reset(); + switch (error.state()) { + case GoogleServiceAuthError::CONNECTION_FAILED: + case GoogleServiceAuthError::SERVICE_UNAVAILABLE: { + // Transient error. Retry after some time. + request_access_token_backoff_.InformOfRequest(false); + request_access_token_retry_timer_.Start( + FROM_HERE, + request_access_token_backoff_.GetTimeUntilRelease(), + base::Bind(&TiclInvalidationService::RequestAccessToken, + base::Unretained(this))); + break; + } + case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: { + // This is a real auth error. + invalidator_registrar_->UpdateInvalidatorState( + syncer::INVALIDATION_CREDENTIALS_REJECTED); + break; + } + default: { + // We have no way to notify the user of this. Do nothing. + } + } +} + void TiclInvalidationService::OnInvalidatorStateChange( syncer::InvalidatorState state) { invalidator_registrar_->UpdateInvalidatorState(state); @@ -172,19 +276,25 @@ void TiclInvalidationService::Shutdown() { } bool TiclInvalidationService::IsReadyToStart() { + if (ManagedUserService::ProfileIsManaged(profile_)) { + DVLOG(2) << "Not starting TiclInvalidationService: User is managed."; + return false; + } + if (signin_manager_->GetAuthenticatedUsername().empty()) { - DVLOG(2) << "Not starting TiclInvalidationService: user is not signed in."; + DVLOG(2) << "Not starting TiclInvalidationService: User is not signed in."; return false; } - if (!token_service_) { + if (!oauth2_token_service_) { DVLOG(2) << "Not starting TiclInvalidationService: TokenService unavailable."; return false; } - if (!token_service_->HasTokenForService(GaiaConstants::kSyncService)) { - DVLOG(2) << "Not starting TiclInvalidationService: Sync token unavailable."; + if (!oauth2_token_service_->RefreshTokenIsAvailable()) { + DVLOG(2) + << "Not starting TiclInvalidationServce: Waiting for refresh token."; return false; } @@ -195,15 +305,24 @@ bool TiclInvalidationService::IsStarted() { return invalidator_.get() != NULL; } -void TiclInvalidationService::Start() { +void TiclInvalidationService::StartInvalidator() { DCHECK(CalledOnValidThread()); DCHECK(!invalidator_); DCHECK(invalidator_storage_); DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty()); + if (access_token_.empty()) { + DVLOG(1) + << "TiclInvalidationService: " + << "Deferring start until we have an access token."; + RequestAccessToken(); + return; + } + notifier::NotifierOptions options = ParseNotifierOptions(*CommandLine::ForCurrentProcess()); options.request_context_getter = profile_->GetRequestContext(); + options.auth_mechanism = "X-OAUTH2"; invalidator_.reset(new syncer::NonBlockingInvalidator( options, invalidator_storage_->GetInvalidatorClientId(), @@ -213,7 +332,7 @@ void TiclInvalidationService::Start() { invalidator_storage_->AsWeakPtr()), content::GetUserAgent(GURL()))); - UpdateToken(); + UpdateInvalidatorCredentials(); invalidator_->RegisterHandler(this); invalidator_->UpdateRegisteredIds( @@ -221,16 +340,14 @@ void TiclInvalidationService::Start() { invalidator_registrar_->GetAllRegisteredIds()); } -void TiclInvalidationService::UpdateToken() { +void TiclInvalidationService::UpdateInvalidatorCredentials() { std::string email = signin_manager_->GetAuthenticatedUsername(); - DCHECK(!email.empty()) << "Expected user to be signed in."; - DCHECK(token_service_->HasTokenForService(GaiaConstants::kSyncService)); - std::string sync_token = token_service_->GetTokenForService( - GaiaConstants::kSyncService); + DCHECK(!email.empty()) << "Expected user to be signed in."; + DCHECK(!access_token_.empty()); DVLOG(2) << "UpdateCredentials: " << email; - invalidator_->UpdateCredentials(email, sync_token); + invalidator_->UpdateCredentials(email, access_token_); } void TiclInvalidationService::StopInvalidator() { @@ -240,6 +357,8 @@ void TiclInvalidationService::StopInvalidator() { } void TiclInvalidationService::Logout() { + request_access_token_retry_timer_.Stop(); + StopInvalidator(); // This service always expects to have a valid invalidator storage. |