11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/gcm_driver/gcm_account_mapper.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h" 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/guid.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/time/clock.h" 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/time/default_clock.h" 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/gcm_driver/gcm_driver_desktop.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "google_apis/gcm/engine/gcm_store.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace gcm { 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace { 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kGCMAccountMapperSenderId[] = "745476177629"; 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kGCMAccountMapperAppId[] = "com.google.android.gms"; 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kGCMAddMappingMessageTTL = 30 * 60; // 0.5 hours in seconds. 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kGCMRemoveMappingMessageTTL = 24 * 60 * 60; // 1 day in seconds. 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kGCMUpdateIntervalHours = 24; 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Because adding an account mapping dependents on a fresh OAuth2 token, we 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// allow the update to happen earlier than update due time, if it is within 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// the early start time to take advantage of that token. 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kGCMUpdateEarlyStartHours = 6; 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kRegistrationIdMessgaeKey[] = "id"; 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kTokenMessageKey[] = "t"; 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kAccountMessageKey[] = "a"; 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kRemoveAccountKey[] = "r"; 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kRemoveAccountValue[] = "1"; 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistd::string GenerateMessageID() { 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return base::GenerateGUID(); 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGCMAccountMapper::GCMAccountMapper(GCMDriver* gcm_driver) 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : gcm_driver_(gcm_driver), 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci clock_(new base::DefaultClock), 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci initialized_(false), 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci weak_ptr_factory_(this) { 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGCMAccountMapper::~GCMAccountMapper() { 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::Initialize( 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::vector<AccountMapping>& account_mappings) { 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(!initialized_); 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci initialized_ = true; 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci accounts_ = account_mappings; 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->AddAppHandler(kGCMAccountMapperAppId, this); 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GetRegistration(); 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::SetAccountTokens( 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::vector<GCMClient::AccountTokenInfo> account_tokens) { 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If account mapper is not ready to handle tasks yet, save the latest 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // account tokens and return. 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!IsReady()) { 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci pending_account_tokens_ = account_tokens; 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If mapper is initialized, but still does not have registration ID, 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // maybe the registration gave up. Retrying in case. 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (initialized_) 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GetRegistration(); 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Start from removing the old tokens, from all of the known accounts. 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (AccountMappings::iterator iter = accounts_.begin(); 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci iter != accounts_.end(); 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++iter) { 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci iter->access_token.clear(); 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Update the internal collection of mappings with the new tokens. 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (std::vector<GCMClient::AccountTokenInfo>::const_iterator token_iter = 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_tokens.begin(); 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci token_iter != account_tokens.end(); 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++token_iter) { 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AccountMapping* account_mapping = 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindMappingByAccountId(token_iter->account_id); 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!account_mapping) { 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AccountMapping new_mapping; 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci new_mapping.status = AccountMapping::NEW; 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci new_mapping.account_id = token_iter->account_id; 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci new_mapping.access_token = token_iter->access_token; 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci new_mapping.email = token_iter->email; 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci accounts_.push_back(new_mapping); 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Since we got a token for an account, drop the remove message and treat 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // it as mapped. 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping->status == AccountMapping::REMOVING) { 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->status = AccountMapping::MAPPED; 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->status_change_timestamp = base::Time(); 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->last_message_id.clear(); 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->email = token_iter->email; 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->access_token = token_iter->access_token; 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Decide what to do with each account (either start mapping, or start 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // removing). 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (AccountMappings::iterator mappings_iter = accounts_.begin(); 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mappings_iter != accounts_.end(); 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++mappings_iter) { 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mappings_iter->access_token.empty()) { 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Send a remove message if the account was not previously being removed, 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // or it doesn't have a pending message, or the pending message is 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // already expired, but OnSendError event was lost. 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mappings_iter->status != AccountMapping::REMOVING || 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mappings_iter->last_message_id.empty() || 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci IsLastStatusChangeOlderThanTTL(*mappings_iter)) { 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SendRemoveMappingMessage(*mappings_iter); 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // A message is sent for all of the mappings considered NEW, or mappings 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // that are ADDING, but have expired message (OnSendError event lost), or 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // for those mapped accounts that can be refreshed. 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (mappings_iter->status == AccountMapping::NEW || 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (mappings_iter->status == AccountMapping::ADDING && 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci IsLastStatusChangeOlderThanTTL(*mappings_iter)) || 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (mappings_iter->status == AccountMapping::MAPPED && 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CanTriggerUpdate(mappings_iter->status_change_timestamp))) { 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci mappings_iter->last_message_id.clear(); 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SendAddMappingMessage(*mappings_iter); 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::ShutdownHandler() { 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->RemoveAppHandler(kGCMAccountMapperAppId); 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::OnMessage(const std::string& app_id, 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const GCMClient::IncomingMessage& message) { 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Account message does not expect messages right now. 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::OnMessagesDeleted(const std::string& app_id) { 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Account message does not expect messages right now. 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::OnSendError( 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& app_id, 1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const GCMClient::SendErrorDetails& send_error_details) { 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(app_id, kGCMAccountMapperAppId); 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AccountMappings::iterator account_mapping_it = 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindMappingByMessageId(send_error_details.message_id); 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping_it == accounts_.end()) 1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (send_error_details.result != GCMClient::TTL_EXCEEDED) { 1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DVLOG(1) << "Send error result different than TTL EXCEEDED: " 1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << send_error_details.result << ". " 1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Postponing the retry until a new batch of tokens arrives."; 1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping_it->status == AccountMapping::REMOVING) { 1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Another message to remove mapping can be sent immediately, because TTL 1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // for those is one day. No need to back off. 1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SendRemoveMappingMessage(*account_mapping_it); 1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping_it->status == AccountMapping::ADDING) { 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // There is no mapping established, so we can remove the entry. 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Getting a fresh token will trigger a new attempt. 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->RemoveAccountMapping(account_mapping_it->account_id); 1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci accounts_.erase(account_mapping_it); 1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Account is already MAPPED, we have to wait for another token. 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping_it->last_message_id.clear(); 1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->UpdateAccountMapping(*account_mapping_it); 1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::OnSendAcknowledged(const std::string& app_id, 1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& message_id) { 1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_EQ(app_id, kGCMAccountMapperAppId); 1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AccountMappings::iterator account_mapping_it = 1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindMappingByMessageId(message_id); 1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DVLOG(1) << "OnSendAcknowledged with message ID: " << message_id; 1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping_it == accounts_.end()) 1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Here is where we advance a status of a mapping and persist or remove. 1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping_it->status == AccountMapping::REMOVING) { 1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Message removing the account has been confirmed by the GCM, we can remove 1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // all the information related to the account (from memory and store). 2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->RemoveAccountMapping(account_mapping_it->account_id); 2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci accounts_.erase(account_mapping_it); 2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Mapping status is ADDING only when it is a first time mapping. 2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(account_mapping_it->status == AccountMapping::ADDING || 2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping_it->status == AccountMapping::MAPPED); 2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Account is marked as mapped with the current time. 2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping_it->status = AccountMapping::MAPPED; 2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping_it->status_change_timestamp = clock_->Now(); 2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // There is no pending message for the account. 2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping_it->last_message_id.clear(); 2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->UpdateAccountMapping(*account_mapping_it); 2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool GCMAccountMapper::CanHandle(const std::string& app_id) const { 2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return app_id.compare(kGCMAccountMapperAppId) == 0; 2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool GCMAccountMapper::IsReady() { 2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return initialized_ && !registration_id_.empty(); 2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::SendAddMappingMessage(AccountMapping& account_mapping) { 2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CreateAndSendMessage(account_mapping); 2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::SendRemoveMappingMessage( 2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AccountMapping& account_mapping) { 2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // We want to persist an account that is being removed as quickly as possible 2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // as well as clean up the last message information. 2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping.status != AccountMapping::REMOVING) { 2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping.status = AccountMapping::REMOVING; 2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping.status_change_timestamp = clock_->Now(); 2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping.last_message_id.clear(); 2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->UpdateAccountMapping(account_mapping); 2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CreateAndSendMessage(account_mapping); 2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::CreateAndSendMessage( 2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const AccountMapping& account_mapping) { 2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GCMClient::OutgoingMessage outgoing_message; 2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.id = GenerateMessageID(); 2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.data[kRegistrationIdMessgaeKey] = registration_id_; 2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.data[kAccountMessageKey] = account_mapping.email; 2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping.status == AccountMapping::REMOVING) { 2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.time_to_live = kGCMRemoveMappingMessageTTL; 2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.data[kRemoveAccountKey] = kRemoveAccountValue; 2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.data[kTokenMessageKey] = account_mapping.access_token; 2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message.time_to_live = kGCMAddMappingMessageTTL; 2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->Send(kGCMAccountMapperAppId, 2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci kGCMAccountMapperSenderId, 2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci outgoing_message, 2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&GCMAccountMapper::OnSendFinished, 2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci weak_ptr_factory_.GetWeakPtr(), 2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping.account_id)); 2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::OnSendFinished(const std::string& account_id, 2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& message_id, 2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GCMClient::Result result) { 2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // TODO(fgorski): Add another attempt, in case the QUEUE is not full. 2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (result != GCMClient::SUCCESS) 2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AccountMapping* account_mapping = FindMappingByAccountId(account_id); 2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(account_mapping); 2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If we are dealing with account with status NEW, it is the first time 2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // mapping, and we should mark it as ADDING. 2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (account_mapping->status == AccountMapping::NEW) { 2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->status = AccountMapping::ADDING; 2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->status_change_timestamp = clock_->Now(); 2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_mapping->last_message_id = message_id; 2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->UpdateAccountMapping(*account_mapping); 2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::GetRegistration() { 2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(registration_id_.empty()); 2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::vector<std::string> sender_ids; 2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sender_ids.push_back(kGCMAccountMapperSenderId); 2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gcm_driver_->Register(kGCMAccountMapperAppId, 2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sender_ids, 2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&GCMAccountMapper::OnRegisterFinished, 2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci weak_ptr_factory_.GetWeakPtr())); 2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::OnRegisterFinished(const std::string& registration_id, 3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GCMClient::Result result) { 3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (result == GCMClient::SUCCESS) 3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci registration_id_ = registration_id; 3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (IsReady()) { 3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!pending_account_tokens_.empty()) { 3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetAccountTokens(pending_account_tokens_); 3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci pending_account_tokens_.clear(); 3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool GCMAccountMapper::CanTriggerUpdate( 3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const base::Time& last_update_time) const { 3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return last_update_time + 3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::TimeDelta::FromHours(kGCMUpdateIntervalHours - 3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci kGCMUpdateEarlyStartHours) < 3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci clock_->Now(); 3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool GCMAccountMapper::IsLastStatusChangeOlderThanTTL( 3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const AccountMapping& account_mapping) const { 3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int ttl_seconds = account_mapping.status == AccountMapping::REMOVING ? 3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci kGCMRemoveMappingMessageTTL : kGCMAddMappingMessageTTL; 3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return account_mapping.status_change_timestamp + 3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::TimeDelta::FromSeconds(ttl_seconds) < clock_->Now(); 3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciAccountMapping* GCMAccountMapper::FindMappingByAccountId( 3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const std::string& account_id) { 3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (AccountMappings::iterator iter = accounts_.begin(); 3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci iter != accounts_.end(); 3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++iter) { 3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (iter->account_id == account_id) 3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return &*iter; 3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return NULL; 3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGCMAccountMapper::AccountMappings::iterator 3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGCMAccountMapper::FindMappingByMessageId(const std::string& message_id) { 3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (std::vector<AccountMapping>::iterator iter = accounts_.begin(); 3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci iter != accounts_.end(); 3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++iter) { 3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (iter->last_message_id == message_id) 3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return iter; 3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return accounts_.end(); 3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GCMAccountMapper::SetClockForTesting(scoped_ptr<base::Clock> clock) { 3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci clock_ = clock.Pass(); 3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} // namespace gcm 358