Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: components/signin/core/browser/account_tracker_service.cc

Issue 425823002: Create a new AccountTrackerService (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "components/signin/core/browser/account_tracker_service.h"
6
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"
17
18 namespace {
19
20 const char kAccountKeyPath[] = "account_id";
21 const char kAccountEmailPath[] = "email";
22 const char kAccountGaiaPath[] = "gaia";
23
24 }
25
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();
34
35 const std::string& account_id() { return account_id_; }
36
37 void Start();
38
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;
45
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;
51
52 private:
53 OAuth2TokenService* token_service_;
54 net::URLRequestContextGetter* request_context_getter_;
55 AccountTrackerService* service_;
56 const std::string account_id_;
57
58 scoped_ptr<OAuth2TokenService::Request> login_token_request_;
59 scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
60 };
61
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);
75 }
76
77 AccountInfoFetcher::~AccountInfoFetcher() {
78 TRACE_EVENT_ASYNC_END0("AccountTrackerService", "AccountIdFetcher", this);
79 }
80
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);
87 }
88
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());
96
97 gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_));
98
99 const int kMaxRetries = 3;
100 gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this);
101 }
102
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);
115 }
116
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());
126 }
127
128 void AccountInfoFetcher::OnOAuthError() {
129 TRACE_EVENT_ASYNC_STEP_PAST0(
130 "AccountTrackerService", "AccountIdFetcher", this, "OnOAuthError");
131 LOG(ERROR) << "OnOAuthError";
132 service_->OnUserInfoFetchFailure(this);
133 }
134
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);
144 }
145
146
147 const char AccountTrackerService::kAccountInfoPref[] = "account_info";
148
149 AccountTrackerService::AccountTrackerService()
150 : token_service_(NULL),
151 pref_service_(NULL),
152 shutdown_called_(false) {
153 }
154
155 AccountTrackerService::~AccountTrackerService() {
156 DCHECK(shutdown_called_);
157 }
158
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();
173 }
174
175 void AccountTrackerService::Shutdown() {
176 shutdown_called_ = true;
177 STLDeleteValues(&user_info_requests_);
178 token_service_->RemoveObserver(this);
179 }
180
181 void AccountTrackerService::AddObserver(Observer* observer) {
182 observer_list_.AddObserver(observer);
183 }
184
185 void AccountTrackerService::RemoveObserver(Observer* observer) {
186 observer_list_.RemoveObserver(observer);
187 }
188
189 bool AccountTrackerService::IsAllUserInfoFetched() const {
190 return user_info_requests_.empty();
191 }
192
193 std::vector<AccountTrackerService::AccountInfo>
194 AccountTrackerService::GetAccounts() const {
195 std::vector<AccountInfo> accounts;
196
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);
203 }
204 return accounts;
205 }
206
207 AccountTrackerService::AccountInfo AccountTrackerService::GetAccountInfo(
208 const std::string& account_id) {
209 if (ContainsKey(accounts_, account_id))
210 return accounts_[account_id].info;
211
212 return AccountInfo();
213 }
214
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;
guohui 2014/08/20 18:05:23 nits: no need for {}
Roger Tawa OOO till Jul 10th 2014/08/21 01:30:17 Done.
225 }
226 }
227
228 return AccountInfo();
229 }
230
231 AccountTrackerService::AccountInfo
232 AccountTrackerService::FindAccountInfoByEmail(
233 const std::string& email) {
234 for (std::map<std::string, AccountState>::const_iterator it =
235 accounts_.begin();
236 it != accounts_.end();
237 ++it) {
238 const AccountState& state = it->second;
239 if (gaia::AreEmailsSame(state.info.email, email)) {
240 return state.info;
guohui 2014/08/20 18:05:23 nits: no need for {}
Roger Tawa OOO till Jul 10th 2014/08/21 01:30:16 Done.
241 }
242 }
243
244 return AccountInfo();
245 }
246
247 void AccountTrackerService::OnRefreshTokenAvailable(
248 const std::string& account_id) {
249 TRACE_EVENT1("AccountTrackerService",
250 "AccountTracker::OnRefreshTokenAvailable",
251 "account_id",
252 account_id);
253 DVLOG(1) << "AVAILABLE " << account_id;
254
255 StartTrackingAccount(account_id);
256 AccountState& state = accounts_[account_id];
257
258 if (state.info.gaia.empty()) {
259 StartFetchingUserInfo(account_id);
260 } else {
261 NotifyAccountUpdated(state);
guohui 2014/08/20 18:05:23 why do we notify account updated here? It seems he
Roger Tawa OOO till Jul 10th 2014/08/21 01:30:16 Oops, correct. That's a left over from when the c
262 }
263 }
264
265 void AccountTrackerService::OnRefreshTokenRevoked(
266 const std::string& account_id) {
267 TRACE_EVENT1("AccountTrackerService",
268 "AccountTracker::OnRefreshTokenRevoked",
269 "account_id",
270 account_id);
271
272 DVLOG(1) << "REVOKED " << account_id;
273 StopTrackingAccount(account_id);
274 }
275
276 void AccountTrackerService::NotifyAccountUpdated(const AccountState& state) {
277 DCHECK(!state.info.gaia.empty());
278 FOR_EACH_OBSERVER(
279 Observer, observer_list_, OnAccountUpdated(state.info));
280 }
281
282 void AccountTrackerService::NotifyAccountRemoved(const AccountState& state) {
283 DCHECK(!state.info.gaia.empty());
284 FOR_EACH_OBSERVER(
285 Observer, observer_list_, OnAccountRemoved(state.info));
guohui 2014/08/20 18:05:23 what is the purpose of OnAccountRemoved? It is fir
Roger Tawa OOO till Jul 10th 2014/08/21 01:30:16 Good point. Should not remove if fetcher fails.
286 }
287
288 void AccountTrackerService::StartTrackingAccount(
289 const std::string& account_id) {
290 if (!ContainsKey(accounts_, account_id)) {
291 DVLOG(1) << "StartTracking " << account_id;
292 AccountState state;
293 state.info.account_id = account_id;
294 accounts_.insert(make_pair(account_id, state));
295 }
296 }
297
298 void AccountTrackerService::StopTrackingAccount(const std::string& account_id) {
299 DVLOG(1) << "StopTracking " << account_id;
300 if (ContainsKey(accounts_, account_id)) {
301 AccountState& state = accounts_[account_id];
302 RemoveFromPrefs(state);
303 if (!state.info.gaia.empty())
304 NotifyAccountRemoved(state);
305
306 accounts_.erase(account_id);
307 }
308
309 if (ContainsKey(user_info_requests_, account_id))
310 DeleteFetcher(user_info_requests_[account_id]);
311 }
312
313 void AccountTrackerService::StartFetchingUserInfo(
314 const std::string& account_id) {
315 if (ContainsKey(user_info_requests_, account_id))
316 DeleteFetcher(user_info_requests_[account_id]);
317
318 DVLOG(1) << "StartFetching " << account_id;
319 AccountInfoFetcher* fetcher =
320 new AccountInfoFetcher(token_service_,
321 request_context_getter_.get(),
322 this,
323 account_id);
324 user_info_requests_[account_id] = fetcher;
325 fetcher->Start();
326 }
327
328 void AccountTrackerService::OnUserInfoFetchSuccess(
329 AccountInfoFetcher* fetcher,
330 const base::DictionaryValue* user_info) {
331 const std::string& account_id = fetcher->account_id();
332 DCHECK(ContainsKey(accounts_, account_id));
333 AccountState& state = accounts_[account_id];
334
335 std::string gaia_id;
336 std::string email;
337 if (user_info->GetString("id", &gaia_id) &&
338 user_info->GetString("email", &email)) {
339 state.info.gaia = gaia_id;
340 state.info.email = email;
341
342 NotifyAccountUpdated(state);
343 SaveToPrefs(state);
344 }
345 DeleteFetcher(fetcher);
346 }
347
348 void AccountTrackerService::OnUserInfoFetchFailure(
349 AccountInfoFetcher* fetcher) {
350 LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_id();
351 std::string account_id = fetcher->account_id();
352 DeleteFetcher(fetcher);
353 StopTrackingAccount(account_id);
354 }
355
356 void AccountTrackerService::DeleteFetcher(AccountInfoFetcher* fetcher) {
357 DVLOG(1) << "DeleteFetcher " << fetcher->account_id();
358 const std::string& account_id = fetcher->account_id();
359 DCHECK(ContainsKey(user_info_requests_, account_id));
360 DCHECK_EQ(fetcher, user_info_requests_[account_id]);
361 user_info_requests_.erase(account_id);
362 delete fetcher;
363 }
364
365 void AccountTrackerService::LoadFromPrefs() {
366 const base::ListValue* list = pref_service_->GetList(kAccountInfoPref);
367 for (size_t i = 0; i < list->GetSize(); ++i) {
368 const base::DictionaryValue* dict;
369 if (list->GetDictionary(i, &dict)) {
370 base::string16 value;
371 if (dict->GetString(kAccountKeyPath, &value)) {
372 std::string account_id = base::UTF16ToUTF8(value);
373 StartTrackingAccount(account_id);
374 AccountState& state = accounts_[account_id];
375
376 if (dict->GetString(kAccountGaiaPath, &value))
377 state.info.gaia = base::UTF16ToUTF8(value);
378 if (dict->GetString(kAccountEmailPath, &value))
379 state.info.email = base::UTF16ToUTF8(value);
guohui 2014/08/20 18:05:23 should we notify account updated here?
Roger Tawa OOO till Jul 10th 2014/08/21 01:30:16 Yes, but only if gaiaid is not empty.
380 }
381 }
382 }
383 }
384
385 void AccountTrackerService::SaveToPrefs(const AccountState& state) {
386 if (!pref_service_)
387 return;
388
389 base::DictionaryValue* dict = NULL;
390 base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
391 ListPrefUpdate update(pref_service_, kAccountInfoPref);
392 for(size_t i = 0; i < update->GetSize(); ++i, dict = NULL) {
393 if (update->GetDictionary(i, &dict)) {
394 base::string16 value;
395 if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16)
396 break;
397 }
398 }
399
400 if (!dict) {
401 dict = new base::DictionaryValue();
402 update->Append(dict); // |update| takes ownership.
403 dict->SetString(kAccountKeyPath, account_id_16);
404 }
405
406 dict->SetString(kAccountEmailPath, state.info.email);
407 dict->SetString(kAccountGaiaPath, state.info.gaia);
408 }
409
410 void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
411 if (!pref_service_)
412 return;
413
414 base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
415 ListPrefUpdate update(pref_service_, kAccountInfoPref);
416 for(size_t i = 0; i < update->GetSize(); ++i) {
417 base::DictionaryValue* dict = NULL;
418 if (update->GetDictionary(i, &dict)) {
419 base::string16 value;
420 if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16) {
421 update->Remove(i, NULL);
422 break;
423 }
424 }
425 }
426 }
427
428 void AccountTrackerService::LoadFromTokenService() {
429 std::vector<std::string> accounts = token_service_->GetAccounts();
430 for (std::vector<std::string>::const_iterator it = accounts.begin();
431 it != accounts.end(); ++it) {
432 OnRefreshTokenAvailable(*it);
433 }
434 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698