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 <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/bind.h"
     13 #include "base/bind_helpers.h"
     14 #include "base/callback.h"
     15 #include "base/command_line.h"
     16 #include "base/compiler_specific.h"
     17 #include "base/files/file_util.h"
     18 #include "base/logging.h"
     19 #include "base/memory/ref_counted.h"
     20 #include "base/message_loop/message_loop.h"
     21 #include "base/metrics/histogram.h"
     22 #include "base/strings/string16.h"
     23 #include "base/strings/stringprintf.h"
     24 #include "base/threading/thread_restrictions.h"
     25 #include "build/build_config.h"
     26 #include "chrome/browser/bookmarks/enhanced_bookmarks_features.h"
     27 #include "chrome/browser/browser_process.h"
     28 #include "chrome/browser/browsing_data/browsing_data_helper.h"
     29 #include "chrome/browser/chrome_notification_types.h"
     30 #include "chrome/browser/defaults.h"
     31 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
     32 #include "chrome/browser/net/chrome_cookie_notification_details.h"
     33 #include "chrome/browser/password_manager/password_store_factory.h"
     34 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
     35 #include "chrome/browser/prefs/pref_service_syncable.h"
     36 #include "chrome/browser/profiles/profile.h"
     37 #include "chrome/browser/services/gcm/gcm_profile_service.h"
     38 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
     39 #include "chrome/browser/signin/about_signin_internals_factory.h"
     40 #include "chrome/browser/signin/chrome_signin_client_factory.h"
     41 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     42 #include "chrome/browser/signin/signin_manager_factory.h"
     43 #include "chrome/browser/sync/backend_migrator.h"
     44 #include "chrome/browser/sync/glue/chrome_report_unrecoverable_error.h"
     45 #include "chrome/browser/sync/glue/favicon_cache.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/typed_url_data_type_controller.h"
     50 #include "chrome/browser/sync/profile_sync_components_factory_impl.h"
     51 #include "chrome/browser/sync/sessions/notification_service_sessions_router.h"
     52 #include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h"
     53 #include "chrome/browser/sync/sync_error_controller.h"
     54 #include "chrome/browser/sync/sync_type_preference_provider.h"
     55 #include "chrome/browser/ui/browser.h"
     56 #include "chrome/browser/ui/browser_list.h"
     57 #include "chrome/browser/ui/browser_window.h"
     58 #include "chrome/browser/ui/global_error/global_error_service.h"
     59 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
     60 #include "chrome/common/chrome_switches.h"
     61 #include "chrome/common/chrome_version_info.h"
     62 #include "chrome/common/pref_names.h"
     63 #include "chrome/common/url_constants.h"
     64 #include "chrome/grit/generated_resources.h"
     65 #include "components/gcm_driver/gcm_driver.h"
     66 #include "components/invalidation/invalidation_service.h"
     67 #include "components/invalidation/profile_invalidation_provider.h"
     68 #include "components/password_manager/core/browser/password_store.h"
     69 #include "components/pref_registry/pref_registry_syncable.h"
     70 #include "components/signin/core/browser/about_signin_internals.h"
     71 #include "components/signin/core/browser/profile_oauth2_token_service.h"
     72 #include "components/signin/core/browser/signin_manager.h"
     73 #include "components/signin/core/browser/signin_metrics.h"
     74 #include "components/sync_driver/change_processor.h"
     75 #include "components/sync_driver/data_type_controller.h"
     76 #include "components/sync_driver/device_info.h"
     77 #include "components/sync_driver/pref_names.h"
     78 #include "components/sync_driver/system_encryptor.h"
     79 #include "components/sync_driver/user_selectable_sync_type.h"
     80 #include "content/public/browser/browser_thread.h"
     81 #include "content/public/browser/notification_details.h"
     82 #include "content/public/browser/notification_service.h"
     83 #include "content/public/browser/notification_source.h"
     84 #include "net/cookies/cookie_monster.h"
     85 #include "net/url_request/url_request_context_getter.h"
     86 #include "sync/api/sync_error.h"
     87 #include "sync/internal_api/public/configure_reason.h"
     88 #include "sync/internal_api/public/http_bridge_network_resources.h"
     89 #include "sync/internal_api/public/network_resources.h"
     90 #include "sync/internal_api/public/sessions/type_debug_info_observer.h"
     91 #include "sync/internal_api/public/shutdown_reason.h"
     92 #include "sync/internal_api/public/sync_context_proxy.h"
     93 #include "sync/internal_api/public/sync_encryption_handler.h"
     94 #include "sync/internal_api/public/util/experiments.h"
     95 #include "sync/internal_api/public/util/sync_db_util.h"
     96 #include "sync/internal_api/public/util/sync_string_conversions.h"
     97 #include "sync/js/js_event_details.h"
     98 #include "sync/util/cryptographer.h"
     99 #include "ui/base/l10n/l10n_util.h"
    100 #include "ui/base/l10n/time_format.h"
    101 
    102 #if defined(OS_ANDROID)
    103 #include "sync/internal_api/public/read_transaction.h"
    104 #endif
    105 
    106 using browser_sync::NotificationServiceSessionsRouter;
    107 using browser_sync::ProfileSyncServiceStartBehavior;
    108 using browser_sync::SessionsSyncManager;
    109 using browser_sync::SyncBackendHost;
    110 using sync_driver::ChangeProcessor;
    111 using sync_driver::DataTypeController;
    112 using sync_driver::DataTypeManager;
    113 using sync_driver::DataTypeStatusTable;
    114 using sync_driver::DeviceInfoSyncService;
    115 using syncer::ModelType;
    116 using syncer::ModelTypeSet;
    117 using syncer::JsBackend;
    118 using syncer::JsController;
    119 using syncer::JsEventDetails;
    120 using syncer::JsEventHandler;
    121 using syncer::ModelSafeRoutingInfo;
    122 using syncer::SyncCredentials;
    123 using syncer::SyncProtocolError;
    124 using syncer::WeakHandle;
    125 
    126 typedef GoogleServiceAuthError AuthError;
    127 
    128 const char* ProfileSyncService::kSyncServerUrl =
    129     "https://clients4.google.com/chrome-sync";
    130 
    131 const char* ProfileSyncService::kDevServerUrl =
    132     "https://clients4.google.com/chrome-sync/dev";
    133 
    134 const char kSyncUnrecoverableErrorHistogram[] =
    135     "Sync.UnrecoverableErrors";
    136 
    137 const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
    138   // Number of initial errors (in sequence) to ignore before applying
    139   // exponential back-off rules.
    140   0,
    141 
    142   // Initial delay for exponential back-off in ms.
    143   2000,
    144 
    145   // Factor by which the waiting time will be multiplied.
    146   2,
    147 
    148   // Fuzzing percentage. ex: 10% will spread requests randomly
    149   // between 90%-100% of the calculated time.
    150   0.2, // 20%
    151 
    152   // Maximum amount of time we are willing to delay our request in ms.
    153   // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
    154   // RequestAccessToken on connection state change after backoff
    155   1000 * 3600 * 4, // 4 hours.
    156 
    157   // Time to keep an entry from being discarded even when it
    158   // has no significant state, -1 to never discard.
    159   -1,
    160 
    161   // Don't use initial delay unless the last request was an error.
    162   false,
    163 };
    164 
    165 static const base::FilePath::CharType kSyncDataFolderName[] =
    166     FILE_PATH_LITERAL("Sync Data");
    167 
    168 static const base::FilePath::CharType kSyncBackupDataFolderName[] =
    169     FILE_PATH_LITERAL("Sync Data Backup");
    170 
    171 namespace {
    172 
    173 void ClearBrowsingData(BrowsingDataRemover::Observer* observer,
    174                        Profile* profile,
    175                        base::Time start,
    176                        base::Time end) {
    177   // BrowsingDataRemover deletes itself when it's done.
    178   BrowsingDataRemover* remover = BrowsingDataRemover::CreateForRange(
    179       profile, start, end);
    180   if (observer)
    181     remover->AddObserver(observer);
    182   remover->Remove(BrowsingDataRemover::REMOVE_ALL,
    183                   BrowsingDataHelper::ALL);
    184 
    185   scoped_refptr<password_manager::PasswordStore> password =
    186       PasswordStoreFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
    187   password->RemoveLoginsSyncedBetween(start, end);
    188 }
    189 
    190 }  // anonymous namespace
    191 
    192 bool ShouldShowActionOnUI(
    193     const syncer::SyncProtocolError& error) {
    194   return (error.action != syncer::UNKNOWN_ACTION &&
    195           error.action != syncer::DISABLE_SYNC_ON_CLIENT &&
    196           error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT);
    197 }
    198 
    199 ProfileSyncService::ProfileSyncService(
    200     scoped_ptr<ProfileSyncComponentsFactory> factory,
    201     Profile* profile,
    202     scoped_ptr<SupervisedUserSigninManagerWrapper> signin_wrapper,
    203     ProfileOAuth2TokenService* oauth2_token_service,
    204     ProfileSyncServiceStartBehavior start_behavior)
    205     : OAuth2TokenService::Consumer("sync"),
    206       last_auth_error_(AuthError::AuthErrorNone()),
    207       passphrase_required_reason_(syncer::REASON_PASSPHRASE_NOT_REQUIRED),
    208       factory_(factory.Pass()),
    209       profile_(profile),
    210       sync_prefs_(profile_->GetPrefs()),
    211       sync_service_url_(GetSyncServiceURL(*CommandLine::ForCurrentProcess())),
    212       is_first_time_sync_configure_(false),
    213       backend_initialized_(false),
    214       sync_disabled_by_admin_(false),
    215       is_auth_in_progress_(false),
    216       signin_(signin_wrapper.Pass()),
    217       unrecoverable_error_reason_(ERROR_REASON_UNSET),
    218       expect_sync_configuration_aborted_(false),
    219       encrypted_types_(syncer::SyncEncryptionHandler::SensitiveTypes()),
    220       encrypt_everything_allowed_(true),
    221       encrypt_everything_(false),
    222       encryption_pending_(false),
    223       configure_status_(DataTypeManager::UNKNOWN),
    224       oauth2_token_service_(oauth2_token_service),
    225       request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
    226       weak_factory_(this),
    227       startup_controller_weak_factory_(this),
    228       connection_status_(syncer::CONNECTION_NOT_ATTEMPTED),
    229       last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
    230       network_resources_(new syncer::HttpBridgeNetworkResources),
    231       startup_controller_(
    232           start_behavior,
    233           oauth2_token_service,
    234           &sync_prefs_,
    235           signin_.get(),
    236           base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
    237                      startup_controller_weak_factory_.GetWeakPtr(),
    238                      SYNC)),
    239       backup_rollback_controller_(
    240           &sync_prefs_,
    241           signin_.get(),
    242           base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
    243                      startup_controller_weak_factory_.GetWeakPtr(),
    244                      BACKUP),
    245           base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
    246                      startup_controller_weak_factory_.GetWeakPtr(),
    247                      ROLLBACK)),
    248       backend_mode_(IDLE),
    249       need_backup_(false),
    250       backup_finished_(false),
    251       clear_browsing_data_(base::Bind(&ClearBrowsingData)),
    252       browsing_data_remover_observer_(NULL) {
    253   DCHECK(profile);
    254   syncer::SyncableService::StartSyncFlare flare(
    255       sync_start_util::GetFlareForSyncableService(profile->GetPath()));
    256   scoped_ptr<browser_sync::LocalSessionEventRouter> router(
    257       new NotificationServiceSessionsRouter(profile, flare));
    258 
    259   DCHECK(factory_.get());
    260   local_device_ = factory_->CreateLocalDeviceInfoProvider();
    261   sessions_sync_manager_.reset(
    262       new SessionsSyncManager(profile, local_device_.get(), router.Pass()));
    263   device_info_sync_service_.reset(
    264       new DeviceInfoSyncService(local_device_.get()));
    265 }
    266 
    267 ProfileSyncService::~ProfileSyncService() {
    268   sync_prefs_.RemoveSyncPrefObserver(this);
    269   // Shutdown() should have been called before destruction.
    270   CHECK(!backend_initialized_);
    271 }
    272 
    273 bool ProfileSyncService::IsSyncEnabledAndLoggedIn() {
    274   // Exit if sync is disabled.
    275   if (IsManaged() || sync_prefs_.IsStartSuppressed())
    276     return false;
    277 
    278   // Sync is logged in if there is a non-empty effective username.
    279   return !signin_->GetEffectiveUsername().empty();
    280 }
    281 
    282 bool ProfileSyncService::IsOAuthRefreshTokenAvailable() {
    283   if (!oauth2_token_service_)
    284     return false;
    285 
    286   return oauth2_token_service_->RefreshTokenIsAvailable(
    287       signin_->GetAccountIdToUse());
    288 }
    289 
    290 void ProfileSyncService::Initialize() {
    291   // We clear this here (vs Shutdown) because we want to remember that an error
    292   // happened on shutdown so we can display details (message, location) about it
    293   // in about:sync.
    294   ClearStaleErrors();
    295 
    296   sync_prefs_.AddSyncPrefObserver(this);
    297 
    298   // For now, the only thing we can do through policy is to turn sync off.
    299   if (IsManaged()) {
    300     DisableForUser();
    301     return;
    302   }
    303 
    304   RegisterAuthNotifications();
    305 
    306   if (!HasSyncSetupCompleted() || signin_->GetEffectiveUsername().empty()) {
    307     // Clean up in case of previous crash / setup abort / signout.
    308     DisableForUser();
    309   }
    310 
    311   TrySyncDatatypePrefRecovery();
    312 
    313 #if defined(OS_CHROMEOS)
    314   std::string bootstrap_token = sync_prefs_.GetEncryptionBootstrapToken();
    315   if (bootstrap_token.empty()) {
    316     sync_prefs_.SetEncryptionBootstrapToken(
    317         sync_prefs_.GetSpareBootstrapToken());
    318   }
    319 #endif
    320 
    321 #if !defined(OS_ANDROID)
    322   DCHECK(sync_error_controller_ == NULL)
    323       << "Initialize() called more than once.";
    324   sync_error_controller_.reset(new SyncErrorController(this));
    325   AddObserver(sync_error_controller_.get());
    326 #endif
    327 
    328   bool running_rollback = false;
    329   if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
    330     // Backup is needed if user's not signed in or signed in but previous
    331     // backup didn't finish, i.e. backend didn't switch from backup to sync.
    332     need_backup_ = signin_->GetEffectiveUsername().empty() ||
    333         sync_prefs_.GetFirstSyncTime().is_null();
    334 
    335     // Try to resume rollback if it didn't finish in last session.
    336     running_rollback = backup_rollback_controller_.StartRollback();
    337   } else {
    338     need_backup_ = false;
    339   }
    340 
    341 #if defined(ENABLE_PRE_SYNC_BACKUP)
    342   if (!running_rollback && signin_->GetEffectiveUsername().empty()) {
    343     CleanUpBackup();
    344   }
    345 #else
    346   DCHECK(!running_rollback);
    347 #endif
    348 
    349   startup_controller_.Reset(GetRegisteredDataTypes());
    350   startup_controller_.TryStart();
    351 }
    352 
    353 void ProfileSyncService::TrySyncDatatypePrefRecovery() {
    354   DCHECK(!sync_initialized());
    355   if (!HasSyncSetupCompleted())
    356     return;
    357 
    358   // There was a bug where OnUserChoseDatatypes was not properly called on
    359   // configuration (see crbug.com/154940). We detect this by checking whether
    360   // kSyncKeepEverythingSynced has a default value. If so, and sync setup has
    361   // completed, it means sync was not properly configured, so we manually
    362   // set kSyncKeepEverythingSynced.
    363   PrefService* const pref_service = profile_->GetPrefs();
    364   if (!pref_service)
    365     return;
    366   if (GetPreferredDataTypes().Size() > 1)
    367     return;
    368 
    369   const PrefService::Preference* keep_everything_synced =
    370       pref_service->FindPreference(
    371           sync_driver::prefs::kSyncKeepEverythingSynced);
    372   // This will be false if the preference was properly set or if it's controlled
    373   // by policy.
    374   if (!keep_everything_synced->IsDefaultValue())
    375     return;
    376 
    377   // kSyncKeepEverythingSynced was not properly set. Set it and the preferred
    378   // types now, before we configure.
    379   UMA_HISTOGRAM_COUNTS("Sync.DatatypePrefRecovery", 1);
    380   sync_prefs_.SetKeepEverythingSynced(true);
    381   syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
    382 }
    383 
    384 void ProfileSyncService::StartSyncingWithServer() {
    385   if (backend_)
    386     backend_->StartSyncingWithServer();
    387 }
    388 
    389 void ProfileSyncService::RegisterAuthNotifications() {
    390   oauth2_token_service_->AddObserver(this);
    391   if (signin())
    392     signin()->AddObserver(this);
    393 }
    394 
    395 void ProfileSyncService::UnregisterAuthNotifications() {
    396   if (signin())
    397     signin()->RemoveObserver(this);
    398   oauth2_token_service_->RemoveObserver(this);
    399 }
    400 
    401 void ProfileSyncService::RegisterDataTypeController(
    402     DataTypeController* data_type_controller) {
    403   DCHECK_EQ(
    404       directory_data_type_controllers_.count(data_type_controller->type()),
    405       0U);
    406   DCHECK(!GetRegisteredNonBlockingDataTypes().Has(
    407       data_type_controller->type()));
    408   directory_data_type_controllers_[data_type_controller->type()] =
    409       data_type_controller;
    410 }
    411 
    412 void ProfileSyncService::RegisterNonBlockingType(syncer::ModelType type) {
    413   DCHECK_EQ(directory_data_type_controllers_.count(type), 0U)
    414       << "Duplicate registration of type " << ModelTypeToString(type);
    415 
    416   // TODO(rlarocque): Set the enable flag properly when crbug.com/368834 is
    417   // fixed and we have some way of telling whether or not this type should be
    418   // enabled.
    419   non_blocking_data_type_manager_.RegisterType(type, false);
    420 }
    421 
    422 void ProfileSyncService::InitializeNonBlockingType(
    423     syncer::ModelType type,
    424     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
    425     const base::WeakPtr<syncer::ModelTypeSyncProxyImpl>& type_sync_proxy) {
    426   non_blocking_data_type_manager_.InitializeType(
    427       type, task_runner, type_sync_proxy);
    428 }
    429 
    430 bool ProfileSyncService::IsDataTypeControllerRunning(
    431     syncer::ModelType type) const {
    432   DataTypeController::TypeMap::const_iterator iter =
    433       directory_data_type_controllers_.find(type);
    434   if (iter == directory_data_type_controllers_.end()) {
    435     return false;
    436   }
    437   return iter->second->state() == DataTypeController::RUNNING;
    438 }
    439 
    440 browser_sync::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
    441   if (!IsDataTypeControllerRunning(syncer::SESSIONS))
    442     return NULL;
    443   return sessions_sync_manager_.get();
    444 }
    445 
    446 browser_sync::FaviconCache* ProfileSyncService::GetFaviconCache() {
    447   return sessions_sync_manager_->GetFaviconCache();
    448 }
    449 
    450 browser_sync::SyncedWindowDelegatesGetter*
    451 ProfileSyncService::GetSyncedWindowDelegatesGetter() const {
    452   return sessions_sync_manager_->GetSyncedWindowDelegatesGetter();
    453 }
    454 
    455 sync_driver::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker()
    456     const {
    457   if (!IsDataTypeControllerRunning(syncer::DEVICE_INFO))
    458     return NULL;
    459 
    460   return device_info_sync_service_.get();
    461 }
    462 
    463 sync_driver::LocalDeviceInfoProvider*
    464 ProfileSyncService::GetLocalDeviceInfoProvider() {
    465   return local_device_.get();
    466 }
    467 
    468 void ProfileSyncService::GetDataTypeControllerStates(
    469   DataTypeController::StateMap* state_map) const {
    470     for (DataTypeController::TypeMap::const_iterator iter =
    471          directory_data_type_controllers_.begin();
    472          iter != directory_data_type_controllers_.end();
    473          ++iter)
    474       (*state_map)[iter->first] = iter->second.get()->state();
    475 }
    476 
    477 SyncCredentials ProfileSyncService::GetCredentials() {
    478   SyncCredentials credentials;
    479   if (backend_mode_ == SYNC) {
    480     credentials.email = signin_->GetEffectiveUsername();
    481     DCHECK(!credentials.email.empty());
    482     credentials.sync_token = access_token_;
    483 
    484     if (credentials.sync_token.empty())
    485       credentials.sync_token = "credentials_lost";
    486 
    487     credentials.scope_set.insert(signin_->GetSyncScopeToUse());
    488   }
    489 
    490   return credentials;
    491 }
    492 
    493 bool ProfileSyncService::ShouldDeleteSyncFolder() {
    494   switch (backend_mode_) {
    495     case SYNC:
    496       return !HasSyncSetupCompleted();
    497     case BACKUP:
    498       return true;
    499     case ROLLBACK:
    500       return false;
    501     case IDLE:
    502       NOTREACHED();
    503       return true;
    504   }
    505   return true;
    506 }
    507 
    508 void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
    509   if (!backend_) {
    510     NOTREACHED();
    511     return;
    512   }
    513 
    514   SyncCredentials credentials = GetCredentials();
    515 
    516   scoped_refptr<net::URLRequestContextGetter> request_context_getter(
    517       profile_->GetRequestContext());
    518 
    519   if (backend_mode_ == SYNC && delete_stale_data)
    520     ClearStaleErrors();
    521 
    522   scoped_ptr<syncer::UnrecoverableErrorHandler>
    523       backend_unrecoverable_error_handler(
    524           new browser_sync::BackendUnrecoverableErrorHandler(
    525               MakeWeakHandle(weak_factory_.GetWeakPtr())));
    526 
    527   backend_->Initialize(
    528       this,
    529       sync_thread_.Pass(),
    530       GetJsEventHandler(),
    531       sync_service_url_,
    532       credentials,
    533       delete_stale_data,
    534       scoped_ptr<syncer::SyncManagerFactory>(
    535           new syncer::SyncManagerFactory(GetManagerType())).Pass(),
    536       backend_unrecoverable_error_handler.Pass(),
    537       &browser_sync::ChromeReportUnrecoverableError,
    538       network_resources_.get());
    539 }
    540 
    541 bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
    542   if (encryption_pending())
    543     return true;
    544   const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
    545   const syncer::ModelTypeSet encrypted_types = GetEncryptedDataTypes();
    546   DCHECK(encrypted_types.Has(syncer::PASSWORDS));
    547   return !Intersection(preferred_types, encrypted_types).Empty();
    548 }
    549 
    550 void ProfileSyncService::OnSyncConfigureRetry() {
    551   // Note: in order to handle auth failures that arise before the backend is
    552   // initialized (e.g. from invalidation notifier, or downloading new control
    553   // types), we have to gracefully handle configuration retries at all times.
    554   // At this point an auth error badge should be shown, which once resolved
    555   // will trigger a new sync cycle.
    556   NotifyObservers();
    557 }
    558 
    559 void ProfileSyncService::OnProtocolEvent(
    560     const syncer::ProtocolEvent& event) {
    561   FOR_EACH_OBSERVER(browser_sync::ProtocolEventObserver,
    562                     protocol_event_observers_,
    563                     OnProtocolEvent(event));
    564 }
    565 
    566 void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
    567     syncer::ModelType type,
    568     const syncer::CommitCounters& counters) {
    569   FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
    570                     type_debug_info_observers_,
    571                     OnCommitCountersUpdated(type, counters));
    572 }
    573 
    574 void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
    575     syncer::ModelType type,
    576     const syncer::UpdateCounters& counters) {
    577   FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
    578                     type_debug_info_observers_,
    579                     OnUpdateCountersUpdated(type, counters));
    580 }
    581 
    582 void ProfileSyncService::OnDirectoryTypeStatusCounterUpdated(
    583     syncer::ModelType type,
    584     const syncer::StatusCounters& counters) {
    585   FOR_EACH_OBSERVER(syncer::TypeDebugInfoObserver,
    586                     type_debug_info_observers_,
    587                     OnStatusCountersUpdated(type, counters));
    588 }
    589 
    590 void ProfileSyncService::OnDataTypeRequestsSyncStartup(
    591     syncer::ModelType type) {
    592   DCHECK(syncer::UserTypes().Has(type));
    593   if (backend_.get()) {
    594     DVLOG(1) << "A data type requested sync startup, but it looks like "
    595                 "something else beat it to the punch.";
    596     return;
    597   }
    598 
    599   if (!GetPreferredDataTypes().Has(type)) {
    600     // We can get here as datatype SyncableServices are typically wired up
    601     // to the native datatype even if sync isn't enabled.
    602     DVLOG(1) << "Dropping sync startup request because type "
    603              << syncer::ModelTypeToString(type) << "not enabled.";
    604     return;
    605   }
    606 
    607   startup_controller_.OnDataTypeRequestsSyncStartup(type);
    608 }
    609 
    610 void ProfileSyncService::StartUpSlowBackendComponents(
    611     ProfileSyncService::BackendMode mode) {
    612   DCHECK_NE(IDLE, mode);
    613   if (backend_mode_ == mode) {
    614     return;
    615   }
    616 
    617   // Backend mode transition rules:
    618   // * can transit from IDLE to any other non-IDLE mode.
    619   // * forbidden to transit from SYNC to any other mode, i.e. SYNC backend must
    620   //   be explicitly shut down before backup/rollback starts.
    621   // * can not transit out of ROLLBACK mode until rollback is finished
    622   //   (successfully or unsuccessfully).
    623   // * can not transit out of BACKUP mode until backup is finished
    624   //   (successfully or unsuccessfully).
    625   // * if backup is needed, can only transit to SYNC if backup is finished,
    626 
    627   if (backend_mode_ == SYNC) {
    628     LOG(DFATAL) << "Shouldn't switch from mode SYNC to mode " << mode;
    629     return;
    630   }
    631 
    632   if (backend_mode_ == ROLLBACK ||
    633       (backend_mode_ == BACKUP && !backup_finished_)) {
    634     // Wait for rollback/backup to finish before start new backend.
    635     return;
    636   }
    637 
    638   if (mode == SYNC && NeedBackup() && !backup_finished_) {
    639     if (backend_mode_ != BACKUP)
    640       backup_rollback_controller_.StartBackup();
    641     return;
    642   }
    643 
    644   DVLOG(1) << "Start backend mode: " << mode;
    645 
    646   if (backend_) {
    647     if (mode == SYNC)
    648       ShutdownImpl(syncer::SWITCH_MODE_SYNC);
    649     else
    650       ShutdownImpl(syncer::STOP_SYNC);
    651   }
    652 
    653   backend_mode_ = mode;
    654 
    655   if (backend_mode_ == BACKUP)
    656     backup_start_time_ = base::Time::Now();
    657 
    658   if (backend_mode_ == SYNC && !backup_start_time_.is_null()) {
    659     UMA_HISTOGRAM_MEDIUM_TIMES("Sync.FirstSyncDelayByBackup",
    660                                base::Time::Now() - backup_start_time_);
    661     backup_start_time_ = base::Time();
    662   }
    663 
    664   if (backend_mode_ == ROLLBACK)
    665     ClearBrowsingDataSinceFirstSync();
    666   else if (backend_mode_ == SYNC)
    667     CheckSyncBackupIfNeeded();
    668 
    669   base::FilePath sync_folder = backend_mode_ == SYNC ?
    670       base::FilePath(kSyncDataFolderName) :
    671       base::FilePath(kSyncBackupDataFolderName);
    672 
    673   invalidation::InvalidationService* invalidator = NULL;
    674   if (backend_mode_ == SYNC) {
    675     invalidation::ProfileInvalidationProvider* provider =
    676         invalidation::ProfileInvalidationProviderFactory::GetForProfile(
    677             profile_);
    678     if (provider)
    679       invalidator = provider->GetInvalidationService();
    680   }
    681 
    682   backend_.reset(
    683       factory_->CreateSyncBackendHost(
    684           profile_->GetDebugName(),
    685           profile_,
    686           invalidator,
    687           sync_prefs_.AsWeakPtr(),
    688           sync_folder));
    689 
    690   // Initialize the backend.  Every time we start up a new SyncBackendHost,
    691   // we'll want to start from a fresh SyncDB, so delete any old one that might
    692   // be there.
    693   InitializeBackend(ShouldDeleteSyncFolder());
    694 
    695   UpdateFirstSyncTimePref();
    696 
    697   NotifyObservers();
    698 }
    699 
    700 void ProfileSyncService::OnGetTokenSuccess(
    701     const OAuth2TokenService::Request* request,
    702     const std::string& access_token,
    703     const base::Time& expiration_time) {
    704   DCHECK_EQ(access_token_request_, request);
    705   access_token_request_.reset();
    706   access_token_ = access_token;
    707   token_receive_time_ = base::Time::Now();
    708   last_get_token_error_ = GoogleServiceAuthError::AuthErrorNone();
    709 
    710   if (sync_prefs_.SyncHasAuthError()) {
    711     sync_prefs_.SetSyncAuthError(false);
    712     UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
    713                               AUTH_ERROR_FIXED,
    714                               AUTH_ERROR_LIMIT);
    715   }
    716 
    717   if (HasSyncingBackend())
    718     backend_->UpdateCredentials(GetCredentials());
    719   else
    720     startup_controller_.TryStart();
    721 }
    722 
    723 void ProfileSyncService::OnGetTokenFailure(
    724     const OAuth2TokenService::Request* request,
    725     const GoogleServiceAuthError& error) {
    726   DCHECK_EQ(access_token_request_, request);
    727   DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
    728   access_token_request_.reset();
    729   last_get_token_error_ = error;
    730   switch (error.state()) {
    731     case GoogleServiceAuthError::CONNECTION_FAILED:
    732     case GoogleServiceAuthError::REQUEST_CANCELED:
    733     case GoogleServiceAuthError::SERVICE_ERROR:
    734     case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
    735       // Transient error. Retry after some time.
    736       request_access_token_backoff_.InformOfRequest(false);
    737       next_token_request_time_ = base::Time::Now() +
    738           request_access_token_backoff_.GetTimeUntilRelease();
    739       request_access_token_retry_timer_.Start(
    740             FROM_HERE,
    741             request_access_token_backoff_.GetTimeUntilRelease(),
    742             base::Bind(&ProfileSyncService::RequestAccessToken,
    743                         weak_factory_.GetWeakPtr()));
    744       NotifyObservers();
    745       break;
    746     }
    747     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
    748       if (!sync_prefs_.SyncHasAuthError()) {
    749         sync_prefs_.SetSyncAuthError(true);
    750         UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError",
    751                                   AUTH_ERROR_ENCOUNTERED,
    752                                   AUTH_ERROR_LIMIT);
    753       }
    754       // Fallthrough.
    755     }
    756     default: {
    757       if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
    758         LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
    759       }
    760       // Show error to user.
    761       UpdateAuthErrorState(error);
    762     }
    763   }
    764 }
    765 
    766 void ProfileSyncService::OnRefreshTokenAvailable(
    767     const std::string& account_id) {
    768   if (account_id == signin_->GetAccountIdToUse())
    769     OnRefreshTokensLoaded();
    770 }
    771 
    772 void ProfileSyncService::OnRefreshTokenRevoked(
    773     const std::string& account_id) {
    774   if (!IsOAuthRefreshTokenAvailable()) {
    775     access_token_.clear();
    776     // The additional check around IsOAuthRefreshTokenAvailable() above
    777     // prevents us sounding the alarm if we actually have a valid token but
    778     // a refresh attempt failed for any variety of reasons
    779     // (e.g. flaky network). It's possible the token we do have is also
    780     // invalid, but in that case we should already have (or can expect) an
    781     // auth error sent from the sync backend.
    782     UpdateAuthErrorState(
    783         GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
    784   }
    785 }
    786 
    787 void ProfileSyncService::OnRefreshTokensLoaded() {
    788   // This notification gets fired when OAuth2TokenService loads the tokens
    789   // from storage.
    790   // Initialize the backend if sync is enabled. If the sync token was
    791   // not loaded, GetCredentials() will generate invalid credentials to
    792   // cause the backend to generate an auth error (crbug.com/121755).
    793   if (HasSyncingBackend()) {
    794     RequestAccessToken();
    795   } else {
    796     startup_controller_.TryStart();
    797   }
    798 }
    799 
    800 void ProfileSyncService::Shutdown() {
    801   UnregisterAuthNotifications();
    802 
    803   ShutdownImpl(syncer::BROWSER_SHUTDOWN);
    804   if (sync_error_controller_) {
    805     // Destroy the SyncErrorController when the service shuts down for good.
    806     RemoveObserver(sync_error_controller_.get());
    807     sync_error_controller_.reset();
    808   }
    809 
    810   if (sync_thread_)
    811     sync_thread_->Stop();
    812 }
    813 
    814 void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
    815   if (!backend_)
    816     return;
    817 
    818   non_blocking_data_type_manager_.DisconnectSyncBackend();
    819 
    820   // First, we spin down the backend to stop change processing as soon as
    821   // possible.
    822   base::Time shutdown_start_time = base::Time::Now();
    823   backend_->StopSyncingForShutdown();
    824 
    825   // Stop all data type controllers, if needed.  Note that until Stop
    826   // completes, it is possible in theory to have a ChangeProcessor apply a
    827   // change from a native model.  In that case, it will get applied to the sync
    828   // database (which doesn't get destroyed until we destroy the backend below)
    829   // as an unsynced change.  That will be persisted, and committed on restart.
    830   if (directory_data_type_manager_) {
    831     if (directory_data_type_manager_->state() != DataTypeManager::STOPPED) {
    832       // When aborting as part of shutdown, we should expect an aborted sync
    833       // configure result, else we'll dcheck when we try to read the sync error.
    834       expect_sync_configuration_aborted_ = true;
    835       directory_data_type_manager_->Stop();
    836     }
    837     directory_data_type_manager_.reset();
    838   }
    839 
    840   // Shutdown the migrator before the backend to ensure it doesn't pull a null
    841   // snapshot.
    842   migrator_.reset();
    843   sync_js_controller_.AttachJsBackend(WeakHandle<syncer::JsBackend>());
    844 
    845   // Move aside the backend so nobody else tries to use it while we are
    846   // shutting it down.
    847   scoped_ptr<SyncBackendHost> doomed_backend(backend_.release());
    848   if (doomed_backend) {
    849     sync_thread_ = doomed_backend->Shutdown(reason);
    850     doomed_backend.reset();
    851   }
    852   base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
    853   UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time);
    854 
    855   weak_factory_.InvalidateWeakPtrs();
    856 
    857   if (backend_mode_ == SYNC)
    858     startup_controller_.Reset(GetRegisteredDataTypes());
    859 
    860   // Don't let backup block sync regardless backup succeeded or not.
    861   if (backend_mode_ == BACKUP)
    862     backup_finished_ = true;
    863 
    864   // Sync could be blocked by rollback/backup. Post task to check whether sync
    865   // should start after shutting down rollback/backup backend.
    866   if ((backend_mode_ == ROLLBACK || backend_mode_ == BACKUP) &&
    867       reason != syncer::SWITCH_MODE_SYNC &&
    868       reason != syncer::BROWSER_SHUTDOWN) {
    869     base::MessageLoop::current()->PostTask(
    870         FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup,
    871                               startup_controller_weak_factory_.GetWeakPtr()));
    872   }
    873 
    874   // Clear various flags.
    875   backend_mode_ = IDLE;
    876   expect_sync_configuration_aborted_ = false;
    877   is_auth_in_progress_ = false;
    878   backend_initialized_ = false;
    879   cached_passphrase_.clear();
    880   access_token_.clear();
    881   encryption_pending_ = false;
    882   encrypt_everything_ = false;
    883   encrypted_types_ = syncer::SyncEncryptionHandler::SensitiveTypes();
    884   passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
    885   request_access_token_retry_timer_.Stop();
    886   // Revert to "no auth error".
    887   if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
    888     UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
    889 
    890   NotifyObservers();
    891 }
    892 
    893 void ProfileSyncService::DisableForUser() {
    894   // Clear prefs (including SyncSetupHasCompleted) before shutting down so
    895   // PSS clients don't think we're set up while we're shutting down.
    896   sync_prefs_.ClearPreferences();
    897   ClearUnrecoverableError();
    898   ShutdownImpl(syncer::DISABLE_SYNC);
    899 }
    900 
    901 bool ProfileSyncService::HasSyncSetupCompleted() const {
    902   return sync_prefs_.HasSyncSetupCompleted();
    903 }
    904 
    905 void ProfileSyncService::SetSyncSetupCompleted() {
    906   sync_prefs_.SetSyncSetupCompleted();
    907 }
    908 
    909 void ProfileSyncService::UpdateLastSyncedTime() {
    910   sync_prefs_.SetLastSyncedTime(base::Time::Now());
    911 }
    912 
    913 void ProfileSyncService::NotifyObservers() {
    914   FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_,
    915                     OnStateChanged());
    916 }
    917 
    918 void ProfileSyncService::NotifySyncCycleCompleted() {
    919   FOR_EACH_OBSERVER(ProfileSyncServiceBase::Observer, observers_,
    920                     OnSyncCycleCompleted());
    921 }
    922 
    923 void ProfileSyncService::ClearStaleErrors() {
    924   ClearUnrecoverableError();
    925   last_actionable_error_ = SyncProtocolError();
    926   // Clear the data type errors as well.
    927   if (directory_data_type_manager_.get())
    928     directory_data_type_manager_->ResetDataTypeErrors();
    929 
    930 }
    931 
    932 void ProfileSyncService::ClearUnrecoverableError() {
    933   unrecoverable_error_reason_ = ERROR_REASON_UNSET;
    934   unrecoverable_error_message_.clear();
    935   unrecoverable_error_location_ = tracked_objects::Location();
    936 }
    937 
    938 void ProfileSyncService::RegisterNewDataType(syncer::ModelType data_type) {
    939   if (directory_data_type_controllers_.count(data_type) > 0)
    940     return;
    941   NOTREACHED();
    942 }
    943 
    944 // An invariant has been violated.  Transition to an error state where we try
    945 // to do as little work as possible, to avoid further corruption or crashes.
    946 void ProfileSyncService::OnUnrecoverableError(
    947     const tracked_objects::Location& from_here,
    948     const std::string& message) {
    949   // Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
    950   // interface are assumed to originate within the syncer.
    951   unrecoverable_error_reason_ = ERROR_REASON_SYNCER;
    952   OnUnrecoverableErrorImpl(from_here, message, true);
    953 }
    954 
    955 void ProfileSyncService::OnUnrecoverableErrorImpl(
    956     const tracked_objects::Location& from_here,
    957     const std::string& message,
    958     bool delete_sync_database) {
    959   DCHECK(HasUnrecoverableError());
    960   unrecoverable_error_message_ = message;
    961   unrecoverable_error_location_ = from_here;
    962 
    963   UMA_HISTOGRAM_ENUMERATION(kSyncUnrecoverableErrorHistogram,
    964                             unrecoverable_error_reason_,
    965                             ERROR_REASON_LIMIT);
    966   NotifyObservers();
    967   std::string location;
    968   from_here.Write(true, true, &location);
    969   LOG(ERROR)
    970       << "Unrecoverable error detected at " << location
    971       << " -- ProfileSyncService unusable: " << message;
    972 
    973   // Shut all data types down.
    974   base::MessageLoop::current()->PostTask(FROM_HERE,
    975       base::Bind(&ProfileSyncService::ShutdownImpl,
    976                  weak_factory_.GetWeakPtr(),
    977                  delete_sync_database ?
    978                      syncer::DISABLE_SYNC : syncer::STOP_SYNC));
    979 }
    980 
    981 void ProfileSyncService::ReenableDatatype(syncer::ModelType type) {
    982   DCHECK(backend_initialized_);
    983   directory_data_type_manager_->ReenableType(type);
    984 }
    985 
    986 void ProfileSyncService::UpdateBackendInitUMA(bool success) {
    987   if (backend_mode_ != SYNC)
    988     return;
    989 
    990   is_first_time_sync_configure_ = !HasSyncSetupCompleted();
    991 
    992   if (is_first_time_sync_configure_) {
    993     UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success);
    994   } else {
    995     UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeRestoreSuccess", success);
    996   }
    997 
    998   base::Time on_backend_initialized_time = base::Time::Now();
    999   base::TimeDelta delta = on_backend_initialized_time -
   1000       startup_controller_.start_backend_time();
   1001   if (is_first_time_sync_configure_) {
   1002     UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta);
   1003   } else {
   1004     UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeRestoreTime", delta);
   1005   }
   1006 }
   1007 
   1008 void ProfileSyncService::PostBackendInitialization() {
   1009   // Never get here for backup / restore.
   1010   DCHECK_EQ(backend_mode_, SYNC);
   1011 
   1012   if (last_backup_time_) {
   1013     DCHECK(device_info_sync_service_);
   1014     device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_);
   1015   }
   1016 
   1017   if (protocol_event_observers_.might_have_observers()) {
   1018     backend_->RequestBufferedProtocolEventsAndEnableForwarding();
   1019   }
   1020 
   1021   non_blocking_data_type_manager_.ConnectSyncBackend(
   1022       backend_->GetSyncContextProxy());
   1023 
   1024   if (type_debug_info_observers_.might_have_observers()) {
   1025     backend_->EnableDirectoryTypeDebugInfoForwarding();
   1026   }
   1027 
   1028   // If we have a cached passphrase use it to decrypt/encrypt data now that the
   1029   // backend is initialized. We want to call this before notifying observers in
   1030   // case this operation affects the "passphrase required" status.
   1031   ConsumeCachedPassphraseIfPossible();
   1032 
   1033   // The very first time the backend initializes is effectively the first time
   1034   // we can say we successfully "synced".  LastSyncedTime will only be null in
   1035   // this case, because the pref wasn't restored on StartUp.
   1036   if (sync_prefs_.GetLastSyncedTime().is_null()) {
   1037     UpdateLastSyncedTime();
   1038   }
   1039 
   1040   if (startup_controller_.auto_start_enabled() && !FirstSetupInProgress()) {
   1041     // Backend is initialized but we're not in sync setup, so this must be an
   1042     // autostart - mark our sync setup as completed and we'll start syncing
   1043     // below.
   1044     SetSyncSetupCompleted();
   1045   }
   1046 
   1047   // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious
   1048   // data type configuration because observer may flag setup as complete and
   1049   // trigger data type configuration.
   1050   if (HasSyncSetupCompleted()) {
   1051     ConfigureDataTypeManager();
   1052   } else {
   1053     DCHECK(FirstSetupInProgress());
   1054   }
   1055 
   1056   NotifyObservers();
   1057 }
   1058 
   1059 void ProfileSyncService::OnBackendInitialized(
   1060     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
   1061     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
   1062         debug_info_listener,
   1063     const std::string& cache_guid,
   1064     bool success) {
   1065   UpdateBackendInitUMA(success);
   1066 
   1067   if (!success) {
   1068     // Something went unexpectedly wrong.  Play it safe: stop syncing at once
   1069     // and surface error UI to alert the user sync has stopped.
   1070     // Keep the directory around for now so that on restart we will retry
   1071     // again and potentially succeed in presence of transient file IO failures
   1072     // or permissions issues, etc.
   1073     //
   1074     // TODO(rlarocque): Consider making this UnrecoverableError less special.
   1075     // Unlike every other UnrecoverableError, it does not delete our sync data.
   1076     // This exception made sense at the time it was implemented, but our new
   1077     // directory corruption recovery mechanism makes it obsolete.  By the time
   1078     // we get here, we will have already tried and failed to delete the
   1079     // directory.  It would be no big deal if we tried to delete it again.
   1080     OnInternalUnrecoverableError(FROM_HERE,
   1081                                  "BackendInitialize failure",
   1082                                  false,
   1083                                  ERROR_REASON_BACKEND_INIT_FAILURE);
   1084     return;
   1085   }
   1086 
   1087   backend_initialized_ = true;
   1088 
   1089   sync_js_controller_.AttachJsBackend(js_backend);
   1090   debug_info_listener_ = debug_info_listener;
   1091 
   1092   SigninClient* signin_client =
   1093       ChromeSigninClientFactory::GetForProfile(profile_);
   1094   DCHECK(signin_client);
   1095   std::string signin_scoped_device_id =
   1096       signin_client->GetSigninScopedDeviceId();
   1097 
   1098   // Initialize local device info.
   1099   local_device_->Initialize(cache_guid, signin_scoped_device_id);
   1100 
   1101   DVLOG(1) << "Setting preferred types for non-blocking DTM";
   1102   non_blocking_data_type_manager_.SetPreferredTypes(GetPreferredDataTypes());
   1103 
   1104   // Give the DataTypeControllers a handle to the now initialized backend
   1105   // as a UserShare.
   1106   for (DataTypeController::TypeMap::iterator it =
   1107        directory_data_type_controllers_.begin();
   1108        it != directory_data_type_controllers_.end(); ++it) {
   1109     it->second->OnUserShareReady(GetUserShare());
   1110   }
   1111 
   1112   if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK)
   1113     ConfigureDataTypeManager();
   1114   else
   1115     PostBackendInitialization();
   1116 }
   1117 
   1118 void ProfileSyncService::OnSyncCycleCompleted() {
   1119   UpdateLastSyncedTime();
   1120   if (IsDataTypeControllerRunning(syncer::SESSIONS)) {
   1121     // Trigger garbage collection of old sessions now that we've downloaded
   1122     // any new session data.
   1123     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
   1124         &SessionsSyncManager::DoGarbageCollection,
   1125             base::AsWeakPtr(sessions_sync_manager_.get())));
   1126   }
   1127   DVLOG(2) << "Notifying observers sync cycle completed";
   1128   NotifySyncCycleCompleted();
   1129 }
   1130 
   1131 void ProfileSyncService::OnExperimentsChanged(
   1132     const syncer::Experiments& experiments) {
   1133   if (current_experiments_.Matches(experiments))
   1134     return;
   1135 
   1136   current_experiments_ = experiments;
   1137 
   1138   // Handle preference-backed experiments first.
   1139   if (experiments.gcm_channel_state == syncer::Experiments::SUPPRESSED) {
   1140     profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, false);
   1141     gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
   1142         ->Disable();
   1143   } else {
   1144     profile()->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled);
   1145     gcm::GCMProfileServiceFactory::GetForProfile(profile())->driver()
   1146         ->Enable();
   1147   }
   1148 
   1149   profile()->GetPrefs()->SetBoolean(prefs::kInvalidationServiceUseGCMChannel,
   1150                                     experiments.gcm_invalidations_enabled);
   1151 
   1152   if (experiments.enhanced_bookmarks_enabled) {
   1153     profile_->GetPrefs()->SetString(
   1154         sync_driver::prefs::kEnhancedBookmarksExtensionId,
   1155         experiments.enhanced_bookmarks_ext_id);
   1156   } else {
   1157     profile_->GetPrefs()->ClearPref(
   1158         sync_driver::prefs::kEnhancedBookmarksExtensionId);
   1159   }
   1160   UpdateBookmarksExperimentState(
   1161       profile_->GetPrefs(), g_browser_process->local_state(), true,
   1162       experiments.enhanced_bookmarks_enabled ? BOOKMARKS_EXPERIMENT_ENABLED :
   1163                                                BOOKMARKS_EXPERIMENT_NONE);
   1164 
   1165   // If this is a first time sync for a client, this will be called before
   1166   // OnBackendInitialized() to ensure the new datatypes are available at sync
   1167   // setup. As a result, the migrator won't exist yet. This is fine because for
   1168   // first time sync cases we're only concerned with making the datatype
   1169   // available.
   1170   if (migrator_.get() &&
   1171       migrator_->state() != browser_sync::BackendMigrator::IDLE) {
   1172     DVLOG(1) << "Dropping OnExperimentsChanged due to migrator busy.";
   1173     return;
   1174   }
   1175 
   1176   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   1177   syncer::ModelTypeSet to_add;
   1178   const syncer::ModelTypeSet to_register =
   1179       Difference(to_add, registered_types);
   1180   DVLOG(2) << "OnExperimentsChanged called with types: "
   1181            << syncer::ModelTypeSetToString(to_add);
   1182   DVLOG(2) << "Enabling types: " << syncer::ModelTypeSetToString(to_register);
   1183 
   1184   for (syncer::ModelTypeSet::Iterator it = to_register.First();
   1185        it.Good(); it.Inc()) {
   1186     // Received notice to enable experimental type. Check if the type is
   1187     // registered, and if not register a new datatype controller.
   1188     RegisterNewDataType(it.Get());
   1189   }
   1190 
   1191   // Check if the user has "Keep Everything Synced" enabled. If so, we want
   1192   // to turn on all experimental types if they're not already on. Otherwise we
   1193   // leave them off.
   1194   // Note: if any types are already registered, we don't turn them on. This
   1195   // covers the case where we're already in the process of reconfiguring
   1196   // to turn an experimental type on.
   1197   if (sync_prefs_.HasKeepEverythingSynced()) {
   1198     // Mark all data types as preferred.
   1199     sync_prefs_.SetPreferredDataTypes(registered_types, registered_types);
   1200 
   1201     // Only automatically turn on types if we have already finished set up.
   1202     // Otherwise, just leave the experimental types on by default.
   1203     if (!to_register.Empty() && HasSyncSetupCompleted() && migrator_) {
   1204       DVLOG(1) << "Dynamically enabling new datatypes: "
   1205                << syncer::ModelTypeSetToString(to_register);
   1206       OnMigrationNeededForTypes(to_register);
   1207     }
   1208   }
   1209 }
   1210 
   1211 void ProfileSyncService::UpdateAuthErrorState(const AuthError& error) {
   1212   is_auth_in_progress_ = false;
   1213   last_auth_error_ = error;
   1214 
   1215   NotifyObservers();
   1216 }
   1217 
   1218 namespace {
   1219 
   1220 AuthError ConnectionStatusToAuthError(
   1221     syncer::ConnectionStatus status) {
   1222   switch (status) {
   1223     case syncer::CONNECTION_OK:
   1224       return AuthError::AuthErrorNone();
   1225       break;
   1226     case syncer::CONNECTION_AUTH_ERROR:
   1227       return AuthError(AuthError::INVALID_GAIA_CREDENTIALS);
   1228       break;
   1229     case syncer::CONNECTION_SERVER_ERROR:
   1230       return AuthError(AuthError::CONNECTION_FAILED);
   1231       break;
   1232     default:
   1233       NOTREACHED();
   1234       return AuthError(AuthError::CONNECTION_FAILED);
   1235   }
   1236 }
   1237 
   1238 }  // namespace
   1239 
   1240 void ProfileSyncService::OnConnectionStatusChange(
   1241     syncer::ConnectionStatus status) {
   1242   connection_status_update_time_ = base::Time::Now();
   1243   connection_status_ = status;
   1244   if (status == syncer::CONNECTION_AUTH_ERROR) {
   1245     // Sync server returned error indicating that access token is invalid. It
   1246     // could be either expired or access is revoked. Let's request another
   1247     // access token and if access is revoked then request for token will fail
   1248     // with corresponding error. If access token is repeatedly reported
   1249     // invalid, there may be some issues with server, e.g. authentication
   1250     // state is inconsistent on sync and token server. In that case, we
   1251     // backoff token requests exponentially to avoid hammering token server
   1252     // too much and to avoid getting same token due to token server's caching
   1253     // policy. |request_access_token_retry_timer_| is used to backoff request
   1254     // triggered by both auth error and failure talking to GAIA server.
   1255     // Therefore, we're likely to reach the backoff ceiling more quickly than
   1256     // you would expect from looking at the BackoffPolicy if both types of
   1257     // errors happen. We shouldn't receive two errors back-to-back without
   1258     // attempting a token/sync request in between, thus crank up request delay
   1259     // unnecessary. This is because we won't make a sync request if we hit an
   1260     // error until GAIA succeeds at sending a new token, and we won't request
   1261     // a new token unless sync reports a token failure. But to be safe, don't
   1262     // schedule request if this happens.
   1263     if (request_access_token_retry_timer_.IsRunning()) {
   1264       NOTREACHED();
   1265     } else if (request_access_token_backoff_.failure_count() == 0) {
   1266       // First time request without delay. Currently invalid token is used
   1267       // to initialize sync backend and we'll always end up here. We don't
   1268       // want to delay initialization.
   1269       request_access_token_backoff_.InformOfRequest(false);
   1270       RequestAccessToken();
   1271     } else  {
   1272       request_access_token_backoff_.InformOfRequest(false);
   1273       request_access_token_retry_timer_.Start(
   1274           FROM_HERE,
   1275           request_access_token_backoff_.GetTimeUntilRelease(),
   1276           base::Bind(&ProfileSyncService::RequestAccessToken,
   1277                      weak_factory_.GetWeakPtr()));
   1278     }
   1279   } else {
   1280     // Reset backoff time after successful connection.
   1281     if (status == syncer::CONNECTION_OK) {
   1282       // Request shouldn't be scheduled at this time. But if it is, it's
   1283       // possible that sync flips between OK and auth error states rapidly,
   1284       // thus hammers token server. To be safe, only reset backoff delay when
   1285       // no scheduled request.
   1286       if (request_access_token_retry_timer_.IsRunning()) {
   1287         NOTREACHED();
   1288       } else {
   1289         request_access_token_backoff_.Reset();
   1290       }
   1291     }
   1292 
   1293     const GoogleServiceAuthError auth_error =
   1294         ConnectionStatusToAuthError(status);
   1295     DVLOG(1) << "Connection status change: " << auth_error.ToString();
   1296     UpdateAuthErrorState(auth_error);
   1297   }
   1298 }
   1299 
   1300 void ProfileSyncService::StopSyncingPermanently() {
   1301   sync_prefs_.SetStartSuppressed(true);
   1302   DisableForUser();
   1303 }
   1304 
   1305 void ProfileSyncService::OnPassphraseRequired(
   1306     syncer::PassphraseRequiredReason reason,
   1307     const sync_pb::EncryptedData& pending_keys) {
   1308   DCHECK(backend_.get());
   1309   DCHECK(backend_->IsNigoriEnabled());
   1310 
   1311   // TODO(lipalani) : add this check to other locations as well.
   1312   if (HasUnrecoverableError()) {
   1313     // When unrecoverable error is detected we post a task to shutdown the
   1314     // backend. The task might not have executed yet.
   1315     return;
   1316   }
   1317 
   1318   DVLOG(1) << "Passphrase required with reason: "
   1319            << syncer::PassphraseRequiredReasonToString(reason);
   1320   passphrase_required_reason_ = reason;
   1321 
   1322   const syncer::ModelTypeSet types = GetPreferredDirectoryDataTypes();
   1323   if (directory_data_type_manager_) {
   1324     // Reconfigure without the encrypted types (excluded implicitly via the
   1325     // failed datatypes handler).
   1326     directory_data_type_manager_->Configure(types,
   1327                                             syncer::CONFIGURE_REASON_CRYPTO);
   1328   }
   1329 
   1330   // TODO(rlarocque): Support non-blocking types.  http://crbug.com/351005.
   1331 
   1332   // Notify observers that the passphrase status may have changed.
   1333   NotifyObservers();
   1334 }
   1335 
   1336 void ProfileSyncService::OnPassphraseAccepted() {
   1337   DVLOG(1) << "Received OnPassphraseAccepted.";
   1338 
   1339   // If the pending keys were resolved via keystore, it's possible we never
   1340   // consumed our cached passphrase. Clear it now.
   1341   if (!cached_passphrase_.empty())
   1342     cached_passphrase_.clear();
   1343 
   1344   // Reset passphrase_required_reason_ since we know we no longer require the
   1345   // passphrase. We do this here rather than down in ResolvePassphraseRequired()
   1346   // because that can be called by OnPassphraseRequired() if no encrypted data
   1347   // types are enabled, and we don't want to clobber the true passphrase error.
   1348   passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
   1349 
   1350   // Make sure the data types that depend on the passphrase are started at
   1351   // this time.
   1352   const syncer::ModelTypeSet types = GetPreferredDirectoryDataTypes();
   1353   if (directory_data_type_manager_) {
   1354     // Re-enable any encrypted types if necessary.
   1355     directory_data_type_manager_->Configure(types,
   1356                                             syncer::CONFIGURE_REASON_CRYPTO);
   1357   }
   1358 
   1359   // TODO(rlarocque): Support non-blocking types.  http://crbug.com/351005.
   1360 
   1361   NotifyObservers();
   1362 }
   1363 
   1364 void ProfileSyncService::OnEncryptedTypesChanged(
   1365     syncer::ModelTypeSet encrypted_types,
   1366     bool encrypt_everything) {
   1367   encrypted_types_ = encrypted_types;
   1368   encrypt_everything_ = encrypt_everything;
   1369   DCHECK(encrypt_everything_allowed_ || !encrypt_everything_);
   1370   DVLOG(1) << "Encrypted types changed to "
   1371            << syncer::ModelTypeSetToString(encrypted_types_)
   1372            << " (encrypt everything is set to "
   1373            << (encrypt_everything_ ? "true" : "false") << ")";
   1374   DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
   1375 
   1376   NotifyObservers();
   1377 }
   1378 
   1379 void ProfileSyncService::OnEncryptionComplete() {
   1380   DVLOG(1) << "Encryption complete";
   1381   if (encryption_pending_ && encrypt_everything_) {
   1382     encryption_pending_ = false;
   1383     // This is to nudge the integration tests when encryption is
   1384     // finished.
   1385     NotifyObservers();
   1386   }
   1387 }
   1388 
   1389 void ProfileSyncService::OnMigrationNeededForTypes(
   1390     syncer::ModelTypeSet types) {
   1391   DCHECK(backend_initialized_);
   1392   DCHECK(directory_data_type_manager_.get());
   1393 
   1394   // Migrator must be valid, because we don't sync until it is created and this
   1395   // callback originates from a sync cycle.
   1396   migrator_->MigrateTypes(types);
   1397 }
   1398 
   1399 void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
   1400   last_actionable_error_ = error;
   1401   DCHECK_NE(last_actionable_error_.action,
   1402             syncer::UNKNOWN_ACTION);
   1403   switch (error.action) {
   1404     case syncer::UPGRADE_CLIENT:
   1405     case syncer::CLEAR_USER_DATA_AND_RESYNC:
   1406     case syncer::ENABLE_SYNC_ON_ACCOUNT:
   1407     case syncer::STOP_AND_RESTART_SYNC:
   1408       // TODO(lipalani) : if setup in progress we want to display these
   1409       // actions in the popup. The current experience might not be optimal for
   1410       // the user. We just dismiss the dialog.
   1411       if (startup_controller_.setup_in_progress()) {
   1412         StopSyncingPermanently();
   1413         expect_sync_configuration_aborted_ = true;
   1414       }
   1415       // Trigger an unrecoverable error to stop syncing.
   1416       OnInternalUnrecoverableError(FROM_HERE,
   1417                                    last_actionable_error_.error_description,
   1418                                    true,
   1419                                    ERROR_REASON_ACTIONABLE_ERROR);
   1420       break;
   1421     case syncer::DISABLE_SYNC_AND_ROLLBACK:
   1422       backup_rollback_controller_.OnRollbackReceived();
   1423       // Fall through to shutdown backend and sign user out.
   1424     case syncer::DISABLE_SYNC_ON_CLIENT:
   1425       StopSyncingPermanently();
   1426 #if !defined(OS_CHROMEOS)
   1427       // On desktop Chrome, sign out the user after a dashboard clear.
   1428       // Skip sign out on ChromeOS/Android.
   1429       if (!startup_controller_.auto_start_enabled()) {
   1430         SigninManagerFactory::GetForProfile(profile_)->SignOut(
   1431             signin_metrics::SERVER_FORCED_DISABLE);
   1432       }
   1433 #endif
   1434       break;
   1435     case syncer::ROLLBACK_DONE:
   1436       backup_rollback_controller_.OnRollbackDone();
   1437       break;
   1438     case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
   1439       // Sync disabled by domain admin. we should stop syncing until next
   1440       // restart.
   1441       sync_disabled_by_admin_ = true;
   1442       ShutdownImpl(syncer::DISABLE_SYNC);
   1443       break;
   1444     default:
   1445       NOTREACHED();
   1446   }
   1447   NotifyObservers();
   1448 
   1449   if (error.action == syncer::DISABLE_SYNC_ON_CLIENT ||
   1450       (error.action == syncer::DISABLE_SYNC_AND_ROLLBACK &&
   1451           !backup_rollback_controller_.StartRollback())) {
   1452     // Clean up backup data for sign-out only or when rollback is disabled.
   1453     CleanUpBackup();
   1454   } else if (error.action == syncer::ROLLBACK_DONE) {
   1455     // Shut down ROLLBACK backend and delete backup DB.
   1456     ShutdownImpl(syncer::DISABLE_SYNC);
   1457     sync_prefs_.ClearFirstSyncTime();
   1458   }
   1459 }
   1460 
   1461 void ProfileSyncService::OnConfigureDone(
   1462     const DataTypeManager::ConfigureResult& result) {
   1463   configure_status_ = result.status;
   1464   data_type_status_table_ = result.data_type_status_table;
   1465 
   1466   if (backend_mode_ != SYNC) {
   1467     if (configure_status_ == DataTypeManager::OK) {
   1468       StartSyncingWithServer();
   1469 
   1470       // Backup is done after models are associated.
   1471       if (backend_mode_ == BACKUP)
   1472         backup_finished_ = true;
   1473 
   1474       // Asynchronously check whether sync needs to start.
   1475       base::MessageLoop::current()->PostTask(
   1476           FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup,
   1477                                 startup_controller_weak_factory_.GetWeakPtr()));
   1478     } else if (!expect_sync_configuration_aborted_) {
   1479       DVLOG(1) << "Backup/rollback backend failed to configure.";
   1480       ShutdownImpl(syncer::STOP_SYNC);
   1481     }
   1482 
   1483     return;
   1484   }
   1485 
   1486   // We should have cleared our cached passphrase before we get here (in
   1487   // OnBackendInitialized()).
   1488   DCHECK(cached_passphrase_.empty());
   1489 
   1490   if (!sync_configure_start_time_.is_null()) {
   1491     if (result.status == DataTypeManager::OK) {
   1492       base::Time sync_configure_stop_time = base::Time::Now();
   1493       base::TimeDelta delta = sync_configure_stop_time -
   1494           sync_configure_start_time_;
   1495       if (is_first_time_sync_configure_) {
   1496         UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceInitialConfigureTime", delta);
   1497       } else {
   1498         UMA_HISTOGRAM_LONG_TIMES("Sync.ServiceSubsequentConfigureTime",
   1499                                   delta);
   1500       }
   1501     }
   1502     sync_configure_start_time_ = base::Time();
   1503   }
   1504 
   1505   // Notify listeners that configuration is done.
   1506   content::NotificationService::current()->Notify(
   1507       chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
   1508       content::Source<ProfileSyncService>(this),
   1509       content::NotificationService::NoDetails());
   1510 
   1511   DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
   1512   // The possible status values:
   1513   //    ABORT - Configuration was aborted. This is not an error, if
   1514   //            initiated by user.
   1515   //    OK - Some or all types succeeded.
   1516   //    Everything else is an UnrecoverableError. So treat it as such.
   1517 
   1518   // First handle the abort case.
   1519   if (configure_status_ == DataTypeManager::ABORTED &&
   1520       expect_sync_configuration_aborted_) {
   1521     DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
   1522     expect_sync_configuration_aborted_ = false;
   1523     return;
   1524   }
   1525 
   1526   // Handle unrecoverable error.
   1527   if (configure_status_ != DataTypeManager::OK) {
   1528     // Something catastrophic had happened. We should only have one
   1529     // error representing it.
   1530     syncer::SyncError error =
   1531         data_type_status_table_.GetUnrecoverableError();
   1532     DCHECK(error.IsSet());
   1533     std::string message =
   1534         "Sync configuration failed with status " +
   1535         DataTypeManager::ConfigureStatusToString(configure_status_) +
   1536         " caused by " +
   1537         syncer::ModelTypeSetToString(
   1538             data_type_status_table_.GetUnrecoverableErrorTypes()) +
   1539         ": " + error.message();
   1540     LOG(ERROR) << "ProfileSyncService error: " << message;
   1541     OnInternalUnrecoverableError(error.location(),
   1542                                  message,
   1543                                  true,
   1544                                  ERROR_REASON_CONFIGURATION_FAILURE);
   1545     return;
   1546   }
   1547 
   1548   // We should never get in a state where we have no encrypted datatypes
   1549   // enabled, and yet we still think we require a passphrase for decryption.
   1550   DCHECK(!(IsPassphraseRequiredForDecryption() &&
   1551            !IsEncryptedDatatypeEnabled()));
   1552 
   1553   // This must be done before we start syncing with the server to avoid
   1554   // sending unencrypted data up on a first time sync.
   1555   if (encryption_pending_)
   1556     backend_->EnableEncryptEverything();
   1557   NotifyObservers();
   1558 
   1559   if (migrator_.get() &&
   1560       migrator_->state() != browser_sync::BackendMigrator::IDLE) {
   1561     // Migration in progress.  Let the migrator know we just finished
   1562     // configuring something.  It will be up to the migrator to call
   1563     // StartSyncingWithServer() if migration is now finished.
   1564     migrator_->OnConfigureDone(result);
   1565   } else {
   1566     StartSyncingWithServer();
   1567   }
   1568 }
   1569 
   1570 void ProfileSyncService::OnConfigureRetry() {
   1571   // We should have cleared our cached passphrase before we get here (in
   1572   // OnBackendInitialized()).
   1573   DCHECK(cached_passphrase_.empty());
   1574 
   1575   OnSyncConfigureRetry();
   1576 }
   1577 
   1578 void ProfileSyncService::OnConfigureStart() {
   1579   sync_configure_start_time_ = base::Time::Now();
   1580   NotifyObservers();
   1581 }
   1582 
   1583 ProfileSyncService::SyncStatusSummary
   1584       ProfileSyncService::QuerySyncStatusSummary() {
   1585   if (HasUnrecoverableError()) {
   1586     return UNRECOVERABLE_ERROR;
   1587   } else if (!backend_) {
   1588     return NOT_ENABLED;
   1589   } else if (backend_mode_ == BACKUP) {
   1590     return BACKUP_USER_DATA;
   1591   } else if (backend_mode_ == ROLLBACK) {
   1592     return ROLLBACK_USER_DATA;
   1593   } else if (backend_.get() && !HasSyncSetupCompleted()) {
   1594     return SETUP_INCOMPLETE;
   1595   } else if (
   1596       backend_.get() && HasSyncSetupCompleted() &&
   1597       directory_data_type_manager_.get() &&
   1598       directory_data_type_manager_->state() != DataTypeManager::CONFIGURED) {
   1599     return DATATYPES_NOT_INITIALIZED;
   1600   } else if (ShouldPushChanges()) {
   1601     return INITIALIZED;
   1602   }
   1603   return UNKNOWN_ERROR;
   1604 }
   1605 
   1606 std::string ProfileSyncService::QuerySyncStatusSummaryString() {
   1607   SyncStatusSummary status = QuerySyncStatusSummary();
   1608 
   1609   std::string config_status_str =
   1610       configure_status_ != DataTypeManager::UNKNOWN ?
   1611           DataTypeManager::ConfigureStatusToString(configure_status_) : "";
   1612 
   1613   switch (status) {
   1614     case UNRECOVERABLE_ERROR:
   1615       return "Unrecoverable error detected";
   1616     case NOT_ENABLED:
   1617       return "Syncing not enabled";
   1618     case SETUP_INCOMPLETE:
   1619       return "First time sync setup incomplete";
   1620     case DATATYPES_NOT_INITIALIZED:
   1621       return "Datatypes not fully initialized";
   1622     case INITIALIZED:
   1623       return "Sync service initialized";
   1624     case BACKUP_USER_DATA:
   1625       return "Backing-up user data. Status: " + config_status_str;
   1626     case ROLLBACK_USER_DATA:
   1627       return "Restoring user data. Status: " + config_status_str;
   1628     default:
   1629       return "Status unknown: Internal error?";
   1630   }
   1631 }
   1632 
   1633 std::string ProfileSyncService::GetBackendInitializationStateString() const {
   1634   return startup_controller_.GetBackendInitializationStateString();
   1635 }
   1636 
   1637 bool ProfileSyncService::auto_start_enabled() const {
   1638   return startup_controller_.auto_start_enabled();
   1639 }
   1640 
   1641 bool ProfileSyncService::setup_in_progress() const {
   1642   return startup_controller_.setup_in_progress();
   1643 }
   1644 
   1645 bool ProfileSyncService::QueryDetailedSyncStatus(
   1646     SyncBackendHost::Status* result) {
   1647   if (backend_.get() && backend_initialized_) {
   1648     *result = backend_->GetDetailedStatus();
   1649     return true;
   1650   } else {
   1651     SyncBackendHost::Status status;
   1652     status.sync_protocol_error = last_actionable_error_;
   1653     *result = status;
   1654     return false;
   1655   }
   1656 }
   1657 
   1658 const AuthError& ProfileSyncService::GetAuthError() const {
   1659   return last_auth_error_;
   1660 }
   1661 
   1662 bool ProfileSyncService::FirstSetupInProgress() const {
   1663   return !HasSyncSetupCompleted() && startup_controller_.setup_in_progress();
   1664 }
   1665 
   1666 void ProfileSyncService::SetSetupInProgress(bool setup_in_progress) {
   1667   // This method is a no-op if |setup_in_progress_| remains unchanged.
   1668   if (startup_controller_.setup_in_progress() == setup_in_progress)
   1669     return;
   1670 
   1671   startup_controller_.set_setup_in_progress(setup_in_progress);
   1672   if (!setup_in_progress && sync_initialized())
   1673     ReconfigureDatatypeManager();
   1674   NotifyObservers();
   1675 }
   1676 
   1677 bool ProfileSyncService::sync_initialized() const {
   1678   return backend_initialized_;
   1679 }
   1680 
   1681 bool ProfileSyncService::waiting_for_auth() const {
   1682   return is_auth_in_progress_;
   1683 }
   1684 
   1685 const syncer::Experiments& ProfileSyncService::current_experiments() const {
   1686   return current_experiments_;
   1687 }
   1688 
   1689 bool ProfileSyncService::HasUnrecoverableError() const {
   1690   return unrecoverable_error_reason_ != ERROR_REASON_UNSET;
   1691 }
   1692 
   1693 bool ProfileSyncService::IsPassphraseRequired() const {
   1694   return passphrase_required_reason_ !=
   1695       syncer::REASON_PASSPHRASE_NOT_REQUIRED;
   1696 }
   1697 
   1698 bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
   1699   // If there is an encrypted datatype enabled and we don't have the proper
   1700   // passphrase, we must prompt the user for a passphrase. The only way for the
   1701   // user to avoid entering their passphrase is to disable the encrypted types.
   1702   return IsEncryptedDatatypeEnabled() && IsPassphraseRequired();
   1703 }
   1704 
   1705 base::string16 ProfileSyncService::GetLastSyncedTimeString() const {
   1706   const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
   1707   if (last_synced_time.is_null())
   1708     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_NEVER);
   1709 
   1710   base::TimeDelta time_since_last_sync = base::Time::Now() - last_synced_time;
   1711 
   1712   if (time_since_last_sync < base::TimeDelta::FromMinutes(1))
   1713     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
   1714 
   1715   return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
   1716                                 ui::TimeFormat::LENGTH_SHORT,
   1717                                 time_since_last_sync);
   1718 }
   1719 
   1720 void ProfileSyncService::UpdateSelectedTypesHistogram(
   1721     bool sync_everything, const syncer::ModelTypeSet chosen_types) const {
   1722   if (!HasSyncSetupCompleted() ||
   1723       sync_everything != sync_prefs_.HasKeepEverythingSynced()) {
   1724     UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything);
   1725   }
   1726 
   1727   // Only log the data types that are shown in the sync settings ui.
   1728   // Note: the order of these types must match the ordering of
   1729   // the respective types in ModelType
   1730   const sync_driver::user_selectable_type::UserSelectableSyncType
   1731       user_selectable_types[] = {
   1732     sync_driver::user_selectable_type::BOOKMARKS,
   1733     sync_driver::user_selectable_type::PREFERENCES,
   1734     sync_driver::user_selectable_type::PASSWORDS,
   1735     sync_driver::user_selectable_type::AUTOFILL,
   1736     sync_driver::user_selectable_type::THEMES,
   1737     sync_driver::user_selectable_type::TYPED_URLS,
   1738     sync_driver::user_selectable_type::EXTENSIONS,
   1739     sync_driver::user_selectable_type::APPS,
   1740     sync_driver::user_selectable_type::PROXY_TABS
   1741   };
   1742 
   1743   COMPILE_ASSERT(32 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
   1744 
   1745   if (!sync_everything) {
   1746     const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
   1747 
   1748     syncer::ModelTypeSet type_set = syncer::UserSelectableTypes();
   1749     syncer::ModelTypeSet::Iterator it = type_set.First();
   1750 
   1751     DCHECK_EQ(arraysize(user_selectable_types), type_set.Size());
   1752 
   1753     for (size_t i = 0; i < arraysize(user_selectable_types) && it.Good();
   1754          ++i, it.Inc()) {
   1755       const syncer::ModelType type = it.Get();
   1756       if (chosen_types.Has(type) &&
   1757           (!HasSyncSetupCompleted() || !current_types.Has(type))) {
   1758         // Selected type has changed - log it.
   1759         UMA_HISTOGRAM_ENUMERATION(
   1760             "Sync.CustomSync",
   1761             user_selectable_types[i],
   1762             sync_driver::user_selectable_type::SELECTABLE_DATATYPE_COUNT + 1);
   1763       }
   1764     }
   1765   }
   1766 }
   1767 
   1768 #if defined(OS_CHROMEOS)
   1769 void ProfileSyncService::RefreshSpareBootstrapToken(
   1770     const std::string& passphrase) {
   1771   sync_driver::SystemEncryptor encryptor;
   1772   syncer::Cryptographer temp_cryptographer(&encryptor);
   1773   // The first 2 params (hostname and username) doesn't have any effect here.
   1774   syncer::KeyParams key_params = {"localhost", "dummy", passphrase};
   1775 
   1776   std::string bootstrap_token;
   1777   if (!temp_cryptographer.AddKey(key_params)) {
   1778     NOTREACHED() << "Failed to add key to cryptographer.";
   1779   }
   1780   temp_cryptographer.GetBootstrapToken(&bootstrap_token);
   1781   sync_prefs_.SetSpareBootstrapToken(bootstrap_token);
   1782 }
   1783 #endif
   1784 
   1785 void ProfileSyncService::OnUserChoseDatatypes(
   1786     bool sync_everything,
   1787     syncer::ModelTypeSet chosen_types) {
   1788   if (!backend_.get() && !HasUnrecoverableError()) {
   1789     NOTREACHED();
   1790     return;
   1791   }
   1792 
   1793   UpdateSelectedTypesHistogram(sync_everything, chosen_types);
   1794   sync_prefs_.SetKeepEverythingSynced(sync_everything);
   1795 
   1796   if (directory_data_type_manager_.get())
   1797     directory_data_type_manager_->ResetDataTypeErrors();
   1798   ChangePreferredDataTypes(chosen_types);
   1799   AcknowledgeSyncedTypes();
   1800   NotifyObservers();
   1801 }
   1802 
   1803 void ProfileSyncService::ChangePreferredDataTypes(
   1804     syncer::ModelTypeSet preferred_types) {
   1805 
   1806   DVLOG(1) << "ChangePreferredDataTypes invoked";
   1807   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   1808   const syncer::ModelTypeSet registered_preferred_types =
   1809       Intersection(registered_types, preferred_types);
   1810   sync_prefs_.SetPreferredDataTypes(registered_types,
   1811                                     registered_preferred_types);
   1812 
   1813   // Now reconfigure the DTM.
   1814   ReconfigureDatatypeManager();
   1815 
   1816   // TODO(rlarocque): Reconfigure the NonBlockingDataTypeManager, too.  Blocked
   1817   // on crbug.com/368834.  Until that bug is fixed, it's difficult to tell
   1818   // which types should be enabled and when.
   1819 }
   1820 
   1821 syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
   1822   const syncer::ModelTypeSet preferred_types = GetPreferredDataTypes();
   1823   const syncer::ModelTypeSet failed_types =
   1824       data_type_status_table_.GetFailedTypes();
   1825   return Difference(preferred_types, failed_types);
   1826 }
   1827 
   1828 syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
   1829   const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
   1830   const syncer::ModelTypeSet preferred_types =
   1831       sync_prefs_.GetPreferredDataTypes(registered_types);
   1832   const syncer::ModelTypeSet enforced_types =
   1833       Intersection(GetDataTypesFromPreferenceProviders(), registered_types);
   1834   return Union(preferred_types, enforced_types);
   1835 }
   1836 
   1837 syncer::ModelTypeSet
   1838 ProfileSyncService::GetPreferredDirectoryDataTypes() const {
   1839   const syncer::ModelTypeSet registered_directory_types =
   1840       GetRegisteredDirectoryDataTypes();
   1841   const syncer::ModelTypeSet preferred_types =
   1842       sync_prefs_.GetPreferredDataTypes(registered_directory_types);
   1843   const syncer::ModelTypeSet enforced_types =
   1844       Intersection(GetDataTypesFromPreferenceProviders(),
   1845                    registered_directory_types);
   1846   return Union(preferred_types, enforced_types);
   1847 }
   1848 
   1849 syncer::ModelTypeSet
   1850 ProfileSyncService::GetPreferredNonBlockingDataTypes() const {
   1851   return sync_prefs_.GetPreferredDataTypes(GetRegisteredNonBlockingDataTypes());
   1852 }
   1853 
   1854 syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const {
   1855   // TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider,
   1856   // we'll need another way to distinguish user-choosable types from
   1857   // programmatically-enabled types.
   1858   return GetDataTypesFromPreferenceProviders();
   1859 }
   1860 
   1861 syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
   1862   return Union(GetRegisteredDirectoryDataTypes(),
   1863                GetRegisteredNonBlockingDataTypes());
   1864 }
   1865 
   1866 syncer::ModelTypeSet
   1867 ProfileSyncService::GetRegisteredDirectoryDataTypes() const {
   1868   syncer::ModelTypeSet registered_types;
   1869   // The directory_data_type_controllers_ are determined by command-line flags;
   1870   // that's effectively what controls the values returned here.
   1871   for (DataTypeController::TypeMap::const_iterator it =
   1872        directory_data_type_controllers_.begin();
   1873        it != directory_data_type_controllers_.end(); ++it) {
   1874     registered_types.Put(it->first);
   1875   }
   1876   return registered_types;
   1877 }
   1878 
   1879 syncer::ModelTypeSet
   1880 ProfileSyncService::GetRegisteredNonBlockingDataTypes() const {
   1881   return non_blocking_data_type_manager_.GetRegisteredTypes();
   1882 }
   1883 
   1884 bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
   1885   syncer::PassphraseType passphrase_type = GetPassphraseType();
   1886   return passphrase_type == syncer::FROZEN_IMPLICIT_PASSPHRASE ||
   1887          passphrase_type == syncer::CUSTOM_PASSPHRASE;
   1888 }
   1889 
   1890 syncer::PassphraseType ProfileSyncService::GetPassphraseType() const {
   1891   return backend_->GetPassphraseType();
   1892 }
   1893 
   1894 base::Time ProfileSyncService::GetExplicitPassphraseTime() const {
   1895   return backend_->GetExplicitPassphraseTime();
   1896 }
   1897 
   1898 bool ProfileSyncService::IsCryptographerReady(
   1899     const syncer::BaseTransaction* trans) const {
   1900   return backend_.get() && backend_->IsCryptographerReady(trans);
   1901 }
   1902 
   1903 void ProfileSyncService::ConfigurePriorityDataTypes() {
   1904   const syncer::ModelTypeSet priority_types =
   1905       Intersection(GetPreferredDirectoryDataTypes(),
   1906                    syncer::PriorityUserTypes());
   1907   if (!priority_types.Empty()) {
   1908     const syncer::ConfigureReason reason = HasSyncSetupCompleted() ?
   1909         syncer::CONFIGURE_REASON_RECONFIGURATION :
   1910         syncer::CONFIGURE_REASON_NEW_CLIENT;
   1911     directory_data_type_manager_->Configure(priority_types, reason);
   1912   }
   1913 }
   1914 
   1915 void ProfileSyncService::ConfigureDataTypeManager() {
   1916   // Don't configure datatypes if the setup UI is still on the screen - this
   1917   // is to help multi-screen setting UIs (like iOS) where they don't want to
   1918   // start syncing data until the user is done configuring encryption options,
   1919   // etc. ReconfigureDatatypeManager() will get called again once the UI calls
   1920   // SetSetupInProgress(false).
   1921   if (backend_mode_ == SYNC && startup_controller_.setup_in_progress())
   1922     return;
   1923 
   1924   bool restart = false;
   1925   if (!directory_data_type_manager_) {
   1926     restart = true;
   1927     directory_data_type_manager_.reset(
   1928         factory_->CreateDataTypeManager(debug_info_listener_,
   1929                                         &directory_data_type_controllers_,
   1930                                         this,
   1931                                         backend_.get(),
   1932                                         this));
   1933 
   1934     // We create the migrator at the same time.
   1935     migrator_.reset(
   1936         new browser_sync::BackendMigrator(
   1937             profile_->GetDebugName(), GetUserShare(),
   1938             this, directory_data_type_manager_.get(),
   1939             base::Bind(&ProfileSyncService::StartSyncingWithServer,
   1940                        base::Unretained(this))));
   1941   }
   1942 
   1943   syncer::ModelTypeSet types;
   1944   syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
   1945   if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK) {
   1946     types = syncer::BackupTypes();
   1947     reason = syncer::CONFIGURE_REASON_BACKUP_ROLLBACK;
   1948   } else {
   1949     types = GetPreferredDirectoryDataTypes();
   1950     if (!HasSyncSetupCompleted()) {
   1951       reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
   1952     } else if (restart) {
   1953       // Datatype downloads on restart are generally due to newly supported
   1954       // datatypes (although it's also possible we're picking up where a failed
   1955       // previous configuration left off).
   1956       // TODO(sync): consider detecting configuration recovery and setting
   1957       // the reason here appropriately.
   1958       reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
   1959     } else {
   1960       // The user initiated a reconfiguration (either to add or remove types).
   1961       reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
   1962     }
   1963   }
   1964 
   1965   directory_data_type_manager_->Configure(types, reason);
   1966 }
   1967 
   1968 syncer::UserShare* ProfileSyncService::GetUserShare() const {
   1969   if (backend_.get() && backend_initialized_) {
   1970     return backend_->GetUserShare();
   1971   }
   1972   NOTREACHED();
   1973   return NULL;
   1974 }
   1975 
   1976 syncer::sessions::SyncSessionSnapshot
   1977 ProfileSyncService::GetLastSessionSnapshot() const {
   1978   if (HasSyncingBackend() && backend_initialized_) {
   1979     return backend_->GetLastSessionSnapshot();
   1980   }
   1981   return syncer::sessions::SyncSessionSnapshot();
   1982 }
   1983 
   1984 bool ProfileSyncService::HasUnsyncedItems() const {
   1985   if (HasSyncingBackend() && backend_initialized_) {
   1986     return backend_->HasUnsyncedItems();
   1987   }
   1988   NOTREACHED();
   1989   return false;
   1990 }
   1991 
   1992 browser_sync::BackendMigrator*
   1993 ProfileSyncService::GetBackendMigratorForTest() {
   1994   return migrator_.get();
   1995 }
   1996 
   1997 void ProfileSyncService::GetModelSafeRoutingInfo(
   1998     syncer::ModelSafeRoutingInfo* out) const {
   1999   if (backend_.get() && backend_initialized_) {
   2000     backend_->GetModelSafeRoutingInfo(out);
   2001   } else {
   2002     NOTREACHED();
   2003   }
   2004 }
   2005 
   2006 base::Value* ProfileSyncService::GetTypeStatusMap() const {
   2007   scoped_ptr<base::ListValue> result(new base::ListValue());
   2008 
   2009   if (!backend_.get() || !backend_initialized_) {
   2010     return result.release();
   2011   }
   2012 
   2013   DataTypeStatusTable::TypeErrorMap error_map =
   2014       data_type_status_table_.GetAllErrors();
   2015   ModelTypeSet active_types;
   2016   ModelTypeSet passive_types;
   2017   ModelSafeRoutingInfo routing_info;
   2018   backend_->GetModelSafeRoutingInfo(&routing_info);
   2019   for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
   2020        it != routing_info.end(); ++it) {
   2021     if (it->second == syncer::GROUP_PASSIVE) {
   2022       passive_types.Put(it->first);
   2023     } else {
   2024       active_types.Put(it->first);
   2025     }
   2026   }
   2027 
   2028   SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
   2029   ModelTypeSet &throttled_types(detailed_status.throttled_types);
   2030   ModelTypeSet registered = GetRegisteredDataTypes();
   2031   scoped_ptr<base::DictionaryValue> type_status_header(
   2032       new base::DictionaryValue());
   2033 
   2034   type_status_header->SetString("name", "Model Type");
   2035   type_status_header->SetString("status", "header");
   2036   type_status_header->SetString("value", "Group Type");
   2037   type_status_header->SetString("num_entries", "Total Entries");
   2038   type_status_header->SetString("num_live", "Live Entries");
   2039   result->Append(type_status_header.release());
   2040 
   2041   scoped_ptr<base::DictionaryValue> type_status;
   2042   for (ModelTypeSet::Iterator it = registered.First(); it.Good(); it.Inc()) {
   2043     ModelType type = it.Get();
   2044 
   2045     type_status.reset(new base::DictionaryValue());
   2046     type_status->SetString("name", ModelTypeToString(type));
   2047 
   2048     if (error_map.find(type) != error_map.end()) {
   2049       const syncer::SyncError &error = error_map.find(type)->second;
   2050       DCHECK(error.IsSet());
   2051       switch (error.GetSeverity()) {
   2052         case syncer::SyncError::SYNC_ERROR_SEVERITY_ERROR: {
   2053             std::string error_text = "Error: " + error.location().ToString() +
   2054                 ", " + error.GetMessagePrefix() + error.message();
   2055             type_status->SetString("status", "error");
   2056             type_status->SetString("value", error_text);
   2057           }
   2058           break;
   2059         case syncer::SyncError::SYNC_ERROR_SEVERITY_INFO:
   2060           type_status->SetString("status", "disabled");
   2061           type_status->SetString("value", error.message());
   2062           break;
   2063         default:
   2064           NOTREACHED() << "Unexpected error severity.";
   2065           break;
   2066       }
   2067     } else if (syncer::IsProxyType(type) && passive_types.Has(type)) {
   2068       // Show a proxy type in "ok" state unless it is disabled by user.
   2069       DCHECK(!throttled_types.Has(type));
   2070       type_status->SetString("status", "ok");
   2071       type_status->SetString("value", "Passive");
   2072     } else if (throttled_types.Has(type) && passive_types.Has(type)) {
   2073       type_status->SetString("status", "warning");
   2074       type_status->SetString("value", "Passive, Throttled");
   2075     } else if (passive_types.Has(type)) {
   2076       type_status->SetString("status", "warning");
   2077       type_status->SetString("value", "Passive");
   2078     } else if (throttled_types.Has(type)) {
   2079       type_status->SetString("status", "warning");
   2080       type_status->SetString("value", "Throttled");
   2081     } else if (GetRegisteredNonBlockingDataTypes().Has(type)) {
   2082       type_status->SetString("status", "ok");
   2083       type_status->SetString("value", "Non-Blocking");
   2084     } else if (active_types.Has(type)) {
   2085       type_status->SetString("status", "ok");
   2086       type_status->SetString("value", "Active: " +
   2087                              ModelSafeGroupToString(routing_info[type]));
   2088     } else {
   2089       type_status->SetString("status", "warning");
   2090       type_status->SetString("value", "Disabled by User");
   2091     }
   2092 
   2093     int live_count = detailed_status.num_entries_by_type[type] -
   2094         detailed_status.num_to_delete_entries_by_type[type];
   2095     type_status->SetInteger("num_entries",
   2096                             detailed_status.num_entries_by_type[type]);
   2097     type_status->SetInteger("num_live", live_count);
   2098 
   2099     result->Append(type_status.release());
   2100   }
   2101   return result.release();
   2102 }
   2103 
   2104 void ProfileSyncService::DeactivateDataType(syncer::ModelType type) {
   2105   if (!backend_)
   2106     return;
   2107   backend_->DeactivateDataType(type);
   2108 }
   2109 
   2110 void ProfileSyncService::ConsumeCachedPassphraseIfPossible() {
   2111   // If no cached passphrase, or sync backend hasn't started up yet, just exit.
   2112   // If the backend isn't running yet, OnBackendInitialized() will call this
   2113   // method again after the backend starts up.
   2114   if (cached_passphrase_.empty() || !sync_initialized())
   2115     return;
   2116 
   2117   // Backend is up and running, so we can consume the cached passphrase.
   2118   std::string passphrase = cached_passphrase_;
   2119   cached_passphrase_.clear();
   2120 
   2121   // If we need a passphrase to decrypt data, try the cached passphrase.
   2122   if (passphrase_required_reason() == syncer::REASON_DECRYPTION) {
   2123     if (SetDecryptionPassphrase(passphrase)) {
   2124       DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
   2125       return;
   2126     }
   2127   }
   2128 
   2129   // If we get here, we don't have pending keys (or at least, the passphrase
   2130   // doesn't decrypt them) - just try to re-encrypt using the encryption
   2131   // passphrase.
   2132   if (!IsUsingSecondaryPassphrase())
   2133     SetEncryptionPassphrase(passphrase, IMPLICIT);
   2134 }
   2135 
   2136 void ProfileSyncService::RequestAccessToken() {
   2137   // Only one active request at a time.
   2138   if (access_token_request_ != NULL)
   2139     return;
   2140   request_access_token_retry_timer_.Stop();
   2141   OAuth2TokenService::ScopeSet oauth2_scopes;
   2142   oauth2_scopes.insert(signin_->GetSyncScopeToUse());
   2143 
   2144   // Invalidate previous token, otherwise token service will return the same
   2145   // token again.
   2146   const std::string& account_id = signin_->GetAccountIdToUse();
   2147   if (!access_token_.empty()) {
   2148     oauth2_token_service_->InvalidateToken(
   2149         account_id, oauth2_scopes, access_token_);
   2150   }
   2151 
   2152   access_token_.clear();
   2153 
   2154   token_request_time_ = base::Time::Now();
   2155   token_receive_time_ = base::Time();
   2156   next_token_request_time_ = base::Time();
   2157   access_token_request_ =
   2158       oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this);
   2159 }
   2160 
   2161 void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
   2162                                                  PassphraseType type) {
   2163   // This should only be called when the backend has been initialized.
   2164   DCHECK(sync_initialized());
   2165   DCHECK(!(type == IMPLICIT && IsUsingSecondaryPassphrase())) <<
   2166       "Data is already encrypted using an explicit passphrase";
   2167   DCHECK(!(type == EXPLICIT &&
   2168            passphrase_required_reason_ == syncer::REASON_DECRYPTION)) <<
   2169          "Can not set explicit passphrase when decryption is needed.";
   2170 
   2171   DVLOG(1) << "Setting " << (type == EXPLICIT ? "explicit" : "implicit")
   2172            << " passphrase for encryption.";
   2173   if (passphrase_required_reason_ == syncer::REASON_ENCRYPTION) {
   2174     // REASON_ENCRYPTION implies that the cryptographer does not have pending
   2175     // keys. Hence, as long as we're not trying to do an invalid passphrase
   2176     // change (e.g. explicit -> explicit or explicit -> implicit), we know this
   2177     // will succeed. If for some reason a new encryption key arrives via
   2178     // sync later, the SBH will trigger another OnPassphraseRequired().
   2179     passphrase_required_reason_ = syncer::REASON_PASSPHRASE_NOT_REQUIRED;
   2180     NotifyObservers();
   2181   }
   2182   backend_->SetEncryptionPassphrase(passphrase, type == EXPLICIT);
   2183 }
   2184 
   2185 bool ProfileSyncService::SetDecryptionPassphrase(
   2186     const std::string& passphrase) {
   2187   if (IsPassphraseRequired()) {
   2188     DVLOG(1) << "Setting passphrase for decryption.";
   2189     return backend_->SetDecryptionPassphrase(passphrase);
   2190   } else {
   2191     NOTREACHED() << "SetDecryptionPassphrase must not be called when "
   2192                     "IsPassphraseRequired() is false.";
   2193     return false;
   2194   }
   2195 }
   2196 
   2197 bool ProfileSyncService::EncryptEverythingAllowed() const {
   2198   return encrypt_everything_allowed_;
   2199 }
   2200 
   2201 void ProfileSyncService::SetEncryptEverythingAllowed(bool allowed) {
   2202   DCHECK(allowed || !backend_initialized_ || !EncryptEverythingEnabled());
   2203   encrypt_everything_allowed_ = allowed;
   2204 }
   2205 
   2206 void ProfileSyncService::EnableEncryptEverything() {
   2207   DCHECK(EncryptEverythingAllowed());
   2208 
   2209   // Tests override sync_initialized() to always return true, so we
   2210   // must check that instead of |backend_initialized_|.
   2211   // TODO(akalin): Fix the above. :/
   2212   DCHECK(sync_initialized());
   2213   // TODO(atwilson): Persist the encryption_pending_ flag to address the various
   2214   // problems around cancelling encryption in the background (crbug.com/119649).
   2215   if (!encrypt_everything_)
   2216     encryption_pending_ = true;
   2217 }
   2218 
   2219 bool ProfileSyncService::encryption_pending() const {
   2220   // We may be called during the setup process before we're
   2221   // initialized (via IsEncryptedDatatypeEnabled and
   2222   // IsPassphraseRequiredForDecryption).
   2223   return encryption_pending_;
   2224 }
   2225 
   2226 bool ProfileSyncService::EncryptEverythingEnabled() const {
   2227   DCHECK(backend_initialized_);
   2228   return encrypt_everything_ || encryption_pending_;
   2229 }
   2230 
   2231 syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const {
   2232   DCHECK(encrypted_types_.Has(syncer::PASSWORDS));
   2233   // We may be called during the setup process before we're
   2234   // initialized.  In this case, we default to the sensitive types.
   2235   return encrypted_types_;
   2236 }
   2237 
   2238 void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
   2239   NotifyObservers();
   2240   if (is_sync_managed) {
   2241     DisableForUser();
   2242   } else {
   2243     // Sync is no longer disabled by policy. Try starting it up if appropriate.
   2244     startup_controller_.TryStart();
   2245   }
   2246 }
   2247 
   2248 void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
   2249                                                const std::string& username,
   2250                                                const std::string& password) {
   2251   if (!sync_prefs_.IsStartSuppressed() && !password.empty()) {
   2252     cached_passphrase_ = password;
   2253     // Try to consume the passphrase we just cached. If the sync backend
   2254     // is not running yet, the passphrase will remain cached until the
   2255     // backend starts up.
   2256     ConsumeCachedPassphraseIfPossible();
   2257   }
   2258 #if defined(OS_CHROMEOS)
   2259   RefreshSpareBootstrapToken(password);
   2260 #endif
   2261   if (!sync_initialized() || GetAuthError().state() != AuthError::NONE) {
   2262     // Track the fact that we're still waiting for auth to complete.
   2263     is_auth_in_progress_ = true;
   2264   }
   2265 }
   2266 
   2267 void ProfileSyncService::GoogleSignedOut(const std::string& account_id,
   2268                                          const std::string& username) {
   2269   sync_disabled_by_admin_ = false;
   2270   DisableForUser();
   2271 
   2272   if (browser_sync::BackupRollbackController::IsBackupEnabled()) {
   2273     need_backup_ = true;
   2274     backup_finished_ = false;
   2275   }
   2276 }
   2277 
   2278 void ProfileSyncService::AddObserver(
   2279     ProfileSyncServiceBase::Observer* observer) {
   2280   observers_.AddObserver(observer);
   2281 }
   2282 
   2283 void ProfileSyncService::RemoveObserver(
   2284     ProfileSyncServiceBase::Observer* observer) {
   2285   observers_.RemoveObserver(observer);
   2286 }
   2287 
   2288 void ProfileSyncService::AddProtocolEventObserver(
   2289     browser_sync::ProtocolEventObserver* observer) {
   2290   protocol_event_observers_.AddObserver(observer);
   2291   if (HasSyncingBackend()) {
   2292     backend_->RequestBufferedProtocolEventsAndEnableForwarding();
   2293   }
   2294 }
   2295 
   2296 void ProfileSyncService::RemoveProtocolEventObserver(
   2297     browser_sync::ProtocolEventObserver* observer) {
   2298   protocol_event_observers_.RemoveObserver(observer);
   2299   if (HasSyncingBackend() &&
   2300       !protocol_event_observers_.might_have_observers()) {
   2301     backend_->DisableProtocolEventForwarding();
   2302   }
   2303 }
   2304 
   2305 void ProfileSyncService::AddTypeDebugInfoObserver(
   2306     syncer::TypeDebugInfoObserver* type_debug_info_observer) {
   2307   type_debug_info_observers_.AddObserver(type_debug_info_observer);
   2308   if (type_debug_info_observers_.might_have_observers() &&
   2309       backend_initialized_) {
   2310     backend_->EnableDirectoryTypeDebugInfoForwarding();
   2311   }
   2312 }
   2313 
   2314 void ProfileSyncService::RemoveTypeDebugInfoObserver(
   2315     syncer::TypeDebugInfoObserver* type_debug_info_observer) {
   2316   type_debug_info_observers_.RemoveObserver(type_debug_info_observer);
   2317   if (!type_debug_info_observers_.might_have_observers() &&
   2318       backend_initialized_) {
   2319     backend_->DisableDirectoryTypeDebugInfoForwarding();
   2320   }
   2321 }
   2322 
   2323 void ProfileSyncService::AddPreferenceProvider(
   2324     SyncTypePreferenceProvider* provider) {
   2325   DCHECK(!HasPreferenceProvider(provider))
   2326       << "Providers may only be added once!";
   2327   preference_providers_.insert(provider);
   2328 }
   2329 
   2330 void ProfileSyncService::RemovePreferenceProvider(
   2331     SyncTypePreferenceProvider* provider) {
   2332   DCHECK(HasPreferenceProvider(provider))
   2333       << "Only providers that have been added before can be removed!";
   2334   preference_providers_.erase(provider);
   2335 }
   2336 
   2337 bool ProfileSyncService::HasPreferenceProvider(
   2338     SyncTypePreferenceProvider* provider) const {
   2339   return preference_providers_.count(provider) > 0;
   2340 }
   2341 
   2342 namespace {
   2343 
   2344 class GetAllNodesRequestHelper
   2345     : public base::RefCountedThreadSafe<GetAllNodesRequestHelper> {
   2346  public:
   2347   GetAllNodesRequestHelper(
   2348       syncer::ModelTypeSet requested_types,
   2349       const base::Callback<void(scoped_ptr<base::ListValue>)>& callback);
   2350 
   2351   void OnReceivedNodesForTypes(
   2352       const std::vector<syncer::ModelType>& types,
   2353       ScopedVector<base::ListValue> scoped_node_lists);
   2354 
   2355  private:
   2356   friend class base::RefCountedThreadSafe<GetAllNodesRequestHelper>;
   2357   virtual ~GetAllNodesRequestHelper();
   2358 
   2359   scoped_ptr<base::ListValue> result_accumulator_;
   2360 
   2361   syncer::ModelTypeSet awaiting_types_;
   2362   base::Callback<void(scoped_ptr<base::ListValue>)> callback_;
   2363 };
   2364 
   2365 GetAllNodesRequestHelper::GetAllNodesRequestHelper(
   2366     syncer::ModelTypeSet requested_types,
   2367     const base::Callback<void(scoped_ptr<base::ListValue>)>& callback)
   2368     : result_accumulator_(new base::ListValue()),
   2369       awaiting_types_(requested_types),
   2370       callback_(callback) {}
   2371 
   2372 GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
   2373   if (!awaiting_types_.Empty()) {
   2374     DLOG(WARNING)
   2375         << "GetAllNodesRequest deleted before request was fulfilled.  "
   2376         << "Missing types are: " << ModelTypeSetToString(awaiting_types_);
   2377   }
   2378 }
   2379 
   2380 // Called when the set of nodes for a type or set of types has been returned.
   2381 //
   2382 // The nodes for several types can be returned at the same time by specifying
   2383 // their types in the |types| array, and putting their results at the
   2384 // correspnding indices in the |scoped_node_lists|.
   2385 void GetAllNodesRequestHelper::OnReceivedNodesForTypes(
   2386     const std::vector<syncer::ModelType>& types,
   2387     ScopedVector<base::ListValue> scoped_node_lists) {
   2388   DCHECK_EQ(types.size(), scoped_node_lists.size());
   2389 
   2390   // Take unsafe ownership of the node list.
   2391   std::vector<base::ListValue*> node_lists;
   2392   scoped_node_lists.release(&node_lists);
   2393 
   2394   for (size_t i = 0; i < node_lists.size() && i < types.size(); ++i) {
   2395     const ModelType type = types[i];
   2396     base::ListValue* node_list = node_lists[i];
   2397 
   2398     // Add these results to our list.
   2399     scoped_ptr<base::DictionaryValue> type_dict(new base::DictionaryValue());
   2400     type_dict->SetString("type", ModelTypeToString(type));
   2401     type_dict->Set("nodes", node_list);
   2402     result_accumulator_->Append(type_dict.release());
   2403 
   2404     // Remember that this part of the request is satisfied.
   2405     awaiting_types_.Remove(type);
   2406   }
   2407 
   2408   if (awaiting_types_.Empty()) {
   2409     callback_.Run(result_accumulator_.Pass());
   2410     callback_.Reset();
   2411   }
   2412 }
   2413 
   2414 }  // namespace
   2415 
   2416 void ProfileSyncService::GetAllNodes(
   2417     const base::Callback<void(scoped_ptr<base::ListValue>)>& callback) {
   2418   ModelTypeSet directory_types = GetRegisteredDirectoryDataTypes();
   2419   directory_types.PutAll(syncer::ControlTypes());
   2420   scoped_refptr<GetAllNodesRequestHelper> helper =
   2421       new GetAllNodesRequestHelper(directory_types, callback);
   2422 
   2423   if (!backend_initialized_) {
   2424     // If there's no backend available to fulfill the request, handle it here.
   2425     ScopedVector<base::ListValue> empty_results;
   2426     std::vector<ModelType> type_vector;
   2427     for (ModelTypeSet::Iterator it = directory_types.First();
   2428          it.Good(); it.Inc()) {
   2429       type_vector.push_back(it.Get());
   2430       empty_results.push_back(new base::ListValue());
   2431     }
   2432     helper->OnReceivedNodesForTypes(type_vector, empty_results.Pass());
   2433   } else {
   2434     backend_->GetAllNodesForTypes(
   2435         directory_types,
   2436         base::Bind(&GetAllNodesRequestHelper::OnReceivedNodesForTypes, helper));
   2437   }
   2438 }
   2439 
   2440 bool ProfileSyncService::HasObserver(
   2441     ProfileSyncServiceBase::Observer* observer) const {
   2442   return observers_.HasObserver(observer);
   2443 }
   2444 
   2445 base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
   2446   return sync_js_controller_.AsWeakPtr();
   2447 }
   2448 
   2449 void ProfileSyncService::SyncEvent(SyncEventCodes code) {
   2450   UMA_HISTOGRAM_ENUMERATION("Sync.EventCodes", code, MAX_SYNC_EVENT_CODE);
   2451 }
   2452 
   2453 // static
   2454 bool ProfileSyncService::IsSyncEnabled() {
   2455   // We have switches::kEnableSync just in case we need to change back to
   2456   // sync-disabled-by-default on a platform.
   2457   return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync);
   2458 }
   2459 
   2460 bool ProfileSyncService::IsManaged() const {
   2461   return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
   2462 }
   2463 
   2464 bool ProfileSyncService::ShouldPushChanges() {
   2465   // True only after all bootstrapping has succeeded: the sync backend
   2466   // is initialized, all enabled data types are consistent with one
   2467   // another, and no unrecoverable error has transpired.
   2468   if (HasUnrecoverableError())
   2469     return false;
   2470 
   2471   if (!directory_data_type_manager_)
   2472     return false;
   2473 
   2474   return directory_data_type_manager_->state() == DataTypeManager::CONFIGURED;
   2475 }
   2476 
   2477 void ProfileSyncService::StopAndSuppress() {
   2478   sync_prefs_.SetStartSuppressed(true);
   2479   if (HasSyncingBackend()) {
   2480     backend_->UnregisterInvalidationIds();
   2481   }
   2482   ShutdownImpl(syncer::STOP_SYNC);
   2483 }
   2484 
   2485 bool ProfileSyncService::IsStartSuppressed() const {
   2486   return sync_prefs_.IsStartSuppressed();
   2487 }
   2488 
   2489 SigninManagerBase* ProfileSyncService::signin() const {
   2490   if (!signin_)
   2491     return NULL;
   2492   return signin_->GetOriginal();
   2493 }
   2494 
   2495 void ProfileSyncService::UnsuppressAndStart() {
   2496   DCHECK(profile_);
   2497   sync_prefs_.SetStartSuppressed(false);
   2498   if (signin_.get() && !signin_->GetOriginal()->IsAuthenticated()) {
   2499     signin_->GetOriginal()->SetAuthenticatedUsername(
   2500         profile_->GetPrefs()->GetString(prefs::kGoogleServicesUsername));
   2501   }
   2502   startup_controller_.TryStart();
   2503 }
   2504 
   2505 void ProfileSyncService::AcknowledgeSyncedTypes() {
   2506   sync_prefs_.AcknowledgeSyncedTypes(GetRegisteredDataTypes());
   2507 }
   2508 
   2509 void ProfileSyncService::ReconfigureDatatypeManager() {
   2510   // If we haven't initialized yet, don't configure the DTM as it could cause
   2511   // association to start before a Directory has even been created.
   2512   if (backend_initialized_) {
   2513     DCHECK(backend_.get());
   2514     ConfigureDataTypeManager();
   2515   } else if (HasUnrecoverableError()) {
   2516     // There is nothing more to configure. So inform the listeners,
   2517     NotifyObservers();
   2518 
   2519     DVLOG(1) << "ConfigureDataTypeManager not invoked because of an "
   2520              << "Unrecoverable error.";
   2521   } else {
   2522     DVLOG(0) << "ConfigureDataTypeManager not invoked because backend is not "
   2523              << "initialized";
   2524   }
   2525 }
   2526 
   2527 syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
   2528     const {
   2529   syncer::ModelTypeSet types;
   2530   for (std::set<SyncTypePreferenceProvider*>::const_iterator it =
   2531            preference_providers_.begin();
   2532        it != preference_providers_.end();
   2533        ++it) {
   2534     types.PutAll((*it)->GetPreferredDataTypes());
   2535   }
   2536   return types;
   2537 }
   2538 
   2539 const DataTypeStatusTable& ProfileSyncService::data_type_status_table()
   2540     const {
   2541   return data_type_status_table_;
   2542 }
   2543 
   2544 void ProfileSyncService::OnInternalUnrecoverableError(
   2545     const tracked_objects::Location& from_here,
   2546     const std::string& message,
   2547     bool delete_sync_database,
   2548     UnrecoverableErrorReason reason) {
   2549   DCHECK(!HasUnrecoverableError());
   2550   unrecoverable_error_reason_ = reason;
   2551   OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
   2552 }
   2553 
   2554 syncer::SyncManagerFactory::MANAGER_TYPE
   2555 ProfileSyncService::GetManagerType() const {
   2556   switch (backend_mode_) {
   2557     case SYNC:
   2558       return syncer::SyncManagerFactory::NORMAL;
   2559     case BACKUP:
   2560       return syncer::SyncManagerFactory::BACKUP;
   2561     case ROLLBACK:
   2562       return syncer::SyncManagerFactory::ROLLBACK;
   2563     case IDLE:
   2564       NOTREACHED();
   2565   }
   2566   return syncer::SyncManagerFactory::NORMAL;
   2567 }
   2568 
   2569 bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
   2570   return request_access_token_retry_timer_.IsRunning();
   2571 }
   2572 
   2573 std::string ProfileSyncService::GetAccessTokenForTest() const {
   2574   return access_token_;
   2575 }
   2576 
   2577 WeakHandle<syncer::JsEventHandler> ProfileSyncService::GetJsEventHandler() {
   2578   return MakeWeakHandle(sync_js_controller_.AsWeakPtr());
   2579 }
   2580 
   2581 syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() {
   2582   return sessions_sync_manager_.get();
   2583 }
   2584 
   2585 syncer::SyncableService* ProfileSyncService::GetDeviceInfoSyncableService() {
   2586   return device_info_sync_service_.get();
   2587 }
   2588 
   2589 ProfileSyncService::SyncTokenStatus::SyncTokenStatus()
   2590     : connection_status(syncer::CONNECTION_NOT_ATTEMPTED),
   2591       last_get_token_error(GoogleServiceAuthError::AuthErrorNone()) {}
   2592 ProfileSyncService::SyncTokenStatus::~SyncTokenStatus() {}
   2593 
   2594 ProfileSyncService::SyncTokenStatus
   2595 ProfileSyncService::GetSyncTokenStatus() const {
   2596   SyncTokenStatus status;
   2597   status.connection_status_update_time = connection_status_update_time_;
   2598   status.connection_status = connection_status_;
   2599   status.token_request_time = token_request_time_;
   2600   status.token_receive_time = token_receive_time_;
   2601   status.last_get_token_error = last_get_token_error_;
   2602   if (request_access_token_retry_timer_.IsRunning())
   2603     status.next_token_request_time = next_token_request_time_;
   2604   return status;
   2605 }
   2606 
   2607 void ProfileSyncService::OverrideNetworkResourcesForTest(
   2608     scoped_ptr<syncer::NetworkResources> network_resources) {
   2609   network_resources_ = network_resources.Pass();
   2610 }
   2611 
   2612 bool ProfileSyncService::HasSyncingBackend() const {
   2613   return backend_mode_ != SYNC ? false : backend_ != NULL;
   2614 }
   2615 
   2616 void ProfileSyncService::UpdateFirstSyncTimePref() {
   2617   if (signin_->GetEffectiveUsername().empty()) {
   2618     // Clear if user's not signed in and rollback is done.
   2619     if (backend_mode_ != ROLLBACK)
   2620       sync_prefs_.ClearFirstSyncTime();
   2621   } else if (sync_prefs_.GetFirstSyncTime().is_null() &&
   2622       backend_mode_ == SYNC) {
   2623     // Set if not set before and it's syncing now.
   2624     sync_prefs_.SetFirstSyncTime(base::Time::Now());
   2625   }
   2626 }
   2627 
   2628 void ProfileSyncService::ClearBrowsingDataSinceFirstSync() {
   2629   base::Time first_sync_time = sync_prefs_.GetFirstSyncTime();
   2630   if (first_sync_time.is_null())
   2631     return;
   2632 
   2633   clear_browsing_data_.Run(browsing_data_remover_observer_,
   2634                            profile_,
   2635                            first_sync_time,
   2636                            base::Time::Now());
   2637 }
   2638 
   2639 void ProfileSyncService::SetBrowsingDataRemoverObserverForTesting(
   2640     BrowsingDataRemover::Observer* observer) {
   2641   browsing_data_remover_observer_ = observer;
   2642 }
   2643 
   2644 void ProfileSyncService::SetClearingBrowseringDataForTesting(
   2645     base::Callback<void(BrowsingDataRemover::Observer* observer,
   2646                         Profile*,
   2647                         base::Time,
   2648                         base::Time)> c) {
   2649   clear_browsing_data_ = c;
   2650 }
   2651 
   2652 GURL ProfileSyncService::GetSyncServiceURL(
   2653     const base::CommandLine& command_line) {
   2654   // By default, dev, canary, and unbranded Chromium users will go to the
   2655   // development servers. Development servers have more features than standard
   2656   // sync servers. Users with officially-branded Chrome stable and beta builds
   2657   // will go to the standard sync servers.
   2658   GURL result(kDevServerUrl);
   2659 
   2660   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
   2661   if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
   2662       channel == chrome::VersionInfo::CHANNEL_BETA) {
   2663     result = GURL(kSyncServerUrl);
   2664   }
   2665 
   2666   // Override the sync server URL from the command-line, if sync server
   2667   // command-line argument exists.
   2668   if (command_line.HasSwitch(switches::kSyncServiceURL)) {
   2669     std::string value(command_line.GetSwitchValueASCII(
   2670         switches::kSyncServiceURL));
   2671     if (!value.empty()) {
   2672       GURL custom_sync_url(value);
   2673       if (custom_sync_url.is_valid()) {
   2674         result = custom_sync_url;
   2675       } else {
   2676         LOG(WARNING) << "The following sync URL specified at the command-line "
   2677                      << "is invalid: " << value;
   2678       }
   2679     }
   2680   }
   2681   return result;
   2682 }
   2683 
   2684 void ProfileSyncService::CheckSyncBackupIfNeeded() {
   2685   DCHECK_EQ(backend_mode_, SYNC);
   2686 
   2687 #if defined(ENABLE_PRE_SYNC_BACKUP)
   2688   const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
   2689   // Check backup once a day.
   2690   if (!last_backup_time_ &&
   2691       (last_synced_time.is_null() ||
   2692           base::Time::Now() - last_synced_time >=
   2693               base::TimeDelta::FromDays(1))) {
   2694     // If sync thread is set, need to serialize check on sync thread after
   2695     // closing backup DB.
   2696     if (sync_thread_) {
   2697       sync_thread_->message_loop_proxy()->PostTask(
   2698           FROM_HERE,
   2699           base::Bind(syncer::CheckSyncDbLastModifiedTime,
   2700                      profile_->GetPath().Append(kSyncBackupDataFolderName),
   2701                      base::MessageLoopProxy::current(),
   2702                      base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
   2703                                 weak_factory_.GetWeakPtr())));
   2704     } else {
   2705       content::BrowserThread::PostTask(
   2706           content::BrowserThread::FILE, FROM_HERE,
   2707           base::Bind(syncer::CheckSyncDbLastModifiedTime,
   2708                      profile_->GetPath().Append(kSyncBackupDataFolderName),
   2709                      base::MessageLoopProxy::current(),
   2710                      base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
   2711                                 weak_factory_.GetWeakPtr())));
   2712     }
   2713   }
   2714 #endif
   2715 }
   2716 
   2717 void ProfileSyncService::CheckSyncBackupCallback(base::Time backup_time) {
   2718   last_backup_time_.reset(new base::Time(backup_time));
   2719 
   2720   DCHECK(device_info_sync_service_);
   2721   device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_);
   2722 }
   2723 
   2724 void ProfileSyncService::TryStartSyncAfterBackup() {
   2725   startup_controller_.Reset(GetRegisteredDataTypes());
   2726   startup_controller_.TryStart();
   2727 }
   2728 
   2729 void ProfileSyncService::CleanUpBackup() {
   2730   sync_prefs_.ClearFirstSyncTime();
   2731   profile_->GetIOTaskRunner()->PostTask(
   2732       FROM_HERE,
   2733       base::Bind(base::IgnoreResult(base::DeleteFile),
   2734                  profile_->GetPath().Append(kSyncBackupDataFolderName),
   2735                  true));
   2736 }
   2737 
   2738 bool ProfileSyncService::NeedBackup() const {
   2739   return need_backup_;
   2740 }
   2741 
   2742 base::Time ProfileSyncService::GetDeviceBackupTimeForTesting() const {
   2743   return device_info_sync_service_->GetLocalDeviceBackupTime();
   2744 }
   2745