Fix a leak in a test from r291170.
[chromium-blink-merge.git] / components / signin / core / browser / account_tracker_service.cc
blob4f205bf7018a14f2f82dfd5634093a73c5873312
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.
5 #include "components/signin/core/browser/account_tracker_service.h"
7 #include "base/debug/trace_event.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/signin/core/browser/signin_manager.h"
12 #include "google_apis/gaia/gaia_auth_util.h"
13 #include "google_apis/gaia/gaia_constants.h"
14 #include "google_apis/gaia/gaia_oauth_client.h"
15 #include "google_apis/gaia/oauth2_token_service.h"
16 #include "net/url_request/url_request_context_getter.h"
18 namespace {
20 const char kAccountKeyPath[] = "account_id";
21 const char kAccountEmailPath[] = "email";
22 const char kAccountGaiaPath[] = "gaia";
26 class AccountInfoFetcher : public OAuth2TokenService::Consumer,
27 public gaia::GaiaOAuthClient::Delegate {
28 public:
29 AccountInfoFetcher(OAuth2TokenService* token_service,
30 net::URLRequestContextGetter* request_context_getter,
31 AccountTrackerService* service,
32 const std::string& account_id);
33 virtual ~AccountInfoFetcher();
35 const std::string& account_id() { return account_id_; }
37 void Start();
39 // OAuth2TokenService::Consumer implementation.
40 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
41 const std::string& access_token,
42 const base::Time& expiration_time) OVERRIDE;
43 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
44 const GoogleServiceAuthError& error) OVERRIDE;
46 // gaia::GaiaOAuthClient::Delegate implementation.
47 virtual void OnGetUserInfoResponse(
48 scoped_ptr<base::DictionaryValue> user_info) OVERRIDE;
49 virtual void OnOAuthError() OVERRIDE;
50 virtual void OnNetworkError(int response_code) OVERRIDE;
52 private:
53 OAuth2TokenService* token_service_;
54 net::URLRequestContextGetter* request_context_getter_;
55 AccountTrackerService* service_;
56 const std::string account_id_;
58 scoped_ptr<OAuth2TokenService::Request> login_token_request_;
59 scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
62 AccountInfoFetcher::AccountInfoFetcher(
63 OAuth2TokenService* token_service,
64 net::URLRequestContextGetter* request_context_getter,
65 AccountTrackerService* service,
66 const std::string& account_id)
67 : OAuth2TokenService::Consumer("gaia_account_tracker"),
68 token_service_(token_service),
69 request_context_getter_(request_context_getter),
70 service_(service),
71 account_id_(account_id) {
72 TRACE_EVENT_ASYNC_BEGIN1(
73 "AccountTrackerService", "AccountIdFetcher", this,
74 "account_id", account_id);
77 AccountInfoFetcher::~AccountInfoFetcher() {
78 TRACE_EVENT_ASYNC_END0("AccountTrackerService", "AccountIdFetcher", this);
81 void AccountInfoFetcher::Start() {
82 OAuth2TokenService::ScopeSet scopes;
83 scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
84 scopes.insert(GaiaConstants::kGoogleUserInfoProfile);
85 login_token_request_ = token_service_->StartRequest(
86 account_id_, scopes, this);
89 void AccountInfoFetcher::OnGetTokenSuccess(
90 const OAuth2TokenService::Request* request,
91 const std::string& access_token,
92 const base::Time& expiration_time) {
93 TRACE_EVENT_ASYNC_STEP_PAST0(
94 "AccountTrackerService", "AccountIdFetcher", this, "OnGetTokenSuccess");
95 DCHECK_EQ(request, login_token_request_.get());
97 gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_));
99 const int kMaxRetries = 3;
100 gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this);
103 void AccountInfoFetcher::OnGetTokenFailure(
104 const OAuth2TokenService::Request* request,
105 const GoogleServiceAuthError& error) {
106 TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService",
107 "AccountIdFetcher",
108 this,
109 "OnGetTokenFailure",
110 "google_service_auth_error",
111 error.ToString());
112 LOG(ERROR) << "OnGetTokenFailure: " << error.ToString();
113 DCHECK_EQ(request, login_token_request_.get());
114 service_->OnUserInfoFetchFailure(this);
117 void AccountInfoFetcher::OnGetUserInfoResponse(
118 scoped_ptr<base::DictionaryValue> user_info) {
119 TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService",
120 "AccountIdFetcher",
121 this,
122 "OnGetUserInfoResponse",
123 "account_id",
124 account_id_);
125 service_->OnUserInfoFetchSuccess(this, user_info.get());
128 void AccountInfoFetcher::OnOAuthError() {
129 TRACE_EVENT_ASYNC_STEP_PAST0(
130 "AccountTrackerService", "AccountIdFetcher", this, "OnOAuthError");
131 LOG(ERROR) << "OnOAuthError";
132 service_->OnUserInfoFetchFailure(this);
135 void AccountInfoFetcher::OnNetworkError(int response_code) {
136 TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService",
137 "AccountIdFetcher",
138 this,
139 "OnNetworkError",
140 "response_code",
141 response_code);
142 LOG(ERROR) << "OnNetworkError " << response_code;
143 service_->OnUserInfoFetchFailure(this);
147 const char AccountTrackerService::kAccountInfoPref[] = "account_info";
149 AccountTrackerService::AccountTrackerService()
150 : token_service_(NULL),
151 pref_service_(NULL),
152 shutdown_called_(false) {
155 AccountTrackerService::~AccountTrackerService() {
156 DCHECK(shutdown_called_);
159 void AccountTrackerService::Initialize(
160 OAuth2TokenService* token_service,
161 PrefService* pref_service,
162 net::URLRequestContextGetter* request_context_getter) {
163 DCHECK(token_service);
164 DCHECK(!token_service_);
165 DCHECK(pref_service);
166 DCHECK(!pref_service_);
167 token_service_ = token_service;
168 pref_service_ = pref_service;
169 request_context_getter_ = request_context_getter;
170 token_service_->AddObserver(this);
171 LoadFromPrefs();
172 LoadFromTokenService();
175 void AccountTrackerService::Shutdown() {
176 shutdown_called_ = true;
177 STLDeleteValues(&user_info_requests_);
178 token_service_->RemoveObserver(this);
181 void AccountTrackerService::AddObserver(Observer* observer) {
182 observer_list_.AddObserver(observer);
185 void AccountTrackerService::RemoveObserver(Observer* observer) {
186 observer_list_.RemoveObserver(observer);
189 bool AccountTrackerService::IsAllUserInfoFetched() const {
190 return user_info_requests_.empty();
193 std::vector<AccountTrackerService::AccountInfo>
194 AccountTrackerService::GetAccounts() const {
195 std::vector<AccountInfo> accounts;
197 for (std::map<std::string, AccountState>::const_iterator it =
198 accounts_.begin();
199 it != accounts_.end();
200 ++it) {
201 const AccountState& state = it->second;
202 accounts.push_back(state.info);
204 return accounts;
207 AccountTrackerService::AccountInfo AccountTrackerService::GetAccountInfo(
208 const std::string& account_id) {
209 if (ContainsKey(accounts_, account_id))
210 return accounts_[account_id].info;
212 return AccountInfo();
215 AccountTrackerService::AccountInfo
216 AccountTrackerService::FindAccountInfoByGaiaId(
217 const std::string& gaia_id) {
218 for (std::map<std::string, AccountState>::const_iterator it =
219 accounts_.begin();
220 it != accounts_.end();
221 ++it) {
222 const AccountState& state = it->second;
223 if (state.info.gaia == gaia_id)
224 return state.info;
227 return AccountInfo();
230 AccountTrackerService::AccountInfo
231 AccountTrackerService::FindAccountInfoByEmail(
232 const std::string& email) {
233 for (std::map<std::string, AccountState>::const_iterator it =
234 accounts_.begin();
235 it != accounts_.end();
236 ++it) {
237 const AccountState& state = it->second;
238 if (gaia::AreEmailsSame(state.info.email, email))
239 return state.info;
242 return AccountInfo();
245 void AccountTrackerService::OnRefreshTokenAvailable(
246 const std::string& account_id) {
247 TRACE_EVENT1("AccountTrackerService",
248 "AccountTracker::OnRefreshTokenAvailable",
249 "account_id",
250 account_id);
251 DVLOG(1) << "AVAILABLE " << account_id;
253 StartTrackingAccount(account_id);
254 AccountState& state = accounts_[account_id];
256 if (state.info.gaia.empty())
257 StartFetchingUserInfo(account_id);
260 void AccountTrackerService::OnRefreshTokenRevoked(
261 const std::string& account_id) {
262 TRACE_EVENT1("AccountTrackerService",
263 "AccountTracker::OnRefreshTokenRevoked",
264 "account_id",
265 account_id);
267 DVLOG(1) << "REVOKED " << account_id;
268 StopTrackingAccount(account_id);
271 void AccountTrackerService::NotifyAccountUpdated(const AccountState& state) {
272 DCHECK(!state.info.gaia.empty());
273 FOR_EACH_OBSERVER(
274 Observer, observer_list_, OnAccountUpdated(state.info));
277 void AccountTrackerService::NotifyAccountRemoved(const AccountState& state) {
278 DCHECK(!state.info.gaia.empty());
279 FOR_EACH_OBSERVER(
280 Observer, observer_list_, OnAccountRemoved(state.info));
283 void AccountTrackerService::StartTrackingAccount(
284 const std::string& account_id) {
285 if (!ContainsKey(accounts_, account_id)) {
286 DVLOG(1) << "StartTracking " << account_id;
287 AccountState state;
288 state.info.account_id = account_id;
289 accounts_.insert(make_pair(account_id, state));
293 void AccountTrackerService::StopTrackingAccount(const std::string& account_id) {
294 DVLOG(1) << "StopTracking " << account_id;
295 if (ContainsKey(accounts_, account_id)) {
296 AccountState& state = accounts_[account_id];
297 RemoveFromPrefs(state);
298 if (!state.info.gaia.empty())
299 NotifyAccountRemoved(state);
301 accounts_.erase(account_id);
304 if (ContainsKey(user_info_requests_, account_id))
305 DeleteFetcher(user_info_requests_[account_id]);
308 void AccountTrackerService::StartFetchingUserInfo(
309 const std::string& account_id) {
310 if (ContainsKey(user_info_requests_, account_id))
311 DeleteFetcher(user_info_requests_[account_id]);
313 DVLOG(1) << "StartFetching " << account_id;
314 AccountInfoFetcher* fetcher =
315 new AccountInfoFetcher(token_service_,
316 request_context_getter_.get(),
317 this,
318 account_id);
319 user_info_requests_[account_id] = fetcher;
320 fetcher->Start();
323 void AccountTrackerService::OnUserInfoFetchSuccess(
324 AccountInfoFetcher* fetcher,
325 const base::DictionaryValue* user_info) {
326 const std::string& account_id = fetcher->account_id();
327 DCHECK(ContainsKey(accounts_, account_id));
328 AccountState& state = accounts_[account_id];
330 std::string gaia_id;
331 std::string email;
332 if (user_info->GetString("id", &gaia_id) &&
333 user_info->GetString("email", &email)) {
334 state.info.gaia = gaia_id;
335 state.info.email = email;
337 NotifyAccountUpdated(state);
338 SaveToPrefs(state);
340 DeleteFetcher(fetcher);
343 void AccountTrackerService::OnUserInfoFetchFailure(
344 AccountInfoFetcher* fetcher) {
345 LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_id();
346 DeleteFetcher(fetcher);
347 // TODO(rogerta): figure out when to retry.
350 void AccountTrackerService::DeleteFetcher(AccountInfoFetcher* fetcher) {
351 DVLOG(1) << "DeleteFetcher " << fetcher->account_id();
352 const std::string& account_id = fetcher->account_id();
353 DCHECK(ContainsKey(user_info_requests_, account_id));
354 DCHECK_EQ(fetcher, user_info_requests_[account_id]);
355 user_info_requests_.erase(account_id);
356 delete fetcher;
359 void AccountTrackerService::LoadFromPrefs() {
360 const base::ListValue* list = pref_service_->GetList(kAccountInfoPref);
361 for (size_t i = 0; i < list->GetSize(); ++i) {
362 const base::DictionaryValue* dict;
363 if (list->GetDictionary(i, &dict)) {
364 base::string16 value;
365 if (dict->GetString(kAccountKeyPath, &value)) {
366 std::string account_id = base::UTF16ToUTF8(value);
367 StartTrackingAccount(account_id);
368 AccountState& state = accounts_[account_id];
370 if (dict->GetString(kAccountGaiaPath, &value))
371 state.info.gaia = base::UTF16ToUTF8(value);
372 if (dict->GetString(kAccountEmailPath, &value))
373 state.info.email = base::UTF16ToUTF8(value);
375 if (!state.info.gaia.empty())
376 NotifyAccountUpdated(state);
382 void AccountTrackerService::SaveToPrefs(const AccountState& state) {
383 if (!pref_service_)
384 return;
386 base::DictionaryValue* dict = NULL;
387 base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
388 ListPrefUpdate update(pref_service_, kAccountInfoPref);
389 for(size_t i = 0; i < update->GetSize(); ++i, dict = NULL) {
390 if (update->GetDictionary(i, &dict)) {
391 base::string16 value;
392 if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16)
393 break;
397 if (!dict) {
398 dict = new base::DictionaryValue();
399 update->Append(dict); // |update| takes ownership.
400 dict->SetString(kAccountKeyPath, account_id_16);
403 dict->SetString(kAccountEmailPath, state.info.email);
404 dict->SetString(kAccountGaiaPath, state.info.gaia);
407 void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
408 if (!pref_service_)
409 return;
411 base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
412 ListPrefUpdate update(pref_service_, kAccountInfoPref);
413 for(size_t i = 0; i < update->GetSize(); ++i) {
414 base::DictionaryValue* dict = NULL;
415 if (update->GetDictionary(i, &dict)) {
416 base::string16 value;
417 if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16) {
418 update->Remove(i, NULL);
419 break;
425 void AccountTrackerService::LoadFromTokenService() {
426 std::vector<std::string> accounts = token_service_->GetAccounts();
427 for (std::vector<std::string>::const_iterator it = accounts.begin();
428 it != accounts.end(); ++it) {
429 OnRefreshTokenAvailable(*it);