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 da473e4540cc2246f0b555ceeb573a97581237ae..c6ba85b50633bf7eebeb1442c2b1c8fe27fdeede 100644 |
--- a/chrome/browser/sync/profile_sync_service.cc |
+++ b/chrome/browser/sync/profile_sync_service.cc |
@@ -28,6 +28,8 @@ |
#include "chrome/browser/net/chrome_cookie_notification_details.h" |
#include "chrome/browser/prefs/pref_service_syncable.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/signin_manager_factory.h" |
#include "chrome/browser/signin/token_service.h" |
@@ -104,24 +106,15 @@ const char* ProfileSyncService::kDevServerUrl = |
static const int kSyncClearDataTimeoutInSeconds = 60; // 1 minute. |
-static const char* kRelevantTokenServices[] = { |
- GaiaConstants::kSyncService |
+static const char* kOAuth2Scopes[] = { |
tim (not reviewing)
2013/05/23 19:03:41
These belong in google_apis / GaiaConstants.
pavely
2013/05/30 07:42:12
Done.
Andrew T Wilson (Slow)
2013/05/31 12:57:28
That's too bad - I guess we need to move a little
|
+ "https://www.googleapis.com/auth/chromesync", |
+ "https://www.googleapis.com/auth/googletalk" |
Andrew T Wilson (Slow)
2013/05/31 12:57:28
So, this means we *cannot* sync if the user has th
pavely
2013/06/04 00:49:59
Currently if notifications server returns auth err
|
}; |
-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 && |
@@ -154,7 +147,9 @@ ProfileSyncService::ProfileSyncService(ProfileSyncComponentsFactory* factory, |
failed_datatypes_handler_(this), |
configure_status_(DataTypeManager::UNKNOWN), |
setup_in_progress_(false), |
- invalidator_state_(syncer::DEFAULT_INVALIDATION_ERROR) { |
+ invalidator_state_(syncer::DEFAULT_INVALIDATION_ERROR), |
+ access_token_(), |
tim (not reviewing)
2013/05/23 19:03:41
Remove these two initializers as they are not nece
pavely
2013/05/30 07:42:12
Done.
|
+ access_token_request_() { |
// By default, dev, canary, and unbranded Chromium users will go to the |
// development servers. Development servers have more features than standard |
// sync servers. Users with officially-branded Chrome stable and beta builds |
@@ -190,7 +185,7 @@ bool ProfileSyncService::IsSyncTokenAvailable() { |
TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
if (!token_service) |
return false; |
- return token_service->HasTokenForService(GaiaConstants::kSyncService); |
+ return token_service->HasOAuthLoginToken(); |
tim (not reviewing)
2013/05/23 19:03:41
Is there a better name than just "OAuthLoginToken"
Andrew T Wilson (Slow)
2013/05/24 14:10:15
I wonder if it's better to call OAuth2TokenService
pavely
2013/05/30 07:42:12
Done.
|
} |
#if defined(OS_ANDROID) |
bool ProfileSyncService::ShouldEnablePasswordSyncForAndroid() const { |
@@ -238,6 +233,12 @@ void ProfileSyncService::Initialize() { |
TrySyncDatatypePrefRecovery(); |
+ if (IsSyncTokenAvailable()) { |
+ // 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(); |
} |
@@ -414,10 +415,8 @@ SyncCredentials ProfileSyncService::GetCredentials() { |
SyncCredentials credentials; |
credentials.email = signin_->GetAuthenticatedUsername(); |
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()) { |
tim (not reviewing)
2013/05/23 19:03:41
Can you explain the semantics here in a comment if
Andrew T Wilson (Slow)
2013/05/24 14:10:15
Note the varying UMAs being logged. I do wonder if
pavely
2013/05/30 07:42:12
Like it was before if access token is empty then s
pavely
2013/05/30 07:42:12
Let me explain cases that you listed:
- In tempora
Andrew T Wilson (Slow)
2013/05/31 12:57:28
Is this true? I thought that sync would generate a
|
+ credentials.sync_token = access_token_; |
UMA_HISTOGRAM_BOOLEAN("Sync.CredentialsLost", false); |
} else { |
// We've lost our sync credentials (crbug.com/121755), so just make up some |
@@ -499,6 +498,11 @@ void ProfileSyncService::StartUp(StartUpDeferredOption deferred_option) { |
DCHECK(IsSyncEnabledAndLoggedIn()); |
+ if (access_token_.empty()) { |
tim (not reviewing)
2013/05/23 19:03:41
The relationship between TryStart and StartUp is t
pavely
2013/05/30 07:42:12
TryStart gathers all local information to decide i
|
+ RequestAccessToken(false, true); |
Andrew T Wilson (Slow)
2013/05/31 12:57:28
Should we only do this if deferred_option = STARTU
|
+ return; |
+ } |
+ |
last_synced_time_ = sync_prefs_.GetLastSyncedTime(); |
DCHECK(start_up_time_.is_null()); |
@@ -607,6 +611,25 @@ 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) { |
+ access_token_request_.reset(); |
tim (not reviewing)
2013/05/23 19:03:42
DCHECK(access_token_request_.get()) in both these
Andrew T Wilson (Slow)
2013/05/24 14:10:15
Actually, I think you should do DCHECK_EQ(access_t
pavely
2013/05/30 07:42:12
Done.
|
+ access_token_ = access_token; |
+ if (backend_) |
+ backend_->UpdateCredentials(GetCredentials()); |
+ else |
+ TryStart(); |
+} |
+ |
+void ProfileSyncService::OnGetTokenFailure( |
+ const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) { |
+ access_token_request_.reset(); |
+ UpdateAuthErrorState(error); |
+} |
+ |
void ProfileSyncService::EmitInvalidationForTest( |
const invalidation::ObjectId& id, |
const std::string& payload) { |
@@ -1029,10 +1052,14 @@ 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) { |
tim (not reviewing)
2013/05/23 19:03:42
Comment this - is this known to be a transient acc
pavely
2013/05/30 07:42:12
Done.
|
+ RequestAccessToken(true, true); |
+ } else { |
+ const GoogleServiceAuthError auth_error = |
+ ConnectionStatusToAuthError(status); |
+ DVLOG(1) << "Connection status change: " << auth_error.ToString(); |
+ UpdateAuthErrorState(auth_error); |
+ } |
} |
void ProfileSyncService::OnStopSyncingPermanently() { |
@@ -1777,6 +1804,31 @@ void ProfileSyncService::ConsumeCachedPassphraseIfPossible() { |
SetEncryptionPassphrase(passphrase, IMPLICIT); |
} |
+void ProfileSyncService::RequestAccessToken( |
+ bool invalidate_previous_token, |
+ bool invoke_callback) |
+{ |
tim (not reviewing)
2013/05/23 19:03:42
nit: { on previous line.
pavely
2013/05/30 07:42:12
Done.
|
+ // Only one active request at a time. |
+ if (access_token_request_ != NULL) |
tim (not reviewing)
2013/05/23 19:03:42
Think this should be a DCHECK?
Andrew T Wilson (Slow)
2013/05/24 14:10:15
I think this can happen in practice - there's noth
pavely
2013/05/30 07:42:12
Yes, there could be multiple calls to RequestAcces
|
+ 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 |
+ // token again |
+ token_service->InvalidateToken(oauth2_scopes, access_token_); |
+ access_token_ = std::string(); |
tim (not reviewing)
2013/05/23 19:03:42
use access_token_.clear()
pavely
2013/05/30 07:42:12
Done.
|
+ } |
+ 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(); |
Andrew T Wilson (Slow)
2013/05/24 14:10:15
I am confused by this - on startup, won't this cau
pavely
2013/05/30 07:42:12
I discussed this with Tim, the question was whenev
Andrew T Wilson (Slow)
2013/05/31 12:57:28
Is this a real concern? I didn't think we were tha
|
+ } |
+} |
+ |
void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase, |
PassphraseType type) { |
// This should only be called when the backend has been initialized. |
@@ -1883,7 +1935,8 @@ void ProfileSyncService::Observe(int type, |
const TokenService::TokenRequestFailedDetails& token_details = |
*(content::Details<const TokenService::TokenRequestFailedDetails>( |
details).ptr()); |
- if (IsTokenServiceRelevant(token_details.service()) && |
+ if (token_details.service() == |
+ GaiaConstants::kGaiaOAuth2LoginRefreshToken && |
Andrew T Wilson (Slow)
2013/05/24 14:10:15
I'd really like to see us get out of the "listen f
pavely
2013/05/30 07:42:12
Done.
|
!IsSyncTokenAvailable()) { |
// The additional check around IsSyncTokenAvailable() above prevents us |
// sounding the alarm if we actually have a valid token but a refresh |
@@ -1900,7 +1953,8 @@ void ProfileSyncService::Observe(int type, |
const TokenService::TokenAvailableDetails& token_details = |
*(content::Details<const TokenService::TokenAvailableDetails>( |
details).ptr()); |
- if (!IsTokenServiceRelevant(token_details.service())) |
+ if (token_details.service() != |
+ GaiaConstants::kGaiaOAuth2LoginRefreshToken) |
Andrew T Wilson (Slow)
2013/05/24 14:10:15
We should really move NOTIFICATION_TOKEN_AVAILABLE
pavely
2013/05/30 07:42:12
Done.
|
break; |
} // Fall through. |
case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: { |
@@ -1910,14 +1964,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); |
TryStart(); |
break; |
} |
case chrome::NOTIFICATION_TOKENS_CLEARED: { |
// GetCredentials() will generate invalid credentials to cause the backend |
// to generate an auth error. |
+ access_token_ = std::string(); |
tim (not reviewing)
2013/05/23 19:03:42
use .clear()
pavely
2013/05/30 07:42:12
Done.
|
if (backend_) |
backend_->UpdateCredentials(GetCredentials()); |
break; |