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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: components/signin/core/browser/account_tracker_service.cc
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4f205bf7018a14f2f82dfd5634093a73c5873312
--- /dev/null
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -0,0 +1,431 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/signin/core/browser/account_tracker_service.h"
+
+#include "base/debug/trace_event.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace {
+
+const char kAccountKeyPath[] = "account_id";
+const char kAccountEmailPath[] = "email";
+const char kAccountGaiaPath[] = "gaia";
+
+}
+
+class AccountInfoFetcher : public OAuth2TokenService::Consumer,
+ public gaia::GaiaOAuthClient::Delegate {
+ public:
+ AccountInfoFetcher(OAuth2TokenService* token_service,
+ net::URLRequestContextGetter* request_context_getter,
+ AccountTrackerService* service,
+ const std::string& account_id);
+ virtual ~AccountInfoFetcher();
+
+ const std::string& account_id() { return account_id_; }
+
+ void Start();
+
+ // OAuth2TokenService::Consumer implementation.
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
+
+ // gaia::GaiaOAuthClient::Delegate implementation.
+ virtual void OnGetUserInfoResponse(
+ scoped_ptr<base::DictionaryValue> user_info) OVERRIDE;
+ virtual void OnOAuthError() OVERRIDE;
+ virtual void OnNetworkError(int response_code) OVERRIDE;
+
+ private:
+ OAuth2TokenService* token_service_;
+ net::URLRequestContextGetter* request_context_getter_;
+ AccountTrackerService* service_;
+ const std::string account_id_;
+
+ scoped_ptr<OAuth2TokenService::Request> login_token_request_;
+ scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
+};
+
+AccountInfoFetcher::AccountInfoFetcher(
+ OAuth2TokenService* token_service,
+ net::URLRequestContextGetter* request_context_getter,
+ AccountTrackerService* service,
+ const std::string& account_id)
+ : OAuth2TokenService::Consumer("gaia_account_tracker"),
+ token_service_(token_service),
+ request_context_getter_(request_context_getter),
+ service_(service),
+ account_id_(account_id) {
+ TRACE_EVENT_ASYNC_BEGIN1(
+ "AccountTrackerService", "AccountIdFetcher", this,
+ "account_id", account_id);
+}
+
+AccountInfoFetcher::~AccountInfoFetcher() {
+ TRACE_EVENT_ASYNC_END0("AccountTrackerService", "AccountIdFetcher", this);
+}
+
+void AccountInfoFetcher::Start() {
+ OAuth2TokenService::ScopeSet scopes;
+ scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
+ scopes.insert(GaiaConstants::kGoogleUserInfoProfile);
+ login_token_request_ = token_service_->StartRequest(
+ account_id_, scopes, this);
+}
+
+void AccountInfoFetcher::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ TRACE_EVENT_ASYNC_STEP_PAST0(
+ "AccountTrackerService", "AccountIdFetcher", this, "OnGetTokenSuccess");
+ DCHECK_EQ(request, login_token_request_.get());
+
+ gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_));
+
+ const int kMaxRetries = 3;
+ gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this);
+}
+
+void AccountInfoFetcher::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService",
+ "AccountIdFetcher",
+ this,
+ "OnGetTokenFailure",
+ "google_service_auth_error",
+ error.ToString());
+ LOG(ERROR) << "OnGetTokenFailure: " << error.ToString();
+ DCHECK_EQ(request, login_token_request_.get());
+ service_->OnUserInfoFetchFailure(this);
+}
+
+void AccountInfoFetcher::OnGetUserInfoResponse(
+ scoped_ptr<base::DictionaryValue> user_info) {
+ TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService",
+ "AccountIdFetcher",
+ this,
+ "OnGetUserInfoResponse",
+ "account_id",
+ account_id_);
+ service_->OnUserInfoFetchSuccess(this, user_info.get());
+}
+
+void AccountInfoFetcher::OnOAuthError() {
+ TRACE_EVENT_ASYNC_STEP_PAST0(
+ "AccountTrackerService", "AccountIdFetcher", this, "OnOAuthError");
+ LOG(ERROR) << "OnOAuthError";
+ service_->OnUserInfoFetchFailure(this);
+}
+
+void AccountInfoFetcher::OnNetworkError(int response_code) {
+ TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService",
+ "AccountIdFetcher",
+ this,
+ "OnNetworkError",
+ "response_code",
+ response_code);
+ LOG(ERROR) << "OnNetworkError " << response_code;
+ service_->OnUserInfoFetchFailure(this);
+}
+
+
+const char AccountTrackerService::kAccountInfoPref[] = "account_info";
+
+AccountTrackerService::AccountTrackerService()
+ : token_service_(NULL),
+ pref_service_(NULL),
+ shutdown_called_(false) {
+}
+
+AccountTrackerService::~AccountTrackerService() {
+ DCHECK(shutdown_called_);
+}
+
+void AccountTrackerService::Initialize(
+ OAuth2TokenService* token_service,
+ PrefService* pref_service,
+ net::URLRequestContextGetter* request_context_getter) {
+ DCHECK(token_service);
+ DCHECK(!token_service_);
+ DCHECK(pref_service);
+ DCHECK(!pref_service_);
+ token_service_ = token_service;
+ pref_service_ = pref_service;
+ request_context_getter_ = request_context_getter;
+ token_service_->AddObserver(this);
+ LoadFromPrefs();
+ LoadFromTokenService();
+}
+
+void AccountTrackerService::Shutdown() {
+ shutdown_called_ = true;
+ STLDeleteValues(&user_info_requests_);
+ token_service_->RemoveObserver(this);
+}
+
+void AccountTrackerService::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void AccountTrackerService::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+bool AccountTrackerService::IsAllUserInfoFetched() const {
+ return user_info_requests_.empty();
+}
+
+std::vector<AccountTrackerService::AccountInfo>
+AccountTrackerService::GetAccounts() const {
+ std::vector<AccountInfo> accounts;
+
+ for (std::map<std::string, AccountState>::const_iterator it =
+ accounts_.begin();
+ it != accounts_.end();
+ ++it) {
+ const AccountState& state = it->second;
+ accounts.push_back(state.info);
+ }
+ return accounts;
+}
+
+AccountTrackerService::AccountInfo AccountTrackerService::GetAccountInfo(
+ const std::string& account_id) {
+ if (ContainsKey(accounts_, account_id))
+ return accounts_[account_id].info;
+
+ return AccountInfo();
+}
+
+AccountTrackerService::AccountInfo
+AccountTrackerService::FindAccountInfoByGaiaId(
+ const std::string& gaia_id) {
+ for (std::map<std::string, AccountState>::const_iterator it =
+ accounts_.begin();
+ it != accounts_.end();
+ ++it) {
+ const AccountState& state = it->second;
+ if (state.info.gaia == gaia_id)
+ return state.info;
+ }
+
+ return AccountInfo();
+}
+
+AccountTrackerService::AccountInfo
+AccountTrackerService::FindAccountInfoByEmail(
+ const std::string& email) {
+ for (std::map<std::string, AccountState>::const_iterator it =
+ accounts_.begin();
+ it != accounts_.end();
+ ++it) {
+ const AccountState& state = it->second;
+ if (gaia::AreEmailsSame(state.info.email, email))
+ return state.info;
+ }
+
+ return AccountInfo();
+}
+
+void AccountTrackerService::OnRefreshTokenAvailable(
+ const std::string& account_id) {
+ TRACE_EVENT1("AccountTrackerService",
+ "AccountTracker::OnRefreshTokenAvailable",
+ "account_id",
+ account_id);
+ DVLOG(1) << "AVAILABLE " << account_id;
+
+ StartTrackingAccount(account_id);
+ AccountState& state = accounts_[account_id];
+
+ if (state.info.gaia.empty())
+ StartFetchingUserInfo(account_id);
+}
+
+void AccountTrackerService::OnRefreshTokenRevoked(
+ const std::string& account_id) {
+ TRACE_EVENT1("AccountTrackerService",
+ "AccountTracker::OnRefreshTokenRevoked",
+ "account_id",
+ account_id);
+
+ DVLOG(1) << "REVOKED " << account_id;
+ StopTrackingAccount(account_id);
+}
+
+void AccountTrackerService::NotifyAccountUpdated(const AccountState& state) {
+ DCHECK(!state.info.gaia.empty());
+ FOR_EACH_OBSERVER(
+ Observer, observer_list_, OnAccountUpdated(state.info));
+}
+
+void AccountTrackerService::NotifyAccountRemoved(const AccountState& state) {
+ DCHECK(!state.info.gaia.empty());
+ FOR_EACH_OBSERVER(
+ Observer, observer_list_, OnAccountRemoved(state.info));
+}
+
+void AccountTrackerService::StartTrackingAccount(
+ const std::string& account_id) {
+ if (!ContainsKey(accounts_, account_id)) {
+ DVLOG(1) << "StartTracking " << account_id;
+ AccountState state;
+ state.info.account_id = account_id;
+ accounts_.insert(make_pair(account_id, state));
+ }
+}
+
+void AccountTrackerService::StopTrackingAccount(const std::string& account_id) {
+ DVLOG(1) << "StopTracking " << account_id;
+ if (ContainsKey(accounts_, account_id)) {
+ AccountState& state = accounts_[account_id];
+ RemoveFromPrefs(state);
+ if (!state.info.gaia.empty())
+ NotifyAccountRemoved(state);
+
+ accounts_.erase(account_id);
+ }
+
+ if (ContainsKey(user_info_requests_, account_id))
+ DeleteFetcher(user_info_requests_[account_id]);
+}
+
+void AccountTrackerService::StartFetchingUserInfo(
+ const std::string& account_id) {
+ if (ContainsKey(user_info_requests_, account_id))
+ DeleteFetcher(user_info_requests_[account_id]);
+
+ DVLOG(1) << "StartFetching " << account_id;
+ AccountInfoFetcher* fetcher =
+ new AccountInfoFetcher(token_service_,
+ request_context_getter_.get(),
+ this,
+ account_id);
+ user_info_requests_[account_id] = fetcher;
+ fetcher->Start();
+}
+
+void AccountTrackerService::OnUserInfoFetchSuccess(
+ AccountInfoFetcher* fetcher,
+ const base::DictionaryValue* user_info) {
+ const std::string& account_id = fetcher->account_id();
+ DCHECK(ContainsKey(accounts_, account_id));
+ AccountState& state = accounts_[account_id];
+
+ std::string gaia_id;
+ std::string email;
+ if (user_info->GetString("id", &gaia_id) &&
+ user_info->GetString("email", &email)) {
+ state.info.gaia = gaia_id;
+ state.info.email = email;
+
+ NotifyAccountUpdated(state);
+ SaveToPrefs(state);
+ }
+ DeleteFetcher(fetcher);
+}
+
+void AccountTrackerService::OnUserInfoFetchFailure(
+ AccountInfoFetcher* fetcher) {
+ LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_id();
+ DeleteFetcher(fetcher);
+ // TODO(rogerta): figure out when to retry.
+}
+
+void AccountTrackerService::DeleteFetcher(AccountInfoFetcher* fetcher) {
+ DVLOG(1) << "DeleteFetcher " << fetcher->account_id();
+ const std::string& account_id = fetcher->account_id();
+ DCHECK(ContainsKey(user_info_requests_, account_id));
+ DCHECK_EQ(fetcher, user_info_requests_[account_id]);
+ user_info_requests_.erase(account_id);
+ delete fetcher;
+}
+
+void AccountTrackerService::LoadFromPrefs() {
+ const base::ListValue* list = pref_service_->GetList(kAccountInfoPref);
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ const base::DictionaryValue* dict;
+ if (list->GetDictionary(i, &dict)) {
+ base::string16 value;
+ if (dict->GetString(kAccountKeyPath, &value)) {
+ std::string account_id = base::UTF16ToUTF8(value);
+ StartTrackingAccount(account_id);
+ AccountState& state = accounts_[account_id];
+
+ if (dict->GetString(kAccountGaiaPath, &value))
+ state.info.gaia = base::UTF16ToUTF8(value);
+ if (dict->GetString(kAccountEmailPath, &value))
+ state.info.email = base::UTF16ToUTF8(value);
+
+ if (!state.info.gaia.empty())
+ NotifyAccountUpdated(state);
+ }
+ }
+ }
+}
+
+void AccountTrackerService::SaveToPrefs(const AccountState& state) {
+ if (!pref_service_)
+ return;
+
+ base::DictionaryValue* dict = NULL;
+ base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
+ ListPrefUpdate update(pref_service_, kAccountInfoPref);
+ for(size_t i = 0; i < update->GetSize(); ++i, dict = NULL) {
+ if (update->GetDictionary(i, &dict)) {
+ base::string16 value;
+ if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16)
+ break;
+ }
+ }
+
+ if (!dict) {
+ dict = new base::DictionaryValue();
+ update->Append(dict); // |update| takes ownership.
+ dict->SetString(kAccountKeyPath, account_id_16);
+ }
+
+ dict->SetString(kAccountEmailPath, state.info.email);
+ dict->SetString(kAccountGaiaPath, state.info.gaia);
+}
+
+void AccountTrackerService::RemoveFromPrefs(const AccountState& state) {
+ if (!pref_service_)
+ return;
+
+ base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
+ ListPrefUpdate update(pref_service_, kAccountInfoPref);
+ for(size_t i = 0; i < update->GetSize(); ++i) {
+ base::DictionaryValue* dict = NULL;
+ if (update->GetDictionary(i, &dict)) {
+ base::string16 value;
+ if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16) {
+ update->Remove(i, NULL);
+ break;
+ }
+ }
+ }
+}
+
+void AccountTrackerService::LoadFromTokenService() {
+ std::vector<std::string> accounts = token_service_->GetAccounts();
+ for (std::vector<std::string>::const_iterator it = accounts.begin();
+ it != accounts.end(); ++it) {
+ OnRefreshTokenAvailable(*it);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698