1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/signin/oauth2_token_service.h" 6 7 #include <vector> 8 9 #include "base/bind.h" 10 #include "base/memory/weak_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/rand_util.h" 13 #include "base/stl_util.h" 14 #include "base/time/time.h" 15 #include "base/timer/timer.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "google_apis/gaia/gaia_urls.h" 18 #include "google_apis/gaia/google_service_auth_error.h" 19 #include "google_apis/gaia/oauth2_access_token_consumer.h" 20 #include "google_apis/gaia/oauth2_access_token_fetcher.h" 21 #include "net/url_request/url_request_context_getter.h" 22 23 int OAuth2TokenService::max_fetch_retry_num_ = 5; 24 25 OAuth2TokenService::RequestImpl::RequestImpl( 26 OAuth2TokenService::Consumer* consumer) 27 : consumer_(consumer) { 28 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 29 } 30 31 OAuth2TokenService::RequestImpl::~RequestImpl() { 32 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 33 } 34 35 void OAuth2TokenService::RequestImpl::InformConsumer( 36 const GoogleServiceAuthError& error, 37 const std::string& access_token, 38 const base::Time& expiration_date) { 39 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 40 if (error.state() == GoogleServiceAuthError::NONE) 41 consumer_->OnGetTokenSuccess(this, access_token, expiration_date); 42 else 43 consumer_->OnGetTokenFailure(this, error); 44 } 45 46 // Class that fetches OAuth2 access tokens for given scopes and refresh token. 47 // 48 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry 49 // mechanism is used to handle failures. 50 // 51 // To use this class, call CreateAndStart() to create and start a Fetcher. 52 // 53 // The Fetcher will call back the service by calling 54 // OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is 55 // not destructed before it completes fetching; if the Fetcher is destructed 56 // before it completes fetching, the service will never be called back. The 57 // Fetcher destructs itself after calling back the service when finishes 58 // fetching. 59 // 60 // Requests that are waiting for the fetching results of this Fetcher can be 61 // added to the Fetcher by calling 62 // OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher completes 63 // fetching. 64 // 65 // The waiting requests are taken as weak pointers and they can be deleted. The 66 // waiting requests will be called back with fetching results if they are not 67 // deleted 68 // - when the Fetcher completes fetching, if the Fetcher is not destructed 69 // before it completes fetching, or 70 // - when the Fetcher is destructed if the Fetcher is destructed before it 71 // completes fetching (in this case, the waiting requests will be called back 72 // with error). 73 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer { 74 public: 75 // Creates a Fetcher and starts fetching an OAuth2 access token for 76 // |refresh_token| and |scopes| in the request context obtained by |getter|. 77 // The given |oauth2_token_service| will be informed when fetching is done. 78 static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service, 79 net::URLRequestContextGetter* getter, 80 const std::string& chrome_client_id, 81 const std::string& chrome_client_secret, 82 const std::string& refresh_token, 83 const OAuth2TokenService::ScopeSet& scopes, 84 base::WeakPtr<RequestImpl> waiting_request); 85 virtual ~Fetcher(); 86 87 // Add a request that is waiting for the result of this Fetcher. 88 void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request); 89 90 void Cancel(); 91 92 const OAuth2TokenService::ScopeSet& GetScopeSet() const; 93 const std::string& GetRefreshToken() const; 94 95 // The error result from this fetcher. 96 const GoogleServiceAuthError& error() const { return error_; } 97 98 protected: 99 // OAuth2AccessTokenConsumer 100 virtual void OnGetTokenSuccess(const std::string& access_token, 101 const base::Time& expiration_date) OVERRIDE; 102 virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; 103 104 private: 105 Fetcher(OAuth2TokenService* oauth2_token_service, 106 net::URLRequestContextGetter* getter, 107 const std::string& chrome_client_id, 108 const std::string& chrome_client_secret, 109 const std::string& refresh_token, 110 const OAuth2TokenService::ScopeSet& scopes, 111 base::WeakPtr<RequestImpl> waiting_request); 112 void Start(); 113 void InformWaitingRequests(); 114 void InformWaitingRequestsAndDelete(); 115 static bool ShouldRetry(const GoogleServiceAuthError& error); 116 int64 ComputeExponentialBackOffMilliseconds(int retry_num); 117 118 // |oauth2_token_service_| remains valid for the life of this Fetcher, since 119 // this Fetcher is destructed in the dtor of the OAuth2TokenService or is 120 // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess 121 // (whichever comes first). 122 OAuth2TokenService* const oauth2_token_service_; 123 scoped_refptr<net::URLRequestContextGetter> getter_; 124 const std::string refresh_token_; 125 const OAuth2TokenService::ScopeSet scopes_; 126 std::vector<base::WeakPtr<RequestImpl> > waiting_requests_; 127 128 int retry_number_; 129 base::OneShotTimer<OAuth2TokenService::Fetcher> retry_timer_; 130 scoped_ptr<OAuth2AccessTokenFetcher> fetcher_; 131 132 // Variables that store fetch results. 133 // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle 134 // destruction. 135 GoogleServiceAuthError error_; 136 std::string access_token_; 137 base::Time expiration_date_; 138 // OAuth2 client id and secret. 139 std::string chrome_client_id_; 140 std::string chrome_client_secret_; 141 142 DISALLOW_COPY_AND_ASSIGN(Fetcher); 143 }; 144 145 // static 146 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart( 147 OAuth2TokenService* oauth2_token_service, 148 net::URLRequestContextGetter* getter, 149 const std::string& chrome_client_id, 150 const std::string& chrome_client_secret, 151 const std::string& refresh_token, 152 const OAuth2TokenService::ScopeSet& scopes, 153 base::WeakPtr<RequestImpl> waiting_request) { 154 OAuth2TokenService::Fetcher* fetcher = new Fetcher( 155 oauth2_token_service, 156 getter, 157 chrome_client_id, 158 chrome_client_secret, 159 refresh_token, 160 scopes, 161 waiting_request); 162 fetcher->Start(); 163 return fetcher; 164 } 165 166 OAuth2TokenService::Fetcher::Fetcher( 167 OAuth2TokenService* oauth2_token_service, 168 net::URLRequestContextGetter* getter, 169 const std::string& chrome_client_id, 170 const std::string& chrome_client_secret, 171 const std::string& refresh_token, 172 const OAuth2TokenService::ScopeSet& scopes, 173 base::WeakPtr<RequestImpl> waiting_request) 174 : oauth2_token_service_(oauth2_token_service), 175 getter_(getter), 176 refresh_token_(refresh_token), 177 scopes_(scopes), 178 retry_number_(0), 179 error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE), 180 chrome_client_id_(chrome_client_id), 181 chrome_client_secret_(chrome_client_secret) { 182 DCHECK(oauth2_token_service_); 183 DCHECK(getter_.get()); 184 DCHECK(refresh_token_.length()); 185 waiting_requests_.push_back(waiting_request); 186 } 187 188 OAuth2TokenService::Fetcher::~Fetcher() { 189 // Inform the waiting requests if it has not done so. 190 if (waiting_requests_.size()) 191 InformWaitingRequests(); 192 } 193 194 void OAuth2TokenService::Fetcher::Start() { 195 fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_.get())); 196 fetcher_->Start(chrome_client_id_, 197 chrome_client_secret_, 198 refresh_token_, 199 std::vector<std::string>(scopes_.begin(), scopes_.end())); 200 retry_timer_.Stop(); 201 } 202 203 void OAuth2TokenService::Fetcher::OnGetTokenSuccess( 204 const std::string& access_token, 205 const base::Time& expiration_date) { 206 fetcher_.reset(); 207 208 // Fetch completes. 209 error_ = GoogleServiceAuthError::AuthErrorNone(); 210 access_token_ = access_token; 211 expiration_date_ = expiration_date; 212 213 // Subclasses may override this method to skip caching in some cases, but 214 // we still inform all waiting Consumers of a successful token fetch below. 215 // This is intentional -- some consumers may need the token for cleanup 216 // tasks. https://chromiumcodereview.appspot.com/11312124/ 217 oauth2_token_service_->RegisterCacheEntry(refresh_token_, 218 scopes_, 219 access_token_, 220 expiration_date_); 221 InformWaitingRequestsAndDelete(); 222 } 223 224 void OAuth2TokenService::Fetcher::OnGetTokenFailure( 225 const GoogleServiceAuthError& error) { 226 fetcher_.reset(); 227 228 if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) { 229 int64 backoff = ComputeExponentialBackOffMilliseconds(retry_number_); 230 ++retry_number_; 231 retry_timer_.Stop(); 232 retry_timer_.Start(FROM_HERE, 233 base::TimeDelta::FromMilliseconds(backoff), 234 this, 235 &OAuth2TokenService::Fetcher::Start); 236 return; 237 } 238 239 error_ = error; 240 InformWaitingRequestsAndDelete(); 241 } 242 243 // Returns an exponential backoff in milliseconds including randomness less than 244 // 1000 ms when retrying fetching an OAuth2 access token. 245 int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds( 246 int retry_num) { 247 DCHECK(retry_num < max_fetch_retry_num_); 248 int64 exponential_backoff_in_seconds = 1 << retry_num; 249 // Returns a backoff with randomness < 1000ms 250 return (exponential_backoff_in_seconds + base::RandDouble()) * 1000; 251 } 252 253 // static 254 bool OAuth2TokenService::Fetcher::ShouldRetry( 255 const GoogleServiceAuthError& error) { 256 GoogleServiceAuthError::State error_state = error.state(); 257 return error_state == GoogleServiceAuthError::CONNECTION_FAILED || 258 error_state == GoogleServiceAuthError::REQUEST_CANCELED || 259 error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE; 260 } 261 262 void OAuth2TokenService::Fetcher::InformWaitingRequests() { 263 std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter = 264 waiting_requests_.begin(); 265 for (; iter != waiting_requests_.end(); ++iter) { 266 base::WeakPtr<RequestImpl> waiting_request = *iter; 267 if (waiting_request.get()) 268 waiting_request->InformConsumer(error_, access_token_, expiration_date_); 269 } 270 waiting_requests_.clear(); 271 } 272 273 void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() { 274 // Deregisters itself from the service to prevent more waiting requests to 275 // be added when it calls back the waiting requests. 276 oauth2_token_service_->OnFetchComplete(this); 277 InformWaitingRequests(); 278 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 279 } 280 281 void OAuth2TokenService::Fetcher::AddWaitingRequest( 282 base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) { 283 waiting_requests_.push_back(waiting_request); 284 } 285 286 void OAuth2TokenService::Fetcher::Cancel() { 287 fetcher_.reset(); 288 retry_timer_.Stop(); 289 error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); 290 InformWaitingRequestsAndDelete(); 291 } 292 293 const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet() 294 const { 295 return scopes_; 296 } 297 298 const std::string& OAuth2TokenService::Fetcher::GetRefreshToken() const { 299 return refresh_token_; 300 } 301 302 OAuth2TokenService::Request::Request() { 303 } 304 305 OAuth2TokenService::Request::~Request() { 306 } 307 308 OAuth2TokenService::Consumer::Consumer() { 309 } 310 311 OAuth2TokenService::Consumer::~Consumer() { 312 } 313 314 OAuth2TokenService::OAuth2TokenService() { 315 } 316 317 OAuth2TokenService::~OAuth2TokenService() { 318 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 319 // Release all the pending fetchers. 320 STLDeleteContainerPairSecondPointers( 321 pending_fetchers_.begin(), pending_fetchers_.end()); 322 } 323 324 void OAuth2TokenService::AddObserver(Observer* observer) { 325 observer_list_.AddObserver(observer); 326 } 327 328 void OAuth2TokenService::RemoveObserver(Observer* observer) { 329 observer_list_.RemoveObserver(observer); 330 } 331 332 bool OAuth2TokenService::RefreshTokenIsAvailable() { 333 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 334 return !GetRefreshToken().empty(); 335 } 336 337 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( 338 const OAuth2TokenService::ScopeSet& scopes, 339 OAuth2TokenService::Consumer* consumer) { 340 return StartRequestForClientWithContext( 341 GetRequestContext(), 342 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), 343 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), 344 scopes, 345 consumer); 346 } 347 348 scoped_ptr<OAuth2TokenService::Request> 349 OAuth2TokenService::StartRequestForClient( 350 const std::string& client_id, 351 const std::string& client_secret, 352 const OAuth2TokenService::ScopeSet& scopes, 353 OAuth2TokenService::Consumer* consumer) { 354 return StartRequestForClientWithContext( 355 GetRequestContext(), 356 client_id, 357 client_secret, 358 scopes, 359 consumer); 360 } 361 362 scoped_ptr<OAuth2TokenService::Request> 363 OAuth2TokenService::StartRequestWithContext( 364 net::URLRequestContextGetter* getter, 365 const ScopeSet& scopes, 366 Consumer* consumer) { 367 return StartRequestForClientWithContext( 368 getter, 369 GaiaUrls::GetInstance()->oauth2_chrome_client_id(), 370 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), 371 scopes, 372 consumer); 373 } 374 375 scoped_ptr<OAuth2TokenService::Request> 376 OAuth2TokenService::StartRequestForClientWithContext( 377 net::URLRequestContextGetter* getter, 378 const std::string& client_id, 379 const std::string& client_secret, 380 const ScopeSet& scopes, 381 Consumer* consumer) { 382 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 383 384 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); 385 386 std::string refresh_token = GetRefreshToken(); 387 if (refresh_token.empty()) { 388 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 389 &RequestImpl::InformConsumer, 390 request->AsWeakPtr(), 391 GoogleServiceAuthError( 392 GoogleServiceAuthError::USER_NOT_SIGNED_UP), 393 std::string(), 394 base::Time())); 395 return request.PassAs<Request>(); 396 } 397 398 if (HasCacheEntry(scopes)) 399 return StartCacheLookupRequest(scopes, consumer); 400 401 // If there is already a pending fetcher for |scopes| and |refresh_token|, 402 // simply register this |request| for those results rather than starting 403 // a new fetcher. 404 FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes); 405 std::map<FetchParameters, Fetcher*>::iterator iter = 406 pending_fetchers_.find(fetch_parameters); 407 if (iter != pending_fetchers_.end()) { 408 iter->second->AddWaitingRequest(request->AsWeakPtr()); 409 return request.PassAs<Request>(); 410 } 411 412 pending_fetchers_[fetch_parameters] = 413 Fetcher::CreateAndStart(this, 414 getter, 415 client_id, 416 client_secret, 417 refresh_token, 418 scopes, 419 request->AsWeakPtr()); 420 return request.PassAs<Request>(); 421 } 422 423 scoped_ptr<OAuth2TokenService::Request> 424 OAuth2TokenService::StartCacheLookupRequest( 425 const OAuth2TokenService::ScopeSet& scopes, 426 OAuth2TokenService::Consumer* consumer) { 427 CHECK(HasCacheEntry(scopes)); 428 const CacheEntry* cache_entry = GetCacheEntry(scopes); 429 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); 430 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 431 &RequestImpl::InformConsumer, 432 request->AsWeakPtr(), 433 GoogleServiceAuthError(GoogleServiceAuthError::NONE), 434 cache_entry->access_token, 435 cache_entry->expiration_date)); 436 return request.PassAs<Request>(); 437 } 438 439 void OAuth2TokenService::InvalidateToken(const ScopeSet& scopes, 440 const std::string& invalid_token) { 441 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 442 RemoveCacheEntry(scopes, invalid_token); 443 } 444 445 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { 446 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 447 448 // Update the auth error state so auth errors are appropriately communicated 449 // to the user. 450 UpdateAuthError(fetcher->error()); 451 452 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh 453 // token and scope set. This is guaranteed as follows; here a Fetcher is said 454 // to be uncompleted if it has not finished calling back 455 // OAuth2TokenService::OnFetchComplete(). 456 // 457 // (1) All the live Fetchers are created by this service. 458 // This is because (1) all the live Fetchers are created by a live 459 // service, as all the fetchers created by a service are destructed in the 460 // service's dtor. 461 // 462 // (2) All the uncompleted Fetchers created by this service are recorded in 463 // |pending_fetchers_|. 464 // This is because (1) all the created Fetchers are added to 465 // |pending_fetchers_| (in method StartRequest()) and (2) method 466 // OnFetchComplete() is the only place where a Fetcher is erased from 467 // |pending_fetchers_|. Note no Fetcher is erased in method 468 // StartRequest(). 469 // 470 // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its 471 // refresh token and ScopeSet. This is guaranteed by Fetcher creation in 472 // method StartRequest(). 473 // 474 // When this method is called, |fetcher| is alive and uncompleted. 475 // By (1), |fetcher| is created by this service. 476 // Then by (2), |fetcher| is recorded in |pending_fetchers_|. 477 // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet. 478 std::map<FetchParameters, Fetcher*>::iterator iter = 479 pending_fetchers_.find(std::make_pair( 480 fetcher->GetRefreshToken(), fetcher->GetScopeSet())); 481 DCHECK(iter != pending_fetchers_.end()); 482 DCHECK_EQ(fetcher, iter->second); 483 pending_fetchers_.erase(iter); 484 } 485 486 bool OAuth2TokenService::HasCacheEntry( 487 const OAuth2TokenService::ScopeSet& scopes) { 488 const CacheEntry* cache_entry = GetCacheEntry(scopes); 489 return cache_entry && cache_entry->access_token.length(); 490 } 491 492 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry( 493 const OAuth2TokenService::ScopeSet& scopes) { 494 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 495 TokenCache::iterator token_iterator = token_cache_.find(scopes); 496 if (token_iterator == token_cache_.end()) 497 return NULL; 498 if (token_iterator->second.expiration_date <= base::Time::Now()) { 499 token_cache_.erase(token_iterator); 500 return NULL; 501 } 502 return &token_iterator->second; 503 } 504 505 bool OAuth2TokenService::RemoveCacheEntry( 506 const OAuth2TokenService::ScopeSet& scopes, 507 const std::string& token_to_remove) { 508 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 509 TokenCache::iterator token_iterator = token_cache_.find(scopes); 510 if (token_iterator != token_cache_.end() && 511 token_iterator->second.access_token == token_to_remove) { 512 token_cache_.erase(token_iterator); 513 return true; 514 } 515 return false; 516 } 517 518 void OAuth2TokenService::RegisterCacheEntry( 519 const std::string& refresh_token, 520 const OAuth2TokenService::ScopeSet& scopes, 521 const std::string& access_token, 522 const base::Time& expiration_date) { 523 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 524 525 CacheEntry& token = token_cache_[scopes]; 526 token.access_token = access_token; 527 token.expiration_date = expiration_date; 528 } 529 530 void OAuth2TokenService::UpdateAuthError(const GoogleServiceAuthError& error) { 531 // Default implementation does nothing. 532 } 533 534 void OAuth2TokenService::ClearCache() { 535 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 536 token_cache_.clear(); 537 } 538 539 void OAuth2TokenService::CancelAllRequests() { 540 std::vector<Fetcher*> fetchers_to_cancel; 541 for (std::map<FetchParameters, Fetcher*>::iterator iter = 542 pending_fetchers_.begin(); 543 iter != pending_fetchers_.end(); 544 ++iter) { 545 fetchers_to_cancel.push_back(iter->second); 546 } 547 CancelFetchers(fetchers_to_cancel); 548 } 549 550 void OAuth2TokenService::CancelRequestsForToken( 551 const std::string& refresh_token) { 552 std::vector<Fetcher*> fetchers_to_cancel; 553 for (std::map<FetchParameters, Fetcher*>::iterator iter = 554 pending_fetchers_.begin(); 555 iter != pending_fetchers_.end(); 556 ++iter) { 557 if (iter->first.first == refresh_token) 558 fetchers_to_cancel.push_back(iter->second); 559 } 560 CancelFetchers(fetchers_to_cancel); 561 } 562 563 void OAuth2TokenService::CancelFetchers( 564 std::vector<Fetcher*> fetchers_to_cancel) { 565 for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter = 566 fetchers_to_cancel.begin(); 567 iter != fetchers_to_cancel.end(); 568 ++iter) { 569 (*iter)->Cancel(); 570 } 571 } 572 573 void OAuth2TokenService::FireRefreshTokenAvailable( 574 const std::string& account_id) { 575 FOR_EACH_OBSERVER(Observer, observer_list_, 576 OnRefreshTokenAvailable(account_id)); 577 } 578 579 void OAuth2TokenService::FireRefreshTokenRevoked( 580 const std::string& account_id, 581 const GoogleServiceAuthError& error) { 582 FOR_EACH_OBSERVER(Observer, observer_list_, 583 OnRefreshTokenRevoked(account_id, error)); 584 } 585 586 void OAuth2TokenService::FireRefreshTokensLoaded() { 587 FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded()); 588 } 589 590 void OAuth2TokenService::FireRefreshTokensCleared() { 591 FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensCleared()); 592 } 593 594 int OAuth2TokenService::cache_size_for_testing() const { 595 return token_cache_.size(); 596 } 597 598 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing( 599 int max_retries) { 600 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 601 max_fetch_retry_num_ = max_retries; 602 } 603