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() { |