account_tracker.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "google_apis/gaia/account_tracker.h" 6 7#include "base/logging.h" 8#include "base/stl_util.h" 9#include "net/url_request/url_request_context_getter.h" 10 11namespace gaia { 12 13AccountTracker::AccountTracker( 14 IdentityProvider* identity_provider, 15 net::URLRequestContextGetter* request_context_getter) 16 : identity_provider_(identity_provider), 17 request_context_getter_(request_context_getter), 18 shutdown_called_(false) { 19 identity_provider_->AddObserver(this); 20 identity_provider_->GetTokenService()->AddObserver(this); 21} 22 23AccountTracker::~AccountTracker() { 24 DCHECK(shutdown_called_); 25} 26 27void AccountTracker::Shutdown() { 28 shutdown_called_ = true; 29 STLDeleteValues(&user_info_requests_); 30 identity_provider_->GetTokenService()->RemoveObserver(this); 31 identity_provider_->RemoveObserver(this); 32} 33 34void AccountTracker::AddObserver(Observer* observer) { 35 observer_list_.AddObserver(observer); 36} 37 38void AccountTracker::RemoveObserver(Observer* observer) { 39 observer_list_.RemoveObserver(observer); 40} 41 42std::vector<AccountIds> AccountTracker::GetAccounts() const { 43 const std::string active_account_id = 44 identity_provider_->GetActiveAccountId(); 45 std::vector<AccountIds> accounts; 46 47 for (std::map<std::string, AccountState>::const_iterator it = 48 accounts_.begin(); 49 it != accounts_.end(); 50 ++it) { 51 const AccountState& state = it->second; 52 bool is_visible = state.is_signed_in && !state.ids.gaia.empty(); 53 54 if (it->first == active_account_id) { 55 if (is_visible) 56 accounts.insert(accounts.begin(), state.ids); 57 else 58 return std::vector<AccountIds>(); 59 60 } else if (is_visible) { 61 accounts.push_back(state.ids); 62 } 63 } 64 return accounts; 65} 66 67AccountIds AccountTracker::FindAccountIdsByGaiaId(const std::string& gaia_id) { 68 for (std::map<std::string, AccountState>::const_iterator it = 69 accounts_.begin(); 70 it != accounts_.end(); 71 ++it) { 72 const AccountState& state = it->second; 73 if (state.ids.gaia == gaia_id) { 74 return state.ids; 75 } 76 } 77 78 return AccountIds(); 79} 80 81void AccountTracker::OnRefreshTokenAvailable(const std::string& account_id) { 82 // Ignore refresh tokens if there is no active account ID at all. 83 if (identity_provider_->GetActiveAccountId().empty()) 84 return; 85 86 DVLOG(1) << "AVAILABLE " << account_id; 87 UpdateSignInState(account_id, true); 88} 89 90void AccountTracker::OnRefreshTokenRevoked(const std::string& account_id) { 91 DVLOG(1) << "REVOKED " << account_id; 92 UpdateSignInState(account_id, false); 93} 94 95void AccountTracker::OnActiveAccountLogin() { 96 std::vector<std::string> accounts = 97 identity_provider_->GetTokenService()->GetAccounts(); 98 99 DVLOG(1) << "LOGIN " << accounts.size() << " accounts available."; 100 101 for (std::vector<std::string>::const_iterator it = accounts.begin(); 102 it != accounts.end(); 103 ++it) { 104 OnRefreshTokenAvailable(*it); 105 } 106} 107 108void AccountTracker::OnActiveAccountLogout() { 109 DVLOG(1) << "LOGOUT"; 110 StopTrackingAllAccounts(); 111} 112 113void AccountTracker::SetAccountStateForTest(AccountIds ids, bool is_signed_in) { 114 accounts_[ids.account_key].ids = ids; 115 accounts_[ids.account_key].is_signed_in = is_signed_in; 116 117 DVLOG(1) << "SetAccountStateForTest " << ids.account_key << ":" 118 << is_signed_in; 119 120 if (VLOG_IS_ON(1)) { 121 for (std::map<std::string, AccountState>::const_iterator it = 122 accounts_.begin(); 123 it != accounts_.end(); 124 ++it) { 125 DVLOG(1) << it->first << ":" << it->second.is_signed_in; 126 } 127 } 128} 129 130void AccountTracker::NotifyAccountAdded(const AccountState& account) { 131 DCHECK(!account.ids.gaia.empty()); 132 FOR_EACH_OBSERVER( 133 Observer, observer_list_, OnAccountAdded(account.ids)); 134} 135 136void AccountTracker::NotifyAccountRemoved(const AccountState& account) { 137 DCHECK(!account.ids.gaia.empty()); 138 FOR_EACH_OBSERVER( 139 Observer, observer_list_, OnAccountRemoved(account.ids)); 140} 141 142void AccountTracker::NotifySignInChanged(const AccountState& account) { 143 DCHECK(!account.ids.gaia.empty()); 144 FOR_EACH_OBSERVER(Observer, 145 observer_list_, 146 OnAccountSignInChanged(account.ids, account.is_signed_in)); 147} 148 149void AccountTracker::UpdateSignInState(const std::string account_key, 150 bool is_signed_in) { 151 StartTrackingAccount(account_key); 152 AccountState& account = accounts_[account_key]; 153 bool needs_gaia_id = account.ids.gaia.empty(); 154 bool was_signed_in = account.is_signed_in; 155 account.is_signed_in = is_signed_in; 156 157 if (needs_gaia_id && is_signed_in) 158 StartFetchingUserInfo(account_key); 159 160 if (!needs_gaia_id && (was_signed_in != is_signed_in)) 161 NotifySignInChanged(account); 162} 163 164void AccountTracker::StartTrackingAccount(const std::string account_key) { 165 if (!ContainsKey(accounts_, account_key)) { 166 DVLOG(1) << "StartTracking " << account_key; 167 AccountState account_state; 168 account_state.ids.account_key = account_key; 169 account_state.ids.email = account_key; 170 account_state.is_signed_in = false; 171 accounts_.insert(make_pair(account_key, account_state)); 172 } 173} 174 175void AccountTracker::StopTrackingAccount(const std::string account_key) { 176 DVLOG(1) << "StopTracking " << account_key; 177 if (ContainsKey(accounts_, account_key)) { 178 AccountState& account = accounts_[account_key]; 179 if (!account.ids.gaia.empty()) { 180 UpdateSignInState(account_key, false); 181 NotifyAccountRemoved(account); 182 } 183 accounts_.erase(account_key); 184 } 185 186 if (ContainsKey(user_info_requests_, account_key)) 187 DeleteFetcher(user_info_requests_[account_key]); 188} 189 190void AccountTracker::StopTrackingAllAccounts() { 191 while (!accounts_.empty()) 192 StopTrackingAccount(accounts_.begin()->first); 193} 194 195void AccountTracker::StartFetchingUserInfo(const std::string account_key) { 196 if (ContainsKey(user_info_requests_, account_key)) 197 DeleteFetcher(user_info_requests_[account_key]); 198 199 DVLOG(1) << "StartFetching " << account_key; 200 AccountIdFetcher* fetcher = 201 new AccountIdFetcher(identity_provider_->GetTokenService(), 202 request_context_getter_.get(), 203 this, 204 account_key); 205 user_info_requests_[account_key] = fetcher; 206 fetcher->Start(); 207} 208 209void AccountTracker::OnUserInfoFetchSuccess(AccountIdFetcher* fetcher, 210 const std::string& gaia_id) { 211 const std::string& account_key = fetcher->account_key(); 212 DCHECK(ContainsKey(accounts_, account_key)); 213 AccountState& account = accounts_[account_key]; 214 215 account.ids.gaia = gaia_id; 216 NotifyAccountAdded(account); 217 218 if (account.is_signed_in) 219 NotifySignInChanged(account); 220 221 DeleteFetcher(fetcher); 222} 223 224void AccountTracker::OnUserInfoFetchFailure(AccountIdFetcher* fetcher) { 225 LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_key(); 226 std::string key = fetcher->account_key(); 227 DeleteFetcher(fetcher); 228 StopTrackingAccount(key); 229} 230 231void AccountTracker::DeleteFetcher(AccountIdFetcher* fetcher) { 232 DVLOG(1) << "DeleteFetcher " << fetcher->account_key(); 233 const std::string& account_key = fetcher->account_key(); 234 DCHECK(ContainsKey(user_info_requests_, account_key)); 235 DCHECK_EQ(fetcher, user_info_requests_[account_key]); 236 user_info_requests_.erase(account_key); 237 delete fetcher; 238} 239 240AccountIdFetcher::AccountIdFetcher( 241 OAuth2TokenService* token_service, 242 net::URLRequestContextGetter* request_context_getter, 243 AccountTracker* tracker, 244 const std::string& account_key) 245 : OAuth2TokenService::Consumer("gaia_account_tracker"), 246 token_service_(token_service), 247 request_context_getter_(request_context_getter), 248 tracker_(tracker), 249 account_key_(account_key) { 250} 251 252AccountIdFetcher::~AccountIdFetcher() {} 253 254void AccountIdFetcher::Start() { 255 login_token_request_ = token_service_->StartRequest( 256 account_key_, OAuth2TokenService::ScopeSet(), this); 257} 258 259void AccountIdFetcher::OnGetTokenSuccess( 260 const OAuth2TokenService::Request* request, 261 const std::string& access_token, 262 const base::Time& expiration_time) { 263 DCHECK_EQ(request, login_token_request_.get()); 264 265 gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_)); 266 267 const int kMaxGetUserIdRetries = 3; 268 gaia_oauth_client_->GetUserId(access_token, kMaxGetUserIdRetries, this); 269} 270 271void AccountIdFetcher::OnGetTokenFailure( 272 const OAuth2TokenService::Request* request, 273 const GoogleServiceAuthError& error) { 274 LOG(ERROR) << "OnGetTokenFailure: " << error.ToString(); 275 DCHECK_EQ(request, login_token_request_.get()); 276 tracker_->OnUserInfoFetchFailure(this); 277} 278 279void AccountIdFetcher::OnGetUserIdResponse(const std::string& gaia_id) { 280 tracker_->OnUserInfoFetchSuccess(this, gaia_id); 281} 282 283void AccountIdFetcher::OnOAuthError() { 284 LOG(ERROR) << "OnOAuthError"; 285 tracker_->OnUserInfoFetchFailure(this); 286} 287 288void AccountIdFetcher::OnNetworkError(int response_code) { 289 LOG(ERROR) << "OnNetworkError " << response_code; 290 tracker_->OnUserInfoFetchFailure(this); 291} 292 293} // namespace gaia 294