account_reconcilor.cc revision 010d83a9304c5a91596085d917d248abff47903a
124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// Copyright 2014 The Chromium Authors. All rights reserved.
224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// Use of this source code is governed by a BSD-style license that can be
324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// found in the LICENSE file.
424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "components/signin/core/browser/account_reconcilor.h"
624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include <algorithm>
824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/bind.h"
1024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/json/json_reader.h"
1152fd984f7e67c3a0ab18d5565f40356bcfa84822Greg Clayton#include "base/logging.h"
1224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/message_loop/message_loop.h"
1324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/message_loop/message_loop_proxy.h"
1424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "base/strings/string_number_conversions.h"
1590df56354288b44e5b6c2844c52f1e0eefd5509bGreg Clayton#include "base/time/time.h"
16a39fa4b8c67886e0d7df0752fe176ad7723e305fJim Ingham#include "components/signin/core/browser/profile_oauth2_token_service.h"
178da92a74478ff2465e092aea92ce29ad7ad6ddddGreg Clayton#include "components/signin/core/browser/signin_client.h"
18a39fa4b8c67886e0d7df0752fe176ad7723e305fJim Ingham#include "components/signin/core/browser/signin_oauth_helper.h"
1914ef59fe5728d862c040cf5a6b99c384229a34eeGreg Clayton#include "google_apis/gaia/gaia_auth_fetcher.h"
20a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham#include "google_apis/gaia/gaia_auth_util.h"
218da92a74478ff2465e092aea92ce29ad7ad6ddddGreg Clayton#include "google_apis/gaia/gaia_constants.h"
2224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "google_apis/gaia/gaia_oauth_client.h"
23e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice#include "google_apis/gaia/gaia_urls.h"
2422defe8b06df5b1f09b53bda255ef07513abc04cGreg Clayton#include "net/cookies/canonical_cookie.h"
2522defe8b06df5b1f09b53bda255ef07513abc04cGreg Clayton
26e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice
272f28ece553d2ef0d7b3e8d1419020591ec3818f9Greg Claytonnamespace {
285f54ac373b119a4c6693e4875c48aa761fba0c86Greg Clayton
2924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerclass EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > {
3024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner public:
3149ce8969d3154e1560106cfe530444c09410f217Greg Clayton  bool operator()(const std::pair<std::string, bool>& p1,
3224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                  const std::pair<std::string, bool>& p2) const;
33eddffe93d2c9ebb575e7b03fe1c5e71f9ecaf9f1Caroline Tice};
3452fd984f7e67c3a0ab18d5565f40356bcfa84822Greg Clayton
3524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerbool EmailEqualToFunc::operator()(
3624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const std::pair<std::string, bool>& p1,
3724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const std::pair<std::string, bool>& p2) const {
3824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first);
3924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
4024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
4124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}  // namespace
4224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
4324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
44ff44ab42e9f5d8e4d550e11d1b69413e0bc75b71Greg Clayton// Fetches a refresh token from the given session in the GAIA cookie.  This is
4524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// a best effort only.  If it should fail, another reconcile action will occur
4624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner// shortly anyway.
4724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerclass AccountReconcilor::RefreshTokenFetcher
4824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    : public SigninOAuthHelper,
4914ef59fe5728d862c040cf5a6b99c384229a34eeGreg Clayton      public SigninOAuthHelper::Consumer {
508da92a74478ff2465e092aea92ce29ad7ad6ddddGreg Clayton public:
5124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  RefreshTokenFetcher(AccountReconcilor* reconcilor,
5224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                      const std::string& account_id,
5324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                      int session_index);
5424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  virtual ~RefreshTokenFetcher() {}
5524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
5624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner private:
57a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  // Overridden from GaiaAuthConsumer:
58a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  virtual void OnSigninOAuthInformationAvailable(
59a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      const std::string& email,
60a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      const std::string& display_email,
61a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      const std::string& refresh_token) OVERRIDE;
6224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
6324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // Called when an error occurs while getting the information.
6424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  virtual void OnSigninOAuthInformationFailure(
6524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      const GoogleServiceAuthError& error) OVERRIDE;
6624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
6724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  AccountReconcilor* reconcilor_;
6882cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton  const std::string account_id_;
6982cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton  int session_index_;
70a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
71a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  DISALLOW_COPY_AND_ASSIGN(RefreshTokenFetcher);
72a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham};
73a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
74a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim InghamAccountReconcilor::RefreshTokenFetcher::RefreshTokenFetcher(
7554e7afa84d945f9137f9372ecde432f9e1a702fcGreg Clayton    AccountReconcilor* reconcilor,
76a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    const std::string& account_id,
77a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    int session_index)
7882cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton    : SigninOAuthHelper(reconcilor->client()->GetURLRequestContext(),
7982cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton                        base::IntToString(session_index),
8082cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton                        this),
8182cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton      reconcilor_(reconcilor),
8282cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton      account_id_(account_id),
83a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      session_index_(session_index) {
84a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  DCHECK(reconcilor_);
85a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  DCHECK(!account_id.empty());
86b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton}
87a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
88a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Inghamvoid AccountReconcilor::RefreshTokenFetcher::OnSigninOAuthInformationAvailable(
89a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    const std::string& email,
9054e7afa84d945f9137f9372ecde432f9e1a702fcGreg Clayton    const std::string& display_email,
91a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    const std::string& refresh_token) {
92a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  VLOG(1) << "RefreshTokenFetcher::OnSigninOAuthInformationAvailable:"
93b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton          << " account=" << account_id_ << " email=" << email
94b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton          << " displayEmail=" << display_email;
95a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
96a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  // TODO(rogerta): because of the problem with email vs displayEmail and
97b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton  // emails that have been canonicalized, the argument |email| is used here
98b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton  // to make sure the correct string is used when calling the token service.
99a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  // This will be cleaned up when chrome moves to using gaia obfuscated id.
100a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  reconcilor_->HandleRefreshTokenFetched(email, refresh_token);
101a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham}
1029c3cfe397d6040a46677e201c2682cc2a5163fe9Eli Friedman
103a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Inghamvoid AccountReconcilor::RefreshTokenFetcher::OnSigninOAuthInformationFailure(
104a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    const GoogleServiceAuthError& error) {
105a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  VLOG(1) << "RefreshTokenFetcher::OnSigninOAuthInformationFailure:"
106a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham          << " account=" << account_id_ << " session_index=" << session_index_;
107a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  reconcilor_->HandleRefreshTokenFetched(account_id_, std::string());
108a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham}
109a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
110a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Inghambool AccountReconcilor::EmailLessFunc::operator()(const std::string& s1,
111a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham                                                  const std::string& s2) const {
112a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  return gaia::CanonicalizeEmail(s1) < gaia::CanonicalizeEmail(s2);
11336da2aa6dc5ad9994b638ed09eb81c44cc05540bGreg Clayton}
114b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton
115a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Inghamclass AccountReconcilor::UserIdFetcher
116a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    : public gaia::GaiaOAuthClient::Delegate {
117a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham public:
118b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton  UserIdFetcher(AccountReconcilor* reconcilor,
119a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham                const std::string& access_token,
120b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton                const std::string& account_id);
121a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
122a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  // Returns the scopes needed by the UserIdFetcher.
123a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  static OAuth2TokenService::ScopeSet GetScopes();
124a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
125a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham private:
12654e7afa84d945f9137f9372ecde432f9e1a702fcGreg Clayton  // Overriden from gaia::GaiaOAuthClient::Delegate.
127a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  virtual void OnGetUserIdResponse(const std::string& user_id) OVERRIDE;
128a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  virtual void OnOAuthError() OVERRIDE;
129a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  virtual void OnNetworkError(int response_code) OVERRIDE;
130a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
131a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  AccountReconcilor* const reconcilor_;
132a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  const std::string account_id_;
133a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  const std::string access_token_;
134b1a9862ba1ceb219b6042ff3f8c6ff591867ae26Greg Clayton  gaia::GaiaOAuthClient gaia_auth_client_;
135a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
136a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  DISALLOW_COPY_AND_ASSIGN(UserIdFetcher);
137a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham};
138a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
139a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim InghamAccountReconcilor::UserIdFetcher::UserIdFetcher(AccountReconcilor* reconcilor,
140a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham                                                const std::string& access_token,
141a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham                                                const std::string& account_id)
142a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham    : reconcilor_(reconcilor),
14382cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton      account_id_(account_id),
14482cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton      access_token_(access_token),
14582cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton      gaia_auth_client_(reconcilor_->client()->GetURLRequestContext()) {
14682cfaed47126a17b4fa21e42e05546e7a041b9e3Greg Clayton  DCHECK(reconcilor_);
147a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham  DCHECK(!account_id_.empty());
148a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham
14954e7afa84d945f9137f9372ecde432f9e1a702fcGreg Clayton  const int kMaxRetries = 5;
150158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  gaia_auth_client_.GetUserId(access_token_, kMaxRetries, this);
151158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham}
152158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
153158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham// static
154158842ca982c53aca6c5ad7345d7b261e309292dJim InghamOAuth2TokenService::ScopeSet AccountReconcilor::UserIdFetcher::GetScopes() {
155158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  OAuth2TokenService::ScopeSet scopes;
156158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
157158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  return scopes;
158158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham}
159158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
160158842ca982c53aca6c5ad7345d7b261e309292dJim Inghamvoid AccountReconcilor::UserIdFetcher::OnGetUserIdResponse(
161158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham    const std::string& user_id) {
162158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  VLOG(1) << "AccountReconcilor::OnGetUserIdResponse: " << account_id_;
163158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
164158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  // HandleSuccessfulAccountIdCheck() may delete |this|, so call it last.
165158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  reconcilor_->HandleSuccessfulAccountIdCheck(account_id_);
166158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham}
167158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
168158842ca982c53aca6c5ad7345d7b261e309292dJim Inghamvoid AccountReconcilor::UserIdFetcher::OnOAuthError() {
169158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  VLOG(1) << "AccountReconcilor::OnOAuthError: " << account_id_;
170158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
171158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  // Invalidate the access token to force a refetch next time.
172158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  reconcilor_->token_service()->InvalidateToken(
173158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham      account_id_, GetScopes(), access_token_);
174158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
175158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  // HandleFailedAccountIdCheck() may delete |this|, so call it last.
176158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  reconcilor_->HandleFailedAccountIdCheck(account_id_);
177158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham}
178158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
179158842ca982c53aca6c5ad7345d7b261e309292dJim Inghamvoid AccountReconcilor::UserIdFetcher::OnNetworkError(int response_code) {
180158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  VLOG(1) << "AccountReconcilor::OnNetworkError: " << account_id_
181158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham          << " response_code=" << response_code;
182158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham
183158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  // TODO(rogerta): some response error should not be treated like
184158842ca982c53aca6c5ad7345d7b261e309292dJim Ingham  // permanent errors.  Figure out appropriate ones.
18524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // HandleFailedAccountIdCheck() may delete |this|, so call it last.
18624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  reconcilor_->HandleFailedAccountIdCheck(account_id_);
18724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
18824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
18924943d2ee8bfaa7cf5893e4709143924157a5c1eChris LattnerAccountReconcilor::AccountReconcilor(ProfileOAuth2TokenService* token_service,
19024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                                     SigninManagerBase* signin_manager,
19124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                                     SigninClient* client)
19214ef59fe5728d862c040cf5a6b99c384229a34eeGreg Clayton    : OAuth2TokenService::Consumer("account_reconcilor"),
193a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      token_service_(token_service),
194a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      signin_manager_(signin_manager),
19554e7afa84d945f9137f9372ecde432f9e1a702fcGreg Clayton      client_(client),
196a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      merge_session_helper_(token_service_,
197a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham                            client->GetURLRequestContext(),
198a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham                            this),
199a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      registered_with_token_service_(false),
200a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      is_reconcile_started_(false),
201a30baf5b257c7a62c5888679e7c1ac8eb47ca6d7Jim Ingham      are_gaia_accounts_set_(false),
20224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      requests_(NULL) {
20314ef59fe5728d862c040cf5a6b99c384229a34eeGreg Clayton  VLOG(1) << "AccountReconcilor::AccountReconcilor";
2048da92a74478ff2465e092aea92ce29ad7ad6ddddGreg Clayton}
2058da92a74478ff2465e092aea92ce29ad7ad6ddddGreg Clayton
2068da92a74478ff2465e092aea92ce29ad7ad6ddddGreg ClaytonAccountReconcilor::~AccountReconcilor() {
20724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::~AccountReconcilor";
20824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // Make sure shutdown was called first.
20924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK(!registered_with_token_service_);
21024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK(!reconciliation_timer_.IsRunning());
21124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK(!requests_);
21224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK_EQ(0u, user_id_fetchers_.size());
21324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK_EQ(0u, refresh_token_fetchers_.size());
21424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
21524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
21624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
21724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::Initialize";
21824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  RegisterWithSigninManager();
21924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
22024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // If this user is not signed in, the reconcilor should do nothing but
22124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // wait for signin.
22224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (IsProfileConnected()) {
22324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    RegisterForCookieChanges();
22424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    RegisterWithTokenService();
22524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    StartPeriodicReconciliation();
22624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
22724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Start a reconcile if the tokens are already loaded.
22824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (start_reconcile_if_tokens_available &&
22924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        token_service_->GetAccounts().size() > 0) {
23024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      StartReconcile();
23124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
232c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  }
233c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham}
234d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
235d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::Shutdown() {
236c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  VLOG(1) << "AccountReconcilor::Shutdown";
237c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  merge_session_helper_.CancelAll();
238c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  merge_session_helper_.RemoveObserver(this);
239c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  gaia_fetcher_.reset();
240c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  DeleteFetchers();
241c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  UnregisterWithSigninManager();
24224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  UnregisterWithTokenService();
24324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  UnregisterForCookieChanges();
24424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  StopPeriodicReconciliation();
24524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
246d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
247d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::AddMergeSessionObserver(
24824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    MergeSessionHelper::Observer* observer) {
24924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  merge_session_helper_.AddObserver(observer);
25024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
25124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
25224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::RemoveMergeSessionObserver(
25324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    MergeSessionHelper::Observer* observer) {
25424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  merge_session_helper_.RemoveObserver(observer);
25524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
25624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
25724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::DeleteFetchers() {
25824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  delete[] requests_;
25924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  requests_ = NULL;
26024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
26124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  user_id_fetchers_.clear();
26224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  refresh_token_fetchers_.clear();
26324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
26424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
26524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerbool AccountReconcilor::AreAllRefreshTokensChecked() const {
26624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  return chrome_accounts_.size() ==
26724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner         (valid_chrome_accounts_.size() + invalid_chrome_accounts_.size());
26824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
26924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
27024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::RegisterForCookieChanges() {
27124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // First clear any existing registration to avoid DCHECKs that can otherwise
27224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // go off in some embedders on reauth (e.g., ChromeSigninClient).
27324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  UnregisterForCookieChanges();
27424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  client_->SetCookieChangedCallback(
27524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
27624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
27724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
27824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::UnregisterForCookieChanges() {
279d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  client_->SetCookieChangedCallback(SigninClient::CookieChangedCallback());
28024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
28124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
28224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::RegisterWithSigninManager() {
28324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  signin_manager_->AddObserver(this);
28424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
28524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
28624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::UnregisterWithSigninManager() {
28724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  signin_manager_->RemoveObserver(this);
28824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
28924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
290d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::RegisterWithTokenService() {
29124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::RegisterWithTokenService";
29224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // During re-auth, the reconcilor will get a callback about successful signin
29324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // even when the profile is already connected.  Avoid re-registering
294d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  // with the token service since this will DCHECK.
29524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (registered_with_token_service_)
29624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return;
29724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
29824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  token_service_->AddObserver(this);
299c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  registered_with_token_service_ = true;
300c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham}
301c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham
302c4547c59f2e8390bdbf92484c851be06395b8e77Jim Inghamvoid AccountReconcilor::UnregisterWithTokenService() {
303c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  if (!registered_with_token_service_)
304d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    return;
305c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham
306c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  token_service_->RemoveObserver(this);
307c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  registered_with_token_service_ = false;
308d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton}
309d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
310d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonbool AccountReconcilor::IsProfileConnected() {
311c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  return !signin_manager_->GetAuthenticatedUsername().empty();
312c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham}
313d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
314c4547c59f2e8390bdbf92484c851be06395b8e77Jim Inghamvoid AccountReconcilor::StartPeriodicReconciliation() {
31524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::StartPeriodicReconciliation";
316c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  // TODO(rogerta): pick appropriate thread and timeout value.
317c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  reconciliation_timer_.Start(FROM_HERE,
31824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                              base::TimeDelta::FromSeconds(300),
31924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                              this,
32024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                              &AccountReconcilor::PeriodicReconciliation);
32124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
32224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
32324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::StopPeriodicReconciliation() {
32424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::StopPeriodicReconciliation";
32524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  reconciliation_timer_.Stop();
32624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
32724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
32824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::PeriodicReconciliation() {
32924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::PeriodicReconciliation";
33024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  StartReconcile();
33124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
33224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
33324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::OnCookieChanged(const net::CanonicalCookie* cookie) {
33424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (cookie->Name() == "LSID" &&
33524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      cookie->Domain() == GaiaUrls::GetInstance()->gaia_url().host() &&
33624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      cookie->IsSecure() && cookie->IsHttpOnly()) {
33724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    VLOG(1) << "AccountReconcilor::OnCookieChanged: LSID changed";
33824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#ifdef OS_CHROMEOS
33924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // On Chrome OS it is possible that O2RT is not available at this moment
34024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // because profile data transfer is still in progress.
34124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (!token_service_->GetAccounts().size()) {
34224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored"
34324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                 "because profile data transfer is in progress.";
34424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      return;
34524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
34624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#endif
34724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    StartReconcile();
34824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
34924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
35024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
35124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) {
35224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::OnRefreshTokenAvailable: " << account_id;
35324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  StartReconcile();
35424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
35524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
35624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) {
35731cf0e7c5ff8233eccef28ca22d025d7b490cb7aGreg Clayton  VLOG(1) << "AccountReconcilor::OnRefreshTokenRevoked: " << account_id;
35824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  StartRemoveAction(account_id);
35931cf0e7c5ff8233eccef28ca22d025d7b490cb7aGreg Clayton}
36024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
36124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::OnRefreshTokensLoaded() {}
36224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
36324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::GoogleSigninSucceeded(const std::string& username,
36424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                                              const std::string& password) {
36524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
36624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  RegisterForCookieChanges();
36724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  RegisterWithTokenService();
36824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  StartPeriodicReconciliation();
36924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
37024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
37124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::GoogleSignedOut(const std::string& username) {
37224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::GoogleSignedOut: signed out";
37324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  UnregisterWithTokenService();
37424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  UnregisterForCookieChanges();
37524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  StopPeriodicReconciliation();
37624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
37724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
37824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::PerformMergeAction(const std::string& account_id) {
37924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
38024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  merge_session_helper_.LogIn(account_id);
381d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton}
382d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
383d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::StartRemoveAction(const std::string& account_id) {
384d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  VLOG(1) << "AccountReconcilor::StartRemoveAction: " << account_id;
385d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  GetAccountsFromCookie(base::Bind(&AccountReconcilor::FinishRemoveAction,
386d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton                                   base::Unretained(this),
387d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton                                   account_id));
388d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton}
389d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
390d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::FinishRemoveAction(
391d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    const std::string& account_id,
392d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    const GoogleServiceAuthError& error,
393d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    const std::vector<std::pair<std::string, bool> >& accounts) {
394d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  VLOG(1) << "AccountReconcilor::FinishRemoveAction:"
395d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton          << " account=" << account_id << " error=" << error.ToString();
396d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  if (error.state() == GoogleServiceAuthError::NONE) {
397d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    AbortReconcile();
398d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    std::vector<std::string> accounts_only;
399d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    for (std::vector<std::pair<std::string, bool> >::const_iterator i =
400d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton             accounts.begin();
401d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton         i != accounts.end();
402d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton         ++i) {
403d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton      accounts_only.push_back(i->first);
404d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    }
405d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    merge_session_helper_.LogOut(account_id, accounts_only);
406d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  }
407d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  // Wait for the next ReconcileAction if there is an error.
408d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton}
409d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
410d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::PerformAddToChromeAction(const std::string& account_id,
411d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton                                                 int session_index) {
412d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  VLOG(1) << "AccountReconcilor::PerformAddToChromeAction:"
413d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton          << " account=" << account_id << " session_index=" << session_index;
414d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
415d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton#if !defined(OS_ANDROID) && !defined(OS_IOS)
416d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  refresh_token_fetchers_.push_back(
417d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton      new RefreshTokenFetcher(this, account_id, session_index));
418d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton#endif
419d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton}
420d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
421d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::PerformLogoutAllAccountsAction() {
422d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
4239b8550ee5ca4bb85b67352e1c63a1abf7f4a3809Jim Ingham  merge_session_helper_.LogOutAllAccounts();
424d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton}
425d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
426d6d806ceff943ca26c008f704013f18920685cfdGreg Claytonvoid AccountReconcilor::StartReconcile() {
427d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  if (!IsProfileConnected() || is_reconcile_started_)
428d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    return;
429d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
430d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  is_reconcile_started_ = true;
431d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
432d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  // Reset state for validating gaia cookie.
433d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  are_gaia_accounts_set_ = false;
434d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  gaia_accounts_.clear();
43524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  GetAccountsFromCookie(base::Bind(
43624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts,
43724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      base::Unretained(this)));
43824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
43924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // Reset state for validating oauth2 tokens.
44024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  primary_account_.clear();
44124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  chrome_accounts_.clear();
44224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DeleteFetchers();
443d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  valid_chrome_accounts_.clear();
44424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  invalid_chrome_accounts_.clear();
44524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  add_to_cookie_.clear();
44624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  add_to_chrome_.clear();
44724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  ValidateAccountsFromTokenService();
44824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
44924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
45024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::GetAccountsFromCookie(
45124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    GetAccountsFromCookieCallback callback) {
45224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  get_gaia_accounts_callbacks_.push_back(callback);
45324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (!gaia_fetcher_) {
45424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // There is no list account request in flight.
45524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    gaia_fetcher_.reset(new GaiaAuthFetcher(
45624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
45724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    gaia_fetcher_->StartListAccounts();
45824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
45924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
46024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
46124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::OnListAccountsSuccess(const std::string& data) {
46224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  gaia_fetcher_.reset();
46324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
46424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // Get account information from response data.
46524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  std::vector<std::pair<std::string, bool> > gaia_accounts;
46624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  bool valid_json = gaia::ParseListAccountsData(data, &gaia_accounts);
46724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (!valid_json) {
46824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: parsing error";
46924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  } else if (gaia_accounts.size() > 0) {
47024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: "
47124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            << "Gaia " << gaia_accounts.size() << " accounts, "
47224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            << "Primary is '" << gaia_accounts[0].first << "'";
47324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  } else {
47424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts";
47524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
47624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
47724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // There must be at least one callback waiting for result.
47824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK(!get_gaia_accounts_callbacks_.empty());
47924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
48024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  GoogleServiceAuthError error =
48124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      !valid_json ? GoogleServiceAuthError(
48224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                        GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE)
48324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                  : GoogleServiceAuthError::AuthErrorNone();
48424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  get_gaia_accounts_callbacks_.front().Run(error, gaia_accounts);
48524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  get_gaia_accounts_callbacks_.pop_front();
48624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
48724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  MayBeDoNextListAccounts();
48824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
48924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
49024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::OnListAccountsFailure(
49124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const GoogleServiceAuthError& error) {
49224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  gaia_fetcher_.reset();
49324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString();
49424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  std::vector<std::pair<std::string, bool> > empty_accounts;
49524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
49624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // There must be at least one callback waiting for result.
49724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK(!get_gaia_accounts_callbacks_.empty());
49824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
49924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  get_gaia_accounts_callbacks_.front().Run(error, empty_accounts);
50024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  get_gaia_accounts_callbacks_.pop_front();
50124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
50224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  MayBeDoNextListAccounts();
50324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
50424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
50524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::MayBeDoNextListAccounts() {
50624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (!get_gaia_accounts_callbacks_.empty()) {
50724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    gaia_fetcher_.reset(new GaiaAuthFetcher(
50824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
50924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    gaia_fetcher_->StartListAccounts();
51024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
511d6d47976b71187907c1cdeea86fabf7d5534314fJim Ingham}
51224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
513d6d47976b71187907c1cdeea86fabf7d5534314fJim Inghamvoid AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts(
514d6d47976b71187907c1cdeea86fabf7d5534314fJim Ingham    const GoogleServiceAuthError& error,
51524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const std::vector<std::pair<std::string, bool> >& accounts) {
51624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (error.state() == GoogleServiceAuthError::NONE) {
51724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    gaia_accounts_ = accounts;
51824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    are_gaia_accounts_set_ = true;
51924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    FinishReconcile();
52024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  } else {
52124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    AbortReconcile();
52224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
52324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
52424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
52524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::ValidateAccountsFromTokenService() {
52624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  primary_account_ = signin_manager_->GetAuthenticatedUsername();
527fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata  DCHECK(!primary_account_.empty());
528fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata
529fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata  chrome_accounts_ = token_service_->GetAccounts();
530fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata  DCHECK_GT(chrome_accounts_.size(), 0u);
531fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata
532fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata  VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
533fb2d05b85d8185f06d97d2c5444652fa74c246c3Enrico Granata          << "Chrome " << chrome_accounts_.size() << " accounts, "
53424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner          << "Primary is '" << primary_account_ << "'";
53524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
53624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DCHECK(!requests_);
53724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  requests_ =
53824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      new scoped_ptr<OAuth2TokenService::Request>[chrome_accounts_.size()];
53924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  const OAuth2TokenService::ScopeSet scopes =
54024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      AccountReconcilor::UserIdFetcher::GetScopes();
54124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
54224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    requests_[i] =
54324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        token_service_->StartRequest(chrome_accounts_[i], scopes, this);
544eddffe93d2c9ebb575e7b03fe1c5e71f9ecaf9f1Caroline Tice  }
545eddffe93d2c9ebb575e7b03fe1c5e71f9ecaf9f1Caroline Tice
546eddffe93d2c9ebb575e7b03fe1c5e71f9ecaf9f1Caroline Tice  DCHECK_EQ(0u, user_id_fetchers_.size());
547eddffe93d2c9ebb575e7b03fe1c5e71f9ecaf9f1Caroline Tice  user_id_fetchers_.resize(chrome_accounts_.size());
548eddffe93d2c9ebb575e7b03fe1c5e71f9ecaf9f1Caroline Tice}
549537a7a86687683fd403ce652d178fbc89e06ef9fGreg Clayton
550e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Ticevoid AccountReconcilor::OnGetTokenSuccess(
55127345db7bc4167078014798032137b0452f4cab9Greg Clayton    const OAuth2TokenService::Request* request,
55227345db7bc4167078014798032137b0452f4cab9Greg Clayton    const std::string& access_token,
553e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice    const base::Time& expiration_time) {
55427345db7bc4167078014798032137b0452f4cab9Greg Clayton  size_t index;
55527345db7bc4167078014798032137b0452f4cab9Greg Clayton  for (index = 0; index < chrome_accounts_.size(); ++index) {
55627345db7bc4167078014798032137b0452f4cab9Greg Clayton    if (request == requests_[index].get())
55727345db7bc4167078014798032137b0452f4cab9Greg Clayton      break;
55827345db7bc4167078014798032137b0452f4cab9Greg Clayton  }
55927345db7bc4167078014798032137b0452f4cab9Greg Clayton  DCHECK(index < chrome_accounts_.size());
560e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice
56127345db7bc4167078014798032137b0452f4cab9Greg Clayton  const std::string& account_id = chrome_accounts_[index];
56227345db7bc4167078014798032137b0452f4cab9Greg Clayton
56327345db7bc4167078014798032137b0452f4cab9Greg Clayton  VLOG(1) << "AccountReconcilor::OnGetTokenSuccess: valid " << account_id;
56427345db7bc4167078014798032137b0452f4cab9Greg Clayton
56527345db7bc4167078014798032137b0452f4cab9Greg Clayton  DCHECK(!user_id_fetchers_[index]);
56627345db7bc4167078014798032137b0452f4cab9Greg Clayton  user_id_fetchers_[index] = new UserIdFetcher(this, access_token, account_id);
567e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice}
56827345db7bc4167078014798032137b0452f4cab9Greg Clayton
56927345db7bc4167078014798032137b0452f4cab9Greg Claytonvoid AccountReconcilor::OnGetTokenFailure(
57027345db7bc4167078014798032137b0452f4cab9Greg Clayton    const OAuth2TokenService::Request* request,
57127345db7bc4167078014798032137b0452f4cab9Greg Clayton    const GoogleServiceAuthError& error) {
57227345db7bc4167078014798032137b0452f4cab9Greg Clayton  size_t index;
57327345db7bc4167078014798032137b0452f4cab9Greg Clayton  for (index = 0; index < chrome_accounts_.size(); ++index) {
57427345db7bc4167078014798032137b0452f4cab9Greg Clayton    if (request == requests_[index].get())
57527345db7bc4167078014798032137b0452f4cab9Greg Clayton      break;
57627345db7bc4167078014798032137b0452f4cab9Greg Clayton  }
57727345db7bc4167078014798032137b0452f4cab9Greg Clayton  DCHECK(index < chrome_accounts_.size());
578e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice
579e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice  const std::string& account_id = chrome_accounts_[index];
580e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice
581e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice  VLOG(1) << "AccountReconcilor::OnGetTokenFailure: invalid " << account_id;
582e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice  HandleFailedAccountIdCheck(account_id);
583e9ca3a4130bfb76765256549e01c759da8ec2f1dCaroline Tice}
584c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham
585c4547c59f2e8390bdbf92484c851be06395b8e77Jim Inghamvoid AccountReconcilor::FinishReconcile() {
586c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  // Make sure that the process of validating the gaia cookie and the oauth2
587c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  // tokens individually is done before proceeding with reconciliation.
588c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  if (!are_gaia_accounts_set_ || !AreAllRefreshTokensChecked())
589d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton    return;
590d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
591d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  VLOG(1) << "AccountReconcilor::FinishReconcile";
592d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton
593c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  DeleteFetchers();
594c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham
595d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  DCHECK(add_to_cookie_.empty());
596c4547c59f2e8390bdbf92484c851be06395b8e77Jim Ingham  DCHECK(add_to_chrome_.empty());
597d6d806ceff943ca26c008f704013f18920685cfdGreg Clayton  bool are_primaries_equal =
59824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      gaia_accounts_.size() > 0 &&
59924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
60024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
60124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (are_primaries_equal) {
60224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Determine if we need to merge accounts from gaia cookie to chrome.
60324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
60424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      const std::string& gaia_account = gaia_accounts_[i].first;
60524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      if (gaia_accounts_[i].second &&
60624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner          valid_chrome_accounts_.find(gaia_account) ==
60724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner              valid_chrome_accounts_.end()) {
60824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        add_to_chrome_.push_back(std::make_pair(gaia_account, i));
60924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      }
61024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
61124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  } else {
61224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
61324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // Really messed up state.  Blow away the gaia cookie completely and
61424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // rebuild it, making sure the primary account as specified by the
61524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    // SigninManager is the first session in the gaia cookie.
61624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    PerformLogoutAllAccountsAction();
61724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    gaia_accounts_.clear();
61824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
61924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
62024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // Create a list of accounts that need to be added to the gaia cookie.
62124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // The primary account must be first to make sure it becomes the default
62224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // account in the case where chrome is completely rebuilding the cookie.
62324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  add_to_cookie_.push_back(primary_account_);
62424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  for (EmailSet::const_iterator i = valid_chrome_accounts_.begin();
62524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        i != valid_chrome_accounts_.end();
62652fd984f7e67c3a0ab18d5565f40356bcfa84822Greg Clayton        ++i) {
62724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (*i != primary_account_)
62824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      add_to_cookie_.push_back(*i);
62924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
63024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
63124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // For each account known to chrome, PerformMergeAction() if the account is
63224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // not already in the cookie jar or its state is invalid, or signal merge
63324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // completed otherwise.  Make a copy of |add_to_cookie_| since calls to
63424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // SignalComplete() will change the array.
63524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  std::vector<std::string> add_to_cookie_copy = add_to_cookie_;
63624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  for (size_t i = 0; i < add_to_cookie_copy.size(); ++i) {
637b586901fb633b898e19bdfc8d605b4e89a3ab5b8Eli Friedman    if (gaia_accounts_.end() !=
63824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner            std::find_if(gaia_accounts_.begin(),
63924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                         gaia_accounts_.end(),
64024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                         std::bind1st(EmailEqualToFunc(),
64124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                                      std::make_pair(add_to_cookie_copy[i],
64224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner                                                     true)))) {
64324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      merge_session_helper_.SignalComplete(
64424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner          add_to_cookie_copy[i],
64524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner          GoogleServiceAuthError::AuthErrorNone());
64624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    } else {
64724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      PerformMergeAction(add_to_cookie_copy[i]);
64824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
64924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
65024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
65124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // For each account in the gaia cookie not known to chrome,
65224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // PerformAddToChromeAction.
65324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  for (std::vector<std::pair<std::string, int> >::const_iterator i =
65424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner           add_to_chrome_.begin();
65524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner       i != add_to_chrome_.end();
65624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner       ++i) {
65724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    PerformAddToChromeAction(i->first, i->second);
65824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
65924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
66024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  CalculateIfReconcileIsDone();
66124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  ScheduleStartReconcileIfChromeAccountsChanged();
66224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
66324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
66424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::AbortReconcile() {
66524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
66624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  DeleteFetchers();
66724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  add_to_cookie_.clear();
66824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  add_to_chrome_.clear();
66924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  CalculateIfReconcileIsDone();
67024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
67124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
67224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::CalculateIfReconcileIsDone() {
67324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  is_reconcile_started_ = !add_to_cookie_.empty() || !add_to_chrome_.empty();
67424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (!is_reconcile_started_)
67524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
67624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
67724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
67824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() {
67924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  if (is_reconcile_started_)
68024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    return;
68124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
68249ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  // Start a reconcile as the token accounts have changed.
68349ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged";
68424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  std::vector<std::string> reconciled_accounts(chrome_accounts_);
68549ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  std::vector<std::string> new_chrome_accounts(token_service_->GetAccounts());
68624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  std::sort(reconciled_accounts.begin(), reconciled_accounts.end());
68749ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  std::sort(new_chrome_accounts.begin(), new_chrome_accounts.end());
68849ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  if (reconciled_accounts != new_chrome_accounts) {
68924b48ff28b7c60dd4598212c3e77935a0fc1142dGreg Clayton    base::MessageLoop::current()->PostTask(
69024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner        FROM_HERE,
69124b48ff28b7c60dd4598212c3e77935a0fc1142dGreg Clayton        base::Bind(&AccountReconcilor::StartReconcile, base::Unretained(this)));
69249ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  }
69324b48ff28b7c60dd4598212c3e77935a0fc1142dGreg Clayton}
69449ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton
69524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnervoid AccountReconcilor::MergeSessionCompleted(
69624b48ff28b7c60dd4598212c3e77935a0fc1142dGreg Clayton    const std::string& account_id,
69724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    const GoogleServiceAuthError& error) {
69849ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton  VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id="
69924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner          << account_id;
70024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
70159df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  // Remove the account from the list that is being merged.
70259df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  for (std::vector<std::string>::iterator i = add_to_cookie_.begin();
70349ce682dfa7993d31206cea19ce7006cd3f3077eGreg Clayton       i != add_to_cookie_.end();
70424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner       ++i) {
70524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (account_id == *i) {
70659df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata      add_to_cookie_.erase(i);
70759df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata      break;
70859df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata    }
70949ce8969d3154e1560106cfe530444c09410f217Greg Clayton  }
71049ce8969d3154e1560106cfe530444c09410f217Greg Clayton
71149ce8969d3154e1560106cfe530444c09410f217Greg Clayton  CalculateIfReconcileIsDone();
71249ce8969d3154e1560106cfe530444c09410f217Greg Clayton  ScheduleStartReconcileIfChromeAccountsChanged();
71349ce8969d3154e1560106cfe530444c09410f217Greg Clayton}
71449ce8969d3154e1560106cfe530444c09410f217Greg Clayton
71549ce8969d3154e1560106cfe530444c09410f217Greg Claytonvoid AccountReconcilor::HandleSuccessfulAccountIdCheck(
71649ce8969d3154e1560106cfe530444c09410f217Greg Clayton    const std::string& account_id) {
71759df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  valid_chrome_accounts_.insert(account_id);
71859df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  FinishReconcile();
71959df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata}
72059df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata
72159df36f99b76e33852e6848a162f5c2851074ea2Enrico Granatavoid AccountReconcilor::HandleFailedAccountIdCheck(
72259df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata    const std::string& account_id) {
72359df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  invalid_chrome_accounts_.insert(account_id);
72459df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  FinishReconcile();
72559df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata}
726cbed99955c9a7cadc457fd8af2ec6946124fa9a1Johnny Chen
72759df36f99b76e33852e6848a162f5c2851074ea2Enrico Granatavoid AccountReconcilor::HandleRefreshTokenFetched(
72859df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata    const std::string& account_id,
72959df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata    const std::string& refresh_token) {
73059df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  if (!refresh_token.empty()) {
73159df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata    token_service_->UpdateCredentials(account_id, refresh_token);
73259df36f99b76e33852e6848a162f5c2851074ea2Enrico Granata  }
73324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
73424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  // Remove the account from the list that is being updated.
73524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  for (std::vector<std::pair<std::string, int> >::iterator i =
73624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner           add_to_chrome_.begin();
73724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner       i != add_to_chrome_.end();
73824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner       ++i) {
73924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    if (gaia::AreEmailsSame(account_id, i->first)) {
74024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      add_to_chrome_.erase(i);
74124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner      break;
74224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner    }
74324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  }
74424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
74524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner  CalculateIfReconcileIsDone();
74624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner}
74724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner