Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/sync/profile_sync_service.h"
      6 
      7 #include <stddef.h>
      8 #include <map>
      9 #include <ostream>
     10 #include <set>
     11 #include <utility>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/command_line.h"
     15 #include "base/compiler_specific.h"
     16 #include "base/logging.h"
     17 #include "base/memory/ref_counted.h"
     18 #include "base/message_loop.h"
     19 #include "base/metrics/histogram.h"
     20 #include "base/string16.h"
     21 #include "base/stringprintf.h"
     22 #include "base/task.h"
     23 #include "base/threading/thread_restrictions.h"
     24 #include "chrome/browser/net/gaia/token_service.h"
     25 #include "chrome/browser/platform_util.h"
     26 #include "chrome/browser/prefs/pref_service.h"
     27 #include "chrome/browser/profiles/profile.h"
     28 #include "chrome/browser/sync/backend_migrator.h"
     29 #include "chrome/browser/sync/engine/syncapi.h"
     30 #include "chrome/browser/sync/glue/change_processor.h"
     31 #include "chrome/browser/sync/glue/data_type_controller.h"
     32 #include "chrome/browser/sync/glue/data_type_manager.h"
     33 #include "chrome/browser/sync/glue/session_data_type_controller.h"
     34 #include "chrome/browser/sync/js_arg_list.h"
     35 #include "chrome/browser/sync/profile_sync_factory.h"
     36 #include "chrome/browser/sync/signin_manager.h"
     37 #include "chrome/browser/ui/browser.h"
     38 #include "chrome/browser/ui/browser_list.h"
     39 #include "chrome/common/chrome_switches.h"
     40 #include "chrome/common/net/gaia/gaia_constants.h"
     41 #include "chrome/common/pref_names.h"
     42 #include "chrome/common/time_format.h"
     43 #include "chrome/common/url_constants.h"
     44 #include "content/common/notification_details.h"
     45 #include "content/common/notification_source.h"
     46 #include "content/common/notification_type.h"
     47 #include "grit/generated_resources.h"
     48 #include "ui/base/l10n/l10n_util.h"
     49 #include "ui/gfx/native_widget_types.h"
     50 
     51 using browser_sync::ChangeProcessor;
     52 using browser_sync::DataTypeController;
     53 using browser_sync::DataTypeManager;
     54 using browser_sync::SyncBackendHost;
     55 using sync_api::SyncCredentials;
     56 
     57 typedef GoogleServiceAuthError AuthError;
     58 
     59 const char* ProfileSyncService::kSyncServerUrl =
     60     "https://clients4.google.com/chrome-sync";
     61 
     62 const char* ProfileSyncService::kDevServerUrl =
     63     "https://clients4.google.com/chrome-sync/dev";
     64 
     65 static const int kSyncClearDataTimeoutInSeconds = 60;  // 1 minute.
     66 
     67 ProfileSyncService::ProfileSyncService(ProfileSyncFactory* factory,
     68                                        Profile* profile,
     69                                        const std::string& cros_user)
     70     : last_auth_error_(AuthError::None()),
     71       observed_passphrase_required_(false),
     72       passphrase_required_for_decryption_(false),
     73       passphrase_migration_in_progress_(false),
     74       factory_(factory),
     75       profile_(profile),
     76       cros_user_(cros_user),
     77       sync_service_url_(kDevServerUrl),
     78       backend_initialized_(false),
     79       is_auth_in_progress_(false),
     80       wizard_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
     81       unrecoverable_error_detected_(false),
     82       scoped_runnable_method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
     83       expect_sync_configuration_aborted_(false),
     84       clear_server_data_state_(CLEAR_NOT_STARTED) {
     85   registrar_.Add(this,
     86                  NotificationType::SYNC_DATA_TYPES_UPDATED,
     87                  Source<Profile>(profile));
     88 
     89   // By default, dev & chromium users will go to the development servers.
     90   // Dev servers have more features than standard sync servers.
     91   // Chrome stable and beta builds will go to the standard sync servers.
     92 #if defined(GOOGLE_CHROME_BUILD)
     93   // GetVersionStringModifier hits the registry. See http://crbug.com/70380.
     94   base::ThreadRestrictions::ScopedAllowIO allow_io;
     95   // For stable, this is "". For dev, this is "dev". For beta, this is "beta".
     96   // For daily, this is "canary build".
     97   // For Linux Chromium builds, this could be anything depending on the
     98   // distribution, so always direct those users to dev server urls.
     99   // If this is an official build, it will always be one of the above.
    100   std::string channel = platform_util::GetVersionStringModifier();
    101   if (channel.empty() || channel == "beta") {
    102     sync_service_url_ = GURL(kSyncServerUrl);
    103   }
    104 #endif
    105 
    106   tried_implicit_gaia_remove_when_bug_62103_fixed_ = false;
    107 }
    108 
    109 ProfileSyncService::~ProfileSyncService() {
    110   Shutdown(false);
    111 }
    112 
    113 bool ProfileSyncService::AreCredentialsAvailable() {
    114   if (IsManaged()) {
    115     return false;
    116   }
    117 
    118   // CrOS user is always logged in. Chrome uses signin_ to check logged in.
    119   if (!cros_user_.empty() || !signin_->GetUsername().empty()) {
    120     // TODO(chron): Verify CrOS unit test behavior.
    121     if (profile()->GetTokenService() &&
    122         profile()->GetTokenService()->HasTokenForService(
    123             GaiaConstants::kSyncService)) {
    124       return true;
    125     }
    126   }
    127   return false;
    128 }
    129 
    130 void ProfileSyncService::Initialize() {
    131   InitSettings();
    132   RegisterPreferences();
    133 
    134   // Watch the preference that indicates sync is managed so we can take
    135   // appropriate action.
    136   pref_sync_managed_.Init(prefs::kSyncManaged, profile_->GetPrefs(), this);
    137 
    138   // For now, the only thing we can do through policy is to turn sync off.
    139   if (IsManaged()) {
    140     DisableForUser();
    141     return;
    142   }
    143 
    144   RegisterAuthNotifications();
    145 
    146   // In Chrome, we integrate a SigninManager which works with the sync
    147   // setup wizard to kick off the TokenService. CrOS does its own plumbing
    148   // for the TokenService.
    149   if (cros_user_.empty()) {
    150     // Will load tokens from DB and broadcast Token events after.
    151     // Note: We rely on signin_ != NULL unless !cros_user_.empty().
    152     signin_.reset(new SigninManager());
    153     signin_->Initialize(profile_);
    154   }
    155 
    156   if (!HasSyncSetupCompleted()) {
    157     DisableForUser();  // Clean up in case of previous crash / setup abort.
    158 
    159     // Under ChromeOS, just autostart it anyway if creds are here and start
    160     // is not being suppressed by preferences.
    161     if (!cros_user_.empty() &&
    162         !profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart) &&
    163         AreCredentialsAvailable()) {
    164       StartUp();
    165     }
    166   } else if (AreCredentialsAvailable()) {
    167     // If we have credentials and sync setup finished, autostart the backend.
    168     // Note that if we haven't finished setting up sync, backend bring up will
    169     // be done by the wizard.
    170     StartUp();
    171   }
    172 }
    173 
    174 void ProfileSyncService::RegisterAuthNotifications() {
    175   registrar_.Add(this,
    176                  NotificationType::TOKEN_AVAILABLE,
    177                  Source<TokenService>(profile_->GetTokenService()));
    178   registrar_.Add(this,
    179                  NotificationType::TOKEN_LOADING_FINISHED,
    180                  Source<TokenService>(profile_->GetTokenService()));
    181   registrar_.Add(this,
    182                  NotificationType::GOOGLE_SIGNIN_SUCCESSFUL,
    183                  Source<Profile>(profile_));
    184   registrar_.Add(this,
    185                  NotificationType::GOOGLE_SIGNIN_FAILED,
    186                  Source<Profile>(profile_));
    187 }
    188 
    189 void ProfileSyncService::RegisterDataTypeController(
    190     DataTypeController* data_type_controller) {
    191   DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
    192   data_type_controllers_[data_type_controller->type()] =
    193       data_type_controller;
    194 }
    195 
    196 browser_sync::SessionModelAssociator*
    197     ProfileSyncService::GetSessionModelAssociator() {
    198   if (data_type_controllers_.find(syncable::SESSIONS) ==
    199       data_type_controllers_.end() ||
    200       data_type_controllers_.find(syncable::SESSIONS)->second->state() !=
    201       DataTypeController::RUNNING) {
    202     return NULL;
    203   }
    204   return static_cast<browser_sync::SessionDataTypeController*>(
    205       data_type_controllers_.find(
    206       syncable::SESSIONS)->second.get())->GetModelAssociator();
    207 }
    208 
    209 void ProfileSyncService::ResetClearServerDataState() {
    210   clear_server_data_state_ = CLEAR_NOT_STARTED;
    211 }
    212 
    213 ProfileSyncService::ClearServerDataState
    214     ProfileSyncService::GetClearServerDataState() {
    215   return clear_server_data_state_;
    216 }
    217 
    218 void ProfileSyncService::GetDataTypeControllerStates(
    219   browser_sync::DataTypeController::StateMap* state_map) const {
    220     for (browser_sync::DataTypeController::TypeMap::const_iterator iter =
    221          data_type_controllers_.begin(); iter != data_type_controllers_.end();
    222          ++iter)
    223       (*state_map)[iter->first] = iter->second.get()->state();
    224 }
    225 
    226 void ProfileSyncService::InitSettings() {
    227   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    228 
    229   // Override the sync server URL from the command-line, if sync server
    230   // command-line argument exists.
    231   if (command_line.HasSwitch(switches::kSyncServiceURL)) {
    232     std::string value(command_line.GetSwitchValueASCII(
    233         switches::kSyncServiceURL));
    234     if (!value.empty()) {
    235       GURL custom_sync_url(value);
    236       if (custom_sync_url.is_valid()) {
    237         sync_service_url_ = custom_sync_url;
    238       } else {
    239         LOG(WARNING) << "The following sync URL specified at the command-line "
    240                      << "is invalid: " << value;
    241       }
    242     }
    243   }
    244 }
    245 
    246 void ProfileSyncService::RegisterPreferences() {
    247   PrefService* pref_service = profile_->GetPrefs();
    248   if (pref_service->FindPreference(prefs::kSyncLastSyncedTime))
    249     return;
    250   pref_service->RegisterInt64Pref(prefs::kSyncLastSyncedTime, 0);
    251   pref_service->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, false);
    252   pref_service->RegisterBooleanPref(prefs::kSyncSuppressStart, false);
    253 
    254   // If you've never synced before, or if you're using Chrome OS, all datatypes
    255   // are on by default.
    256   // TODO(nick): Perhaps a better model would be to always default to false,
    257   // and explicitly call SetDataTypes() when the user shows the wizard.
    258 #if defined(OS_CHROMEOS)
    259   bool enable_by_default = true;
    260 #else
    261   bool enable_by_default =
    262       !pref_service->HasPrefPath(prefs::kSyncHasSetupCompleted);
    263 #endif
    264 
    265   pref_service->RegisterBooleanPref(prefs::kSyncBookmarks, true);
    266   pref_service->RegisterBooleanPref(prefs::kSyncPasswords, enable_by_default);
    267   pref_service->RegisterBooleanPref(prefs::kSyncPreferences, enable_by_default);
    268   pref_service->RegisterBooleanPref(prefs::kSyncAutofill, enable_by_default);
    269   pref_service->RegisterBooleanPref(prefs::kSyncThemes, enable_by_default);
    270   pref_service->RegisterBooleanPref(prefs::kSyncTypedUrls, enable_by_default);
    271   pref_service->RegisterBooleanPref(prefs::kSyncExtensions, enable_by_default);
    272   pref_service->RegisterBooleanPref(prefs::kSyncApps, enable_by_default);
    273   pref_service->RegisterBooleanPref(prefs::kSyncSessions, enable_by_default);
    274   pref_service->RegisterBooleanPref(prefs::kKeepEverythingSynced,
    275       enable_by_default);
    276   pref_service->RegisterBooleanPref(prefs::kSyncManaged, false);
    277   pref_service->RegisterStringPref(prefs::kEncryptionBootstrapToken, "");
    278 
    279   pref_service->RegisterBooleanPref(prefs::kSyncAutofillProfile,
    280       enable_by_default);
    281 }
    282 
    283 void ProfileSyncService::ClearPreferences() {
    284   PrefService* pref_service = profile_->GetPrefs();
    285   pref_service->ClearPref(prefs::kSyncLastSyncedTime);
    286   pref_service->ClearPref(prefs::kSyncHasSetupCompleted);
    287   pref_service->ClearPref(prefs::kEncryptionBootstrapToken);
    288 
    289   // TODO(nick): The current behavior does not clear e.g. prefs::kSyncBookmarks.
    290   // Is that really what we want?
    291   pref_service->ScheduleSavePersistentPrefs();
    292 }
    293 
    294 SyncCredentials ProfileSyncService::GetCredentials() {
    295   SyncCredentials credentials;
    296   credentials.email = !cros_user_.empty() ? cros_user_ : signin_->GetUsername();
    297   DCHECK(!credentials.email.empty());
    298   TokenService* service = profile_->GetTokenService();
    299   credentials.sync_token = service->GetTokenForService(
    300       GaiaConstants::kSyncService);
    301   return credentials;
    302 }
    303 
    304 void ProfileSyncService::InitializeBackend(bool delete_sync_data_folder) {
    305   if (!backend_.get()) {
    306     NOTREACHED();
    307     return;
    308   }
    309 
    310   syncable::ModelTypeSet types;
    311   // If sync setup hasn't finished, we don't want to initialize routing info
    312   // for any data types so that we don't download updates for types that the
    313   // user chooses not to sync on the first DownloadUpdatesCommand.
    314   if (HasSyncSetupCompleted()) {
    315     GetPreferredDataTypes(&types);
    316   }
    317 
    318   SyncCredentials credentials = GetCredentials();
    319 
    320   backend_->Initialize(this,
    321                        sync_service_url_,
    322                        types,
    323                        profile_->GetRequestContext(),
    324                        credentials,
    325                        delete_sync_data_folder);
    326 }
    327 
    328 void ProfileSyncService::CreateBackend() {
    329   backend_.reset(new SyncBackendHost(profile_));
    330 }
    331 
    332 bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
    333   return !encrypted_types_.empty();
    334 }
    335 
    336 void ProfileSyncService::StartUp() {
    337   // Don't start up multiple times.
    338   if (backend_.get()) {
    339     VLOG(1) << "Skipping bringing up backend host.";
    340     return;
    341   }
    342 
    343   DCHECK(AreCredentialsAvailable());
    344 
    345   last_synced_time_ = base::Time::FromInternalValue(
    346       profile_->GetPrefs()->GetInt64(prefs::kSyncLastSyncedTime));
    347 
    348   CreateBackend();
    349 
    350   // Initialize the backend.  Every time we start up a new SyncBackendHost,
    351   // we'll want to start from a fresh SyncDB, so delete any old one that might
    352   // be there.
    353   InitializeBackend(!HasSyncSetupCompleted());
    354 }
    355 
    356 void ProfileSyncService::Shutdown(bool sync_disabled) {
    357   // Stop all data type controllers, if needed.
    358   if (data_type_manager_.get()) {
    359     if (data_type_manager_->state() != DataTypeManager::STOPPED) {
    360       data_type_manager_->Stop();
    361     }
    362 
    363     registrar_.Remove(this,
    364                       NotificationType::SYNC_CONFIGURE_START,
    365                       Source<DataTypeManager>(data_type_manager_.get()));
    366     registrar_.Remove(this,
    367                       NotificationType::SYNC_CONFIGURE_DONE,
    368                       Source<DataTypeManager>(data_type_manager_.get()));
    369     data_type_manager_.reset();
    370   }
    371 
    372   js_event_handlers_.RemoveBackend();
    373 
    374   // Move aside the backend so nobody else tries to use it while we are
    375   // shutting it down.
    376   scoped_ptr<SyncBackendHost> doomed_backend(backend_.release());
    377   if (doomed_backend.get()) {
    378     doomed_backend->Shutdown(sync_disabled);
    379 
    380     doomed_backend.reset();
    381   }
    382 
    383   // Clear various flags.
    384   is_auth_in_progress_ = false;
    385   backend_initialized_ = false;
    386   observed_passphrase_required_ = false;
    387   last_attempted_user_email_.clear();
    388   last_auth_error_ = GoogleServiceAuthError::None();
    389 }
    390 
    391 void ProfileSyncService::ClearServerData() {
    392   clear_server_data_state_ = CLEAR_CLEARING;
    393   clear_server_data_timer_.Start(
    394       base::TimeDelta::FromSeconds(kSyncClearDataTimeoutInSeconds), this,
    395       &ProfileSyncService::OnClearServerDataTimeout);
    396   backend_->RequestClearServerData();
    397 }
    398 
    399 void ProfileSyncService::DisableForUser() {
    400   // Clear prefs (including SyncSetupHasCompleted) before shutting down so
    401   // PSS clients don't think we're set up while we're shutting down.
    402   ClearPreferences();
    403   Shutdown(true);
    404 
    405   if (signin_.get()) {
    406     signin_->SignOut();
    407   }
    408 
    409   NotifyObservers();
    410 }
    411 
    412 bool ProfileSyncService::HasSyncSetupCompleted() const {
    413   return profile_->GetPrefs()->GetBoolean(prefs::kSyncHasSetupCompleted);
    414 }
    415 
    416 void ProfileSyncService::SetSyncSetupCompleted() {
    417   PrefService* prefs = profile()->GetPrefs();
    418   prefs->SetBoolean(prefs::kSyncHasSetupCompleted, true);
    419   prefs->SetBoolean(prefs::kSyncSuppressStart, false);
    420 
    421   prefs->ScheduleSavePersistentPrefs();
    422 }
    423 
    424 void ProfileSyncService::UpdateLastSyncedTime() {
    425   last_synced_time_ = base::Time::Now();
    426   profile_->GetPrefs()->SetInt64(prefs::kSyncLastSyncedTime,
    427       last_synced_time_.ToInternalValue());
    428   profile_->GetPrefs()->ScheduleSavePersistentPrefs();
    429 }
    430 
    431 void ProfileSyncService::NotifyObservers() {
    432   FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
    433   // TODO(akalin): Make an Observer subclass that listens and does the
    434   // event routing.
    435   js_event_handlers_.RouteJsEvent(
    436       "onSyncServiceStateChanged", browser_sync::JsArgList(), NULL);
    437 }
    438 
    439 // static
    440 const char* ProfileSyncService::GetPrefNameForDataType(
    441     syncable::ModelType data_type) {
    442   switch (data_type) {
    443     case syncable::BOOKMARKS:
    444       return prefs::kSyncBookmarks;
    445     case syncable::PASSWORDS:
    446       return prefs::kSyncPasswords;
    447     case syncable::PREFERENCES:
    448       return prefs::kSyncPreferences;
    449     case syncable::AUTOFILL:
    450       return prefs::kSyncAutofill;
    451     case syncable::AUTOFILL_PROFILE:
    452       return prefs::kSyncAutofillProfile;
    453     case syncable::THEMES:
    454       return prefs::kSyncThemes;
    455     case syncable::TYPED_URLS:
    456       return prefs::kSyncTypedUrls;
    457     case syncable::EXTENSIONS:
    458       return prefs::kSyncExtensions;
    459     case syncable::APPS:
    460       return prefs::kSyncApps;
    461     case syncable::SESSIONS:
    462       return prefs::kSyncSessions;
    463     default:
    464       break;
    465   }
    466   NOTREACHED();
    467   return NULL;
    468 }
    469 
    470 // An invariant has been violated.  Transition to an error state where we try
    471 // to do as little work as possible, to avoid further corruption or crashes.
    472 void ProfileSyncService::OnUnrecoverableError(
    473     const tracked_objects::Location& from_here,
    474     const std::string& message) {
    475   unrecoverable_error_detected_ = true;
    476   unrecoverable_error_message_ = message;
    477   unrecoverable_error_location_.reset(
    478       new tracked_objects::Location(from_here.function_name(),
    479                                     from_here.file_name(),
    480                                     from_here.line_number()));
    481 
    482   // Tell the wizard so it can inform the user only if it is already open.
    483   wizard_.Step(SyncSetupWizard::FATAL_ERROR);
    484 
    485   NotifyObservers();
    486   LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable."
    487       << message;
    488   std::string location;
    489   from_here.Write(true, true, &location);
    490   LOG(ERROR) << location;
    491 
    492   // Shut all data types down.
    493   MessageLoop::current()->PostTask(FROM_HERE,
    494         scoped_runnable_method_factory_.NewRunnableMethod(
    495         &ProfileSyncService::Shutdown, true));
    496 }
    497 
    498 void ProfileSyncService::OnBackendInitialized() {
    499   backend_initialized_ = true;
    500 
    501   js_event_handlers_.SetBackend(backend_->GetJsBackend());
    502 
    503   // The very first time the backend initializes is effectively the first time
    504   // we can say we successfully "synced".  last_synced_time_ will only be null
    505   // in this case, because the pref wasn't restored on StartUp.
    506   if (last_synced_time_.is_null()) {
    507     UpdateLastSyncedTime();
    508   }
    509   NotifyObservers();
    510 
    511   if (!cros_user_.empty()) {
    512     if (profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart)) {
    513       ShowConfigure(NULL, true);
    514     } else {
    515       SetSyncSetupCompleted();
    516     }
    517   }
    518 
    519   if (HasSyncSetupCompleted()) {
    520     ConfigureDataTypeManager();
    521   }
    522 }
    523 
    524 void ProfileSyncService::OnSyncCycleCompleted() {
    525   UpdateLastSyncedTime();
    526   VLOG(2) << "Notifying observers sync cycle completed";
    527   NotifyObservers();
    528 }
    529 
    530 void ProfileSyncService::UpdateAuthErrorState(
    531     const GoogleServiceAuthError& error) {
    532   last_auth_error_ = error;
    533   // Protect against the in-your-face dialogs that pop out of nowhere.
    534   // Require the user to click somewhere to run the setup wizard in the case
    535   // of a steady-state auth failure.
    536   if (WizardIsVisible()) {
    537     wizard_.Step(AuthError::NONE == last_auth_error_.state() ?
    538         SyncSetupWizard::GAIA_SUCCESS : SyncSetupWizard::GAIA_LOGIN);
    539   } else {
    540     auth_error_time_ = base::TimeTicks::Now();
    541   }
    542 
    543   if (!auth_start_time_.is_null()) {
    544     UMA_HISTOGRAM_TIMES("Sync.AuthorizationTimeInNetwork",
    545                     base::TimeTicks::Now() - auth_start_time_);
    546     auth_start_time_ = base::TimeTicks();
    547   }
    548 
    549   is_auth_in_progress_ = false;
    550   // Fan the notification out to interested UI-thread components.
    551   NotifyObservers();
    552 }
    553 
    554 void ProfileSyncService::OnAuthError() {
    555   UpdateAuthErrorState(backend_->GetAuthError());
    556 }
    557 
    558 void ProfileSyncService::OnStopSyncingPermanently() {
    559   if (SetupInProgress()) {
    560     wizard_.Step(SyncSetupWizard::SETUP_ABORTED_BY_PENDING_CLEAR);
    561     expect_sync_configuration_aborted_ = true;
    562   }
    563   profile_->GetPrefs()->SetBoolean(prefs::kSyncSuppressStart, true);
    564   DisableForUser();
    565 }
    566 
    567 void ProfileSyncService::OnClearServerDataTimeout() {
    568   if (clear_server_data_state_ != CLEAR_SUCCEEDED &&
    569       clear_server_data_state_ != CLEAR_FAILED) {
    570     clear_server_data_state_ = CLEAR_FAILED;
    571     NotifyObservers();
    572   }
    573 }
    574 
    575 void ProfileSyncService::OnClearServerDataFailed() {
    576   clear_server_data_timer_.Stop();
    577 
    578   // Only once clear has succeeded there is no longer a need to transition to
    579   // a failed state as sync is disabled locally.  Also, no need to fire off
    580   // the observers if the state didn't change (i.e. it was FAILED before).
    581   if (clear_server_data_state_ != CLEAR_SUCCEEDED &&
    582       clear_server_data_state_ != CLEAR_FAILED) {
    583     clear_server_data_state_ = CLEAR_FAILED;
    584     NotifyObservers();
    585   }
    586 }
    587 
    588 void ProfileSyncService::OnClearServerDataSucceeded() {
    589   clear_server_data_timer_.Stop();
    590 
    591   // Even if the timout fired, we still transition to the succeeded state as
    592   // we want UI to update itself and no longer allow the user to press "clear"
    593   if (clear_server_data_state_ != CLEAR_SUCCEEDED) {
    594     clear_server_data_state_ = CLEAR_SUCCEEDED;
    595     NotifyObservers();
    596   }
    597 }
    598 
    599 void ProfileSyncService::OnPassphraseRequired(bool for_decryption) {
    600   DCHECK(backend_.get());
    601   DCHECK(backend_->IsNigoriEnabled());
    602 
    603   // TODO(lipalani) : add this check to other locations as well.
    604   if (unrecoverable_error_detected_) {
    605     // When unrecoverable error is detected we post a task to shutdown the
    606     // backend. The task might not have executed yet.
    607     return;
    608   }
    609   observed_passphrase_required_ = true;
    610   passphrase_required_for_decryption_ = for_decryption;
    611 
    612   // First try supplying gaia password as the passphrase.
    613   if (!gaia_password_.empty()) {
    614     SetPassphrase(gaia_password_, false, true);
    615     gaia_password_ = std::string();
    616     return;
    617   }
    618 
    619   // If the above failed then try the custom passphrase the user might have
    620   // entered in setup.
    621   if (!cached_passphrase_.value.empty()) {
    622     SetPassphrase(cached_passphrase_.value,
    623                   cached_passphrase_.is_explicit,
    624                   cached_passphrase_.is_creation);
    625     cached_passphrase_ = CachedPassphrase();
    626     return;
    627   }
    628 
    629   // We will skip the passphrase prompt and suppress the warning
    630   // if the passphrase is needed for decryption but the user is
    631   // not syncing an encrypted data type on this machine.
    632   // Otherwise we prompt.
    633   if (!IsEncryptedDatatypeEnabled() && for_decryption) {
    634     OnPassphraseAccepted();
    635     return;
    636   }
    637 
    638   if (WizardIsVisible() && for_decryption) {
    639     wizard_.Step(SyncSetupWizard::ENTER_PASSPHRASE);
    640   }
    641 
    642   NotifyObservers();
    643 }
    644 
    645 void ProfileSyncService::OnPassphraseAccepted() {
    646   // Make sure the data types that depend on the passphrase are started at
    647   // this time.
    648   syncable::ModelTypeSet types;
    649   GetPreferredDataTypes(&types);
    650   // Reset "passphrase_required" flag before configuring the DataTypeManager
    651   // since we know we no longer require the passphrase.
    652   observed_passphrase_required_ = false;
    653   if (data_type_manager_.get())
    654     data_type_manager_->Configure(types);
    655 
    656   NotifyObservers();
    657 
    658   wizard_.Step(SyncSetupWizard::DONE);
    659 }
    660 
    661 void ProfileSyncService::OnEncryptionComplete(
    662     const syncable::ModelTypeSet& encrypted_types) {
    663   if (encrypted_types_ != encrypted_types) {
    664     encrypted_types_ = encrypted_types;
    665     NotifyObservers();
    666   }
    667 }
    668 
    669 void ProfileSyncService::OnMigrationNeededForTypes(
    670     const syncable::ModelTypeSet& types) {
    671   DCHECK(backend_initialized_);
    672   DCHECK(data_type_manager_.get());
    673 
    674   // Migrator must be valid, because we don't sync until it is created and this
    675   // callback originates from a sync cycle.
    676   migrator_->MigrateTypes(types);
    677 }
    678 
    679 void ProfileSyncService::ShowLoginDialog(gfx::NativeWindow parent_window) {
    680   if (WizardIsVisible()) {
    681     wizard_.Focus();
    682     // Force the wizard to step to the login screen (which will only actually
    683     // happen if the transition is valid).
    684     wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
    685     return;
    686   }
    687 
    688   if (!auth_error_time_.is_null()) {
    689     UMA_HISTOGRAM_LONG_TIMES("Sync.ReauthorizationTime",
    690                              base::TimeTicks::Now() - auth_error_time_);
    691     auth_error_time_ = base::TimeTicks();  // Reset auth_error_time_ to null.
    692   }
    693 
    694   wizard_.Step(SyncSetupWizard::GAIA_LOGIN);
    695 
    696   NotifyObservers();
    697 }
    698 
    699 void ProfileSyncService::ShowErrorUI(gfx::NativeWindow parent_window) {
    700   if (observed_passphrase_required()) {
    701     if (IsUsingSecondaryPassphrase())
    702       PromptForExistingPassphrase(parent_window);
    703     else
    704       SigninForPassphraseMigration(parent_window);
    705     return;
    706   }
    707   const GoogleServiceAuthError& error = GetAuthError();
    708   if (error.state() == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
    709       error.state() == GoogleServiceAuthError::CAPTCHA_REQUIRED ||
    710       error.state() == GoogleServiceAuthError::ACCOUNT_DELETED ||
    711       error.state() == GoogleServiceAuthError::ACCOUNT_DISABLED ||
    712       error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
    713     ShowLoginDialog(parent_window);
    714   }
    715 }
    716 
    717 
    718 void ProfileSyncService::ShowConfigure(
    719     gfx::NativeWindow parent_window, bool sync_everything) {
    720   if (WizardIsVisible()) {
    721     wizard_.Focus();
    722     return;
    723   }
    724 
    725   if (sync_everything)
    726     wizard_.Step(SyncSetupWizard::SYNC_EVERYTHING);
    727   else
    728     wizard_.Step(SyncSetupWizard::CONFIGURE);
    729 }
    730 
    731 void ProfileSyncService::PromptForExistingPassphrase(
    732     gfx::NativeWindow parent_window) {
    733   if (WizardIsVisible()) {
    734     wizard_.Focus();
    735     return;
    736   }
    737 
    738   wizard_.Step(SyncSetupWizard::ENTER_PASSPHRASE);
    739 }
    740 
    741 void ProfileSyncService::SigninForPassphraseMigration(
    742     gfx::NativeWindow parent_window) {
    743   passphrase_migration_in_progress_ = true;
    744   ShowLoginDialog(parent_window);
    745 }
    746 
    747 SyncBackendHost::StatusSummary ProfileSyncService::QuerySyncStatusSummary() {
    748   if (backend_.get() && backend_initialized_)
    749     return backend_->GetStatusSummary();
    750   else
    751     return SyncBackendHost::Status::OFFLINE_UNUSABLE;
    752 }
    753 
    754 SyncBackendHost::Status ProfileSyncService::QueryDetailedSyncStatus() {
    755   if (backend_.get() && backend_initialized_) {
    756     return backend_->GetDetailedStatus();
    757   } else {
    758     SyncBackendHost::Status status =
    759         { SyncBackendHost::Status::OFFLINE_UNUSABLE };
    760     return status;
    761   }
    762 }
    763 
    764 bool ProfileSyncService::SetupInProgress() const {
    765   return !HasSyncSetupCompleted() && WizardIsVisible();
    766 }
    767 
    768 std::string ProfileSyncService::BuildSyncStatusSummaryText(
    769     const sync_api::SyncManager::Status::Summary& summary) {
    770   const char* strings[] = {"INVALID", "OFFLINE", "OFFLINE_UNSYNCED", "SYNCING",
    771       "READY", "CONFLICT", "OFFLINE_UNUSABLE"};
    772   COMPILE_ASSERT(arraysize(strings) ==
    773                  sync_api::SyncManager::Status::SUMMARY_STATUS_COUNT,
    774                  enum_indexed_array);
    775   if (summary < 0 ||
    776       summary >= sync_api::SyncManager::Status::SUMMARY_STATUS_COUNT) {
    777     LOG(DFATAL) << "Illegal Summary Value: " << summary;
    778     return "UNKNOWN";
    779   }
    780   return strings[summary];
    781 }
    782 
    783 bool ProfileSyncService::unrecoverable_error_detected() const {
    784   return unrecoverable_error_detected_;
    785 }
    786 
    787 string16 ProfileSyncService::GetLastSyncedTimeString() const {
    788   if (last_synced_time_.is_null())
    789     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
    790 
    791   base::TimeDelta last_synced = base::Time::Now() - last_synced_time_;
    792 
    793   if (last_synced < base::TimeDelta::FromMinutes(1))
    794     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
    795 
    796   return TimeFormat::TimeElapsed(last_synced);
    797 }
    798 
    799 string16 ProfileSyncService::GetAuthenticatedUsername() const {
    800   if (backend_.get() && backend_initialized_)
    801     return backend_->GetAuthenticatedUsername();
    802   else
    803     return string16();
    804 }
    805 
    806 void ProfileSyncService::OnUserSubmittedAuth(
    807     const std::string& username, const std::string& password,
    808     const std::string& captcha, const std::string& access_code) {
    809   last_attempted_user_email_ = username;
    810   is_auth_in_progress_ = true;
    811   NotifyObservers();
    812 
    813   auth_start_time_ = base::TimeTicks::Now();
    814 
    815   if (!signin_.get()) {
    816     // In ChromeOS we sign in during login, so we do not instantiate signin_.
    817     // If this function gets called, we need to re-authenticate (e.g. for
    818     // two factor signin), so instantiate signin_ here.
    819     signin_.reset(new SigninManager());
    820     signin_->Initialize(profile_);
    821   }
    822 
    823   if (!access_code.empty()) {
    824     signin_->ProvideSecondFactorAccessCode(access_code);
    825     return;
    826   }
    827 
    828   if (!signin_->GetUsername().empty()) {
    829     signin_->SignOut();
    830   }
    831 
    832   // The user has submitted credentials, which indicates they don't
    833   // want to suppress start up anymore.
    834   PrefService* prefs = profile_->GetPrefs();
    835   prefs->SetBoolean(prefs::kSyncSuppressStart, false);
    836   prefs->ScheduleSavePersistentPrefs();
    837 
    838   signin_->StartSignIn(username,
    839                        password,
    840                        last_auth_error_.captcha().token,
    841                        captcha);
    842 }
    843 
    844 void ProfileSyncService::OnUserChoseDatatypes(bool sync_everything,
    845     const syncable::ModelTypeSet& chosen_types) {
    846   if (!backend_.get()) {
    847     NOTREACHED();
    848     return;
    849   }
    850 
    851   profile_->GetPrefs()->SetBoolean(prefs::kKeepEverythingSynced,
    852       sync_everything);
    853 
    854   ChangePreferredDataTypes(chosen_types);
    855   profile_->GetPrefs()->ScheduleSavePersistentPrefs();
    856 }
    857 
    858 void ProfileSyncService::OnUserCancelledDialog() {
    859   if (!HasSyncSetupCompleted()) {
    860     // A sync dialog was aborted before authentication.
    861     // Rollback.
    862     expect_sync_configuration_aborted_ = true;
    863     DisableForUser();
    864   }
    865 
    866   // Though an auth could still be in progress, once the dialog is closed we
    867   // don't want the UI to stay stuck in the "waiting for authentication" state
    868   // as that could take forever.  We set this to false so the buttons to re-
    869   // login will appear until either a) the original request finishes and
    870   // succeeds, calling OnAuthError(NONE), or b) the user clicks the button,
    871   // and tries to re-authenticate. (b) is a little awkward as this second
    872   // request will get queued behind the first and could wind up "undoing" the
    873   // good if invalid creds were provided, but it's an edge case and the user
    874   // can of course get themselves out of it.
    875   is_auth_in_progress_ = false;
    876   NotifyObservers();
    877 }
    878 
    879 void ProfileSyncService::ChangePreferredDataTypes(
    880     const syncable::ModelTypeSet& preferred_types) {
    881 
    882   // Filter out any datatypes which aren't registered, or for which
    883   // the preference can't be set.
    884   syncable::ModelTypeSet registered_types;
    885   GetRegisteredDataTypes(&registered_types);
    886   for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
    887     syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
    888     if (!registered_types.count(model_type))
    889       continue;
    890     const char* pref_name = GetPrefNameForDataType(model_type);
    891     if (!pref_name)
    892       continue;
    893     profile_->GetPrefs()->SetBoolean(pref_name,
    894         preferred_types.count(model_type) != 0);
    895     if (syncable::AUTOFILL == model_type) {
    896       profile_->GetPrefs()->SetBoolean(prefs::kSyncAutofillProfile,
    897           preferred_types.count(model_type) != 0);
    898     }
    899   }
    900 
    901   // If we haven't initialized yet, don't configure the DTM as it could cause
    902   // association to start before a Directory has even been created.
    903   if (backend_initialized_)
    904     ConfigureDataTypeManager();
    905 }
    906 
    907 void ProfileSyncService::GetPreferredDataTypes(
    908     syncable::ModelTypeSet* preferred_types) const {
    909   preferred_types->clear();
    910   if (profile_->GetPrefs()->GetBoolean(prefs::kKeepEverythingSynced)) {
    911     GetRegisteredDataTypes(preferred_types);
    912   } else {
    913     // Filter out any datatypes which aren't registered, or for which
    914     // the preference can't be read.
    915     syncable::ModelTypeSet registered_types;
    916     GetRegisteredDataTypes(&registered_types);
    917     for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
    918       syncable::ModelType model_type = syncable::ModelTypeFromInt(i);
    919       if (!registered_types.count(model_type))
    920         continue;
    921       if (model_type == syncable::AUTOFILL_PROFILE)
    922         continue;
    923       const char* pref_name = GetPrefNameForDataType(model_type);
    924       if (!pref_name)
    925         continue;
    926 
    927       // We are trying to group autofill_profile tag with the same
    928       // enabled/disabled state as autofill. Because the UI only shows autofill.
    929       if (profile_->GetPrefs()->GetBoolean(pref_name)) {
    930         preferred_types->insert(model_type);
    931         if (model_type == syncable::AUTOFILL) {
    932           if (!registered_types.count(syncable::AUTOFILL_PROFILE))
    933             continue;
    934           preferred_types->insert(syncable::AUTOFILL_PROFILE);
    935         }
    936       }
    937     }
    938   }
    939 }
    940 
    941 void ProfileSyncService::GetRegisteredDataTypes(
    942     syncable::ModelTypeSet* registered_types) const {
    943   registered_types->clear();
    944   // The data_type_controllers_ are determined by command-line flags; that's
    945   // effectively what controls the values returned here.
    946   for (DataTypeController::TypeMap::const_iterator it =
    947        data_type_controllers_.begin();
    948        it != data_type_controllers_.end(); ++it) {
    949     registered_types->insert((*it).first);
    950   }
    951 }
    952 
    953 bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
    954   return backend_.get() && (backend_->IsUsingExplicitPassphrase() ||
    955       (tried_implicit_gaia_remove_when_bug_62103_fixed_ &&
    956        observed_passphrase_required_));
    957 }
    958 
    959 bool ProfileSyncService::IsCryptographerReady(
    960     const sync_api::BaseTransaction* trans) const {
    961   return backend_.get() && backend_->IsCryptographerReady(trans);
    962 }
    963 
    964 SyncBackendHost* ProfileSyncService::GetBackendForTest() {
    965   // We don't check |backend_initialized_|; we assume the test class
    966   // knows what it's doing.
    967   return backend_.get();
    968 }
    969 
    970 void ProfileSyncService::ConfigureDataTypeManager() {
    971   if (!data_type_manager_.get()) {
    972     data_type_manager_.reset(
    973         factory_->CreateDataTypeManager(backend_.get(),
    974                                         data_type_controllers_));
    975     registrar_.Add(this,
    976                    NotificationType::SYNC_CONFIGURE_START,
    977                    Source<DataTypeManager>(data_type_manager_.get()));
    978     registrar_.Add(this,
    979                    NotificationType::SYNC_CONFIGURE_DONE,
    980                    Source<DataTypeManager>(data_type_manager_.get()));
    981 
    982     // We create the migrator at the same time.
    983     migrator_.reset(
    984         new browser_sync::BackendMigrator(this, data_type_manager_.get()));
    985   }
    986 
    987   syncable::ModelTypeSet types;
    988   GetPreferredDataTypes(&types);
    989   // We set this special case here since it's the only datatype whose encryption
    990   // status we already know. All others are set after the initial sync
    991   // completes (for now).
    992   // TODO(zea): Implement a better way that uses preferences for which types
    993   // need encryption.
    994   encrypted_types_.clear();
    995   if (types.count(syncable::PASSWORDS) > 0)
    996     encrypted_types_.insert(syncable::PASSWORDS);
    997   if (observed_passphrase_required_ && passphrase_required_for_decryption_) {
    998     if (IsEncryptedDatatypeEnabled()) {
    999       // We need a passphrase still. Prompt the user for a passphrase, and
   1000       // DataTypeManager::Configure() will get called once the passphrase is
   1001       // accepted.
   1002       OnPassphraseRequired(true);
   1003       return;
   1004     } else {
   1005       // We've been informed that a passphrase is required for decryption, but
   1006       // now there are no encrypted data types enabled, so clear the flag
   1007       // (NotifyObservers() will be called when configuration completes).
   1008       observed_passphrase_required_ = false;
   1009     }
   1010   }
   1011   data_type_manager_->Configure(types);
   1012 }
   1013 
   1014 sync_api::UserShare* ProfileSyncService::GetUserShare() const {
   1015   if (backend_.get() && backend_initialized_) {
   1016     return backend_->GetUserShare();
   1017   }
   1018   NOTREACHED();
   1019   return NULL;
   1020 }
   1021 
   1022 const browser_sync::sessions::SyncSessionSnapshot*
   1023     ProfileSyncService::GetLastSessionSnapshot() const {
   1024   if (backend_.get() && backend_initialized_) {
   1025     return backend_->GetLastSessionSnapshot();
   1026   }
   1027   NOTREACHED();
   1028   return NULL;
   1029 }
   1030 
   1031 bool ProfileSyncService::HasUnsyncedItems() const {
   1032   if (backend_.get() && backend_initialized_) {
   1033     return backend_->HasUnsyncedItems();
   1034   }
   1035   NOTREACHED();
   1036   return false;
   1037 }
   1038 
   1039 void ProfileSyncService::GetModelSafeRoutingInfo(
   1040     browser_sync::ModelSafeRoutingInfo* out) {
   1041   if (backend_.get() && backend_initialized_) {
   1042     backend_->GetModelSafeRoutingInfo(out);
   1043   } else {
   1044     NOTREACHED();
   1045   }
   1046 }
   1047 
   1048 syncable::AutofillMigrationState
   1049     ProfileSyncService::GetAutofillMigrationState() {
   1050   if (backend_.get() && backend_initialized_) {
   1051     return backend_->GetAutofillMigrationState();
   1052   }
   1053   NOTREACHED();
   1054   return syncable::NOT_DETERMINED;
   1055 }
   1056 
   1057 void ProfileSyncService::SetAutofillMigrationState(
   1058     syncable::AutofillMigrationState state) {
   1059   if (backend_.get() && backend_initialized_) {
   1060     backend_->SetAutofillMigrationState(state);
   1061   } else {
   1062     NOTREACHED();
   1063   }
   1064 }
   1065 
   1066 syncable::AutofillMigrationDebugInfo
   1067     ProfileSyncService::GetAutofillMigrationDebugInfo() {
   1068   if (backend_.get() && backend_initialized_) {
   1069     return backend_->GetAutofillMigrationDebugInfo();
   1070   }
   1071   NOTREACHED();
   1072   syncable::AutofillMigrationDebugInfo debug_info = { 0 };
   1073   return debug_info;
   1074 }
   1075 
   1076 void ProfileSyncService::SetAutofillMigrationDebugInfo(
   1077     syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
   1078     const syncable::AutofillMigrationDebugInfo& info) {
   1079   if (backend_.get() && backend_initialized_) {
   1080     backend_->SetAutofillMigrationDebugInfo(property_to_set, info);
   1081   } else {
   1082     NOTREACHED();
   1083   }
   1084 }
   1085 
   1086 void ProfileSyncService::ActivateDataType(
   1087     DataTypeController* data_type_controller,
   1088     ChangeProcessor* change_processor) {
   1089   if (!backend_.get()) {
   1090     NOTREACHED();
   1091     return;
   1092   }
   1093   DCHECK(backend_initialized_);
   1094   change_processor->Start(profile(), backend_->GetUserShare());
   1095   backend_->ActivateDataType(data_type_controller, change_processor);
   1096 }
   1097 
   1098 void ProfileSyncService::DeactivateDataType(
   1099     DataTypeController* data_type_controller,
   1100     ChangeProcessor* change_processor) {
   1101   change_processor->Stop();
   1102   if (backend_.get())
   1103     backend_->DeactivateDataType(data_type_controller, change_processor);
   1104 }
   1105 
   1106 void ProfileSyncService::SetPassphrase(const std::string& passphrase,
   1107                                        bool is_explicit,
   1108                                        bool is_creation) {
   1109   if (ShouldPushChanges() || observed_passphrase_required_) {
   1110     backend_->SetPassphrase(passphrase, is_explicit);
   1111   } else {
   1112     if (is_explicit) {
   1113       cached_passphrase_.value = passphrase;
   1114       cached_passphrase_.is_explicit = is_explicit;
   1115       cached_passphrase_.is_creation = is_creation;
   1116     } else {
   1117       gaia_password_ = passphrase;
   1118     }
   1119   }
   1120 }
   1121 
   1122 void ProfileSyncService::EncryptDataTypes(
   1123     const syncable::ModelTypeSet& encrypted_types) {
   1124   backend_->EncryptDataTypes(encrypted_types);
   1125 }
   1126 
   1127 void ProfileSyncService::GetEncryptedDataTypes(
   1128     syncable::ModelTypeSet* encrypted_types) const {
   1129   *encrypted_types = encrypted_types_;
   1130 }
   1131 
   1132 void ProfileSyncService::Observe(NotificationType type,
   1133                                  const NotificationSource& source,
   1134                                  const NotificationDetails& details) {
   1135   switch (type.value) {
   1136     case NotificationType::SYNC_CONFIGURE_START: {
   1137       NotifyObservers();
   1138       // TODO(sync): Maybe toast?
   1139       break;
   1140     }
   1141     case NotificationType::SYNC_CONFIGURE_DONE: {
   1142       DataTypeManager::ConfigureResultWithErrorLocation* result_with_location =
   1143           Details<DataTypeManager::ConfigureResultWithErrorLocation>(
   1144               details).ptr();
   1145 
   1146       DataTypeManager::ConfigureResult result = result_with_location->result;
   1147       if (result == DataTypeManager::ABORTED &&
   1148           expect_sync_configuration_aborted_) {
   1149         expect_sync_configuration_aborted_ = false;
   1150         return;
   1151       }
   1152       // Clear out the gaia password if it is already there.
   1153       gaia_password_ = std::string();
   1154       if (result != DataTypeManager::OK) {
   1155         std::string message = StringPrintf("Sync Configuration failed with %d",
   1156                                             result);
   1157         OnUnrecoverableError(*(result_with_location->location), message);
   1158         cached_passphrase_ = CachedPassphrase();
   1159         return;
   1160       }
   1161 
   1162       // If the user had entered a custom passphrase use it now.
   1163       if (!cached_passphrase_.value.empty()) {
   1164         // Don't hold on to the passphrase in raw form longer than needed.
   1165         SetPassphrase(cached_passphrase_.value,
   1166                       cached_passphrase_.is_explicit,
   1167                       cached_passphrase_.is_creation);
   1168         cached_passphrase_ = CachedPassphrase();
   1169       }
   1170 
   1171       // We should never get in a state where we have no encrypted datatypes
   1172       // enabled, and yet we still think we require a passphrase.
   1173       DCHECK(!(observed_passphrase_required_ &&
   1174                passphrase_required_for_decryption_ &&
   1175                !IsEncryptedDatatypeEnabled()));
   1176 
   1177       // TODO(sync): Less wizard, more toast.
   1178       wizard_.Step(SyncSetupWizard::DONE);
   1179       NotifyObservers();
   1180 
   1181       // In the old world, this would be a no-op.  With new syncer thread,
   1182       // this is the point where it is safe to switch from config-mode to
   1183       // normal operation.
   1184       backend_->StartSyncingWithServer();
   1185       break;
   1186     }
   1187     case NotificationType::SYNC_DATA_TYPES_UPDATED: {
   1188       if (!HasSyncSetupCompleted()) break;
   1189 
   1190       syncable::ModelTypeSet types;
   1191       GetPreferredDataTypes(&types);
   1192       OnUserChoseDatatypes(false, types);
   1193       break;
   1194     }
   1195     case NotificationType::PREF_CHANGED: {
   1196       std::string* pref_name = Details<std::string>(details).ptr();
   1197       if (*pref_name == prefs::kSyncManaged) {
   1198         NotifyObservers();
   1199         if (*pref_sync_managed_) {
   1200           DisableForUser();
   1201         } else if (HasSyncSetupCompleted() && AreCredentialsAvailable()) {
   1202           StartUp();
   1203         }
   1204       }
   1205       break;
   1206     }
   1207     case NotificationType::GOOGLE_SIGNIN_SUCCESSFUL: {
   1208       const GoogleServiceSigninSuccessDetails* successful =
   1209           (Details<const GoogleServiceSigninSuccessDetails>(details).ptr());
   1210       // We pass 'false' to SetPassphrase to denote that this is an implicit
   1211       // request and shouldn't override an explicit one.  Thus, we either
   1212       // update the implicit passphrase (idempotent if the passphrase didn't
   1213       // actually change), or the user has an explicit passphrase set so this
   1214       // becomes a no-op.
   1215       tried_implicit_gaia_remove_when_bug_62103_fixed_ = true;
   1216       SetPassphrase(successful->password, false, true);
   1217 
   1218       // If this signin was to initiate a passphrase migration (on the
   1219       // first computer, thus not for decryption), continue the migration.
   1220       if (passphrase_migration_in_progress_ &&
   1221           !passphrase_required_for_decryption_) {
   1222         wizard_.Step(SyncSetupWizard::PASSPHRASE_MIGRATION);
   1223         passphrase_migration_in_progress_ = false;
   1224       }
   1225 
   1226       break;
   1227     }
   1228     case NotificationType::GOOGLE_SIGNIN_FAILED: {
   1229       GoogleServiceAuthError error =
   1230           *(Details<const GoogleServiceAuthError>(details).ptr());
   1231       UpdateAuthErrorState(error);
   1232       break;
   1233     }
   1234     case NotificationType::TOKEN_AVAILABLE: {
   1235       if (AreCredentialsAvailable()) {
   1236         if (backend_initialized_) {
   1237           backend_->UpdateCredentials(GetCredentials());
   1238         }
   1239 
   1240         if (!profile_->GetPrefs()->GetBoolean(prefs::kSyncSuppressStart))
   1241           StartUp();
   1242       }
   1243       break;
   1244     }
   1245     case NotificationType::TOKEN_LOADING_FINISHED: {
   1246       // If not in Chrome OS, and we have a username without tokens,
   1247       // the user will need to signin again, so sign out.
   1248       if (cros_user_.empty() &&
   1249           !signin_->GetUsername().empty() &&
   1250           !AreCredentialsAvailable()) {
   1251         DisableForUser();
   1252       }
   1253       break;
   1254     }
   1255     default: {
   1256       NOTREACHED();
   1257     }
   1258   }
   1259 }
   1260 
   1261 void ProfileSyncService::AddObserver(Observer* observer) {
   1262   observers_.AddObserver(observer);
   1263 }
   1264 
   1265 void ProfileSyncService::RemoveObserver(Observer* observer) {
   1266   observers_.RemoveObserver(observer);
   1267 }
   1268 
   1269 bool ProfileSyncService::HasObserver(Observer* observer) const {
   1270   return observers_.HasObserver(observer);
   1271 }
   1272 
   1273 browser_sync::JsFrontend* ProfileSyncService::GetJsFrontend() {
   1274   return &js_event_handlers_;
   1275 }
   1276 
   1277 void ProfileSyncService::SyncEvent(SyncEventCodes code) {
   1278   UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
   1279 }
   1280 
   1281 // static
   1282 bool ProfileSyncService::IsSyncEnabled() {
   1283   // We have switches::kEnableSync just in case we need to change back to
   1284   // sync-disabled-by-default on a platform.
   1285   return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync);
   1286 }
   1287 
   1288 bool ProfileSyncService::IsManaged() {
   1289   // Some tests use ProfileSyncServiceMock which doesn't have a profile.
   1290   return profile_ && profile_->GetPrefs()->GetBoolean(prefs::kSyncManaged);
   1291 }
   1292 
   1293 bool ProfileSyncService::ShouldPushChanges() {
   1294   // True only after all bootstrapping has succeeded: the sync backend
   1295   // is initialized, all enabled data types are consistent with one
   1296   // another, and no unrecoverable error has transpired.
   1297   if (unrecoverable_error_detected_)
   1298     return false;
   1299 
   1300   if (!data_type_manager_.get())
   1301     return false;
   1302 
   1303   return data_type_manager_->state() == DataTypeManager::CONFIGURED;
   1304 }
   1305