| Index: chrome/browser/invalidation/ticl_invalidation_service.cc
|
| diff --git a/chrome/browser/invalidation/ticl_invalidation_service.cc b/chrome/browser/invalidation/ticl_invalidation_service.cc
|
| index bfee8f0ac885fec779b042367d9575090ebe8d14..4d724f5a8d01f331fc582062e3dd5f4c647a91fc 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.
|
|
|