Index: components/gcm_driver/gcm_client_impl.cc |
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc |
index e36d36c79735e46432bac2d1fb6764b0de917f43..2000403b63bc72239410ee6627d104210c4117cd 100644 |
--- a/components/gcm_driver/gcm_client_impl.cc |
+++ b/components/gcm_driver/gcm_client_impl.cc |
@@ -247,6 +247,31 @@ scoped_ptr<ConnectionFactory> GCMInternalsBuilder::BuildConnectionFactory( |
recorder)); |
} |
+GCMClientImpl::CheckinInfo::CheckinInfo() |
+ : android_id(0), secret(0), accounts_set(false) { |
+} |
+ |
+GCMClientImpl::CheckinInfo::~CheckinInfo() { |
+} |
+ |
+void GCMClientImpl::CheckinInfo::SnapshotCheckinAccounts() { |
+ last_checkin_accounts.clear(); |
+ for (std::map<std::string, std::string>::iterator iter = |
+ account_tokens.begin(); |
+ iter != account_tokens.end(); |
+ ++iter) { |
+ last_checkin_accounts.insert(iter->first); |
+ } |
+} |
+ |
+void GCMClientImpl::CheckinInfo::Reset() { |
+ android_id = 0; |
+ secret = 0; |
+ accounts_set = false; |
+ account_tokens.clear(); |
+ last_checkin_accounts.clear(); |
+} |
+ |
GCMClientImpl::GCMClientImpl(scoped_ptr<GCMInternalsBuilder> internals_builder) |
: internals_builder_(internals_builder.Pass()), |
state_(UNINITIALIZED), |
@@ -314,6 +339,14 @@ void GCMClientImpl::OnLoadCompleted(scoped_ptr<GCMStore::LoadResult> result) { |
registrations_ = result->registrations; |
device_checkin_info_.android_id = result->device_android_id; |
device_checkin_info_.secret = result->device_security_token; |
+ device_checkin_info_.last_checkin_accounts = result->last_checkin_accounts; |
+ // A case where there were previously no accounts reported with checkin is |
+ // considered to be the same as when the list of accounts is empty. It enables |
+ // scheduling a periodic checkin for devices with no signed in users |
+ // immediately after restart, while keeping |accounts_set == false| delays the |
+ // checkin until the list of accounts is set explicitly. |
+ if (result->last_checkin_accounts.size() == 0) |
+ device_checkin_info_.accounts_set = true; |
last_checkin_time_ = result->last_checkin_time; |
gservices_settings_.UpdateFromLoadResult(*result); |
InitializeMCSClient(result.Pass()); |
@@ -363,6 +396,9 @@ void GCMClientImpl::OnFirstTimeDeviceCheckinCompleted( |
device_checkin_info_.android_id = checkin_info.android_id; |
device_checkin_info_.secret = checkin_info.secret; |
+ // If accounts were not set by now, we can consider them set (to empty list) |
+ // to make sure periodic checkins get scheduled after initial checkin. |
+ device_checkin_info_.accounts_set = true; |
gcm_store_->SetDeviceCredentials( |
checkin_info.android_id, checkin_info.secret, |
base::Bind(&GCMClientImpl::SetDeviceCredentialsCallback, |
@@ -390,6 +426,43 @@ void GCMClientImpl::ResetState() { |
// TODO(fgorski): reset all of the necessart objects and start over. |
} |
+void GCMClientImpl::SetAccountsForCheckin( |
+ const std::map<std::string, std::string>& account_tokens) { |
+ bool accounts_set_before = device_checkin_info_.accounts_set; |
+ device_checkin_info_.account_tokens = account_tokens; |
+ device_checkin_info_.accounts_set = true; |
+ |
+ DVLOG(1) << "Set account called with: " << account_tokens.size() |
+ << " accounts."; |
+ |
+ if (state_ != READY && state_ != INITIAL_DEVICE_CHECKIN) |
+ return; |
+ |
+ bool account_removed = false; |
+ for (std::set<std::string>::iterator iter = |
+ device_checkin_info_.last_checkin_accounts.begin(); |
+ iter != device_checkin_info_.last_checkin_accounts.end(); |
+ ++iter) { |
+ if (account_tokens.find(*iter) == account_tokens.end()) |
+ account_removed = true; |
+ } |
+ |
+ // Checkin will be forced when any of the accounts was removed during the |
+ // current Chrome session or if there has been an account removed between the |
+ // restarts of Chrome. If there is a checkin in progress, it will be canceled. |
+ // We only force checkin when user signs out. When there is a new account |
+ // signed in, the periodic checkin will take care of adding the association in |
+ // reasonable time. |
+ if (account_removed) { |
+ DVLOG(1) << "Detected that account has been removed. Forcing checkin."; |
+ checkin_request_.reset(); |
+ StartCheckin(); |
+ } else if (!accounts_set_before) { |
+ SchedulePeriodicCheckin(); |
+ DVLOG(1) << "Accounts set for the first time. Scheduled periodic checkin."; |
+ } |
+} |
+ |
void GCMClientImpl::StartCheckin() { |
// Make sure no checkin is in progress. |
if (checkin_request_.get()) |
@@ -399,6 +472,7 @@ void GCMClientImpl::StartCheckin() { |
ToCheckinProtoVersion(chrome_build_info_, &chrome_build_proto); |
CheckinRequest::RequestInfo request_info(device_checkin_info_.android_id, |
device_checkin_info_.secret, |
+ device_checkin_info_.account_tokens, |
gservices_settings_.digest(), |
chrome_build_proto); |
checkin_request_.reset( |
@@ -409,6 +483,9 @@ void GCMClientImpl::StartCheckin() { |
weak_ptr_factory_.GetWeakPtr()), |
url_request_context_getter_, |
&recorder_)); |
+ // Taking a snapshot of the accounts count here, as there might be an asynch |
+ // update of the account tokens while checkin is in progress. |
+ device_checkin_info_.SnapshotCheckinAccounts(); |
checkin_request_->Start(); |
} |
@@ -448,9 +525,10 @@ void GCMClientImpl::OnCheckinCompleted( |
} |
last_checkin_time_ = clock_->Now(); |
- gcm_store_->SetLastCheckinTime( |
+ gcm_store_->SetLastCheckinInfo( |
last_checkin_time_, |
- base::Bind(&GCMClientImpl::SetLastCheckinTimeCallback, |
+ device_checkin_info_.last_checkin_accounts, |
+ base::Bind(&GCMClientImpl::SetLastCheckinInfoCallback, |
weak_ptr_factory_.GetWeakPtr())); |
SchedulePeriodicCheckin(); |
} |
@@ -462,7 +540,7 @@ void GCMClientImpl::SetGServicesSettingsCallback(bool success) { |
void GCMClientImpl::SchedulePeriodicCheckin() { |
// Make sure no checkin is in progress. |
- if (checkin_request_.get()) |
+ if (checkin_request_.get() || !device_checkin_info_.accounts_set) |
return; |
// There should be only one periodic checkin pending at a time. Removing |
@@ -485,7 +563,7 @@ base::TimeDelta GCMClientImpl::GetTimeToNextCheckin() const { |
clock_->Now(); |
} |
-void GCMClientImpl::SetLastCheckinTimeCallback(bool success) { |
+void GCMClientImpl::SetLastCheckinInfoCallback(bool success) { |
// TODO(fgorski): This is one of the signals that store needs a rebuild. |
DCHECK(success); |
} |