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 bfea304d422f680c4dc02f746109fd8162f2c7ef..8b9f3cf646cb4ae286d5fd89e33f03c861e4fabe 100644 |
--- a/chrome/browser/sync/profile_sync_service.cc |
+++ b/chrome/browser/sync/profile_sync_service.cc |
@@ -30,6 +30,8 @@ |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/signin/about_signin_internals.h" |
#include "chrome/browser/signin/about_signin_internals_factory.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/signin_manager_factory.h" |
#include "chrome/browser/signin/token_service.h" |
@@ -110,24 +112,16 @@ const char* ProfileSyncService::kDevServerUrl = |
static const int kSyncClearDataTimeoutInSeconds = 60; // 1 minute. |
-static const char* kRelevantTokenServices[] = { |
- GaiaConstants::kSyncService |
+static const char* kOAuth2Scopes[] = { |
+ GaiaConstants::kChromeSyncOAuth2Scope, |
+ // GoogleTalk scope is needed for notifications |
Andrew T Wilson (Slow)
2013/05/31 12:57:28
nit: add period at the end for sentence punctuatio
pavely
2013/06/04 00:49:59
Done.
|
+ GaiaConstants::kGoogleTalkOAuth2Scope |
}; |
-static const int kRelevantTokenServicesCount = |
- arraysize(kRelevantTokenServices); |
+ |
static const char* kSyncUnrecoverableErrorHistogram = |
"Sync.UnrecoverableErrors"; |
-// Helper to check if the given token service is relevant for sync. |
-static bool IsTokenServiceRelevant(const std::string& service) { |
- for (int i = 0; i < kRelevantTokenServicesCount; ++i) { |
- if (service == kRelevantTokenServices[i]) |
- return true; |
- } |
- return false; |
-} |
- |
bool ShouldShowActionOnUI( |
const syncer::SyncProtocolError& error) { |
return (error.action != syncer::UNKNOWN_ACTION && |
@@ -193,11 +187,12 @@ bool ProfileSyncService::IsSyncEnabledAndLoggedIn() { |
return !GetEffectiveUsername().empty(); |
} |
-bool ProfileSyncService::IsSyncTokenAvailable() { |
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
+bool ProfileSyncService::IsOAuthRefreshTokenAvailable() { |
+ ProfileOAuth2TokenService* token_service = |
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); |
if (!token_service) |
return false; |
- return token_service->HasTokenForService(GaiaConstants::kSyncService); |
+ return token_service->RefreshTokenIsAvailable(); |
} |
#if defined(OS_ANDROID) |
bool ProfileSyncService::ShouldEnablePasswordSyncForAndroid() const { |
@@ -245,6 +240,12 @@ void ProfileSyncService::Initialize() { |
TrySyncDatatypePrefRecovery(); |
+ if (IsOAuthRefreshTokenAvailable()) { |
+ // Tell token service to pre-request access token. We likely don't need it |
+ // right away but it will be available when we decide to initialize backend. |
+ RequestAccessToken(false, false); |
+ } |
+ |
TryStart(); |
} |
@@ -292,7 +293,7 @@ void ProfileSyncService::TryStart() { |
// (like ChromeOS) we don't start sync until tokens are loaded, because the |
// user can be "signed in" on those platforms long before the tokens get |
// loaded, and we don't want to generate spurious auth errors. |
- if (!IsSyncTokenAvailable() && |
+ if (!IsOAuthRefreshTokenAvailable() && |
!(!auto_start_enabled_ && token_service->TokensLoadedFromDB())) { |
return; |
} |
@@ -426,13 +427,11 @@ SyncCredentials ProfileSyncService::GetCredentials() { |
SyncCredentials credentials; |
credentials.email = GetEffectiveUsername(); |
DCHECK(!credentials.email.empty()); |
- TokenService* service = TokenServiceFactory::GetForProfile(profile_); |
- if (service->HasTokenForService(GaiaConstants::kSyncService)) { |
- credentials.sync_token = service->GetTokenForService( |
- GaiaConstants::kSyncService); |
+ if (!access_token_.empty()) { |
+ credentials.sync_token = access_token_; |
credentials.sync_token_time = |
AboutSigninInternalsFactory::GetForProfile(profile_)-> |
- GetTokenTime(GaiaConstants::kSyncService); |
+ GetTokenTime(GaiaConstants::kGaiaOAuth2LoginRefreshToken); |
UMA_HISTOGRAM_BOOLEAN("Sync.CredentialsLost", false); |
} else { |
// We've lost our sync credentials (crbug.com/121755), so just make up some |
@@ -514,6 +513,11 @@ void ProfileSyncService::StartUp(StartUpDeferredOption deferred_option) { |
DCHECK(IsSyncEnabledAndLoggedIn()); |
+ if (access_token_.empty()) { |
+ RequestAccessToken(false, true); |
+ return; |
+ } |
+ |
if (start_up_time_.is_null()) { |
start_up_time_ = base::Time::Now(); |
last_synced_time_ = sync_prefs_.GetLastSyncedTime(); |
@@ -661,6 +665,27 @@ syncer::InvalidatorState ProfileSyncService::GetInvalidatorState() const { |
return invalidator_registrar_->GetInvalidatorState(); |
} |
+void ProfileSyncService::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(); |
+ access_token_ = access_token; |
+ if (backend_) |
+ backend_->UpdateCredentials(GetCredentials()); |
+ else |
+ TryStart(); |
+} |
+ |
+void ProfileSyncService::OnGetTokenFailure( |
+ const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) { |
+ DCHECK_EQ(access_token_request_, request); |
+ access_token_request_.reset(); |
+ UpdateAuthErrorState(error); |
+} |
+ |
void ProfileSyncService::EmitInvalidationForTest( |
const invalidation::ObjectId& id, |
const std::string& payload) { |
@@ -1087,10 +1112,18 @@ AuthError ConnectionStatusToAuthError( |
void ProfileSyncService::OnConnectionStatusChange( |
syncer::ConnectionStatus status) { |
- const GoogleServiceAuthError auth_error = |
- ConnectionStatusToAuthError(status); |
- DVLOG(1) << "Connection status change: " << auth_error.ToString(); |
- UpdateAuthErrorState(auth_error); |
+ if (status == syncer::CONNECTION_AUTH_ERROR) { |
+ // Sync or Tango 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(true, true); |
+ } else { |
+ const GoogleServiceAuthError auth_error = |
+ ConnectionStatusToAuthError(status); |
+ DVLOG(1) << "Connection status change: " << auth_error.ToString(); |
+ UpdateAuthErrorState(auth_error); |
+ } |
} |
void ProfileSyncService::OnStopSyncingPermanently() { |
@@ -1833,6 +1866,30 @@ void ProfileSyncService::ConsumeCachedPassphraseIfPossible() { |
SetEncryptionPassphrase(passphrase, IMPLICIT); |
} |
+void ProfileSyncService::RequestAccessToken( |
+ bool invalidate_previous_token, |
+ bool invoke_callback) { |
+ // Only one active request at a time. |
+ if (access_token_request_ != NULL) |
+ return; |
+ OAuth2TokenService::ScopeSet oauth2_scopes; |
+ for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++) |
+ oauth2_scopes.insert(kOAuth2Scopes[i]); |
+ OAuth2TokenService* token_service = |
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); |
+ if (invalidate_previous_token) { |
+ // Invalidate previous token, othervise token service will return the same |
Andrew T Wilson (Slow)
2013/05/31 12:57:28
nit:othervise->otherwise. Also add a period at the
pavely
2013/06/04 00:49:59
Done.
|
+ // token again |
+ token_service->InvalidateToken(oauth2_scopes, access_token_); |
+ access_token_.clear(); |
+ } |
+ access_token_request_ = token_service->StartRequest(oauth2_scopes, this); |
+ if (!invoke_callback) { |
+ // Deleting request will not cancel RPC but callbacks won't be invoked. |
+ access_token_request_.reset(); |
+ } |
+} |
+ |
void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase, |
PassphraseType type) { |
// This should only be called when the backend has been initialized. |
@@ -1936,27 +1993,33 @@ void ProfileSyncService::Observe(int type, |
break; |
} |
case chrome::NOTIFICATION_TOKEN_REQUEST_FAILED: { |
+ // TODO(atwilson): sync shouldn't report refresh token request failures. |
+ // TokenService should do that instead. |
const TokenService::TokenRequestFailedDetails& token_details = |
*(content::Details<const TokenService::TokenRequestFailedDetails>( |
details).ptr()); |
- if (IsTokenServiceRelevant(token_details.service()) && |
- !IsSyncTokenAvailable()) { |
- // The additional check around IsSyncTokenAvailable() above prevents us |
- // sounding the alarm if we actually have a valid token but a refresh |
- // attempt by TokenService failed for any variety of reasons (e.g. flaky |
- // network). It's possible the token we do have is also invalid, but in |
- // that case we should already have (or can expect) an auth error sent |
- // from the sync backend. |
+ if (token_details.service() == |
+ GaiaConstants::kGaiaOAuth2LoginRefreshToken && |
+ !IsOAuthRefreshTokenAvailable()) { |
+ // The additional check around IsOAuthRefreshTokenAvailable() above |
+ // prevents us sounding the alarm if we actually have a valid token but |
+ // a refresh attempt by TokenService failed for any variety of reasons |
+ // (e.g. flaky network). It's possible the token we do have is also |
+ // invalid, but in that case we should already have (or can expect) an |
+ // auth error sent from the sync backend. |
AuthError error(AuthError::INVALID_GAIA_CREDENTIALS); |
UpdateAuthErrorState(error); |
} |
break; |
} |
case chrome::NOTIFICATION_TOKEN_AVAILABLE: { |
+ // TODO(atwilson): Listen for notifications on OAuth2TokenService |
+ // (crbug.com/243737) |
const TokenService::TokenAvailableDetails& token_details = |
*(content::Details<const TokenService::TokenAvailableDetails>( |
details).ptr()); |
- if (!IsTokenServiceRelevant(token_details.service())) |
+ if (token_details.service() != |
+ GaiaConstants::kGaiaOAuth2LoginRefreshToken) |
break; |
} // Fall through. |
case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: { |
@@ -1966,14 +2029,16 @@ void ProfileSyncService::Observe(int type, |
// not loaded, GetCredentials() will generate invalid credentials to |
// cause the backend to generate an auth error (crbug.com/121755). |
if (backend_) |
- backend_->UpdateCredentials(GetCredentials()); |
+ RequestAccessToken(true, true); |
else |
+ RequestAccessToken(true, false); |
Andrew T Wilson (Slow)
2013/05/31 12:57:28
Doesn't this fetch a token on every startup even i
|
TryStart(); |
break; |
} |
case chrome::NOTIFICATION_TOKENS_CLEARED: { |
// GetCredentials() will generate invalid credentials to cause the backend |
// to generate an auth error. |
+ access_token_.clear(); |
if (backend_) |
backend_->UpdateCredentials(GetCredentials()); |
break; |
@@ -2110,4 +2175,3 @@ std::string ProfileSyncService::GetEffectiveUsername() { |
return signin_->GetAuthenticatedUsername(); |
} |
- |