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"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/signin/core/browser/signin_metrics.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/signin/core/common/profile_management_switches.h"
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_fetcher.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h"
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_oauth_client.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "net/cookies/canonical_cookie.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace {
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > {
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bool operator()(const std::pair<std::string, bool>& p1,
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                  const std::pair<std::string, bool>& p2) const;
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool EmailEqualToFunc::operator()(
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::pair<std::string, bool>& p1,
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::pair<std::string, bool>& p2) const {
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first);
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass AreEmailsSameFunc : public std::equal_to<std::string> {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool operator()(const std::string& p1,
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  const std::string& p2) const;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool AreEmailsSameFunc::operator()(
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& p1,
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& p2) const {
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return gaia::AreEmailsSame(p1, p2);
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochAccountReconcilor::AccountReconcilor(ProfileOAuth2TokenService* token_service,
58c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                     SigninManagerBase* signin_manager,
59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                     SigninClient* client)
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : token_service_(token_service),
61c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      signin_manager_(signin_manager),
62e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      client_(client),
63c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      merge_session_helper_(token_service_,
64c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            client->GetURLRequestContext(),
65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            this),
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registered_with_token_service_(false),
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      is_reconcile_started_(false),
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      first_execution_(true),
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      are_gaia_accounts_set_(false) {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::AccountReconcilor";
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AccountReconcilor::~AccountReconcilor() {
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::~AccountReconcilor";
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Make sure shutdown was called first.
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!registered_with_token_service_);
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AccountReconcilor::Initialize(bool start_reconcile_if_tokens_available) {
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::Initialize";
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  RegisterWithSigninManager();
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // If this user is not signed in, the reconcilor should do nothing but
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // wait for signin.
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsProfileConnected()) {
86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    RegisterForCookieChanges();
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RegisterWithTokenService();
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Start a reconcile if the tokens are already loaded.
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (start_reconcile_if_tokens_available &&
91c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        token_service_->GetAccounts().size() > 0) {
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      StartReconcile();
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::Shutdown() {
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::Shutdown";
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.CancelAll();
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.RemoveObserver(this);
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gaia_fetcher_.reset();
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  get_gaia_accounts_callbacks_.clear();
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UnregisterWithSigninManager();
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UnregisterWithTokenService();
105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  UnregisterForCookieChanges();
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::AddMergeSessionObserver(
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MergeSessionHelper::Observer* observer) {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.AddObserver(observer);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::RemoveMergeSessionObserver(
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MergeSessionHelper::Observer* observer) {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.RemoveObserver(observer);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AccountReconcilor::RegisterForCookieChanges() {
119e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // First clear any existing registration to avoid DCHECKs that can otherwise
120e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // go off in some embedders on reauth (e.g., ChromeSigninClient).
121e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  UnregisterForCookieChanges();
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  cookie_changed_subscription_ = client_->AddCookieChangedCallback(
123e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Bind(&AccountReconcilor::OnCookieChanged, base::Unretained(this)));
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
126e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AccountReconcilor::UnregisterForCookieChanges() {
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  cookie_changed_subscription_.reset();
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::RegisterWithSigninManager() {
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  signin_manager_->AddObserver(this);
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::UnregisterWithSigninManager() {
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  signin_manager_->RemoveObserver(this);
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::RegisterWithTokenService() {
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::RegisterWithTokenService";
1404ad1aa43a48567659193a298fad74f55e00b3dd9Ben Murdoch  // During re-auth, the reconcilor will get a callback about successful signin
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // even when the profile is already connected.  Avoid re-registering
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // with the token service since this will DCHECK.
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (registered_with_token_service_)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  token_service_->AddObserver(this);
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registered_with_token_service_ = true;
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::UnregisterWithTokenService() {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!registered_with_token_service_)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  token_service_->RemoveObserver(this);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  registered_with_token_service_ = false;
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool AccountReconcilor::IsProfileConnected() {
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return signin_manager_->IsAuthenticated();
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid AccountReconcilor::OnCookieChanged(const net::CanonicalCookie* cookie) {
163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (cookie->Name() == "LSID" &&
164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      cookie->Domain() == GaiaUrls::GetInstance()->gaia_url().host() &&
165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      cookie->IsSecure() && cookie->IsHttpOnly()) {
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnCookieChanged: LSID changed";
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // It is possible that O2RT is not available at this moment.
169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!token_service_->GetAccounts().size()) {
170e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      VLOG(1) << "AccountReconcilor::OnCookieChanged: cookie change is ingored"
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 "because O2RT is not available yet.";
172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      return;
173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    StartReconcile();
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid AccountReconcilor::OnEndBatchChanges() {
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VLOG(1) << "AccountReconcilor::OnEndBatchChanges";
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  StartReconcile();
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
1838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AccountReconcilor::GoogleSigninSucceeded(const std::string& account_id,
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                              const std::string& username,
186c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                              const std::string& password) {
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::GoogleSigninSucceeded: signed in";
188e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  RegisterForCookieChanges();
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RegisterWithTokenService();
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AccountReconcilor::GoogleSignedOut(const std::string& account_id,
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                        const std::string& username) {
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::GoogleSignedOut: signed out";
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  gaia_fetcher_.reset();
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  get_gaia_accounts_callbacks_.clear();
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AbortReconcile();
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UnregisterWithTokenService();
199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  UnregisterForCookieChanges();
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PerformLogoutAllAccountsAction();
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!switches::IsEnableAccountConsistency()) {
2056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    MarkAccountAsAddedToCookie(account_id);
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
2076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.LogIn(account_id);
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::PerformLogoutAllAccountsAction() {
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!switches::IsEnableAccountConsistency())
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  merge_session_helper_.LogOutAllAccounts();
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::StartReconcile() {
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!IsProfileConnected() || is_reconcile_started_ ||
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      get_gaia_accounts_callbacks_.size() > 0 ||
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      merge_session_helper_.is_running())
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_reconcile_started_ = true;
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  StartFetchingExternalCcResult();
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Reset state for validating gaia cookie.
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  are_gaia_accounts_set_ = false;
231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gaia_accounts_.clear();
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  GetAccountsFromCookie(base::Bind(
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      &AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts,
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Unretained(this)));
235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Reset state for validating oauth2 tokens.
237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  primary_account_.clear();
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  chrome_accounts_.clear();
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  add_to_cookie_.clear();
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ValidateAccountsFromTokenService();
2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::GetAccountsFromCookie(
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GetAccountsFromCookieCallback callback) {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.push_back(callback);
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!gaia_fetcher_) {
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // There is no list account request in flight.
248c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    gaia_fetcher_.reset(new GaiaAuthFetcher(
249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gaia_fetcher_->StartListAccounts();
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void AccountReconcilor::StartFetchingExternalCcResult() {
2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  merge_session_helper_.StartFetchingExternalCcResult();
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::OnListAccountsSuccess(const std::string& data) {
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gaia_fetcher_.reset();
260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Get account information from response data.
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::pair<std::string, bool> > gaia_accounts;
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool valid_json = gaia::ParseListAccountsData(data, &gaia_accounts);
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!valid_json) {
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: parsing error";
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (gaia_accounts.size() > 0) {
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: "
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "Gaia " << gaia_accounts.size() << " accounts, "
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << "Primary is '" << gaia_accounts[0].first << "'";
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts";
272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There must be at least one callback waiting for result.
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!get_gaia_accounts_callbacks_.empty());
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
277c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GoogleServiceAuthError error =
278c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      !valid_json ? GoogleServiceAuthError(
279c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                        GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE)
280c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                  : GoogleServiceAuthError::AuthErrorNone();
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.front().Run(error, gaia_accounts);
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.pop_front();
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MayBeDoNextListAccounts();
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::OnListAccountsFailure(
288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const GoogleServiceAuthError& error) {
289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gaia_fetcher_.reset();
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString();
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::pair<std::string, bool> > empty_accounts;
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There must be at least one callback waiting for result.
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!get_gaia_accounts_callbacks_.empty());
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.front().Run(error, empty_accounts);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  get_gaia_accounts_callbacks_.pop_front();
298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MayBeDoNextListAccounts();
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::MayBeDoNextListAccounts() {
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!get_gaia_accounts_callbacks_.empty()) {
304c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    gaia_fetcher_.reset(new GaiaAuthFetcher(
305c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        this, GaiaConstants::kChromeSource, client_->GetURLRequestContext()));
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gaia_fetcher_->StartListAccounts();
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::ContinueReconcileActionAfterGetGaiaAccounts(
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GoogleServiceAuthError& error,
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::vector<std::pair<std::string, bool> >& accounts) {
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error.state() == GoogleServiceAuthError::NONE) {
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gaia_accounts_ = accounts;
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    are_gaia_accounts_set_ = true;
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FinishReconcile();
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AbortReconcile();
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AccountReconcilor::ValidateAccountsFromTokenService() {
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  primary_account_ = signin_manager_->GetAuthenticatedAccountId();
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!primary_account_.empty());
325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
326c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  chrome_accounts_ = token_service_->GetAccounts();
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: "
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << "Chrome " << chrome_accounts_.size() << " accounts, "
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << "Primary is '" << primary_account_ << "'";
331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
332f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void AccountReconcilor::OnNewProfileManagementFlagChanged(
334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool new_flag_status) {
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (new_flag_status) {
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // The reconciler may have been newly created just before this call, or may
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // have already existed and in mid-reconcile. To err on the safe side, force
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // a restart.
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Shutdown();
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Initialize(true);
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Shutdown();
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::FinishReconcile() {
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::FinishReconcile";
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(are_gaia_accounts_set_);
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(add_to_cookie_.empty());
3506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  int number_gaia_accounts = gaia_accounts_.size();
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool are_primaries_equal = number_gaia_accounts > 0 &&
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If there are any accounts in the gaia cookie but not in chrome, then
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // those accounts need to be removed from the cookie.  This means we need
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // to blow the cookie away.
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int removed_from_cookie = 0;
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& gaia_account = gaia_accounts_[i].first;
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (gaia_accounts_[i].second &&
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        chrome_accounts_.end() ==
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            std::find_if(chrome_accounts_.begin(),
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         chrome_accounts_.end(),
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         std::bind1st(AreEmailsSameFunc(), gaia_account))) {
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ++removed_from_cookie;
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool rebuild_cookie = !are_primaries_equal || removed_from_cookie > 0;
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<std::pair<std::string, bool> > original_gaia_accounts =
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      gaia_accounts_;
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (rebuild_cookie) {
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Really messed up state.  Blow away the gaia cookie completely and
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // rebuild it, making sure the primary account as specified by the
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // SigninManager is the first session in the gaia cookie.
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PerformLogoutAllAccountsAction();
378010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    gaia_accounts_.clear();
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
381010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Create a list of accounts that need to be added to the gaia cookie.
382010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The primary account must be first to make sure it becomes the default
383010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // account in the case where chrome is completely rebuilding the cookie.
384010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  add_to_cookie_.push_back(primary_account_);
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < chrome_accounts_.size(); ++i) {
3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (chrome_accounts_[i] != primary_account_)
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      add_to_cookie_.push_back(chrome_accounts_[i]);
388010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
389010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
390010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // For each account known to chrome, PerformMergeAction() if the account is
391010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // not already in the cookie jar or its state is invalid, or signal merge
392010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // completed otherwise.  Make a copy of |add_to_cookie_| since calls to
393010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // SignalComplete() will change the array.
394010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<std::string> add_to_cookie_copy = add_to_cookie_;
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int added_to_cookie = 0;
3966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  bool external_cc_result_completed =
3976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      !merge_session_helper_.StillFetchingExternalCcResult();
398010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (size_t i = 0; i < add_to_cookie_copy.size(); ++i) {
399010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (gaia_accounts_.end() !=
400010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            std::find_if(gaia_accounts_.begin(),
401010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                         gaia_accounts_.end(),
402010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                         std::bind1st(EmailEqualToFunc(),
403010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                      std::make_pair(add_to_cookie_copy[i],
404010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                                     true)))) {
405010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      merge_session_helper_.SignalComplete(
406010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          add_to_cookie_copy[i],
407010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)          GoogleServiceAuthError::AuthErrorNone());
408010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    } else {
409010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      PerformMergeAction(add_to_cookie_copy[i]);
4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (original_gaia_accounts.end() ==
4111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              std::find_if(original_gaia_accounts.begin(),
4121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           original_gaia_accounts.end(),
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           std::bind1st(EmailEqualToFunc(),
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                        std::make_pair(add_to_cookie_copy[i],
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                       true)))) {
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        added_to_cookie++;
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      }
418010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
419010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Log whether the external connection checks were completed when we tried
4226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // to add the accounts to the cookie.
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (rebuild_cookie || added_to_cookie > 0)
4246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    signin_metrics::LogExternalCcResultFetches(external_cc_result_completed);
4256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
4261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  signin_metrics::LogSigninAccountReconciliation(chrome_accounts_.size(),
427cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                 added_to_cookie,
4281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                 removed_from_cookie,
429cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                 are_primaries_equal,
4306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                 first_execution_,
4316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                 number_gaia_accounts);
432cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  first_execution_ = false;
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateIfReconcileIsDone();
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScheduleStartReconcileIfChromeAccountsChanged();
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::AbortReconcile() {
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  add_to_cookie_.clear();
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CalculateIfReconcileIsDone();
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AccountReconcilor::CalculateIfReconcileIsDone() {
4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  is_reconcile_started_ = !add_to_cookie_.empty();
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!is_reconcile_started_)
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() {
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (is_reconcile_started_)
451a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Start a reconcile as the token accounts have changed.
454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::StartReconcileIfChromeAccountsChanged";
455a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<std::string> reconciled_accounts(chrome_accounts_);
456c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::vector<std::string> new_chrome_accounts(token_service_->GetAccounts());
457a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::sort(reconciled_accounts.begin(), reconciled_accounts.end());
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::sort(new_chrome_accounts.begin(), new_chrome_accounts.end());
459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (reconciled_accounts != new_chrome_accounts) {
460a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
461a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        FROM_HERE,
462a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&AccountReconcilor::StartReconcile, base::Unretained(this)));
463a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
464a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
465a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
4666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// Remove the account from the list that is being merged.
467116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool AccountReconcilor::MarkAccountAsAddedToCookie(
4686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::string& account_id) {
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<std::string>::iterator i = add_to_cookie_.begin();
470c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       i != add_to_cookie_.end();
471c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       ++i) {
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (account_id == *i) {
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      add_to_cookie_.erase(i);
474116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return true;
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
477116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return false;
4786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4806d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void AccountReconcilor::MergeSessionCompleted(
4816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const std::string& account_id,
4826d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const GoogleServiceAuthError& error) {
4836d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  VLOG(1) << "AccountReconcilor::MergeSessionCompleted: account_id="
4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          << account_id << " error=" << error.ToString();
4856d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
486116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (MarkAccountAsAddedToCookie(account_id)) {
487116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CalculateIfReconcileIsDone();
488116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ScheduleStartReconcileIfChromeAccountsChanged();
489116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
491