Chromium Code Reviews| Index: chrome/browser/services/gcm/gcm_account_tracker.cc |
| diff --git a/chrome/browser/services/gcm/gcm_account_tracker.cc b/chrome/browser/services/gcm/gcm_account_tracker.cc |
| index 8779b47a2d995a582aa41ea1ef9e4babf52b4a99..f971cca641a2a5d356383fc813e796d3493658f0 100644 |
| --- a/chrome/browser/services/gcm/gcm_account_tracker.cc |
| +++ b/chrome/browser/services/gcm/gcm_account_tracker.cc |
| @@ -7,19 +7,30 @@ |
| #include <algorithm> |
| #include <vector> |
| +#include "base/prefs/pref_service.h" |
| #include "base/time/time.h" |
| #include "components/gcm_driver/gcm_driver.h" |
| +#include "components/pref_registry/pref_registry_syncable.h" |
| #include "google_apis/gaia/google_service_auth_error.h" |
| #include "net/base/ip_endpoint.h" |
| namespace gcm { |
| namespace { |
| + |
| +// Scopes needed by the OAuth2 access tokens. |
| const char kGCMGroupServerScope[] = "https://www.googleapis.com/auth/gcm"; |
| const char kGCMCheckinServerScope[] = |
| "https://www.googleapis.com/auth/android_checkin"; |
| +// Name of the GCM account tracker for the OAuth2TokenService. |
| const char kGCMAccountTrackerName[] = "gcm_account_tracker"; |
| +// Minimum token validity when sending to GCM groups server. |
| const int64 kMinimumTokenValidityMs = 500; |
| +// Token fetching interval, when no account changes are detected. |
| +const int64 kTokenFetchingIntervalMs = 12 * 60 * 60 * 1000; // 12 hours in ms. |
| +// Preference name for last token fetching timestamp. |
| +const char kGCMLastTokenFetchingTs[] = "gcm.last_token_fetching_ts"; |
| + |
| } // namespace |
| GCMAccountTracker::AccountInfo::AccountInfo(const std::string& email, |
| @@ -30,13 +41,28 @@ GCMAccountTracker::AccountInfo::AccountInfo(const std::string& email, |
| GCMAccountTracker::AccountInfo::~AccountInfo() { |
| } |
| +// static |
| +void GCMAccountTracker::RegisterProfilePrefs( |
| + user_prefs::PrefRegistrySyncable* registry) { |
| + registry->RegisterInt64Pref( |
| + kGCMLastTokenFetchingTs, |
|
Nicolas Zea
2014/10/08 00:45:29
remind me why we store this in the prefs rather th
fgorski
2014/11/06 01:16:14
Done.
|
| + 0L, |
| + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| +} |
| + |
| GCMAccountTracker::GCMAccountTracker( |
| scoped_ptr<gaia::AccountTracker> account_tracker, |
| - GCMDriver* driver) |
| + GCMDriver* driver, |
| + PrefService* prefs) |
| : OAuth2TokenService::Consumer(kGCMAccountTrackerName), |
| account_tracker_(account_tracker.release()), |
| driver_(driver), |
| - shutdown_called_(false) { |
| + shutdown_called_(false), |
| + prefs_(prefs), |
| + weak_ptr_factory_(this) { |
| + int64 last_token_fetch_internal = prefs_->GetInt64(kGCMLastTokenFetchingTs); |
| + last_token_fetch_time_ = |
| + base::Time::FromInternalValue(last_token_fetch_internal); |
| } |
| GCMAccountTracker::~GCMAccountTracker() { |
| @@ -56,11 +82,6 @@ void GCMAccountTracker::Start() { |
| driver_->AddConnectionObserver(this); |
| std::vector<gaia::AccountIds> accounts = account_tracker_->GetAccounts(); |
| - if (accounts.empty()) { |
| - CompleteCollectingTokens(); |
| - return; |
| - } |
| - |
| for (std::vector<gaia::AccountIds>::const_iterator iter = accounts.begin(); |
| iter != accounts.end(); |
| ++iter) { |
| @@ -70,7 +91,23 @@ void GCMAccountTracker::Start() { |
| } |
| } |
| - GetAllNeededTokens(); |
| + ScheduleFetchingTokens(); |
| +} |
| + |
| +void GCMAccountTracker::ScheduleFetchingTokens() { |
| + if (!IsTokenReportingRequired()) { |
| + DVLOG(1) << "Deferring the token fetching for: " |
| + << GetTimeToNextTokenFetching().InSeconds() << " seconds."; |
| + base::MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&GCMAccountTracker::ReportTokens, |
| + weak_ptr_factory_.GetWeakPtr()), |
| + GetTimeToNextTokenFetching()); |
| + return; |
| + } |
| + |
| + DVLOG(1) << "Token fetching is due calling Complete immediately."; |
| + ReportTokens(); |
| } |
| void GCMAccountTracker::OnAccountAdded(const gaia::AccountIds& ids) { |
| @@ -115,7 +152,7 @@ void GCMAccountTracker::OnGetTokenSuccess( |
| } |
| DeleteTokenRequest(request); |
| - CompleteCollectingTokens(); |
| + ReportTokens(); |
| } |
| void GCMAccountTracker::OnGetTokenFailure( |
| @@ -137,21 +174,22 @@ void GCMAccountTracker::OnGetTokenFailure( |
| } |
| DeleteTokenRequest(request); |
| - CompleteCollectingTokens(); |
| + ReportTokens(); |
| } |
| void GCMAccountTracker::OnConnected(const net::IPEndPoint& ip_endpoint) { |
| - if (SanitizeTokens()) |
| - GetAllNeededTokens(); |
| + if (IsTokenReportingRequired()) |
| + ReportTokens(); |
| } |
| void GCMAccountTracker::OnDisconnected() { |
| // We are disconnected, so no point in trying to work with tokens. |
| } |
| -void GCMAccountTracker::CompleteCollectingTokens() { |
| +void GCMAccountTracker::ReportTokens() { |
| + SanitizeTokens(); |
| // Make sure all tokens are valid. |
| - if (SanitizeTokens()) { |
| + if (IsTokenFetchingRequired()) { |
| GetAllNeededTokens(); |
| return; |
| } |
| @@ -208,6 +246,15 @@ void GCMAccountTracker::CompleteCollectingTokens() { |
| if (!account_tokens.empty() || account_removed) { |
| DVLOG(1) << "Reporting the tokens to driver: " << account_tokens.size(); |
| driver_->SetAccountTokens(account_tokens); |
| + last_token_fetch_time_ = base::Time::Now(); |
| + prefs_->SetInt64(kGCMLastTokenFetchingTs, |
| + last_token_fetch_time_.ToInternalValue()); |
| + weak_ptr_factory_.InvalidateWeakPtrs(); |
| + base::MessageLoop::current()->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&GCMAccountTracker::ReportTokens, |
| + weak_ptr_factory_.GetWeakPtr()), |
| + GetTimeToNextTokenFetching()); |
| } else { |
| DVLOG(1) << "No tokens and nothing removed. Skipping callback."; |
| } |
| @@ -234,6 +281,42 @@ bool GCMAccountTracker::SanitizeTokens() { |
| return tokens_needed; |
| } |
| +bool GCMAccountTracker::IsTokenReportingRequired() { |
| + if (GetTimeToNextTokenFetching() == base::TimeDelta()) |
| + return true; |
| + |
| + bool reporting_required = false; |
| + for (AccountInfos::iterator iter = account_infos_.begin(); |
| + iter != account_infos_.end(); |
| + ++iter) { |
| + if (iter->second.state == ACCOUNT_REMOVED) |
| + reporting_required = true; |
| + } |
| + |
| + return reporting_required; |
| +} |
| + |
| +bool GCMAccountTracker::IsTokenFetchingRequired() { |
| + bool token_needed = false; |
| + for (AccountInfos::iterator iter = account_infos_.begin(); |
| + iter != account_infos_.end(); |
| + ++iter) { |
| + if (iter->second.state == TOKEN_NEEDED) |
| + token_needed = true; |
| + } |
| + |
| + return token_needed; |
| +} |
| + |
| +base::TimeDelta GCMAccountTracker::GetTimeToNextTokenFetching() { |
| + base::TimeDelta time_till_next_fetching = |
| + last_token_fetch_time_ + |
| + base::TimeDelta::FromMilliseconds(kTokenFetchingIntervalMs) - |
| + base::Time::Now(); |
| + return time_till_next_fetching < base::TimeDelta() ? base::TimeDelta() |
| + : time_till_next_fetching; |
| +} |
| + |
| void GCMAccountTracker::DeleteTokenRequest( |
| const OAuth2TokenService::Request* request) { |
| ScopedVector<OAuth2TokenService::Request>::iterator iter = std::find( |
| @@ -245,6 +328,9 @@ void GCMAccountTracker::DeleteTokenRequest( |
| void GCMAccountTracker::GetAllNeededTokens() { |
| // Only start fetching tokens if driver is running, they have a limited |
| // validity time and GCM connection is a good indication of network running. |
| + // If the GetAllNeededTokens was called as part of periodic schedule, it may |
| + // not have network. In that case the next network change will trigger token |
| + // fetching. |
| if (!driver_->IsConnected()) |
| return; |
| @@ -292,7 +378,7 @@ void GCMAccountTracker::OnAccountSignedOut(const gaia::AccountIds& ids) { |
| iter->second.access_token.clear(); |
| iter->second.state = ACCOUNT_REMOVED; |
| - CompleteCollectingTokens(); |
| + ReportTokens(); |
| } |
| OAuth2TokenService* GCMAccountTracker::GetTokenService() { |