Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: chrome/browser/invalidation/ticl_invalidation_service.cc

Issue 15580002: Make use of InvalidationService (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update with OAuth2 support Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/invalidation/ticl_invalidation_service.h" 5 #include "chrome/browser/invalidation/ticl_invalidation_service.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "chrome/browser/invalidation/invalidation_service_util.h" 8 #include "chrome/browser/invalidation/invalidation_service_util.h"
9 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/signin/profile_oauth2_token_service.h"
11 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
10 #include "chrome/browser/signin/signin_manager.h" 12 #include "chrome/browser/signin/signin_manager.h"
11 #include "chrome/browser/signin/token_service.h"
12 #include "chrome/common/chrome_notification_types.h" 13 #include "chrome/common/chrome_notification_types.h"
13 #include "content/public/browser/notification_service.h" 14 #include "content/public/browser/notification_service.h"
14 #include "google_apis/gaia/gaia_constants.h" 15 #include "google_apis/gaia/gaia_constants.h"
15 #include "sync/notifier/invalidator.h" 16 #include "sync/notifier/invalidator.h"
16 #include "sync/notifier/invalidator_state.h" 17 #include "sync/notifier/invalidator_state.h"
17 #include "sync/notifier/non_blocking_invalidator.h" 18 #include "sync/notifier/non_blocking_invalidator.h"
18 19
20 static const char* kOAuth2Scopes[] = {
21 GaiaConstants::kGoogleTalkOAuth2Scope
22 };
23
24 static const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
25 // Number of initial errors (in sequence) to ignore before applying
26 // exponential back-off rules.
27 0,
28
29 // Initial delay for exponential back-off in ms.
30 2000,
31
32 // Factor by which the waiting time will be multiplied.
33 2,
34
35 // Fuzzing percentage. ex: 10% will spread requests randomly
36 // between 90%-100% of the calculated time.
37 0.2, // 20%
38
39 // Maximum amount of time we are willing to delay our request in ms.
40 // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
41 // RequestAccessToken on connection state change after backoff
42 1000 * 3600 * 4, // 4 hours.
43
44 // Time to keep an entry from being discarded even when it
45 // has no significant state, -1 to never discard.
46 -1,
47
48 // Don't use initial delay unless the last request was an error.
49 false,
50 };
51
19 namespace invalidation { 52 namespace invalidation {
20 53
21 TiclInvalidationService::TiclInvalidationService(SigninManagerBase* signin, 54 TiclInvalidationService::TiclInvalidationService(
22 TokenService* token_service, 55 SigninManagerBase* signin,
23 Profile* profile) 56 TokenService* token_service,
24 : profile_(profile), 57 OAuth2TokenService* oauth2_token_service,
25 signin_manager_(signin), 58 Profile* profile)
26 token_service_(token_service), 59 : profile_(profile),
27 invalidator_registrar_(new syncer::InvalidatorRegistrar()) { } 60 signin_manager_(signin),
61 token_service_(token_service),
62 oauth2_token_service_(oauth2_token_service),
63 invalidator_registrar_(new syncer::InvalidatorRegistrar()),
64 request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy) {
65 }
28 66
29 TiclInvalidationService::~TiclInvalidationService() { 67 TiclInvalidationService::~TiclInvalidationService() {
30 DCHECK(CalledOnValidThread()); 68 DCHECK(CalledOnValidThread());
31 } 69 }
32 70
33 void TiclInvalidationService::Init() { 71 void TiclInvalidationService::Init() {
34 DCHECK(CalledOnValidThread()); 72 DCHECK(CalledOnValidThread());
35 73
36 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); 74 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs()));
37 if (invalidator_storage_->GetInvalidatorClientId().empty()) { 75 if (invalidator_storage_->GetInvalidatorClientId().empty()) {
38 // This also clears any existing state. We can't reuse old invalidator 76 // This also clears any existing state. We can't reuse old invalidator
39 // state with the new ID anyway. 77 // state with the new ID anyway.
40 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId()); 78 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId());
41 } 79 }
42 80
43 if (IsReadyToStart()) { 81 if (IsReadyToStart()) {
44 Start(); 82 StartInvalidator();
45 } 83 }
46 84
47 notification_registrar_.Add(this, 85 notification_registrar_.Add(this,
48 chrome::NOTIFICATION_TOKEN_AVAILABLE, 86 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
87 content::Source<Profile>(profile_));
88 notification_registrar_.Add(this,
89 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
49 content::Source<TokenService>(token_service_)); 90 content::Source<TokenService>(token_service_));
50 notification_registrar_.Add(this, 91 notification_registrar_.Add(this,
51 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, 92 chrome::NOTIFICATION_TOKENS_CLEARED,
52 content::Source<Profile>(profile_)); 93 content::Source<TokenService>(token_service_));
53 } 94 }
54 95
55 void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) { 96 void TiclInvalidationService::InitForTest(syncer::Invalidator* invalidator) {
56 // Here we perform the equivalent of Init() and Start(), but with some minor 97 // Here we perform the equivalent of Init() and StartInvalidator(), but with
57 // changes to account for the fact that we're injecting the invalidator. 98 // some minor changes to account for the fact that we're injecting the
99 // invalidator.
58 invalidator_.reset(invalidator); 100 invalidator_.reset(invalidator);
59 101
60 invalidator_->RegisterHandler(this); 102 invalidator_->RegisterHandler(this);
61 invalidator_->UpdateRegisteredIds( 103 invalidator_->UpdateRegisteredIds(
62 this, 104 this,
63 invalidator_registrar_->GetAllRegisteredIds()); 105 invalidator_registrar_->GetAllRegisteredIds());
64 } 106 }
65 107
66 void TiclInvalidationService::RegisterInvalidationHandler( 108 void TiclInvalidationService::RegisterInvalidationHandler(
67 syncer::InvalidationHandler* handler) { 109 syncer::InvalidationHandler* handler) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 return invalidator_storage_->GetInvalidatorClientId(); 163 return invalidator_storage_->GetInvalidatorClientId();
122 } 164 }
123 165
124 void TiclInvalidationService::Observe( 166 void TiclInvalidationService::Observe(
125 int type, 167 int type,
126 const content::NotificationSource& source, 168 const content::NotificationSource& source,
127 const content::NotificationDetails& details) { 169 const content::NotificationDetails& details) {
128 DCHECK(CalledOnValidThread()); 170 DCHECK(CalledOnValidThread());
129 171
130 switch (type) { 172 switch (type) {
131 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { 173 case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
132 const TokenService::TokenAvailableDetails& token_details = 174 if (!IsStarted() && IsReadyToStart()) {
133 *(content::Details<const TokenService::TokenAvailableDetails>( 175 StartInvalidator();
134 details).ptr());
135 if (token_details.service() == GaiaConstants::kSyncService) {
136 DCHECK(IsReadyToStart());
137 if (!IsStarted()) {
138 Start();
139 } else {
140 UpdateToken();
141 }
142 } 176 }
143 break; 177 break;
144 } 178 }
179 case chrome::NOTIFICATION_TOKENS_CLEARED: {
180 access_token_.clear();
181 if (IsStarted()) {
182 UpdateInvalidatorCredentials();
183 }
184 break;
185 }
145 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: { 186 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: {
146 Logout(); 187 Logout();
147 break; 188 break;
148 } 189 }
149 default: { 190 default: {
150 NOTREACHED(); 191 NOTREACHED();
151 } 192 }
152 } 193 }
153 } 194 }
154 195
196 void TiclInvalidationService::RequestAccessToken() {
197 // Only one active request at a time.
198 if (access_token_request_ != NULL)
199 return;
200 request_access_token_retry_timer_.Stop();
201 OAuth2TokenService::ScopeSet oauth2_scopes;
202 for (size_t i = 0; i < arraysize(kOAuth2Scopes); i++)
203 oauth2_scopes.insert(kOAuth2Scopes[i]);
204 OAuth2TokenService* token_service =
205 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
206 // Invalidate previous token, otherwise token service will return the same
207 // token again.
208 token_service->InvalidateToken(oauth2_scopes, access_token_);
209 access_token_.clear();
210 access_token_request_ = token_service->StartRequest(oauth2_scopes, this);
211 }
212
213 void TiclInvalidationService::OnGetTokenSuccess(
214 const OAuth2TokenService::Request* request,
215 const std::string& access_token,
216 const base::Time& expiration_time) {
217 DCHECK_EQ(access_token_request_, request);
218 access_token_request_.reset();
219 // Reset backoff time after successful response.
220 request_access_token_backoff_.Reset();
221 access_token_ = access_token;
222 if (!IsStarted()) {
223 StartInvalidator();
224 } else {
225 UpdateInvalidatorCredentials();
226 }
227 }
228
229 void TiclInvalidationService::OnGetTokenFailure(
230 const OAuth2TokenService::Request* request,
231 const GoogleServiceAuthError& error) {
232 DCHECK_EQ(access_token_request_, request);
233 DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
234 access_token_request_.reset();
235 switch (error.state()) {
236 case GoogleServiceAuthError::CONNECTION_FAILED:
237 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
238 // Transient error. Retry after some time.
239 request_access_token_backoff_.InformOfRequest(false);
240 request_access_token_retry_timer_.Start(
241 FROM_HERE,
242 request_access_token_backoff_.GetTimeUntilRelease(),
243 base::Bind(&TiclInvalidationService::RequestAccessToken,
244 base::Unretained(this)));
245 break;
246 }
247 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
248 // Now *this* is a real auth error.
249 invalidator_registrar_->UpdateInvalidatorState(
250 syncer::INVALIDATION_CREDENTIALS_REJECTED);
251 break;
252 }
253 default: {
254 // We have no way to notify the user of this. Do nothing.
255 }
256 }
257 }
258
155 void TiclInvalidationService::OnInvalidatorStateChange( 259 void TiclInvalidationService::OnInvalidatorStateChange(
156 syncer::InvalidatorState state) { 260 syncer::InvalidatorState state) {
157 invalidator_registrar_->UpdateInvalidatorState(state); 261 if (state == syncer::INVALIDATION_CREDENTIALS_REJECTED) {
rlarocque 2013/06/14 23:48:27 I decided against modifying SyncManager's invalida
262 // Don't report this as an auth error right away. It's possible that we
263 // just need to refresh our access token. If that fails, then we can update
264 // the user-facing state.
265 RequestAccessToken();
266 } else {
267 invalidator_registrar_->UpdateInvalidatorState(state);
268 }
158 } 269 }
159 270
160 void TiclInvalidationService::OnIncomingInvalidation( 271 void TiclInvalidationService::OnIncomingInvalidation(
161 const syncer::ObjectIdInvalidationMap& invalidation_map) { 272 const syncer::ObjectIdInvalidationMap& invalidation_map) {
162 invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map); 273 invalidator_registrar_->DispatchInvalidationsToHandlers(invalidation_map);
163 } 274 }
164 275
165 void TiclInvalidationService::Shutdown() { 276 void TiclInvalidationService::Shutdown() {
166 DCHECK(CalledOnValidThread()); 277 DCHECK(CalledOnValidThread());
167 if (IsStarted()) { 278 if (IsStarted()) {
168 StopInvalidator(); 279 StopInvalidator();
169 } 280 }
170 invalidator_storage_.reset(); 281 invalidator_storage_.reset();
171 invalidator_registrar_.reset(); 282 invalidator_registrar_.reset();
172 } 283 }
173 284
174 bool TiclInvalidationService::IsReadyToStart() { 285 bool TiclInvalidationService::IsReadyToStart() {
175 if (signin_manager_->GetAuthenticatedUsername().empty()) { 286 if (signin_manager_->GetAuthenticatedUsername().empty()) {
176 DVLOG(2) << "Not starting TiclInvalidationService: user is not signed in."; 287 DVLOG(2) << "Not starting TiclInvalidationService: user is not signed in.";
177 return false; 288 return false;
178 } 289 }
179 290
180 if (!token_service_) { 291 if (!oauth2_token_service_) {
181 DVLOG(2) 292 DVLOG(2)
182 << "Not starting TiclInvalidationService: TokenService unavailable."; 293 << "Not starting TiclInvalidationService: TokenService unavailable.";
183 return false; 294 return false;
184 } 295 }
185 296
186 if (!token_service_->HasTokenForService(GaiaConstants::kSyncService)) { 297 if (!oauth2_token_service_->RefreshTokenIsAvailable()) {
187 DVLOG(2) << "Not starting TiclInvalidationService: Sync token unavailable."; 298 DVLOG(2)
299 << "Not starting TiclInvalidationServce: Waiting for refresh token.";
188 return false; 300 return false;
189 } 301 }
190 302
191 return true; 303 return true;
192 } 304 }
193 305
194 bool TiclInvalidationService::IsStarted() { 306 bool TiclInvalidationService::IsStarted() {
195 return invalidator_.get() != NULL; 307 return invalidator_.get() != NULL;
196 } 308 }
197 309
198 void TiclInvalidationService::Start() { 310 void TiclInvalidationService::StartInvalidator() {
199 DCHECK(CalledOnValidThread()); 311 DCHECK(CalledOnValidThread());
200 DCHECK(!invalidator_); 312 DCHECK(!invalidator_);
201 DCHECK(invalidator_storage_); 313 DCHECK(invalidator_storage_);
202 DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty()); 314 DCHECK(!invalidator_storage_->GetInvalidatorClientId().empty());
203 315
316 if (access_token_.empty()) {
317 DVLOG(1)
318 << "TiclInvalidationService: "
319 << "Deferring start until we have an access token.";
320 RequestAccessToken();
321 return;
322 }
323
204 notifier::NotifierOptions options = 324 notifier::NotifierOptions options =
205 ParseNotifierOptions(*CommandLine::ForCurrentProcess()); 325 ParseNotifierOptions(*CommandLine::ForCurrentProcess());
206 options.request_context_getter = profile_->GetRequestContext(); 326 options.request_context_getter = profile_->GetRequestContext();
327 options.auth_mechanism = "X-OAUTH2";
207 invalidator_.reset(new syncer::NonBlockingInvalidator( 328 invalidator_.reset(new syncer::NonBlockingInvalidator(
208 options, 329 options,
209 invalidator_storage_->GetInvalidatorClientId(), 330 invalidator_storage_->GetInvalidatorClientId(),
210 invalidator_storage_->GetAllInvalidationStates(), 331 invalidator_storage_->GetAllInvalidationStates(),
211 invalidator_storage_->GetBootstrapData(), 332 invalidator_storage_->GetBootstrapData(),
212 syncer::WeakHandle<syncer::InvalidationStateTracker>( 333 syncer::WeakHandle<syncer::InvalidationStateTracker>(
213 invalidator_storage_->AsWeakPtr()), 334 invalidator_storage_->AsWeakPtr()),
214 content::GetUserAgent(GURL()))); 335 content::GetUserAgent(GURL())));
215 336
216 UpdateToken(); 337 UpdateInvalidatorCredentials();
217 338
218 invalidator_->RegisterHandler(this); 339 invalidator_->RegisterHandler(this);
219 invalidator_->UpdateRegisteredIds( 340 invalidator_->UpdateRegisteredIds(
220 this, 341 this,
221 invalidator_registrar_->GetAllRegisteredIds()); 342 invalidator_registrar_->GetAllRegisteredIds());
222 } 343 }
223 344
224 void TiclInvalidationService::UpdateToken() { 345 void TiclInvalidationService::UpdateInvalidatorCredentials() {
225 std::string email = signin_manager_->GetAuthenticatedUsername(); 346 std::string email = signin_manager_->GetAuthenticatedUsername();
347
226 DCHECK(!email.empty()) << "Expected user to be signed in."; 348 DCHECK(!email.empty()) << "Expected user to be signed in.";
227 DCHECK(token_service_->HasTokenForService(GaiaConstants::kSyncService)); 349 DCHECK(!access_token_.empty());
228
229 std::string sync_token = token_service_->GetTokenForService(
230 GaiaConstants::kSyncService);
231 350
232 DVLOG(2) << "UpdateCredentials: " << email; 351 DVLOG(2) << "UpdateCredentials: " << email;
233 invalidator_->UpdateCredentials(email, sync_token); 352 invalidator_->UpdateCredentials(email, access_token_);
234 } 353 }
235 354
236 void TiclInvalidationService::StopInvalidator() { 355 void TiclInvalidationService::StopInvalidator() {
237 DCHECK(invalidator_); 356 DCHECK(invalidator_);
238 invalidator_->UnregisterHandler(this); 357 invalidator_->UnregisterHandler(this);
239 invalidator_.reset(); 358 invalidator_.reset();
240 } 359 }
241 360
242 void TiclInvalidationService::Logout() { 361 void TiclInvalidationService::Logout() {
362 request_access_token_retry_timer_.Stop();
363
243 StopInvalidator(); 364 StopInvalidator();
244 365
245 // This service always expects to have a valid invalidator storage. 366 // This service always expects to have a valid invalidator storage.
246 // So we must not only clear the old one, but also start a new one. 367 // So we must not only clear the old one, but also start a new one.
247 invalidator_storage_->Clear(); 368 invalidator_storage_->Clear();
248 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); 369 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs()));
249 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId()); 370 invalidator_storage_->SetInvalidatorClientId(GenerateInvalidatorClientId());
250 } 371 }
251 372
252 } // namespace invalidation 373 } // namespace invalidation
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698