| 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);
 | 
|  }
 | 
| 
 |