account_reconcilor.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "components/signin/core/browser/account_reconcilor.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <algorithm>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/bind.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/json/json_reader.h"
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/logging.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/message_loop/message_loop.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/time/time.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
17e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_client.h"
18c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "components/signin/core/browser/signin_oauth_helper.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_fetcher.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_oauth_client.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/cookies/canonical_cookie.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Fetches a refresh token from the given session in the GAIA cookie.  This is
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// a best effort only.  If it should fail, another reconcile action will occur
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// shortly anyway.
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class AccountReconcilor::RefreshTokenFetcher
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : public SigninOAuthHelper,
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      public SigninOAuthHelper::Consumer {
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RefreshTokenFetcher(AccountReconcilor* reconcilor,
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      const std::string& account_id,
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      int session_index);
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~RefreshTokenFetcher() {}
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Overridden from GaiaAuthConsumer:
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void OnSigninOAuthInformationAvailable(
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const std::string& email,
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const std::string& display_email,
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const std::string& refresh_token) OVERRIDE;
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Called when an error occurs while getting the information.
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void OnSigninOAuthInformationFailure(
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const GoogleServiceAuthError& error) OVERRIDE;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AccountReconcilor* reconcilor_;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string account_id_;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int session_index_;
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(RefreshTokenFetcher);
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AccountReconcilor::RefreshTokenFetcher::RefreshTokenFetcher(
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AccountReconcilor* reconcilor,
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int session_index)
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : SigninOAuthHelper(reconcilor->client()->GetURLRequestContext(),
61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        base::IntToString(session_index),
62c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        this),
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      reconcilor_(reconcilor),
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      account_id_(account_id),
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      session_index_(session_index) {
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(reconcilor_);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!account_id.empty());
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AccountReconcilor::RefreshTokenFetcher::OnSigninOAuthInformationAvailable(
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& email,
72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& display_email,
73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& refresh_token) {
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "RefreshTokenFetcher::OnSigninOAuthInformationAvailable:"
75c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          << " account=" << account_id_ << " email=" << email
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          << " displayEmail=" << display_email;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(rogerta): because of the problem with email vs displayEmail and
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // emails that have been canonicalized, the argument |email| is used here
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // to make sure the correct string is used when calling the token service.
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // This will be cleaned up when chrome moves to using gaia obfuscated id.
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  reconcilor_->HandleRefreshTokenFetched(email, refresh_token);
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AccountReconcilor::RefreshTokenFetcher::OnSigninOAuthInformationFailure(
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GoogleServiceAuthError& error) {
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "RefreshTokenFetcher::OnSigninOAuthInformationFailure:"
88c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          << " account=" << account_id_ << " session_index=" << session_index_;
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  reconcilor_->HandleRefreshTokenFetched(account_id_, std::string());
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AccountReconcilor::EmailLessFunc::operator()(const std::string& s1,
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                  const std::string& s2) const {
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return gaia::CanonicalizeEmail(s1) < gaia::CanonicalizeEmail(s2);
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class AccountReconcilor::UserIdFetcher
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : public gaia::GaiaOAuthClient::Delegate {
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UserIdFetcher(AccountReconcilor* reconcilor,
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                const std::string& access_token,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                const std::string& account_id);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Returns the scopes needed by the UserIdFetcher.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static OAuth2TokenService::ScopeSet GetScopes();
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Overriden from gaia::GaiaOAuthClient::Delegate.
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnGetUserIdResponse(const std::string& user_id) OVERRIDE;
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnOAuthError() OVERRIDE;
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void OnNetworkError(int response_code) OVERRIDE;
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AccountReconcilor* const reconcilor_;
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string account_id_;
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string access_token_;
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gaia::GaiaOAuthClient gaia_auth_client_;
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(UserIdFetcher);
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AccountReconcilor::UserIdFetcher::UserIdFetcher(AccountReconcilor* reconcilor,
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                const std::string& access_token,
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                const std::string& account_id)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : reconcilor_(reconcilor),
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      account_id_(account_id),
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      access_token_(access_token),
127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      gaia_auth_client_(reconcilor_->client()->GetURLRequestContext()) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(reconcilor_);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!account_id_.empty());
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int kMaxRetries = 5;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gaia_auth_client_.GetUserId(access_token_, kMaxRetries, this);
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)OAuth2TokenService::ScopeSet AccountReconcilor::UserIdFetcher::GetScopes() {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  OAuth2TokenService::ScopeSet scopes;
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return scopes;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::UserIdFetcher::OnGetUserIdResponse(
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& user_id) {
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnGetUserIdResponse: " << account_id_;
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // HandleSuccessfulAccountIdCheck() may delete |this|, so call it last.
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  reconcilor_->HandleSuccessfulAccountIdCheck(account_id_);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::UserIdFetcher::OnOAuthError() {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnOAuthError: " << account_id_;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Invalidate the access token to force a refetch next time.
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  reconcilor_->token_service()->InvalidateToken(
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      account_id_, GetScopes(), access_token_);
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // HandleFailedAccountIdCheck() may delete |this|, so call it last.
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  reconcilor_->HandleFailedAccountIdCheck(account_id_);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::UserIdFetcher::OnNetworkError(int response_code) {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnNetworkError: " << account_id_
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << " response_code=" << response_code;
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(rogerta): some response error should not be treated like
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // permanent errors.  Figure out appropriate ones.
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // HandleFailedAccountIdCheck() may delete |this|, so call it last.
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  reconcilor_->HandleFailedAccountIdCheck(account_id_);
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochAccountReconcilor::AccountReconcilor(ProfileOAuth2TokenService* token_service,
172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                     SigninManagerBase* signin_manager,
173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                     SigninClient* client)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : OAuth2TokenService::Consumer("account_reconcilor"),
175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      token_service_(token_service),
176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      signin_manager_(signin_manager),
177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      client_(client),
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      merge_session_helper_(token_service_,
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            client->GetURLRequestContext(),
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            this),
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registered_with_token_service_(false),
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      is_reconcile_started_(false),
183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      are_gaia_accounts_set_(false),
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      requests_(NULL) {
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::AccountReconcilor";
1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AccountReconcilor::~AccountReconcilor() {
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::~AccountReconcilor";
190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Make sure shutdown was called first.
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!registered_with_token_service_);
192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!reconciliation_timer_.IsRunning());
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!requests_);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(0u, user_id_fetchers_.size());
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(0u, refresh_token_fetchers_.size());
196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::Initialize";
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RegisterWithSigninManager();
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
202c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // If this user is not signed in, the reconcilor should do nothing but
203c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // wait for signin.
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsProfileConnected()) {
205e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    RegisterForCookieChanges();
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RegisterWithTokenService();
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    StartPeriodicReconciliation();
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Start a reconcile if the tokens are already loaded.
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (start_reconcile_if_tokens_available &&
211c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        token_service_->GetAccounts().size() > 0) {
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      StartReconcile();
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::Shutdown() {
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::Shutdown";
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.CancelAll();
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.RemoveObserver(this);
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gaia_fetcher_.reset();
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeleteFetchers();
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UnregisterWithSigninManager();
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UnregisterWithTokenService();
225e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  UnregisterForCookieChanges();
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  StopPeriodicReconciliation();
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::AddMergeSessionObserver(
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MergeSessionHelper::Observer* observer) {
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.AddObserver(observer);
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::RemoveMergeSessionObserver(
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MergeSessionHelper::Observer* observer) {
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.RemoveObserver(observer);
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::DeleteFetchers() {
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  delete[] requests_;
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  requests_ = NULL;
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  user_id_fetchers_.clear();
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  refresh_token_fetchers_.clear();
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool AccountReconcilor::AreAllRefreshTokensChecked() const {
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return chrome_accounts_.size() ==
249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         (valid_chrome_accounts_.size() + invalid_chrome_accounts_.size());
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
252e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AccountReconcilor::RegisterForCookieChanges() {
253e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // First clear any existing registration to avoid DCHECKs that can otherwise
254e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // go off in some embedders on reauth (e.g., ChromeSigninClient).
255e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  UnregisterForCookieChanges();
256e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  client_->SetCookieChangedCallback(
257e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
260e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AccountReconcilor::UnregisterForCookieChanges() {
261e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  client_->SetCookieChangedCallback(SigninClient::CookieChangedCallback());
2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::RegisterWithSigninManager() {
265c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  signin_manager_->AddObserver(this);
2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::UnregisterWithSigninManager() {
269c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  signin_manager_->RemoveObserver(this);
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::RegisterWithTokenService() {
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::RegisterWithTokenService";
2744ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  // During re-auth, the reconcilor will get a callback about successful signin
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // even when the profile is already connected.  Avoid re-registering
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // with the token service since this will DCHECK.
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (registered_with_token_service_)
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
280c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  token_service_->AddObserver(this);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registered_with_token_service_ = true;
2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::UnregisterWithTokenService() {
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!registered_with_token_service_)
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
288c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  token_service_->RemoveObserver(this);
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registered_with_token_service_ = false;
2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool AccountReconcilor::IsProfileConnected() {
293c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return !signin_manager_->GetAuthenticatedUsername().empty();
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::StartPeriodicReconciliation() {
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::StartPeriodicReconciliation";
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // TODO(rogerta): pick appropriate thread and timeout value.
299c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  reconciliation_timer_.Start(FROM_HERE,
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                              base::TimeDelta::FromSeconds(300),
301c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                              this,
302c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                              &AccountReconcilor::PeriodicReconciliation);
3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::StopPeriodicReconciliation() {
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::StopPeriodicReconciliation";
3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  reconciliation_timer_.Stop();
3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::PeriodicReconciliation() {
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::PeriodicReconciliation";
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StartReconcile();
3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
315e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AccountReconcilor::OnCookieChanged(const net::CanonicalCookie* cookie) {
316e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (cookie->Name() == "LSID" &&
317e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      cookie->Domain() == GaiaUrls::GetInstance()->gaia_url().host() &&
318e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      cookie->IsSecure() && cookie->IsHttpOnly()) {
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnCookieChanged: LSID changed";
320e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#ifdef OS_CHROMEOS
321e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // On Chrome OS it is possible that O2RT is not available at this moment
322e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // because profile data transfer is still in progress.
323c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!token_service_->GetAccounts().size()) {
324e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored"
325e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                 "because profile data transfer is in progress.";
326e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
327e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
328e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#endif
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    StartReconcile();
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) {
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnRefreshTokenAvailable: " << account_id;
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StartReconcile();
3361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) {
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnRefreshTokenRevoked: " << account_id;
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StartRemoveAction(account_id);
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
3431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::OnRefreshTokensLoaded() {}
3448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
345c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid AccountReconcilor::GoogleSigninSucceeded(const std::string& username,
346c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                              const std::string& password) {
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
348e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  RegisterForCookieChanges();
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegisterWithTokenService();
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StartPeriodicReconciliation();
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::GoogleSignedOut(const std::string& username) {
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::GoogleSignedOut: signed out";
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UnregisterWithTokenService();
356e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  UnregisterForCookieChanges();
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StopPeriodicReconciliation();
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.LogIn(account_id);
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::StartRemoveAction(const std::string& account_id) {
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::StartRemoveAction: " << account_id;
367c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GetAccountsFromCookie(base::Bind(&AccountReconcilor::FinishRemoveAction,
368c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                   base::Unretained(this),
369c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                   account_id));
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::FinishRemoveAction(
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GoogleServiceAuthError& error,
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::vector<std::pair<std::string, bool> >& accounts) {
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::FinishRemoveAction:"
377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          << " account=" << account_id << " error=" << error.ToString();
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error.state() == GoogleServiceAuthError::NONE) {
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AbortReconcile();
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::vector<std::string> accounts_only;
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (std::vector<std::pair<std::string, bool> >::const_iterator i =
382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch             accounts.begin();
383c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         i != accounts.end();
384c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         ++i) {
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      accounts_only.push_back(i->first);
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    merge_session_helper_.LogOut(account_id, accounts_only);
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Wait for the next ReconcileAction if there is an error.
3901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
392c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid AccountReconcilor::PerformAddToChromeAction(const std::string& account_id,
393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                                 int session_index) {
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::PerformAddToChromeAction:"
395c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          << " account=" << account_id << " session_index=" << session_index;
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if !defined(OS_ANDROID) && !defined(OS_IOS)
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  refresh_token_fetchers_.push_back(
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new RefreshTokenFetcher(this, account_id, session_index));
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
4011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::PerformLogoutAllAccountsAction() {
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.LogOutAllAccounts();
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::StartReconcile() {
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!IsProfileConnected() || is_reconcile_started_)
410f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_reconcile_started_ = true;
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
414f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Reset state for validating gaia cookie.
415f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  are_gaia_accounts_set_ = false;
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gaia_accounts_.clear();
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetAccountsFromCookie(base::Bind(
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts,
419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Unretained(this)));
420f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Reset state for validating oauth2 tokens.
422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  primary_account_.clear();
423f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  chrome_accounts_.clear();
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeleteFetchers();
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  valid_chrome_accounts_.clear();
426f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  invalid_chrome_accounts_.clear();
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  add_to_cookie_.clear();
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  add_to_chrome_.clear();
429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ValidateAccountsFromTokenService();
4301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::GetAccountsFromCookie(
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetAccountsFromCookieCallback callback) {
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.push_back(callback);
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!gaia_fetcher_) {
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // There is no list account request in flight.
437c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    gaia_fetcher_.reset(new GaiaAuthFetcher(
438c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gaia_fetcher_->StartListAccounts();
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::OnListAccountsSuccess(const std::string& data) {
444f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gaia_fetcher_.reset();
445f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
446f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Get account information from response data.
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::pair<std::string, bool> > gaia_accounts;
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool valid_json = gaia::ParseListAccountsData(data, &gaia_accounts);
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!valid_json) {
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: parsing error";
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (gaia_accounts.size() > 0) {
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: "
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "Gaia " << gaia_accounts.size() << " accounts, "
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << "Primary is '" << gaia_accounts[0].first << "'";
455f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts";
457f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There must be at least one callback waiting for result.
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!get_gaia_accounts_callbacks_.empty());
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
462c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GoogleServiceAuthError error =
463c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !valid_json ? GoogleServiceAuthError(
464c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE)
465c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                  : GoogleServiceAuthError::AuthErrorNone();
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.front().Run(error, gaia_accounts);
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.pop_front();
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MayBeDoNextListAccounts();
470f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
471f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
472f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::OnListAccountsFailure(
473f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const GoogleServiceAuthError& error) {
474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gaia_fetcher_.reset();
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString();
476a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::pair<std::string, bool> > empty_accounts;
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There must be at least one callback waiting for result.
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!get_gaia_accounts_callbacks_.empty());
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.front().Run(error, empty_accounts);
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.pop_front();
483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MayBeDoNextListAccounts();
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::MayBeDoNextListAccounts() {
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!get_gaia_accounts_callbacks_.empty()) {
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    gaia_fetcher_.reset(new GaiaAuthFetcher(
490c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gaia_fetcher_->StartListAccounts();
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts(
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GoogleServiceAuthError& error,
497a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::vector<std::pair<std::string, bool> >& accounts) {
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error.state() == GoogleServiceAuthError::NONE) {
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gaia_accounts_ = accounts;
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    are_gaia_accounts_set_ = true;
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FinishReconcile();
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AbortReconcile();
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
505f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
506f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
507f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::ValidateAccountsFromTokenService() {
508c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  primary_account_ = signin_manager_->GetAuthenticatedUsername();
509f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!primary_account_.empty());
510f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
511c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  chrome_accounts_ = token_service_->GetAccounts();
512a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_GT(chrome_accounts_.size(), 0u);
513f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << "Chrome " << chrome_accounts_.size() << " accounts, "
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << "Primary is '" << primary_account_ << "'";
517f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
518f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!requests_);
519f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  requests_ =
520f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      new scoped_ptr<OAuth2TokenService::Request>[chrome_accounts_.size()];
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const OAuth2TokenService::ScopeSet scopes =
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      AccountReconcilor::UserIdFetcher::GetScopes();
523f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
524c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    requests_[i] =
525c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        token_service_->StartRequest(chrome_accounts_[i], scopes, this);
526f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(0u, user_id_fetchers_.size());
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  user_id_fetchers_.resize(chrome_accounts_.size());
530f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
531f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
532f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::OnGetTokenSuccess(
533f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const OAuth2TokenService::Request* request,
534f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& access_token,
535f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const base::Time& expiration_time) {
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t index;
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (index = 0; index < chrome_accounts_.size(); ++index) {
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (request == requests_[index].get())
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(index < chrome_accounts_.size());
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& account_id = chrome_accounts_[index];
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnGetTokenSuccess: valid " << account_id;
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!user_id_fetchers_[index]);
548c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  user_id_fetchers_[index] = new UserIdFetcher(this, access_token, account_id);
549f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::OnGetTokenFailure(
552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const OAuth2TokenService::Request* request,
553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const GoogleServiceAuthError& error) {
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t index;
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (index = 0; index < chrome_accounts_.size(); ++index) {
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (request == requests_[index].get())
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(index < chrome_accounts_.size());
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& account_id = chrome_accounts_[index];
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
563c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  VLOG(1) << "AccountReconcilor::OnGetTokenFailure: invalid " << account_id;
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HandleFailedAccountIdCheck(account_id);
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::FinishReconcile() {
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Make sure that the process of validating the gaia cookie and the oauth2
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // tokens individually is done before proceeding with reconciliation.
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!are_gaia_accounts_set_ || !AreAllRefreshTokensChecked())
571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
572f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::FinishReconcile";
574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeleteFetchers();
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(add_to_cookie_.empty());
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(add_to_chrome_.empty());
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool are_primaries_equal =
580a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      gaia_accounts_.size() > 0 &&
581a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (are_primaries_equal) {
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determine if we need to merge accounts from gaia cookie to chrome.
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const std::string& gaia_account = gaia_accounts_[i].first;
587a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (gaia_accounts_[i].second &&
588c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch          valid_chrome_accounts_.find(gaia_account) ==
589c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch              valid_chrome_accounts_.end()) {
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        add_to_chrome_.push_back(std::make_pair(gaia_account, i));
591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
592f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determine if we need to merge accounts from chrome into gaia cookie.
595a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (EmailSet::const_iterator i = valid_chrome_accounts_.begin();
596c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         i != valid_chrome_accounts_.end();
597c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         ++i) {
598a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      bool add_to_cookie = true;
599a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      for (size_t j = 0; j < gaia_accounts_.size(); ++j) {
600a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (gaia::AreEmailsSame(gaia_accounts_[j].first, *i)) {
601a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          add_to_cookie = !gaia_accounts_[j].second;
602a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          break;
603a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
605a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (add_to_cookie)
606a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        add_to_cookie_.push_back(*i);
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Really messed up state.  Blow away the gaia cookie completely and
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // rebuild it, making sure the primary account as specified by the
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // SigninManager is the first session in the gaia cookie.
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PerformLogoutAllAccountsAction();
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    add_to_cookie_.push_back(primary_account_);
615a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (EmailSet::const_iterator i = valid_chrome_accounts_.begin();
616c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         i != valid_chrome_accounts_.end();
617c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         ++i) {
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (*i != primary_account_)
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        add_to_cookie_.push_back(*i);
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // For each account known to chrome but not in the gaia cookie,
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // PerformMergeAction().
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < add_to_cookie_.size(); ++i)
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PerformMergeAction(add_to_cookie_[i]);
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // For each account in the gaia cookie not known to chrome,
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // PerformAddToChromeAction.
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<std::pair<std::string, int> >::const_iterator i =
631c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch           add_to_chrome_.begin();
632c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       i != add_to_chrome_.end();
633c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       ++i) {
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PerformAddToChromeAction(i->first, i->second);
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateIfReconcileIsDone();
638a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScheduleStartReconcileIfChromeAccountsChanged();
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::AbortReconcile() {
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeleteFetchers();
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  add_to_cookie_.clear();
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  add_to_chrome_.clear();
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateIfReconcileIsDone();
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::CalculateIfReconcileIsDone() {
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_reconcile_started_ = !add_to_cookie_.empty() || !add_to_chrome_.empty();
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!is_reconcile_started_)
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() {
656a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (is_reconcile_started_)
657a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
658a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
659a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Start a reconcile as the token accounts have changed.
660a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged";
661a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::string> reconciled_accounts(chrome_accounts_);
662c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<std::string> new_chrome_accounts(token_service_->GetAccounts());
663a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::sort(reconciled_accounts.begin(), reconciled_accounts.end());
664a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::sort(new_chrome_accounts.begin(), new_chrome_accounts.end());
665a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (reconciled_accounts != new_chrome_accounts) {
666a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
667a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
668a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&AccountReconcilor::StartReconcile, base::Unretained(this)));
669a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
670a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
671a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::MergeSessionCompleted(
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GoogleServiceAuthError& error) {
6755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id="
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << account_id;
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Remove the account from the list that is being merged.
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<std::string>::iterator i = add_to_cookie_.begin();
680c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       i != add_to_cookie_.end();
681c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       ++i) {
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (account_id == *i) {
6835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      add_to_cookie_.erase(i);
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateIfReconcileIsDone();
689a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScheduleStartReconcileIfChromeAccountsChanged();
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::HandleSuccessfulAccountIdCheck(
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id) {
6945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  valid_chrome_accounts_.insert(account_id);
6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FinishReconcile();
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::HandleFailedAccountIdCheck(
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id) {
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  invalid_chrome_accounts_.insert(account_id);
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FinishReconcile();
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::HandleRefreshTokenFetched(
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& account_id,
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& refresh_token) {
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!refresh_token.empty()) {
708c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    token_service_->UpdateCredentials(account_id, refresh_token);
709f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
710f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Remove the account from the list that is being updated.
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<std::pair<std::string, int> >::iterator i =
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           add_to_chrome_.begin();
714c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       i != add_to_chrome_.end();
715c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       ++i) {
716a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (gaia::AreEmailsSame(account_id, i->first)) {
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      add_to_chrome_.erase(i);
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
720f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
7215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateIfReconcileIsDone();
7231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
724