Home | History | Annotate | Download | only in sync
      1 // Copyright (c) 2012 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 <cstddef>
      8 #include <map>
      9 #include <set>
     10 #include <utility>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/bind.h"
     14 #include "base/callback.h"
     15 #include "base/command_line.h"
     16 #include "base/compiler_specific.h"
     17 #include "base/logging.h"
     18 #include "base/memory/ref_counted.h"
     19 #include "base/message_loop/message_loop.h"
     20 #include "base/metrics/histogram.h"
     21 #include "base/strings/string16.h"
     22 #include "base/strings/stringprintf.h"
     23 #include "base/threading/thread_restrictions.h"
     24 #include "build/build_config.h"
     25 #include "chrome/browser/browser_process.h"
     26 #include "chrome/browser/chrome_notification_types.h"
     27 #include "chrome/browser/defaults.h"
     28 #include "chrome/browser/net/chrome_cookie_notification_details.h"
     29 #include "chrome/browser/prefs/pref_service_syncable.h"
     30 #include "chrome/browser/profiles/profile.h"
     31 #include "chrome/browser/signin/about_signin_internals.h"
     32 #include "chrome/browser/signin/about_signin_internals_factory.h"
     33 #include "chrome/browser/signin/profile_oauth2_token_service.h"
     34 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     35 #include "chrome/browser/signin/signin_manager.h"
     36 #include "chrome/browser/signin/signin_manager_factory.h"
     37 #include "chrome/browser/sync/backend_migrator.h"
     38 #include "chrome/browser/sync/glue/change_processor.h"
     39 #include "chrome/browser/sync/glue/chrome_encryptor.h"
     40 #include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
     41 #include "chrome/browser/sync/glue/data_type_controller.h"
     42 #include "chrome/browser/sync/glue/device_info.h"
     43 #include "chrome/browser/sync/glue/favicon_cache.h"
     44 #include "chrome/browser/sync/glue/session_data_type_controller.h"
     45 #include "chrome/browser/sync/glue/session_model_associator.h"
     46 #include "chrome/browser/sync/glue/sync_backend_host.h"
     47 #include "chrome/browser/sync/glue/sync_backend_host_impl.h"
     48 #include "chrome/browser/sync/glue/sync_start_util.h"
     49 #include "chrome/browser/sync/glue/synced_device_tracker.h"
     50 #include "chrome/browser/sync/glue/typed_url_data_type_controller.h"
     51 #include "chrome/browser/sync/profile_sync_components_factory_impl.h"
     52 #include "chrome/browser/sync/sessions2/notification_service_sessions_router.h"
     53 #include "chrome/browser/sync/sessions2/sessions_sync_manager.h"
     54 #include "chrome/browser/sync/sync_global_error.h"
     55 #include "chrome/browser/sync/user_selectable_sync_type.h"
     56 #include "chrome/browser/ui/browser.h"
     57 #include "chrome/browser/ui/browser_list.h"
     58 #include "chrome/browser/ui/browser_window.h"
     59 #include "chrome/browser/ui/global_error/global_error_service.h"
     60 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
     61 #include "chrome/common/chrome_switches.h"
     62 #include "chrome/common/chrome_version_info.h"
     63 #include "chrome/common/pref_names.h"
     64 #include "chrome/common/url_constants.h"
     65 #include "components/user_prefs/pref_registry_syncable.h"
     66 #include "content/public/browser/notification_details.h"
     67 #include "content/public/browser/notification_service.h"
     68 #include "content/public/browser/notification_source.h"
     69 #include "google_apis/gaia/gaia_constants.h"
     70 #include "grit/generated_resources.h"
     71 #include "net/cookies/cookie_monster.h"
     72 #include "net/url_request/url_request_context_getter.h"
     73 #include "sync/api/sync_error.h"
     74 #include "sync/internal_api/public/configure_reason.h"
     75 #include "sync/internal_api/public/http_bridge_network_resources.h"
     76 #include "sync/internal_api/public/network_resources.h"
     77 #include "sync/internal_api/public/sync_encryption_handler.h"
     78 #include "sync/internal_api/public/util/experiments.h"
     79 #include "sync/internal_api/public/util/sync_string_conversions.h"
     80 #include "sync/js/js_arg_list.h"
     81 #include "sync/js/js_event_details.h"
     82 #include "sync/util/cryptographer.h"
     83 #include "ui/base/l10n/l10n_util.h"
     84 #include "ui/base/l10n/time_format.h"
     85 
     86 #if defined(ENABLE_MANAGED_USERS)
     87 #include "chrome/browser/managed_mode/managed_user_constants.h"
     88 #endif
     89 
     90 #if defined(OS_ANDROID)
     91 #include "sync/internal_api/public/read_transaction.h"
     92 #endif
     93 
     94 using browser_sync::ChangeProcessor;
     95 using browser_sync::DataTypeController;
     96 using browser_sync::DataTypeManager;
     97 using browser_sync::FailedDataTypesHandler;
     98 using browser_sync::NotificationServiceSessionsRouter;
     99 using browser_sync::SyncBackendHost;
    100 using syncer::ModelType;
    101 using syncer::ModelTypeSet;
    102 using syncer::JsBackend;
    103 using syncer::JsController;
    104 using syncer::JsEventDetails;
    105 using syncer::JsEventHandler;
    106 using syncer::ModelSafeRoutingInfo;
    107 using syncer::SyncCredentials;
    108 using syncer::SyncProtocolError;
    109 using syncer::WeakHandle;
    110 
    111 typedef GoogleServiceAuthError AuthError;
    112 
    113 const char* ProfileSyncService::kSyncServerUrl =
    114     "https://clients4.google.com/chrome-sync";
    115 
    116 const char* ProfileSyncService::kDevServerUrl =
    117     "https://clients4.google.com/chrome-sync/dev";
    118 
    119 const char kSyncUnrecoverableErrorHistogram[] =
    120     "Sync.UnrecoverableErrors";
    121 
    122 const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
    123   // Number of initial errors (in sequence) to ignore before applying
    124   // exponential back-off rules.
    125   0,
    126 
    127   // Initial delay for exponential back-off in ms.
    128   2000,
    129 
    130   // Factor by which the waiting time will be multiplied.
    131   2,
    132 
    133   // Fuzzing percentage. ex: 10% will spread requests randomly
    134   // between 90%-100% of the calculated time.
    135   0.2, // 20%
    136 
    137   // Maximum amount of time we are willing to delay our request in ms.
    138   // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
    139   // RequestAccessToken on connection state change after backoff
    140   1000 * 3600 * 4, // 4 hours.
    141 
    142   // Time to keep an entry from being discarded even when it
    143   // has no significant state, -1 to never discard.
    144   -1,
    145 
    146   // Don't use initial delay unless the last request was an error.
    147   false,
    148 };
    149 
    150 bool ShouldShowActionOnUI(
    151     const syncer::SyncProtocolError& error) {
    152   return (error.action != syncer::UNKNOWN_ACTION &&
    153           error.action != syncer::DISABLE_SYNC_ON_CLIENT &&
    154           error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT);
    155 }
    156 
    157 ProfileSyncService::ProfileSyncService(
    158     ProfileSyncComponentsFactory* factory,
    159     Profile* profile,
    160     SigninManagerBase* signin_manager,
    161     ProfileOAuth2TokenService* oauth2_token_service,
    162     StartBehavior start_behavior)
    163     : last_auth_error_(AuthError::AuthErrorNone()),
    164       passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
    165       factory_(factory),
    166       profile_(profile),
    167       sync_prefs_(profile_->GetPrefs()),
    168       sync_service_url_(kDevServerUrl),
    169       data_type_requested_sync_startup_(false),
    170       is_first_time_sync_configure_(false),
    171       backend_initialized_(false),
    172       sync_disabled_by_admin_(false),
    173       is_auth_in_progress_(false),
    174       signin_(signin_manager),
    175       unrecoverable_error_reason_(ERROR_REASON_UNSET),
    176       expect_sync_configuration_aborted_(false),
    177       encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
    178       encrypt_everything_(false),
    179       encryption_pending_(false),
    180       auto_start_enabled_(start_behavior == AUTO_START),
    181       configure_status_(DataTypeManager::UNKNOWN),
    182       setup_in_progress_(false),
    183       oauth2_token_service_(oauth2_token_service),
    184       request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
    185       weak_factory_(this),
    186       connection_status_(syncer::CONNECTION_NOT_ATTEMPTED),
    187       last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
    188       network_resources_(new syncer::HttpBridgeNetworkResources) {
    189   DCHECK(profile);
    190   // By default, dev, canary, and unbranded Chromium users will go to the
    191   // development servers. Development servers have more features than standard
    192   // sync servers. Users with officially-branded Chrome stable and beta builds
    193   // will go to the standard sync servers.
    194   //
    195   // GetChannel hits the registry on Windows. See http://crbug.com/70380.
    196   base::ThreadRestrictions::ScopedAllowIO allow_io;
    197   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
    198   if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
    199       channel == chrome::VersionInfo::CHANNEL_BETA) {
    200     sync_service_url_ = GURL(kSyncServerUrl);
    201   }
    202 
    203   if (CommandLine::ForCurrentProcess()->HasSwitch(
    204       switches::kEnableSyncSessionsV2)) {
    205     syncer::SyncableService::StartSyncFlare flare(
    206         sync_start_util::GetFlareForSyncableService(profile->GetPath()));
    207     scoped_ptr<browser_sync::LocalSessionEventRouter> router(
    208         new NotificationServiceSessionsRouter(profile, flare));
    209     sessions_sync_manager_.reset(
    210         new SessionsSyncManager(profile, this, router.Pass()));
    211   }
    212 }
    213 
    214 ProfileSyncService::~ProfileSyncService() {
    215   sync_prefs_.RemoveSyncPrefObserver(this);
    216   // Shutdown() should have been called before destruction.
    217   CHECK(!backend_initialized_);
    218 }
    219 
    220 bool ProfileSyncService::IsSyncEnabledAndLoggedIn() {
    221   // Exit if sync is disabled.
    222   if (IsManaged() || sync_prefs_.IsStartSuppressed())
    223     return false;
    224 
    225   // Sync is logged in if there is a non-empty effective username.
    226   return !GetEffectiveUsername().empty();
    227 }
    228 
    229 bool ProfileSyncService::IsOAuthRefreshTokenAvailable() {
    230   if (!oauth2_token_service_)
    231     return false;
    232 
    233   return oauth2_token_service_->RefreshTokenIsAvailable(GetAccountIdToUse());
    234 }
    235 
    236 void ProfileSyncService::Initialize() {
    237   InitSettings();
    238 
    239   // We clear this here (vs Shutdown) because we want to remember that an error
    240   // happened on shutdown so we can display details (message, location) about it
    241   // in about:sync.
    242   ClearStaleErrors();
    243 
    244   sync_prefs_.AddSyncPrefObserver(this);
    245 
    246   // For now, the only thing we can do through policy is to turn sync off.
    247   if (IsManaged()) {
    248     DisableForUser();
    249     return;
    250   }
    251 
    252   RegisterAuthNotifications();
    253 
    254   if (!HasSyncSetupCompleted() || GetEffectiveUsername().empty()) {
    255     // Clean up in case of previous crash / setup abort / signout.
    256     DisableForUser();
    257   }
    258 
    259   TrySyncDatatypePrefRecovery();
    260 
    261   TryStart();
    262 }
    263 
    264 void ProfileSyncService::TrySyncDatatypePrefRecovery() {
    265   DCHECK(!sync_initialized());
    266   if (!HasSyncSetupCompleted())
    267     return;
    268 
    269   // There was a bug where OnUserChoseDatatypes was not properly called on
    270   // configuration (see crbug.com/154940). We detect this by checking whether
    271   // kSyncKeepEverythingSynced has a default value. If so, and sync setup has
    272   // completed, it means sync was not properly configured, so we manually
    273   // set kSyncKeepEverythingSynced.
    274   PrefService* const pref_service = profile_->GetPrefs();
    275   if (!pref_service)
    276     return;
    277   if (GetPreferredDataTypes().Size() > 1)
    278     return;
    279 
    280   const PrefService::Preference* keep_everything_synced =
    281       pref_service->FindPreference(prefs::kSyncKeepEverythingSynced);
    282   // This will be false if the preference was properly set or if it's controlled
    283   // by policy.
    284   if (!keep_everything_synced->IsDefaultValue())
    285     return;
    286 
    287   // kSyncKeepEverythingSynced was not properly set. Set it and the preferred
    288   // types now, before we configure.
    289   UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1);
    290   sync_prefs_.SetKeepEverythingSynced(true);
    291   syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
    292   sync_prefs_.SetPreferredDataTypes(registered_types,
    293                                     registered_types);
    294 }
    295 
    296 void ProfileSyncService::TryStart() {
    297   if (!IsSyncEnabledAndLoggedIn())
    298     return;
    299 
    300   // Don't start sync until tokens are loaded, because the user can be
    301   // "signed in" long before the tokens get loaded, and we don't want to
    302   // generate spurious auth errors.
    303   if (!IsOAuthRefreshTokenAvailable())
    304     return;
    305 
    306   // If we got here then tokens are loaded and user logged in and sync is
    307   // enabled. If OAuth refresh token is not available then something is wrong.
    308   // When PSS requests access token, OAuth2TokenService will return error and
    309   // PSS will show error to user asking to reauthenticate.
    310   UMA_HISTOGRAM_BOOLEAN("Sync.RefreshTokenAvailable",
    311       IsOAuthRefreshTokenAvailable());
    312 
    313   // If sync setup has completed we always start the backend. If the user is in
    314   // the process of setting up now, we should start the backend to download
    315   // account control state / encryption information). If autostart is enabled,
    316   // but we haven't completed sync setup, we try to start sync anyway, since
    317   // it's possible we crashed/shutdown after logging in but before the backend
    318   // finished initializing the last time.
    319   //
    320   // However, the only time we actually need to start sync _immediately_ is if
    321   // we haven't completed sync setup and the user is in the process of setting
    322   // up - either they just signed in (for the first time) on an auto-start
    323   // platform or they explicitly kicked off sync setup, and e.g we need to
    324   // fetch account details like encryption state to populate UI. Otherwise,
    325   // for performance reasons and maximizing parallelism at chrome startup, we
    326   // defer the heavy lifting for sync init until things have calmed down.
    327   if (HasSyncSetupCompleted()) {
    328     if (!data_type_requested_sync_startup_)
    329       StartUp(STARTUP_BACKEND_DEFERRED);
    330     else if (start_up_time_.is_null())
    331       StartUp(STARTUP_IMMEDIATE);
    332     else
    333       StartUpSlowBackendComponents();
    334   } else if (setup_in_progress_ || auto_start_enabled_) {
    335     // We haven't completed sync setup. Start immediately if the user explicitly
    336     // kicked this off or we're supposed to automatically start syncing.
    337     StartUp(STARTUP_IMMEDIATE);
    338   }
    339 }
    340 
    341 void ProfileSyncService::StartSyncingWithServer() {
    342   if (backend_)
    343     backend_->StartSyncingWithServer();
    344 }
    345 
    346 void ProfileSyncService::RegisterAuthNotifications() {
    347   oauth2_token_service_->AddObserver(this);
    348 
    349   registrar_.Add(this,
    350                  chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
    351                  content::Source<Profile>(profile_));
    352   registrar_.Add(this,
    353                  chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
    354                  content::Source<Profile>(profile_));
    355 }
    356 
    357 void ProfileSyncService::UnregisterAuthNotifications() {
    358   oauth2_token_service_->RemoveObserver(this);
    359   registrar_.RemoveAll();
    360 }
    361 
    362 void ProfileSyncService::RegisterDataTypeController(
    363     DataTypeController* data_type_controller) {
    364   DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
    365   data_type_controllers_[data_type_controller->type()] =
    366       data_type_controller;
    367 }
    368 
    369 browser_sync::SessionModelAssociator*
    370     ProfileSyncService::GetSessionModelAssociatorDeprecated() {
    371   if (!IsSessionsDataTypeControllerRunning())
    372     return NULL;
    373 
    374   // If we're using sessions V2, there's no model associator.
    375   if (sessions_sync_manager_.get())
    376     return NULL;
    377 
    378   return static_cast<browser_sync::SessionDataTypeController*>(
    379       data_type_controllers_.find(
    380       syncer::SESSIONS)->second.get())->GetModelAssociator();
    381 }
    382 
    383 bool ProfileSyncService::IsSessionsDataTypeControllerRunning() const {
    384   return data_type_controllers_.find(syncer::SESSIONS) !=
    385       data_type_controllers_.end() &&
    386       data_type_controllers_.find(syncer::SESSIONS)->second->state() ==
    387       DataTypeController::RUNNING;
    388 }
    389 
    390 browser_sync::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
    391   if (!IsSessionsDataTypeControllerRunning())
    392     return NULL;
    393 
    394   if (CommandLine::ForCurrentProcess()->HasSwitch(
    395       switches::kEnableSyncSessionsV2)) {
    396     return sessions_sync_manager_.get();
    397   } else {
    398     return GetSessionModelAssociatorDeprecated();
    399   }
    400 }
    401 
    402 browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() {
    403   // TODO(tim): Clean this up (or remove) once there's only one implementation.
    404   // Bug 98892.
    405   if (CommandLine::ForCurrentProcess()->HasSwitch(
    406       switches::kEnableSyncSessionsV2)) {
    407     return sessions_sync_manager_->GetFaviconCache();
    408   } else if (GetSessionModelAssociatorDeprecated()) {
    409     return GetSessionModelAssociatorDeprecated()->GetFaviconCache();
    410   } else {
    411     return NULL;
    412   }
    413 }
    414 
    415 scoped_ptr<browser_sync::DeviceInfo>
    416 ProfileSyncService::GetLocalDeviceInfo() const {
    417   if (backend_) {
    418     browser_sync::SyncedDeviceTracker* device_tracker =
    419         backend_->GetSyncedDeviceTracker();
    420     if (device_tracker)
    421       return device_tracker->ReadLocalDeviceInfo();
    422   }
    423   return scoped_ptr<browser_sync::DeviceInfo>();
    424 }
    425 
    426 scoped_ptr<browser_sync::DeviceInfo>
    427 ProfileSyncService::GetDeviceInfo(const std::string& client_id) const {
    428   if (backend_) {
    429     browser_sync::SyncedDeviceTracker* device_tracker =
    430         backend_->GetSyncedDeviceTracker();
    431     if (device_tracker)
    432       return device_tracker->ReadDeviceInfo(client_id);
    433   }
    434   return scoped_ptr<browser_sync::DeviceInfo>();
    435 }
    436 
    437 ScopedVector<browser_sync::DeviceInfo>
    438     ProfileSyncService::GetAllSignedInDevices() const {
    439   ScopedVector<browser_sync::DeviceInfo> devices;
    440   if (backend_) {
    441     browser_sync::SyncedDeviceTracker* device_tracker =
    442         backend_->GetSyncedDeviceTracker();
    443     if (device_tracker) {
    444       // TODO(lipalani) - Make device tracker return a scoped vector.
    445       device_tracker->GetAllSyncedDeviceInfo(&devices);
    446     }
    447   }
    448   return devices.Pass();
    449 }
    450 
    451 std::string ProfileSyncService::GetLocalSyncCacheGUID() const {
    452   if (backend_) {
    453     browser_sync::SyncedDeviceTracker* device_tracker =
    454         backend_->GetSyncedDeviceTracker();
    455     if (device_tracker) {
    456       return device_tracker->cache_guid();
    457     }
    458   }
    459   return std::string();
    460 }
    461 
    462 // Notifies the observer of any device info changes.
    463 void ProfileSyncService::AddObserverForDeviceInfoChange(
    464     browser_sync::SyncedDeviceTracker::Observer* observer) {
    465   if (backend_) {
    466     browser_sync::SyncedDeviceTracker* device_tracker =
    467         backend_->GetSyncedDeviceTracker();
    468     if (device_tracker) {
    469       device_tracker->AddObserver(observer);
    470     }
    471   }
    472 }
    473 
    474 // Removes the observer from device info change notification.
    475 void ProfileSyncService::RemoveObserverForDeviceInfoChange(
    476     browser_sync::SyncedDeviceTracker::Observer* observer) {
    477   if (backend_) {
    478     browser_sync::SyncedDeviceTracker* device_tracker =
    479         backend_->GetSyncedDeviceTracker();
    480     if (device_tracker) {
    481       device_tracker->RemoveObserver(observer);
    482     }
    483   }
    484 }
    485 
    486 void ProfileSyncService::GetDataTypeControllerStates(
    487   browser_sync::DataTypeController::StateMap* state_map) const {
    488     for (browser_sync::DataTypeController::TypeMap::const_iterator iter =
    489          data_type_controllers_.begin(); iter != data_type_controllers_.end();
    490          ++iter)
    491       (*state_map)[iter->first] = iter->second.get()->state();
    492 }
    493 
    494 void ProfileSyncService::InitSettings() {
    495   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    496 
    497   // Override the sync server URL from the command-line, if sync server
    498   // command-line argument exists.
    499   if (command_line.HasSwitch(switches::kSyncServiceURL)) {
    500     std::string value(command_line.GetSwitchValueASCII(
    501         switches::kSyncServiceURL));
    502     if (!value.empty()) {
    503       GURL custom_sync_url(value);
    504       if (custom_sync_url.is_valid()) {
    505         sync_service_url_ = custom_sync_url;
    506       } else {
    507         LOG(WARNING) << "The following sync URL specified at the command-line "
    508                      << "is invalid: " << value;
    509       }
    510     }
    511   }
    512 }
    513 
    514 SyncCredentials ProfileSyncService::GetCredentials() {
    515   SyncCredentials credentials;
    516   credentials.email = GetEffectiveUsername();
    517   DCHECK(!credentials.email.empty());
    518   credentials.sync_token = access_token_;
    519 
    520   if (credentials.sync_token.empty())
    521     credentials.sync_token = "credentials_lost";
    522   return credentials;
    523 }
    524 
    525 void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
    526   if (!backend_) {
    527     NOTREACHED();
    528     return;
    529   }
    530 
    531   SyncCredentials credentials = GetCredentials();
    532 
    533   scoped_refptr<net::URLRequestContextGetter> request_context_getter(
    534       profile_->GetRequestContext());
    535 
    536   if (delete_stale_data)
    537     ClearStaleErrors();
    538 
    539   scoped_ptr<syncer::UnrecoverableErrorHandler>
    540       backend_unrecoverable_error_handler(
    541           new browser_sync::BackendUnrecoverableErrorHandler(
    542               MakeWeakHandle(weak_factory_.GetWeakPtr())));
    543 
    544   backend_->Initialize(
    545       this,
    546       sync_thread_.Pass(),
    547       GetJsEventHandler(),
    548       sync_service_url_,
    549       credentials,
    550       delete_stale_data,
    551       scoped_ptr<syncer::SyncManagerFactory>(
    552           new syncer::SyncManagerFactory).Pass(),
    553       backend_unrecoverable_error_handler.Pass(),
    554       &browser_sync::ChromeReportUnrecoverableError,
    555       network_resources_.get());
    556 }
    557 
    558 void ProfileSyncService::CreateBackend() {
    559   backend_.reset(
    560       factory_->CreateSyncBackendHost(
    561           profile_->GetDebugName(),
    562           profile_,
    563           sync_prefs_.AsWeakPtr()));
    564 }
    565 
    566 bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
    567   if (encryption_pending())
    568     return true;
    569   const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
    570   const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes();
    571   DCHECK(encrypted_types.Has(syncer::PASSWORDS));
    572   return !Intersection(preferred_types, encrypted_types).Empty();
    573 }
    574 
    575 void ProfileSyncService::OnSyncConfigureRetry() {
    576   // Note: in order to handle auth failures that arise before the backend is
    577   // initialized (e.g. from invalidation notifier, or downloading new control
    578   // types), we have to gracefully handle configuration retries at all times.
    579   // At this point an auth error badge should be shown, which once resolved
    580   // will trigger a new sync cycle.
    581   NotifyObservers();
    582 }
    583 
    584 void ProfileSyncService::StartUp(StartUpDeferredOption deferred_option) {
    585   // Don't start up multiple times.
    586   if (backend_) {
    587     DVLOG(1) << "Skipping bringing up backend host.";
    588     return;
    589   }
    590 
    591   DCHECK(IsSyncEnabledAndLoggedIn());
    592 
    593   if (start_up_time_.is_null()) {
    594     start_up_time_ = base::Time::Now();
    595     last_synced_time_ = sync_prefs_.GetLastSyncedTime();
    596 
    597 #if defined(OS_CHROMEOS)
    598     std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
    599     if (bootstrap_token.empty()) {
    600       sync_prefs_.SetEncryptionBootstrapToken(
    601           sync_prefs_.GetSpareBootstrapToken());
    602     }
    603 #endif
    604 
    605 #if !defined(OS_ANDROID)
    606     if (!sync_global_error_) {
    607       sync_global_error_.reset(new SyncGlobalError(this, signin()));
    608       GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError(
    609           sync_global_error_.get());
    610       AddObserver(sync_global_error_.get());
    611     }
    612 #endif
    613   } else {
    614     // We don't care to prevent multiple calls to StartUp in deferred mode
    615     // because it's fast and has no side effects.
    616     DCHECK_EQ(STARTUP_BACKEND_DEFERRED, deferred_option);
    617   }
    618 
    619   if (deferred_option == STARTUP_BACKEND_DEFERRED &&
    620       CommandLine::ForCurrentProcess()->
    621           HasSwitch(switches::kSyncEnableDeferredStartup)) {
    622     return;
    623   }
    624 
    625   StartUpSlowBackendComponents();
    626 }
    627 
    628 void ProfileSyncService::OnDataTypeRequestsSyncStartup(
    629     syncer::ModelType type) {
    630   DCHECK(syncer::UserTypes().Has(type));
    631   if (backend_.get()) {
    632     DVLOG(1) << "A data type requested sync startup, but it looks like "
    633                 "something else beat it to the punch.";
    634     return;
    635   }
    636 
    637   if (!GetActiveDataTypes().Has(type)) {
    638     // We can get here as datatype SyncableServices are typically wired up
    639     // to the native datatype even if sync isn't enabled.
    640     DVLOG(1) << "Dropping sync startup request because type "
    641              << syncer::ModelTypeToString(type) << "not enabled.";
    642     return;
    643   }
    644 
    645   if (CommandLine::ForCurrentProcess()->HasSwitch(
    646           switches::kSyncEnableDeferredStartup)) {
    647     DVLOG(2) << "Data type requesting sync startup: "
    648              << syncer::ModelTypeToString(type);
    649     // Measure the time spent waiting for init and the type that triggered it.
    650     // We could measure the time spent deferred on a per-datatype basis, but
    651     // for now this is probably sufficient.
    652     if (!start_up_time_.is_null()) {
    653       // TODO(tim): Cache |type| and move this tracking to StartUp.  I'd like
    654       // to pull all the complicated init logic and state out of
    655       // ProfileSyncService and have only a StartUp method, though. One step
    656       // at a time. Bug 80149.
    657       base::TimeDelta time_deferred = base::Time::Now() - start_up_time_;
    658       UMA_HISTOGRAM_TIMES("Sync.Startup.TimeDeferred", time_deferred);
    659       UMA_HISTOGRAM_ENUMERATION("Sync.Startup.TypeTriggeringInit",
    660                                 ModelTypeToHistogramInt(type),
    661                                 syncer::MODEL_TYPE_COUNT);
    662     }
    663     data_type_requested_sync_startup_ = true;
    664     TryStart();
    665   }
    666   DVLOG(2) << "Ignoring data type request for sync startup: "
    667            << syncer::ModelTypeToString(type);
    668 }
    669 
    670 void ProfileSyncService::StartUpSlowBackendComponents() {
    671   // Don't start up multiple times.
    672   if (backend_) {
    673     DVLOG(1) << "Skipping bringing up backend host.";
    674     return;
    675   }
    676 
    677   DCHECK(IsSyncEnabledAndLoggedIn());
    678   CreateBackend();
    679 
    680   // Initialize the backend.  Every time we start up a new SyncBackendHost,
    681   // we'll want to start from a fresh SyncDB, so delete any old one that might
    682   // be there.
    683   InitializeBackend(!HasSyncSetupCompleted());
    684 }
    685 
    686 void ProfileSyncService::OnGetTokenSuccess(
    687     const OAuth2TokenService::Request* request,
    688     const std::string& access_token,
    689     const base::Time& expiration_time) {
    690   DCHECK_EQ(access_token_request_, request);
    691   access_token_request_.reset();
    692   access_token_ = access_token;
    693   token_receive_time_ = base::Time::Now();
    694   last_get_token_error_ = GoogleServiceAuthError::AuthErrorNone();
    695 
    696   if (sync_prefs_.SyncHasAuthError()) {
    697     sync_prefs_.SetSyncAuthError(false);
    698     UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
    699                               AUTH_ERROR_FIXED,
    700                               AUTH_ERROR_LIMIT);
    701   }
    702 
    703   if (backend_)
    704     backend_->UpdateCredentials(GetCredentials());
    705   else
    706     TryStart();
    707 }
    708 
    709 void ProfileSyncService::OnGetTokenFailure(
    710     const OAuth2TokenService::Request* request,
    711     const GoogleServiceAuthError& error) {
    712   DCHECK_EQ(access_token_request_, request);
    713   DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
    714   access_token_request_.reset();
    715   last_get_token_error_ = error;
    716   switch (error.state()) {
    717     case GoogleServiceAuthError::CONNECTION_FAILED:
    718     case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
    719       // Transient error. Retry after some time.
    720       request_access_token_backoff_.InformOfRequest(false);
    721       next_token_request_time_ = base::Time::Now() +
    722           request_access_token_backoff_.GetTimeUntilRelease();
    723       request_access_token_retry_timer_.Start(
    724             FROM_HERE,
    725             request_access_token_backoff_.GetTimeUntilRelease(),
    726             base::Bind(&ProfileSyncService::RequestAccessToken,
    727                         weak_factory_.GetWeakPtr()));
    728       NotifyObservers();
    729       break;
    730     }
    731     case GoogleServiceAuthError::SERVICE_ERROR:
    732     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
    733       // Report time since token was issued for invalid credentials error.
    734       base::Time auth_token_time =
    735           AboutSigninInternalsFactory::GetForProfile(profile_)->
    736               GetTokenTime(GaiaConstants::kGaiaOAuth2LoginRefreshToken);
    737       if (!auth_token_time.is_null()) {
    738         base::TimeDelta age = base::Time::Now() - auth_token_time;
    739         if (age < base::TimeDelta::FromHours(1)) {
    740           UMA_HISTOGRAM_CUSTOM_TIMES("Sync.AuthServerRejectedTokenAgeShort",
    741                                      age,
    742                                      base::TimeDelta::FromSeconds(1),
    743                                      base::TimeDelta::FromHours(1),
    744                                      50);
    745         }
    746         UMA_HISTOGRAM_COUNTS("Sync.AuthServerRejectedTokenAgeLong",
    747                              age.InDays());
    748       }
    749 
    750       if (!sync_prefs_.SyncHasAuthError()) {
    751         sync_prefs_.SetSyncAuthError(true);
    752         UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
    753                                   AUTH_ERROR_ENCOUNTERED,
    754                                   AUTH_ERROR_LIMIT);
    755       }
    756       // Fallthrough.
    757     }
    758     default: {
    759       // Show error to user.
    760       UpdateAuthErrorState(error);
    761     }
    762   }
    763 }
    764 
    765 void ProfileSyncService::OnRefreshTokenAvailable(
    766     const std::string& account_id) {
    767   if (account_id == GetAccountIdToUse())
    768     OnRefreshTokensLoaded();
    769 }
    770 
    771 void ProfileSyncService::OnRefreshTokenRevoked(
    772     const std::string& account_id) {
    773   if (!IsOAuthRefreshTokenAvailable()) {
    774     access_token_.clear();
    775     // The additional check around IsOAuthRefreshTokenAvailable() above
    776     // prevents us sounding the alarm if we actually have a valid token but
    777     // a refresh attempt failed for any variety of reasons
    778     // (e.g. flaky network). It's possible the token we do have is also
    779     // invalid, but in that case we should already have (or can expect) an
    780     // auth error sent from the sync backend.
    781     UpdateAuthErrorState(
    782         GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
    783   }
    784 }
    785 
    786 void ProfileSyncService::OnRefreshTokensLoaded() {
    787   // This notification gets fired when OAuth2TokenService loads the tokens
    788   // from storage.
    789   // Initialize the backend if sync is enabled. If the sync token was
    790   // not loaded, GetCredentials() will generate invalid credentials to
    791   // cause the backend to generate an auth error (crbug.com/121755).
    792   if (backend_) {
    793     RequestAccessToken();
    794   } else {
    795     TryStart();
    796   }
    797 }
    798 
    799 void ProfileSyncService::Shutdown() {
    800   UnregisterAuthNotifications();
    801 
    802   ShutdownImpl(browser_sync::SyncBackendHost::STOP);
    803 
    804   if (sync_thread_)
    805     sync_thread_->Stop();
    806 }
    807 
    808 void ProfileSyncService::ShutdownImpl(
    809     browser_sync::SyncBackendHost::ShutdownOption option) {
    810   if (!backend_)
    811     return;
    812 
    813   // First, we spin down the backend to stop change processing as soon as
    814   // possible.
    815   base::Time shutdown_start_time = base::Time::Now();
    816   backend_->StopSyncingForShutdown();
    817 
    818   // Stop all data type controllers, if needed.  Note that until Stop
    819   // completes, it is possible in theory to have a ChangeProcessor apply a
    820   // change from a native model.  In that case, it will get applied to the sync
    821   // database (which doesn't get destroyed until we destroy the backend below)
    822   // as an unsynced change.  That will be persisted, and committed on restart.
    823   if (data_type_manager_) {
    824     if (data_type_manager_->state() != DataTypeManager::STOPPED) {
    825       // When aborting as part of shutdown, we should expect an aborted sync
    826       // configure result, else we'll dcheck when we try to read the sync error.
    827       expect_sync_configuration_aborted_ = true;
    828       data_type_manager_->Stop();
    829     }
    830     data_type_manager_.reset();
    831   }
    832 
    833   // Shutdown the migrator before the backend to ensure it doesn't pull a null
    834   // snapshot.
    835   migrator_.reset();
    836   sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>());
    837 
    838   // Move aside the backend so nobody else tries to use it while we are
    839   // shutting it down.
    840   scoped_ptr<SyncBackendHost> doomed_backend(backend_.release());
    841   if (doomed_backend) {
    842     sync_thread_ = doomed_backend->Shutdown(option);
    843     doomed_backend.reset();
    844   }
    845   base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
    846   UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time);
    847 
    848   weak_factory_.InvalidateWeakPtrs();
    849 
    850   // Clear various flags.
    851   start_up_time_ = base::Time();
    852   expect_sync_configuration_aborted_ = false;
    853   is_auth_in_progress_ = false;
    854   backend_initialized_ = false;
    855   cached_passphrase_.clear();
    856   access_token_.clear();
    857   encryption_pending_ = false;
    858   encrypt_everything_ = false;
    859   encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes();
    860   passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
    861   request_access_token_retry_timer_.Stop();
    862   // Revert to "no auth error".
    863   if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
    864     UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
    865 
    866   if (sync_global_error_) {
    867     GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(
    868         sync_global_error_.get());
    869     RemoveObserver(sync_global_error_.get());
    870     sync_global_error_.reset(NULL);
    871   }
    872 
    873   NotifyObservers();
    874 }
    875 
    876 void ProfileSyncService::DisableForUser() {
    877   // Clear prefs (including SyncSetupHasCompleted) before shutting down so
    878   // PSS clients don't think we're set up while we're shutting down.
    879   sync_prefs_.ClearPreferences();
    880   ClearUnrecoverableError();
    881   ShutdownImpl(browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD);
    882 }
    883 
    884 bool ProfileSyncService::HasSyncSetupCompleted() const {
    885   return sync_prefs_.HasSyncSetupCompleted();
    886 }
    887 
    888 void ProfileSyncService::SetSyncSetupCompleted() {
    889   sync_prefs_.SetSyncSetupCompleted();
    890 }
    891 
    892 void ProfileSyncService::UpdateLastSyncedTime() {
    893   last_synced_time_ = base::Time::Now();
    894   sync_prefs_.SetLastSyncedTime(last_synced_time_);
    895 }
    896 
    897 void ProfileSyncService::NotifyObservers() {
    898   FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_,
    899                     OnStateChanged());
    900   // TODO(akalin): Make an Observer subclass that listens and does the
    901   // event routing.
    902   sync_js_controller_.HandleJsEvent("onServiceStateChanged", JsEventDetails());
    903 }
    904 
    905 void ProfileSyncService::NotifySyncCycleCompleted() {
    906   FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_,
    907                     OnSyncCycleCompleted());
    908   sync_js_controller_.HandleJsEvent(
    909       "onServiceStateChanged", JsEventDetails());
    910 }
    911 
    912 void ProfileSyncService::ClearStaleErrors() {
    913   ClearUnrecoverableError();
    914   last_actionable_error_ = SyncProtocolError();
    915   // Clear the data type errors as well.
    916   failed_data_types_handler_.Reset();
    917 }
    918 
    919 void ProfileSyncService::ClearUnrecoverableError() {
    920   unrecoverable_error_reason_ = ERROR_REASON_UNSET;
    921   unrecoverable_error_message_.clear();
    922   unrecoverable_error_location_ = tracked_objects::Location();
    923 }
    924 
    925 void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) {
    926   if (data_type_controllers_.count(data_type) > 0)
    927     return;
    928   NOTREACHED();
    929 }
    930 
    931 // An invariant has been violated.  Transition to an error state where we try
    932 // to do as little work as possible, to avoid further corruption or crashes.
    933 void ProfileSyncService::OnUnrecoverableError(
    934     const tracked_objects::Location& from_here,
    935     const std::string& message) {
    936   // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
    937   // interface are assumed to originate within the syncer.
    938   unrecoverable_error_reason_ = ERROR_REASON_SYNCER;
    939   OnUnrecoverableErrorImpl(from_here, message, true);
    940 }
    941 
    942 void ProfileSyncService::OnUnrecoverableErrorImpl(
    943     const tracked_objects::Location& from_here,
    944     const std::string& message,
    945     bool delete_sync_database) {
    946   DCHECK(HasUnrecoverableError());
    947   unrecoverable_error_message_ = message;
    948   unrecoverable_error_location_ = from_here;
    949 
    950   UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram,
    951                             unrecoverable_error_reason_,
    952                             ERROR_REASON_LIMIT);
    953   NotifyObservers();
    954   std::string location;
    955   from_here.Write(true, true, &location);
    956   LOG(ERROR)
    957       << "Unrecoverable error detected at " << location
    958       << " -- ProfileSyncService unusable: " << message;
    959 
    960   // Shut all data types down.
    961   base::MessageLoop::current()->PostTask(FROM_HERE,
    962       base::Bind(&ProfileSyncService::ShutdownImpl,
    963                  weak_factory_.GetWeakPtr(),
    964                  delete_sync_database ?
    965                      browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD :
    966                      browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD));
    967 }
    968 
    969 // TODO(zea): Move this logic into the DataTypeController/DataTypeManager.
    970 void ProfileSyncService::DisableBrokenDatatype(
    971     syncer::ModelType type,
    972     const tracked_objects::Location& from_here,
    973     std::string message) {
    974   // First deactivate the type so that no further server changes are
    975   // passed onto the change processor.
    976   DeactivateDataType(type);
    977 
    978   syncer::SyncError error(from_here,
    979                           syncer::SyncError::DATATYPE_ERROR,
    980                           message,
    981                           type);
    982 
    983   std::map<syncer::ModelType, syncer::SyncError> errors;
    984   errors[type] = error;
    985 
    986   // Update this before posting a task. So if a configure happens before
    987   // the task that we are going to post, this type would still be disabled.
    988   failed_data_types_handler_.UpdateFailedDataTypes(errors);
    989 
    990   base::MessageLoop::current()->PostTask(FROM_HERE,
    991       base::Bind(&ProfileSyncService::ReconfigureDatatypeManager,
    992                  weak_factory_.GetWeakPtr()));
    993 }
    994 
    995 void ProfileSyncService::OnBackendInitialized(
    996     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
    997     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
    998         debug_info_listener,
    999     bool success) {
   1000   is_first_time_sync_configure_ = !HasSyncSetupCompleted();
   1001 
   1002   if (is_first_time_sync_configure_) {
   1003     UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success);
   1004   } else {
   1005     UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success);
   1006   }
   1007 
   1008   DCHECK(!start_up_time_.is_null());
   1009   base::Time on_backend_initialized_time = base::Time::Now();
   1010   base::TimeDelta delta = on_backend_initialized_time - start_up_time_;
   1011   if (is_first_time_sync_configure_) {
   1012     UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta);
   1013   } else {
   1014     UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta);
   1015   }
   1016 
   1017   if (!success) {
   1018     // Something went unexpectedly wrong.  Play it safe: stop syncing at once
   1019     // and surface error UI to alert the user sync has stopped.
   1020     // Keep the directory around for now so that on restart we will retry
   1021     // again and potentially succeed in presence of transient file IO failures
   1022     // or permissions issues, etc.
   1023     //
   1024     // TODO(rlarocque): Consider making this UnrecoverableError less special.
   1025     // Unlike every other UnrecoverableError, it does not delete our sync data.
   1026     // This exception made sense at the time it was implemented, but our new
   1027     // directory corruption recovery mechanism makes it obsolete.  By the time
   1028     // we get here, we will have already tried and failed to delete the
   1029     // directory.  It would be no big deal if we tried to delete it again.
   1030     OnInternalUnrecoverableError(FROM_HERE,
   1031                                  "BackendInitialize failure",
   1032                                  false,
   1033                                  ERROR_REASON_BACKEND_INIT_FAILURE);
   1034     return;
   1035   }
   1036 
   1037   backend_initialized_ = true;
   1038 
   1039   sync_js_controller_.AttachJsBackend(js_backend);
   1040   debug_info_listener_ = debug_info_listener;
   1041 
   1042   // If we have a cached passphrase use it to decrypt/encrypt data now that the
   1043   // backend is initialized. We want to call this before notifying observers in
   1044   // case this operation affects the "passphrase required" status.
   1045   ConsumeCachedPassphraseIfPossible();
   1046 
   1047   // The very first time the backend initializes is effectively the first time
   1048   // we can say we successfully "synced".  last_synced_time_ will only be null
   1049   // in this case, because the pref wasn't restored on StartUp.
   1050   if (last_synced_time_.is_null()) {
   1051     UpdateLastSyncedTime();
   1052   }
   1053 
   1054   if (auto_start_enabled_ && !FirstSetupInProgress()) {
   1055     // Backend is initialized but we're not in sync setup, so this must be an
   1056     // autostart - mark our sync setup as completed and we'll start syncing
   1057     // below.
   1058     SetSyncSetupCompleted();
   1059   }
   1060 
   1061   // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious
   1062   // data type configuration because observer may flag setup as complete and
   1063   // trigger data type configuration.
   1064   if (HasSyncSetupCompleted()) {
   1065     ConfigureDataTypeManager();
   1066   } else {
   1067     DCHECK(FirstSetupInProgress());
   1068   }
   1069 
   1070   NotifyObservers();
   1071 }
   1072 
   1073 void ProfileSyncService::OnSyncCycleCompleted() {
   1074   UpdateLastSyncedTime();
   1075   if (IsSessionsDataTypeControllerRunning()) {
   1076     // Trigger garbage collection of old sessions now that we've downloaded
   1077     // any new session data.
   1078     if (sessions_sync_manager_) {
   1079       // Sessions V2.
   1080       base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
   1081           &browser_sync::SessionsSyncManager::DoGarbageCollection,
   1082               base::AsWeakPtr(sessions_sync_manager_.get())));
   1083     } else {
   1084       base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
   1085           &browser_sync::SessionModelAssociator::DeleteStaleSessions,
   1086               GetSessionModelAssociatorDeprecated()->AsWeakPtr()));
   1087     }
   1088   }
   1089   DVLOG(2) << "Notifying observers sync cycle completed";
   1090   NotifySyncCycleCompleted();
   1091 }
   1092 
   1093 void ProfileSyncService::OnExperimentsChanged(
   1094     const syncer::Experiments& experiments) {
   1095   if (current_experiments_.Matches(experiments))
   1096     return;
   1097 
   1098   // If this is a first time sync for a client, this will be called before
   1099   // OnBackendInitialized() to ensure the new datatypes are available at sync
   1100   // setup. As a result, the migrator won't exist yet. This is fine because for
   1101   // first time sync cases we're only concerned with making the datatype
   1102   // available.
   1103   if (migrator_.get() &&
   1104       migrator_->state() != browser_sync::BackendMigrator::IDLE) {
   1105     DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy.";
   1106     return;
   1107   }
   1108 
   1109   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   1110   syncer::ModelTypeSet to_add;
   1111   const syncer::ModelTypeSet to_register =
   1112       Difference(to_add, registered_types);
   1113   DVLOG(2) << "OnExperimentsChanged called with types: "
   1114            << syncer::ModelTypeSetToString(to_add);
   1115   DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register);
   1116 
   1117   for (syncer::ModelTypeSet::Iterator it = to_register.First();
   1118        it.Good(); it.Inc()) {
   1119     // Received notice to enable experimental type. Check if the type is
   1120     // registered, and if not register a new datatype controller.
   1121     RegisterNewDataType(it.Get());
   1122   }
   1123 
   1124   // Check if the user has "Keep Everything Synced" enabled. If so, we want
   1125   // to turn on all experimental types if they're not already on. Otherwise we
   1126   // leave them off.
   1127   // Note: if any types are already registered, we don't turn them on. This
   1128   // covers the case where we're already in the process of reconfiguring
   1129   // to turn an experimental type on.
   1130   if (sync_prefs_.HasKeepEverythingSynced()) {
   1131     // Mark all data types as preferred.
   1132     sync_prefs_.SetPreferredDataTypes(registered_types, registered_types);
   1133 
   1134     // Only automatically turn on types if we have already finished set up.
   1135     // Otherwise, just leave the experimental types on by default.
   1136     if (!to_register.Empty() && HasSyncSetupCompleted() && migrator_) {
   1137       DVLOG(1) << "Dynamically enabling new datatypes: "
   1138                << syncer::ModelTypeSetToString(to_register);
   1139       OnMigrationNeededForTypes(to_register);
   1140     }
   1141   }
   1142 
   1143   current_experiments_ = experiments;
   1144 }
   1145 
   1146 void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) {
   1147   is_auth_in_progress_ = false;
   1148   last_auth_error_ = error;
   1149 
   1150   NotifyObservers();
   1151 }
   1152 
   1153 namespace {
   1154 
   1155 AuthError ConnectionStatusToAuthError(
   1156     syncer::ConnectionStatus status) {
   1157   switch (status) {
   1158     case syncer::CONNECTION_OK:
   1159       return AuthError::AuthErrorNone();
   1160       break;
   1161     case syncer::CONNECTION_AUTH_ERROR:
   1162       return AuthError(AuthError::INVALID_GAIA_CREDENTIALS);
   1163       break;
   1164     case syncer::CONNECTION_SERVER_ERROR:
   1165       return AuthError(AuthError::CONNECTION_FAILED);
   1166       break;
   1167     default:
   1168       NOTREACHED();
   1169       return AuthError(AuthError::CONNECTION_FAILED);
   1170   }
   1171 }
   1172 
   1173 }  // namespace
   1174 
   1175 void ProfileSyncService::OnConnectionStatusChange(
   1176     syncer::ConnectionStatus status) {
   1177   connection_status_update_time_ = base::Time::Now();
   1178   connection_status_ = status;
   1179   if (status == syncer::CONNECTION_AUTH_ERROR) {
   1180     // Sync server returned error indicating that access token is invalid. It
   1181     // could be either expired or access is revoked. Let's request another
   1182     // access token and if access is revoked then request for token will fail
   1183     // with corresponding error. If access token is repeatedly reported
   1184     // invalid, there may be some issues with server, e.g. authentication
   1185     // state is inconsistent on sync and token server. In that case, we
   1186     // backoff token requests exponentially to avoid hammering token server
   1187     // too much and to avoid getting same token due to token server's caching
   1188     // policy. |request_access_token_retry_timer_| is used to backoff request
   1189     // triggered by both auth error and failure talking to GAIA server.
   1190     // Therefore, we're likely to reach the backoff ceiling more quickly than
   1191     // you would expect from looking at the BackoffPolicy if both types of
   1192     // errors happen. We shouldn't receive two errors back-to-back without
   1193     // attempting a token/sync request in between, thus crank up request delay
   1194     // unnecessary. This is because we won't make a sync request if we hit an
   1195     // error until GAIA succeeds at sending a new token, and we won't request
   1196     // a new token unless sync reports a token failure. But to be safe, don't
   1197     // schedule request if this happens.
   1198     if (request_access_token_retry_timer_.IsRunning()) {
   1199       NOTREACHED();
   1200     } else if (request_access_token_backoff_.failure_count() == 0) {
   1201       // First time request without delay. Currently invalid token is used
   1202       // to initialize sync backend and we'll always end up here. We don't
   1203       // want to delay initialization.
   1204       request_access_token_backoff_.InformOfRequest(false);
   1205       RequestAccessToken();
   1206     } else  {
   1207       request_access_token_backoff_.InformOfRequest(false);
   1208       request_access_token_retry_timer_.Start(
   1209           FROM_HERE,
   1210           request_access_token_backoff_.GetTimeUntilRelease(),
   1211           base::Bind(&ProfileSyncService::RequestAccessToken,
   1212                      weak_factory_.GetWeakPtr()));
   1213     }
   1214   } else {
   1215     // Reset backoff time after successful connection.
   1216     if (status == syncer::CONNECTION_OK) {
   1217       // Request shouldn't be scheduled at this time. But if it is, it's
   1218       // possible that sync flips between OK and auth error states rapidly,
   1219       // thus hammers token server. To be safe, only reset backoff delay when
   1220       // no scheduled request.
   1221       if (request_access_token_retry_timer_.IsRunning()) {
   1222         NOTREACHED();
   1223       } else {
   1224         request_access_token_backoff_.Reset();
   1225       }
   1226     }
   1227 
   1228     const GoogleServiceAuthError auth_error =
   1229         ConnectionStatusToAuthError(status);
   1230     DVLOG(1) << "Connection status change: " << auth_error.ToString();
   1231     UpdateAuthErrorState(auth_error);
   1232   }
   1233 }
   1234 
   1235 void ProfileSyncService::OnStopSyncingPermanently() {
   1236   sync_prefs_.SetStartSuppressed(true);
   1237   DisableForUser();
   1238 }
   1239 
   1240 void ProfileSyncService::OnPassphraseRequired(
   1241     syncer::PassphraseRequiredReason reason,
   1242     const sync_pb::EncryptedData& pending_keys) {
   1243   DCHECK(backend_.get());
   1244   DCHECK(backend_->IsNigoriEnabled());
   1245 
   1246   // TODO(lipalani) : add this check to other locations as well.
   1247   if (HasUnrecoverableError()) {
   1248     // When unrecoverable error is detected we post a task to shutdown the
   1249     // backend. The task might not have executed yet.
   1250     return;
   1251   }
   1252 
   1253   DVLOG(1) << "Passphrase required with reason: "
   1254            << syncer::PassphraseRequiredReasonToString(reason);
   1255   passphrase_required_reason_ = reason;
   1256 
   1257   const syncer::ModelTypeSet types = GetPreferredDataTypes();
   1258   if (data_type_manager_) {
   1259     // Reconfigure without the encrypted types (excluded implicitly via the
   1260     // failed datatypes handler).
   1261     data_type_manager_->Configure(types,
   1262                                   syncer::CONFIGURE_REASON_CRYPTO);
   1263   }
   1264 
   1265   // Notify observers that the passphrase status may have changed.
   1266   NotifyObservers();
   1267 }
   1268 
   1269 void ProfileSyncService::OnPassphraseAccepted() {
   1270   DVLOG(1) << "Received OnPassphraseAccepted.";
   1271 
   1272   // If the pending keys were resolved via keystore, it's possible we never
   1273   // consumed our cached passphrase. Clear it now.
   1274   if (!cached_passphrase_.empty())
   1275     cached_passphrase_.clear();
   1276 
   1277   // Reset passphrase_required_reason_ since we know we no longer require the
   1278   // passphrase. We do this here rather than down in ResolvePassphraseRequired()
   1279   // because that can be called by OnPassphraseRequired() if no encrypted data
   1280   // types are enabled, and we don't want to clobber the true passphrase error.
   1281   passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
   1282 
   1283   // Make sure the data types that depend on the passphrase are started at
   1284   // this time.
   1285   const syncer::ModelTypeSet types = GetPreferredDataTypes();
   1286   if (data_type_manager_) {
   1287     // Re-enable any encrypted types if necessary.
   1288     data_type_manager_->Configure(types,
   1289                                   syncer::CONFIGURE_REASON_CRYPTO);
   1290   }
   1291 
   1292   NotifyObservers();
   1293 }
   1294 
   1295 void ProfileSyncService::OnEncryptedTypesChanged(
   1296     syncer::ModelTypeSet encrypted_types,
   1297     bool encrypt_everything) {
   1298   encrypted_types_ = encrypted_types;
   1299   encrypt_everything_ = encrypt_everything;
   1300   DVLOG(1) << "Encrypted types changed to "
   1301            << syncer::ModelTypeSetToString(encrypted_types_)
   1302            << " (encrypt everything is set to "
   1303            << (encrypt_everything_ ? "true" : "false") << ")";
   1304   DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
   1305 
   1306   // If sessions are encrypted, full history sync is not possible, and
   1307   // delete directives are unnecessary.
   1308   if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
   1309       encrypted_types_.Has(syncer::SESSIONS)) {
   1310     DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
   1311                           FROM_HERE,
   1312                           "Delete directives not supported with encryption.");
   1313   }
   1314 }
   1315 
   1316 void ProfileSyncService::OnEncryptionComplete() {
   1317   DVLOG(1) << "Encryption complete";
   1318   if (encryption_pending_ && encrypt_everything_) {
   1319     encryption_pending_ = false;
   1320     // This is to nudge the integration tests when encryption is
   1321     // finished.
   1322     NotifyObservers();
   1323   }
   1324 }
   1325 
   1326 void ProfileSyncService::OnMigrationNeededForTypes(
   1327     syncer::ModelTypeSet types) {
   1328   DCHECK(backend_initialized_);
   1329   DCHECK(data_type_manager_.get());
   1330 
   1331   // Migrator must be valid, because we don't sync until it is created and this
   1332   // callback originates from a sync cycle.
   1333   migrator_->MigrateTypes(types);
   1334 }
   1335 
   1336 void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
   1337   last_actionable_error_ = error;
   1338   DCHECK_NE(last_actionable_error_.action,
   1339             syncer::UNKNOWN_ACTION);
   1340   switch (error.action) {
   1341     case syncer::UPGRADE_CLIENT:
   1342     case syncer::CLEAR_USER_DATA_AND_RESYNC:
   1343     case syncer::ENABLE_SYNC_ON_ACCOUNT:
   1344     case syncer::STOP_AND_RESTART_SYNC:
   1345       // TODO(lipalani) : if setup in progress we want to display these
   1346       // actions in the popup. The current experience might not be optimal for
   1347       // the user. We just dismiss the dialog.
   1348       if (setup_in_progress_) {
   1349         OnStopSyncingPermanently();
   1350         expect_sync_configuration_aborted_ = true;
   1351       }
   1352       // Trigger an unrecoverable error to stop syncing.
   1353       OnInternalUnrecoverableError(FROM_HERE,
   1354                                    last_actionable_error_.error_description,
   1355                                    true,
   1356                                    ERROR_REASON_ACTIONABLE_ERROR);
   1357       break;
   1358     case syncer::DISABLE_SYNC_ON_CLIENT:
   1359       OnStopSyncingPermanently();
   1360 #if !defined(OS_CHROMEOS)
   1361       // On desktop Chrome, sign out the user after a dashboard clear.
   1362       // TODO(rsimha): Revisit this for M30. See http://crbug.com/252049.
   1363       if (!auto_start_enabled_)  // Skip sign out on ChromeOS/Android.
   1364         SigninManagerFactory::GetForProfile(profile_)->SignOut();
   1365 #endif
   1366       break;
   1367     case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
   1368       // Sync disabled by domain admin. we should stop syncing until next
   1369       // restart.
   1370       sync_disabled_by_admin_ = true;
   1371       ShutdownImpl(browser_sync::SyncBackendHost::DISABLE_AND_CLAIM_THREAD);
   1372       break;
   1373     default:
   1374       NOTREACHED();
   1375   }
   1376   NotifyObservers();
   1377 }
   1378 
   1379 void ProfileSyncService::OnConfigureDone(
   1380     const browser_sync::DataTypeManager::ConfigureResult& result) {
   1381   // We should have cleared our cached passphrase before we get here (in
   1382   // OnBackendInitialized()).
   1383   DCHECK(cached_passphrase_.empty());
   1384 
   1385   if (!sync_configure_start_time_.is_null()) {
   1386     if (result.status == DataTypeManager::OK ||
   1387         result.status == DataTypeManager::PARTIAL_SUCCESS) {
   1388       base::Time sync_configure_stop_time = base::Time::Now();
   1389       base::TimeDelta delta = sync_configure_stop_time -
   1390           sync_configure_start_time_;
   1391       if (is_first_time_sync_configure_) {
   1392         UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta);
   1393       } else {
   1394         UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime",
   1395                                   delta);
   1396       }
   1397     }
   1398     sync_configure_start_time_ = base::Time();
   1399   }
   1400 
   1401   // Notify listeners that configuration is done.
   1402   content::NotificationService::current()->Notify(
   1403       chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
   1404       content::Source<ProfileSyncService>(this),
   1405       content::NotificationService::NoDetails());
   1406 
   1407   configure_status_ = result.status;
   1408   DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
   1409   // The possible status values:
   1410   //    ABORT - Configuration was aborted. This is not an error, if
   1411   //            initiated by user.
   1412   //    OK - Everything succeeded.
   1413   //    PARTIAL_SUCCESS - Some datatypes failed to start.
   1414   //    Everything else is an UnrecoverableError. So treat it as such.
   1415 
   1416   // First handle the abort case.
   1417   if (configure_status_ == DataTypeManager::ABORTED &&
   1418       expect_sync_configuration_aborted_) {
   1419     DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
   1420     expect_sync_configuration_aborted_ = false;
   1421     return;
   1422   }
   1423 
   1424   // Handle unrecoverable error.
   1425   if (configure_status_ != DataTypeManager::OK &&
   1426       configure_status_ != DataTypeManager::PARTIAL_SUCCESS) {
   1427     // Something catastrophic had happened. We should only have one
   1428     // error representing it.
   1429     DCHECK_EQ(result.failed_data_types.size(),
   1430               static_cast<unsigned int>(1));
   1431     syncer::SyncError error = result.failed_data_types.begin()->second;
   1432     DCHECK(error.IsSet());
   1433     std::string message =
   1434         "Sync configuration failed with status " +
   1435         DataTypeManager::ConfigureStatusToString(configure_status_) +
   1436         " during " + syncer::ModelTypeToString(error.model_type()) +
   1437         ": " + error.message();
   1438     LOG(ERROR) << "ProfileSyncService error: " << message;
   1439     OnInternalUnrecoverableError(error.location(),
   1440                                  message,
   1441                                  true,
   1442                                  ERROR_REASON_CONFIGURATION_FAILURE);
   1443     return;
   1444   }
   1445 
   1446   // We should never get in a state where we have no encrypted datatypes
   1447   // enabled, and yet we still think we require a passphrase for decryption.
   1448   DCHECK(!(IsPassphraseRequiredForDecryption() &&
   1449            !IsEncryptedDatatypeEnabled()));
   1450 
   1451   // This must be done before we start syncing with the server to avoid
   1452   // sending unencrypted data up on a first time sync.
   1453   if (encryption_pending_)
   1454     backend_->EnableEncryptEverything();
   1455   NotifyObservers();
   1456 
   1457   if (migrator_.get() &&
   1458       migrator_->state() != browser_sync::BackendMigrator::IDLE) {
   1459     // Migration in progress.  Let the migrator know we just finished
   1460     // configuring something.  It will be up to the migrator to call
   1461     // StartSyncingWithServer() if migration is now finished.
   1462     migrator_->OnConfigureDone(result);
   1463   } else {
   1464     StartSyncingWithServer();
   1465   }
   1466 }
   1467 
   1468 void ProfileSyncService::OnConfigureRetry() {
   1469   // We should have cleared our cached passphrase before we get here (in
   1470   // OnBackendInitialized()).
   1471   DCHECK(cached_passphrase_.empty());
   1472 
   1473   OnSyncConfigureRetry();
   1474 }
   1475 
   1476 void ProfileSyncService::OnConfigureStart() {
   1477   sync_configure_start_time_ = base::Time::Now();
   1478   NotifyObservers();
   1479 }
   1480 
   1481 ProfileSyncService::SyncStatusSummary
   1482       ProfileSyncService::QuerySyncStatusSummary() {
   1483   if (HasUnrecoverableError()) {
   1484     return UNRECOVERABLE_ERROR;
   1485   } else if (!backend_) {
   1486     return NOT_ENABLED;
   1487   } else if (backend_.get() && !HasSyncSetupCompleted()) {
   1488     return SETUP_INCOMPLETE;
   1489   } else if (backend_.get() && HasSyncSetupCompleted() &&
   1490              data_type_manager_.get() &&
   1491              data_type_manager_->state() != DataTypeManager::CONFIGURED) {
   1492     return DATATYPES_NOT_INITIALIZED;
   1493   } else if (ShouldPushChanges()) {
   1494     return INITIALIZED;
   1495   }
   1496   return UNKNOWN_ERROR;
   1497 }
   1498 
   1499 std::string ProfileSyncService::QuerySyncStatusSummaryString() {
   1500   SyncStatusSummary status = QuerySyncStatusSummary();
   1501   switch (status) {
   1502     case UNRECOVERABLE_ERROR:
   1503       return "Unrecoverable error detected";
   1504     case NOT_ENABLED:
   1505       return "Syncing not enabled";
   1506     case SETUP_INCOMPLETE:
   1507       return "First time sync setup incomplete";
   1508     case DATATYPES_NOT_INITIALIZED:
   1509       return "Datatypes not fully initialized";
   1510     case INITIALIZED:
   1511       return "Sync service initialized";
   1512     default:
   1513       return "Status unknown: Internal error?";
   1514   }
   1515 }
   1516 
   1517 std::string ProfileSyncService::GetBackendInitializationStateString() const {
   1518   if (sync_initialized())
   1519     return "Done";
   1520   else if (!start_up_time_.is_null())
   1521     return "Deferred";
   1522   else
   1523     return "Not started";
   1524 }
   1525 
   1526 bool ProfileSyncService::QueryDetailedSyncStatus(
   1527     SyncBackendHost::Status* result) {
   1528   if (backend_.get() && backend_initialized_) {
   1529     *result = backend_->GetDetailedStatus();
   1530     return true;
   1531   } else {
   1532     SyncBackendHost::Status status;
   1533     status.sync_protocol_error = last_actionable_error_;
   1534     *result = status;
   1535     return false;
   1536   }
   1537 }
   1538 
   1539 const AuthError& ProfileSyncService::GetAuthError() const {
   1540   return last_auth_error_;
   1541 }
   1542 
   1543 bool ProfileSyncService::FirstSetupInProgress() const {
   1544   return !HasSyncSetupCompleted() && setup_in_progress_;
   1545 }
   1546 
   1547 void ProfileSyncService::SetSetupInProgress(bool setup_in_progress) {
   1548   // This method is a no-op if |setup_in_progress_| remains unchanged.
   1549   if (setup_in_progress_ == setup_in_progress)
   1550     return;
   1551 
   1552   setup_in_progress_ = setup_in_progress;
   1553   if (!setup_in_progress && sync_initialized())
   1554     ReconfigureDatatypeManager();
   1555   NotifyObservers();
   1556 }
   1557 
   1558 bool ProfileSyncService::sync_initialized() const {
   1559   return backend_initialized_;
   1560 }
   1561 
   1562 bool ProfileSyncService::waiting_for_auth() const {
   1563   return is_auth_in_progress_;
   1564 }
   1565 
   1566 const syncer::Experiments& ProfileSyncService::current_experiments() const {
   1567   return current_experiments_;
   1568 }
   1569 
   1570 bool ProfileSyncService::HasUnrecoverableError() const {
   1571   return unrecoverable_error_reason_ != ERROR_REASON_UNSET;
   1572 }
   1573 
   1574 bool ProfileSyncService::IsPassphraseRequired() const {
   1575   return passphrase_required_reason_ !=
   1576       syncer::REASON_PASSPHRASE_NOT_REQUIRED;
   1577 }
   1578 
   1579 bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
   1580   // If there is an encrypted datatype enabled and we don't have the proper
   1581   // passphrase, we must prompt the user for a passphrase. The only way for the
   1582   // user to avoid entering their passphrase is to disable the encrypted types.
   1583   return IsEncryptedDatatypeEnabled() && IsPassphraseRequired();
   1584 }
   1585 
   1586 base::string16 ProfileSyncService::GetLastSyncedTimeString() const {
   1587   if (last_synced_time_.is_null())
   1588     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
   1589 
   1590   base::TimeDelta last_synced = base::Time::Now() - last_synced_time_;
   1591 
   1592   if (last_synced < base::TimeDelta::FromMinutes(1))
   1593     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
   1594 
   1595   return ui::TimeFormat::TimeElapsed(last_synced);
   1596 }
   1597 
   1598 void ProfileSyncService::UpdateSelectedTypesHistogram(
   1599     bool sync_everything, const syncer::ModelTypeSet chosen_types) const {
   1600   if (!HasSyncSetupCompleted() ||
   1601       sync_everything != sync_prefs_.HasKeepEverythingSynced()) {
   1602     UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything);
   1603   }
   1604 
   1605   // Only log the data types that are shown in the sync settings ui.
   1606   // Note: the order of these types must match the ordering of
   1607   // the respective types in ModelType
   1608 const browser_sync::user_selectable_type::UserSelectableSyncType
   1609       user_selectable_types[] = {
   1610     browser_sync::user_selectable_type::BOOKMARKS,
   1611     browser_sync::user_selectable_type::PREFERENCES,
   1612     browser_sync::user_selectable_type::PASSWORDS,
   1613     browser_sync::user_selectable_type::AUTOFILL,
   1614     browser_sync::user_selectable_type::THEMES,
   1615     browser_sync::user_selectable_type::TYPED_URLS,
   1616     browser_sync::user_selectable_type::EXTENSIONS,
   1617     browser_sync::user_selectable_type::APPS,
   1618     browser_sync::user_selectable_type::PROXY_TABS
   1619   };
   1620 
   1621   COMPILE_ASSERT(30 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
   1622 
   1623   if (!sync_everything) {
   1624     const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
   1625 
   1626     syncer::ModelTypeSet type_set = syncer::UserSelectableTypes();
   1627     syncer::ModelTypeSet::Iterator it = type_set.First();
   1628 
   1629     DCHECK_EQ(arraysize(user_selectable_types), type_set.Size());
   1630 
   1631     for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good();
   1632          ++i, it.Inc()) {
   1633       const syncer::ModelType type = it.Get();
   1634       if (chosen_types.Has(type) &&
   1635           (!HasSyncSetupCompleted() || !current_types.Has(type))) {
   1636         // Selected type has changed - log it.
   1637         UMA_HISTOGRAM_ENUMERATION(
   1638             "Sync.CustomSync",
   1639             user_selectable_types[i],
   1640             browser_sync::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
   1641       }
   1642     }
   1643   }
   1644 }
   1645 
   1646 #if defined(OS_CHROMEOS)
   1647 void ProfileSyncService::RefreshSpareBootstrapToken(
   1648     const std::string& passphrase) {
   1649   browser_sync::ChromeEncryptor encryptor;
   1650   syncer::Cryptographer temp_cryptographer(&encryptor);
   1651   // The first 2 params (hostname and username) doesn't have any effect here.
   1652   syncer::KeyParams key_params = {"localhost", "dummy", passphrase};
   1653 
   1654   std::string bootstrap_token;
   1655   if (!temp_cryptographer.AddKey(key_params)) {
   1656     NOTREACHED() << "Failed to add key to cryptographer.";
   1657   }
   1658   temp_cryptographer.GetBootstrapToken(&bootstrap_token);
   1659   sync_prefs_.SetSpareBootstrapToken(bootstrap_token);
   1660 }
   1661 #endif
   1662 
   1663 void ProfileSyncService::OnUserChoseDatatypes(
   1664     bool sync_everything,
   1665     syncer::ModelTypeSet chosen_types) {
   1666   if (!backend_.get() && !HasUnrecoverableError()) {
   1667     NOTREACHED();
   1668     return;
   1669   }
   1670 
   1671   UpdateSelectedTypesHistogram(sync_everything, chosen_types);
   1672   sync_prefs_.SetKeepEverythingSynced(sync_everything);
   1673 
   1674   failed_data_types_handler_.Reset();
   1675   if (GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES) &&
   1676       encrypted_types_.Has(syncer::SESSIONS)) {
   1677     DisableBrokenDatatype(syncer::HISTORY_DELETE_DIRECTIVES,
   1678                           FROM_HERE,
   1679                           "Delete directives not supported with encryption.");
   1680   }
   1681   ChangePreferredDataTypes(chosen_types);
   1682   AcknowledgeSyncedTypes();
   1683   NotifyObservers();
   1684 }
   1685 
   1686 void ProfileSyncService::ChangePreferredDataTypes(
   1687     syncer::ModelTypeSet preferred_types) {
   1688 
   1689   DVLOG(1) << "ChangePreferredDataTypes invoked";
   1690   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   1691   const syncer::ModelTypeSet registered_preferred_types =
   1692       Intersection(registered_types, preferred_types);
   1693   sync_prefs_.SetPreferredDataTypes(registered_types,
   1694                                     registered_preferred_types);
   1695 
   1696   // Now reconfigure the DTM.
   1697   ReconfigureDatatypeManager();
   1698 }
   1699 
   1700 syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
   1701   const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
   1702   const syncer::ModelTypeSet failed_types =
   1703       failed_data_types_handler_.GetFailedTypes();
   1704   return Difference(preferred_types, failed_types);
   1705 }
   1706 
   1707 syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
   1708   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   1709   const syncer::ModelTypeSet preferred_types =
   1710       sync_prefs_.GetPreferredDataTypes(registered_types);
   1711   return preferred_types;
   1712 }
   1713 
   1714 syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
   1715   syncer::ModelTypeSet registered_types;
   1716   // The data_type_controllers_ are determined by command-line flags; that's
   1717   // effectively what controls the values returned here.
   1718   for (DataTypeController::TypeMap::const_iterator it =
   1719        data_type_controllers_.begin();
   1720        it != data_type_controllers_.end(); ++it) {
   1721     registered_types.Put(it->first);
   1722   }
   1723   return registered_types;
   1724 }
   1725 
   1726 bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
   1727   syncer::PassphraseType passphrase_type = GetPassphraseType();
   1728   return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE ||
   1729          passphrase_type == syncer::CUSTOM_PASSPHRASE;
   1730 }
   1731 
   1732 syncer::PassphraseType ProfileSyncService::GetPassphraseType() const {
   1733   return backend_->GetPassphraseType();
   1734 }
   1735 
   1736 base::Time ProfileSyncService::GetExplicitPassphraseTime() const {
   1737   return backend_->GetExplicitPassphraseTime();
   1738 }
   1739 
   1740 bool ProfileSyncService::IsCryptographerReady(
   1741     const syncer::BaseTransaction* trans) const {
   1742   return backend_.get() && backend_->IsCryptographerReady(trans);
   1743 }
   1744 
   1745 void ProfileSyncService::ConfigurePriorityDataTypes() {
   1746   const syncer::ModelTypeSet priority_types =
   1747       Intersection(GetPreferredDataTypes(), syncer::PriorityUserTypes());
   1748   if (!priority_types.Empty()) {
   1749     const syncer::ConfigureReason reason = HasSyncSetupCompleted() ?
   1750         syncer::CONFIGURE_REASON_RECONFIGURATION :
   1751         syncer::CONFIGURE_REASON_NEW_CLIENT;
   1752     data_type_manager_->Configure(priority_types, reason);
   1753   }
   1754 }
   1755 
   1756 void ProfileSyncService::ConfigureDataTypeManager() {
   1757   // Don't configure datatypes if the setup UI is still on the screen - this
   1758   // is to help multi-screen setting UIs (like iOS) where they don't want to
   1759   // start syncing data until the user is done configuring encryption options,
   1760   // etc. ReconfigureDatatypeManager() will get called again once the UI calls
   1761   // SetSetupInProgress(false).
   1762   if (setup_in_progress_)
   1763     return;
   1764 
   1765   bool restart = false;
   1766   if (!data_type_manager_) {
   1767     restart = true;
   1768     data_type_manager_.reset(
   1769         factory_->CreateDataTypeManager(debug_info_listener_,
   1770                                         &data_type_controllers_,
   1771                                         this,
   1772                                         backend_.get(),
   1773                                         this,
   1774                                         &failed_data_types_handler_));
   1775 
   1776     // We create the migrator at the same time.
   1777     migrator_.reset(
   1778         new browser_sync::BackendMigrator(
   1779             profile_->GetDebugName(), GetUserShare(),
   1780             this, data_type_manager_.get(),
   1781             base::Bind(&ProfileSyncService::StartSyncingWithServer,
   1782                        base::Unretained(this))));
   1783   }
   1784 
   1785   const syncer::ModelTypeSet types = GetPreferredDataTypes();
   1786   syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
   1787   if (!HasSyncSetupCompleted()) {
   1788     reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
   1789   } else if (restart) {
   1790     // Datatype downloads on restart are generally due to newly supported
   1791     // datatypes (although it's also possible we're picking up where a failed
   1792     // previous configuration left off).
   1793     // TODO(sync): consider detecting configuration recovery and setting
   1794     // the reason here appropriately.
   1795     reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
   1796   } else {
   1797     // The user initiated a reconfiguration (either to add or remove types).
   1798     reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
   1799   }
   1800 
   1801   data_type_manager_->Configure(types, reason);
   1802 }
   1803 
   1804 syncer::UserShare* ProfileSyncService::GetUserShare() const {
   1805   if (backend_.get() && backend_initialized_) {
   1806     return backend_->GetUserShare();
   1807   }
   1808   NOTREACHED();
   1809   return NULL;
   1810 }
   1811 
   1812 syncer::sessions::SyncSessionSnapshot
   1813     ProfileSyncService::GetLastSessionSnapshot() const {
   1814   if (backend_.get() && backend_initialized_) {
   1815     return backend_->GetLastSessionSnapshot();
   1816   }
   1817   NOTREACHED();
   1818   return syncer::sessions::SyncSessionSnapshot();
   1819 }
   1820 
   1821 bool ProfileSyncService::HasUnsyncedItems() const {
   1822   if (backend_.get() && backend_initialized_) {
   1823     return backend_->HasUnsyncedItems();
   1824   }
   1825   NOTREACHED();
   1826   return false;
   1827 }
   1828 
   1829 browser_sync::BackendMigrator*
   1830     ProfileSyncService::GetBackendMigratorForTest() {
   1831   return migrator_.get();
   1832 }
   1833 
   1834 void ProfileSyncService::GetModelSafeRoutingInfo(
   1835     syncer::ModelSafeRoutingInfo* out) const {
   1836   if (backend_.get() && backend_initialized_) {
   1837     backend_->GetModelSafeRoutingInfo(out);
   1838   } else {
   1839     NOTREACHED();
   1840   }
   1841 }
   1842 
   1843 Value* ProfileSyncService::GetTypeStatusMap() const {
   1844   scoped_ptr<ListValue> result(new ListValue());
   1845 
   1846   if (!backend_.get() || !backend_initialized_) {
   1847     return result.release();
   1848   }
   1849 
   1850   FailedDataTypesHandler::TypeErrorMap error_map =
   1851       failed_data_types_handler_.GetAllErrors();
   1852 
   1853   ModelTypeSet active_types;
   1854   ModelTypeSet passive_types;
   1855   ModelSafeRoutingInfo routing_info;
   1856   backend_->GetModelSafeRoutingInfo(&routing_info);
   1857   for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
   1858        it != routing_info.end(); ++it) {
   1859     if (it->second == syncer::GROUP_PASSIVE) {
   1860       passive_types.Put(it->first);
   1861     } else {
   1862       active_types.Put(it->first);
   1863     }
   1864   }
   1865 
   1866   SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
   1867   ModelTypeSet &throttled_types(detailed_status.throttled_types);
   1868   ModelTypeSet registered = GetRegisteredDataTypes();
   1869   scoped_ptr<DictionaryValue> type_status_header(new DictionaryValue());
   1870 
   1871   type_status_header->SetString("name", "Model Type");
   1872   type_status_header->SetString("status", "header");
   1873   type_status_header->SetString("value", "Group Type");
   1874   type_status_header->SetString("num_entries", "Total Entries");
   1875   type_status_header->SetString("num_live", "Live Entries");
   1876   result->Append(type_status_header.release());
   1877 
   1878   scoped_ptr<DictionaryValue> type_status;
   1879   for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) {
   1880     ModelType type = it.Get();
   1881 
   1882     type_status.reset(new DictionaryValue());
   1883     type_status->SetString("name", ModelTypeToString(type));
   1884 
   1885     if (error_map.find(type) != error_map.end()) {
   1886       const syncer::SyncError &error = error_map.find(type)->second;
   1887       DCHECK(error.IsSet());
   1888       std::string error_text = "Error: " + error.location().ToString() +
   1889           ", " + error.message();
   1890       type_status->SetString("status", "error");
   1891       type_status->SetString("value", error_text);
   1892     } else if (throttled_types.Has(type) && passive_types.Has(type)) {
   1893       type_status->SetString("status", "warning");
   1894       type_status->SetString("value", "Passive, Throttled");
   1895     } else if (passive_types.Has(type)) {
   1896       type_status->SetString("status", "warning");
   1897       type_status->SetString("value", "Passive");
   1898     } else if (throttled_types.Has(type)) {
   1899       type_status->SetString("status", "warning");
   1900       type_status->SetString("value", "Throttled");
   1901     } else if (active_types.Has(type)) {
   1902       type_status->SetString("status", "ok");
   1903       type_status->SetString("value", "Active: " +
   1904                              ModelSafeGroupToString(routing_info[type]));
   1905     } else {
   1906       type_status->SetString("status", "warning");
   1907       type_status->SetString("value", "Disabled by User");
   1908     }
   1909 
   1910     int live_count = detailed_status.num_entries_by_type[type] -
   1911         detailed_status.num_to_delete_entries_by_type[type];
   1912     type_status->SetInteger("num_entries",
   1913                             detailed_status.num_entries_by_type[type]);
   1914     type_status->SetInteger("num_live", live_count);
   1915 
   1916     result->Append(type_status.release());
   1917   }
   1918   return result.release();
   1919 }
   1920 
   1921 void ProfileSyncService::ActivateDataType(
   1922     syncer::ModelType type, syncer::ModelSafeGroup group,
   1923     ChangeProcessor* change_processor) {
   1924   if (!backend_) {
   1925     NOTREACHED();
   1926     return;
   1927   }
   1928   DCHECK(backend_initialized_);
   1929   backend_->ActivateDataType(type, group, change_processor);
   1930 }
   1931 
   1932 void ProfileSyncService::DeactivateDataType(syncer::ModelType type) {
   1933   if (!backend_)
   1934     return;
   1935   backend_->DeactivateDataType(type);
   1936 }
   1937 
   1938 void ProfileSyncService::ConsumeCachedPassphraseIfPossible() {
   1939   // If no cached passphrase, or sync backend hasn't started up yet, just exit.
   1940   // If the backend isn't running yet, OnBackendInitialized() will call this
   1941   // method again after the backend starts up.
   1942   if (cached_passphrase_.empty() || !sync_initialized())
   1943     return;
   1944 
   1945   // Backend is up and running, so we can consume the cached passphrase.
   1946   std::string passphrase = cached_passphrase_;
   1947   cached_passphrase_.clear();
   1948 
   1949   // If we need a passphrase to decrypt data, try the cached passphrase.
   1950   if (passphrase_required_reason() == syncer::REASON_DECRYPTION) {
   1951     if (SetDecryptionPassphrase(passphrase)) {
   1952       DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
   1953       return;
   1954     }
   1955   }
   1956 
   1957   // If we get here, we don't have pending keys (or at least, the passphrase
   1958   // doesn't decrypt them) - just try to re-encrypt using the encryption
   1959   // passphrase.
   1960   if (!IsUsingSecondaryPassphrase())
   1961     SetEncryptionPassphrase(passphrase, IMPLICIT);
   1962 }
   1963 
   1964 void ProfileSyncService::RequestAccessToken() {
   1965   // Only one active request at a time.
   1966   if (access_token_request_ != NULL)
   1967     return;
   1968   request_access_token_retry_timer_.Stop();
   1969   OAuth2TokenService::ScopeSet oauth2_scopes;
   1970   if (profile_->IsManaged()) {
   1971     oauth2_scopes.insert(GaiaConstants::kChromeSyncManagedOAuth2Scope);
   1972   } else {
   1973     oauth2_scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
   1974   }
   1975 
   1976   // Invalidate previous token, otherwise token service will return the same
   1977   // token again.
   1978   const std::string& account_id = GetAccountIdToUse();
   1979   if (!access_token_.empty()) {
   1980     oauth2_token_service_->InvalidateToken(
   1981         account_id, oauth2_scopes, access_token_);
   1982   }
   1983 
   1984   access_token_.clear();
   1985 
   1986   token_request_time_ = base::Time::Now();
   1987   token_receive_time_ = base::Time();
   1988   next_token_request_time_ = base::Time();
   1989   access_token_request_ =
   1990       oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this);
   1991 }
   1992 
   1993 void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
   1994                                                  PassphraseType type) {
   1995   // This should only be called when the backend has been initialized.
   1996   DCHECK(sync_initialized());
   1997   DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) <<
   1998       "Data is already encrypted using an explicit passphrase";
   1999   DCHECK(!(type == EXPLICIT &&
   2000            passphrase_required_reason_ == syncer::REASON_DECRYPTION)) <<
   2001          "Can not set explicit passphrase when decryption is needed.";
   2002 
   2003   DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit")
   2004            << " passphrase for encryption.";
   2005   if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) {
   2006     // REASON_ENCRYPTION implies that the cryptographer does not have pending
   2007     // keys. Hence, as long as we're not trying to do an invalid passphrase
   2008     // change (e.g. explicit -> explicit or explicit -> implicit), we know this
   2009     // will succeed. If for some reason a new encryption key arrives via
   2010     // sync later, the SBH will trigger another OnPassphraseRequired().
   2011     passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
   2012     NotifyObservers();
   2013   }
   2014   backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT);
   2015 }
   2016 
   2017 bool ProfileSyncService::SetDecryptionPassphrase(
   2018     const std::string& passphrase) {
   2019   if (IsPassphraseRequired()) {
   2020     DVLOG(1) << "Setting passphrase for decryption.";
   2021     return backend_->SetDecryptionPassphrase(passphrase);
   2022   } else {
   2023     NOTREACHED() << "SetDecryptionPassphrase must not be called when "
   2024                     "IsPassphraseRequired() is false.";
   2025     return false;
   2026   }
   2027 }
   2028 
   2029 void ProfileSyncService::EnableEncryptEverything() {
   2030   // Tests override sync_initialized() to always return true, so we
   2031   // must check that instead of |backend_initialized_|.
   2032   // TODO(akalin): Fix the above. :/
   2033   DCHECK(sync_initialized());
   2034   // TODO(atwilson): Persist the encryption_pending_ flag to address the various
   2035   // problems around cancelling encryption in the background (crbug.com/119649).
   2036   if (!encrypt_everything_)
   2037     encryption_pending_ = true;
   2038 }
   2039 
   2040 bool ProfileSyncService::encryption_pending() const {
   2041   // We may be called during the setup process before we're
   2042   // initialized (via IsEncryptedDatatypeEnabled and
   2043   // IsPassphraseRequiredForDecryption).
   2044   return encryption_pending_;
   2045 }
   2046 
   2047 bool ProfileSyncService::EncryptEverythingEnabled() const {
   2048   DCHECK(backend_initialized_);
   2049   return encrypt_everything_ || encryption_pending_;
   2050 }
   2051 
   2052 syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const {
   2053   DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
   2054   // We may be called during the setup process before we're
   2055   // initialized.  In this case, we default to the sensitive types.
   2056   return encrypted_types_;
   2057 }
   2058 
   2059 void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
   2060   NotifyObservers();
   2061   if (is_sync_managed) {
   2062     DisableForUser();
   2063   } else {
   2064     // Sync is no longer disabled by policy. Try starting it up if appropriate.
   2065     TryStart();
   2066   }
   2067 }
   2068 
   2069 void ProfileSyncService::Observe(int type,
   2070                                  const content::NotificationSource& source,
   2071                                  const content::NotificationDetails& details) {
   2072   switch (type) {
   2073     case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: {
   2074       const GoogleServiceSigninSuccessDetails* successful =
   2075           content::Details<const GoogleServiceSigninSuccessDetails>(
   2076               details).ptr();
   2077       if (!sync_prefs_.IsStartSuppressed() &&
   2078           !successful->password.empty()) {
   2079         cached_passphrase_ = successful->password;
   2080         // Try to consume the passphrase we just cached. If the sync backend
   2081         // is not running yet, the passphrase will remain cached until the
   2082         // backend starts up.
   2083         ConsumeCachedPassphraseIfPossible();
   2084       }
   2085 #if defined(OS_CHROMEOS)
   2086       RefreshSpareBootstrapToken(successful->password);
   2087 #endif
   2088       if (!sync_initialized() ||
   2089           GetAuthError().state() != AuthError::NONE) {
   2090         // Track the fact that we're still waiting for auth to complete.
   2091         is_auth_in_progress_ = true;
   2092       }
   2093       break;
   2094     }
   2095     case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
   2096       sync_disabled_by_admin_ = false;
   2097       DisableForUser();
   2098       break;
   2099     default: {
   2100       NOTREACHED();
   2101     }
   2102   }
   2103 }
   2104 
   2105 void ProfileSyncService::AddObserver(
   2106     ProfileSyncServiceBase::Observer* observer) {
   2107   observers_.AddObserver(observer);
   2108 }
   2109 
   2110 void ProfileSyncService::RemoveObserver(
   2111     ProfileSyncServiceBase::Observer* observer) {
   2112   observers_.RemoveObserver(observer);
   2113 }
   2114 
   2115 bool ProfileSyncService::HasObserver(
   2116     ProfileSyncServiceBase::Observer* observer) const {
   2117   return observers_.HasObserver(observer);
   2118 }
   2119 
   2120 base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
   2121   return sync_js_controller_.AsWeakPtr();
   2122 }
   2123 
   2124 void ProfileSyncService::SyncEvent(SyncEventCodes code) {
   2125   UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
   2126 }
   2127 
   2128 // static
   2129 bool ProfileSyncService::IsSyncEnabled() {
   2130   // We have switches::kEnableSync just in case we need to change back to
   2131   // sync-disabled-by-default on a platform.
   2132   return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync);
   2133 }
   2134 
   2135 bool ProfileSyncService::IsManaged() const {
   2136   return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
   2137 }
   2138 
   2139 bool ProfileSyncService::ShouldPushChanges() {
   2140   // True only after all bootstrapping has succeeded: the sync backend
   2141   // is initialized, all enabled data types are consistent with one
   2142   // another, and no unrecoverable error has transpired.
   2143   if (HasUnrecoverableError())
   2144     return false;
   2145 
   2146   if (!data_type_manager_)
   2147     return false;
   2148 
   2149   return data_type_manager_->state() == DataTypeManager::CONFIGURED;
   2150 }
   2151 
   2152 void ProfileSyncService::StopAndSuppress() {
   2153   sync_prefs_.SetStartSuppressed(true);
   2154   if (backend_) {
   2155     backend_->UnregisterInvalidationIds();
   2156   }
   2157   ShutdownImpl(browser_sync::SyncBackendHost::STOP_AND_CLAIM_THREAD);
   2158 }
   2159 
   2160 bool ProfileSyncService::IsStartSuppressed() const {
   2161   return sync_prefs_.IsStartSuppressed();
   2162 }
   2163 
   2164 void ProfileSyncService::UnsuppressAndStart() {
   2165   DCHECK(profile_);
   2166   sync_prefs_.SetStartSuppressed(false);
   2167   // Set username in SigninManager, as SigninManager::OnGetUserInfoSuccess
   2168   // is never called for some clients.
   2169   if (signin_ && signin_->GetAuthenticatedUsername().empty()) {
   2170     signin_->SetAuthenticatedUsername(sync_prefs_.GetGoogleServicesUsername());
   2171   }
   2172   TryStart();
   2173 }
   2174 
   2175 void ProfileSyncService::AcknowledgeSyncedTypes() {
   2176   sync_prefs_.AcknowledgeSyncedTypes(GetRegisteredDataTypes());
   2177 }
   2178 
   2179 void ProfileSyncService::ReconfigureDatatypeManager() {
   2180   // If we haven't initialized yet, don't configure the DTM as it could cause
   2181   // association to start before a Directory has even been created.
   2182   if (backend_initialized_) {
   2183     DCHECK(backend_.get());
   2184     ConfigureDataTypeManager();
   2185   } else if (HasUnrecoverableError()) {
   2186     // There is nothing more to configure. So inform the listeners,
   2187     NotifyObservers();
   2188 
   2189     DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
   2190              << "Unrecoverable error.";
   2191   } else {
   2192     DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
   2193              << "initialized";
   2194   }
   2195 }
   2196 
   2197 const FailedDataTypesHandler& ProfileSyncService::failed_data_types_handler()
   2198     const {
   2199   return failed_data_types_handler_;
   2200 }
   2201 
   2202 void ProfileSyncService::OnInternalUnrecoverableError(
   2203     const tracked_objects::Location& from_here,
   2204     const std::string& message,
   2205     bool delete_sync_database,
   2206     UnrecoverableErrorReason reason) {
   2207   DCHECK(!HasUnrecoverableError());
   2208   unrecoverable_error_reason_ = reason;
   2209   OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
   2210 }
   2211 
   2212 bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
   2213   return request_access_token_retry_timer_.IsRunning();
   2214 }
   2215 
   2216 std::string ProfileSyncService::GetAccessTokenForTest() const {
   2217   return access_token_;
   2218 }
   2219 
   2220 std::string ProfileSyncService::GetEffectiveUsername() {
   2221   if (profile_->IsManaged()) {
   2222 #if defined(ENABLE_MANAGED_USERS)
   2223     DCHECK_EQ(std::string(), signin_->GetAuthenticatedUsername());
   2224     return managed_users::kManagedUserPseudoEmail;
   2225 #else
   2226     NOTREACHED();
   2227 #endif
   2228   }
   2229 
   2230   return signin_->GetAuthenticatedUsername();
   2231 }
   2232 
   2233 std::string ProfileSyncService::GetAccountIdToUse() {
   2234   if (profile_->IsManaged()) {
   2235 #if defined(ENABLE_MANAGED_USERS)
   2236     return managed_users::kManagedUserPseudoEmail;
   2237 #else
   2238     NOTREACHED();
   2239 #endif
   2240   }
   2241 
   2242   // TODO(fgorski): Use GetPrimaryAccountId() when it's available.
   2243   return signin_->GetAuthenticatedUsername();
   2244 }
   2245 
   2246 WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() {
   2247   return MakeWeakHandle(sync_js_controller_.AsWeakPtr());
   2248 }
   2249 
   2250 syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() {
   2251   return sessions_sync_manager_.get();
   2252 }
   2253 
   2254 ProfileSyncService::SyncTokenStatus::SyncTokenStatus()
   2255     : connection_status(syncer::CONNECTION_NOT_ATTEMPTED),
   2256       last_get_token_error(GoogleServiceAuthError::AuthErrorNone()) {}
   2257 ProfileSyncService::SyncTokenStatus::~SyncTokenStatus() {}
   2258 
   2259 ProfileSyncService::SyncTokenStatus
   2260 ProfileSyncService::GetSyncTokenStatus() const {
   2261   SyncTokenStatus status;
   2262   status.connection_status_update_time = connection_status_update_time_;
   2263   status.connection_status = connection_status_;
   2264   status.token_request_time = token_request_time_;
   2265   status.token_receive_time = token_receive_time_;
   2266   status.last_get_token_error = last_get_token_error_;
   2267   if (request_access_token_retry_timer_.IsRunning())
   2268     status.next_token_request_time = next_token_request_time_;
   2269   return status;
   2270 }
   2271 
   2272 void ProfileSyncService::OverrideNetworkResourcesForTest(
   2273     scoped_ptr<syncer::NetworkResources> network_resources) {
   2274   network_resources_ = network_resources.Pass();
   2275 }
   2276