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