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