Home | History | Annotate | Download | only in glue
      1 // Copyright 2013 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/glue/sync_backend_host_impl.h"
      6 
      7 #include "base/command_line.h"
      8 #include "chrome/browser/chrome_notification_types.h"
      9 #include "chrome/browser/invalidation/invalidation_service.h"
     10 #include "chrome/browser/invalidation/invalidation_service_factory.h"
     11 #include "chrome/browser/network_time/network_time_tracker.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
     14 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
     15 #include "chrome/browser/sync/glue/sync_frontend.h"
     16 #include "chrome/browser/sync/sync_prefs.h"
     17 #include "chrome/common/chrome_switches.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "content/public/browser/notification_details.h"
     20 #include "content/public/browser/notification_source.h"
     21 #include "sync/internal_api/public/base_transaction.h"
     22 #include "sync/internal_api/public/http_bridge.h"
     23 #include "sync/internal_api/public/internal_components_factory.h"
     24 #include "sync/internal_api/public/internal_components_factory_impl.h"
     25 #include "sync/internal_api/public/network_resources.h"
     26 #include "sync/internal_api/public/sync_manager.h"
     27 #include "sync/internal_api/public/sync_manager_factory.h"
     28 #include "sync/internal_api/public/util/experiments.h"
     29 #include "sync/internal_api/public/util/sync_string_conversions.h"
     30 #include "sync/notifier/object_id_invalidation_map.h"
     31 
     32 // Helper macros to log with the syncer thread name; useful when there
     33 // are multiple syncers involved.
     34 
     35 #define SLOG(severity) LOG(severity) << name_ << ": "
     36 
     37 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
     38 
     39 using syncer::InternalComponentsFactory;
     40 
     41 static const base::FilePath::CharType kSyncDataFolderName[] =
     42     FILE_PATH_LITERAL("Sync Data");
     43 
     44 namespace browser_sync {
     45 
     46 SyncBackendHostImpl::SyncBackendHostImpl(
     47     const std::string& name,
     48     Profile* profile,
     49     const base::WeakPtr<SyncPrefs>& sync_prefs)
     50     : frontend_loop_(base::MessageLoop::current()),
     51       profile_(profile),
     52       name_(name),
     53       initialized_(false),
     54       sync_prefs_(sync_prefs),
     55       frontend_(NULL),
     56       cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
     57       invalidator_(
     58           invalidation::InvalidationServiceFactory::GetForProfile(profile)),
     59       invalidation_handler_registered_(false),
     60       weak_ptr_factory_(this) {
     61   core_ = new SyncBackendHostCore(
     62       name_,
     63       profile_->GetPath().Append(kSyncDataFolderName),
     64       sync_prefs_->HasSyncSetupCompleted(),
     65       weak_ptr_factory_.GetWeakPtr());
     66 }
     67 
     68 SyncBackendHostImpl::~SyncBackendHostImpl() {
     69   DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
     70   DCHECK(!registrar_.get());
     71 }
     72 
     73 void SyncBackendHostImpl::Initialize(
     74     SyncFrontend* frontend,
     75     scoped_ptr<base::Thread> sync_thread,
     76     const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
     77     const GURL& sync_service_url,
     78     const syncer::SyncCredentials& credentials,
     79     bool delete_sync_data_folder,
     80     scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
     81     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
     82     syncer::ReportUnrecoverableErrorFunction
     83         report_unrecoverable_error_function,
     84     syncer::NetworkResources* network_resources) {
     85   registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
     86                                             profile_,
     87                                             sync_thread.Pass()));
     88   CHECK(registrar_->sync_thread());
     89 
     90   frontend_ = frontend;
     91   DCHECK(frontend);
     92 
     93   syncer::ModelSafeRoutingInfo routing_info;
     94   std::vector<syncer::ModelSafeWorker*> workers;
     95   registrar_->GetModelSafeRoutingInfo(&routing_info);
     96   registrar_->GetWorkers(&workers);
     97 
     98   InternalComponentsFactory::Switches factory_switches = {
     99     InternalComponentsFactory::ENCRYPTION_KEYSTORE,
    100     InternalComponentsFactory::BACKOFF_NORMAL
    101   };
    102 
    103   CommandLine* cl = CommandLine::ForCurrentProcess();
    104   if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
    105     factory_switches.backoff_override =
    106         InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
    107   }
    108   if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
    109     factory_switches.pre_commit_updates_policy =
    110         InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
    111   }
    112 
    113   scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
    114       registrar_->sync_thread()->message_loop(),
    115       registrar_.get(),
    116       routing_info,
    117       workers,
    118       extensions_activity_monitor_.GetExtensionsActivity(),
    119       event_handler,
    120       sync_service_url,
    121       network_resources->GetHttpPostProviderFactory(
    122           make_scoped_refptr(profile_->GetRequestContext()),
    123           NetworkTimeTracker::BuildNotifierUpdateCallback(),
    124           core_->GetRequestContextCancelationSignal()),
    125       credentials,
    126       invalidator_->GetInvalidatorClientId(),
    127       sync_manager_factory.Pass(),
    128       delete_sync_data_folder,
    129       sync_prefs_->GetEncryptionBootstrapToken(),
    130       sync_prefs_->GetKeystoreEncryptionBootstrapToken(),
    131       scoped_ptr<InternalComponentsFactory>(
    132           new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(),
    133       unrecoverable_error_handler.Pass(),
    134       report_unrecoverable_error_function));
    135   InitCore(init_opts.Pass());
    136 }
    137 
    138 void SyncBackendHostImpl::UpdateCredentials(
    139     const syncer::SyncCredentials& credentials) {
    140   DCHECK(registrar_->sync_thread()->IsRunning());
    141   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    142       base::Bind(&SyncBackendHostCore::DoUpdateCredentials,
    143                  core_.get(),
    144                  credentials));
    145 }
    146 
    147 void SyncBackendHostImpl::StartSyncingWithServer() {
    148   SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
    149 
    150   syncer::ModelSafeRoutingInfo routing_info;
    151   registrar_->GetModelSafeRoutingInfo(&routing_info);
    152 
    153   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    154       base::Bind(&SyncBackendHostCore::DoStartSyncing,
    155                  core_.get(), routing_info));
    156 }
    157 
    158 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
    159                                               bool is_explicit) {
    160   DCHECK(registrar_->sync_thread()->IsRunning());
    161   if (!IsNigoriEnabled()) {
    162     NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
    163                     " is disabled.";
    164     return;
    165   }
    166 
    167   // We should never be called with an empty passphrase.
    168   DCHECK(!passphrase.empty());
    169 
    170   // This should only be called by the frontend.
    171   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    172 
    173   // SetEncryptionPassphrase should never be called if we are currently
    174   // encrypted with an explicit passphrase.
    175   DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE ||
    176          cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE);
    177 
    178   // Post an encryption task on the syncer thread.
    179   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    180       base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
    181                  core_.get(),
    182                  passphrase, is_explicit));
    183 }
    184 
    185 bool SyncBackendHostImpl::SetDecryptionPassphrase(
    186     const std::string& passphrase) {
    187   if (!IsNigoriEnabled()) {
    188     NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
    189                     " is disabled.";
    190     return false;
    191   }
    192 
    193   // We should never be called with an empty passphrase.
    194   DCHECK(!passphrase.empty());
    195 
    196   // This should only be called by the frontend.
    197   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    198 
    199   // This should only be called when we have cached pending keys.
    200   DCHECK(cached_pending_keys_.has_blob());
    201 
    202   // Check the passphrase that was provided against our local cache of the
    203   // cryptographer's pending keys. If this was unsuccessful, the UI layer can
    204   // immediately call OnPassphraseRequired without showing the user a spinner.
    205   if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
    206     return false;
    207 
    208   // Post a decryption task on the syncer thread.
    209   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    210       base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
    211                  core_.get(),
    212                  passphrase));
    213 
    214   // Since we were able to decrypt the cached pending keys with the passphrase
    215   // provided, we immediately alert the UI layer that the passphrase was
    216   // accepted. This will avoid the situation where a user enters a passphrase,
    217   // clicks OK, immediately reopens the advanced settings dialog, and gets an
    218   // unnecessary prompt for a passphrase.
    219   // Note: It is not guaranteed that the passphrase will be accepted by the
    220   // syncer thread, since we could receive a new nigori node while the task is
    221   // pending. This scenario is a valid race, and SetDecryptionPassphrase can
    222   // trigger a new OnPassphraseRequired if it needs to.
    223   NotifyPassphraseAccepted();
    224   return true;
    225 }
    226 
    227 void SyncBackendHostImpl::StopSyncingForShutdown() {
    228   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    229 
    230   // Immediately stop sending messages to the frontend.
    231   frontend_ = NULL;
    232 
    233   // Stop listening for and forwarding locally-triggered sync refresh requests.
    234   notification_registrar_.RemoveAll();
    235 
    236   DCHECK(registrar_->sync_thread()->IsRunning());
    237 
    238   registrar_->RequestWorkerStopOnUIThread();
    239 
    240   core_->ShutdownOnUIThread();
    241 }
    242 
    243 scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(ShutdownOption option) {
    244   // StopSyncingForShutdown() (which nulls out |frontend_|) should be
    245   // called first.
    246   DCHECK(!frontend_);
    247   DCHECK(registrar_->sync_thread()->IsRunning());
    248 
    249   bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD);
    250   bool sync_thread_claimed =
    251       (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD);
    252 
    253   if (invalidation_handler_registered_) {
    254     if (sync_disabled) {
    255       UnregisterInvalidationIds();
    256     }
    257     invalidator_->UnregisterInvalidationHandler(this);
    258     invalidator_ = NULL;
    259   }
    260   invalidation_handler_registered_ = false;
    261 
    262   // Shut down and destroy sync manager.
    263   registrar_->sync_thread()->message_loop()->PostTask(
    264       FROM_HERE,
    265       base::Bind(&SyncBackendHostCore::DoShutdown,
    266                  core_.get(), sync_disabled));
    267   core_ = NULL;
    268 
    269   // Worker cleanup.
    270   SyncBackendRegistrar* detached_registrar = registrar_.release();
    271   detached_registrar->sync_thread()->message_loop()->PostTask(
    272       FROM_HERE,
    273       base::Bind(&SyncBackendRegistrar::Shutdown,
    274                  base::Unretained(detached_registrar)));
    275 
    276   if (sync_thread_claimed)
    277     return detached_registrar->ReleaseSyncThread();
    278   else
    279     return scoped_ptr<base::Thread>();
    280 }
    281 
    282 void SyncBackendHostImpl::UnregisterInvalidationIds() {
    283   if (invalidation_handler_registered_) {
    284     invalidator_->UpdateRegisteredInvalidationIds(
    285         this,
    286         syncer::ObjectIdSet());
    287   }
    288 }
    289 
    290 void SyncBackendHostImpl::ConfigureDataTypes(
    291     syncer::ConfigureReason reason,
    292     const DataTypeConfigStateMap& config_state_map,
    293     const base::Callback<void(syncer::ModelTypeSet,
    294                               syncer::ModelTypeSet)>& ready_task,
    295     const base::Callback<void()>& retry_callback) {
    296   // Only one configure is allowed at a time.  This is guaranteed by our
    297   // callers.  The SyncBackendHostImpl requests one configure as the backend is
    298   // initializing and waits for it to complete.  After initialization, all
    299   // configurations will pass through the DataTypeManager, which is careful to
    300   // never send a new configure request until the current request succeeds.
    301 
    302   // The SyncBackendRegistrar's routing info will be updated by adding the
    303   // types_to_add to the list then removing types_to_remove.  Any types which
    304   // are not in either of those sets will remain untouched.
    305   //
    306   // Types which were not in the list previously are not fully downloaded, so we
    307   // must ask the syncer to download them.  Any newly supported datatypes will
    308   // not have been in that routing info list, so they will be among the types
    309   // downloaded if they are enabled.
    310   //
    311   // The SyncBackendRegistrar's state was initially derived from the types
    312   // detected to have been downloaded in the database.  Afterwards it is
    313   // modified only by this function.  We expect it to remain in sync with the
    314   // backend because configuration requests are never aborted; they are retried
    315   // until they succeed or the backend is shut down.
    316 
    317   syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes();
    318 
    319   syncer::ModelTypeSet disabled_types =
    320       GetDataTypesInState(DISABLED, config_state_map);
    321   syncer::ModelTypeSet fatal_types =
    322       GetDataTypesInState(FATAL, config_state_map);
    323   syncer::ModelTypeSet crypto_types =
    324       GetDataTypesInState(CRYPTO, config_state_map);
    325   disabled_types.PutAll(fatal_types);
    326   disabled_types.PutAll(crypto_types);
    327   syncer::ModelTypeSet active_types =
    328       GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
    329   syncer::ModelTypeSet clean_first_types =
    330       GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
    331   syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
    332       syncer::Union(active_types, clean_first_types),
    333       disabled_types);
    334   types_to_download.PutAll(clean_first_types);
    335   types_to_download.RemoveAll(syncer::ProxyTypes());
    336   if (!types_to_download.Empty())
    337     types_to_download.Put(syncer::NIGORI);
    338 
    339   // TODO(sync): crbug.com/137550.
    340   // It's dangerous to configure types that have progress markers.  Types with
    341   // progress markers can trigger a MIGRATION_DONE response.  We are not
    342   // prepared to handle a migration during a configure, so we must ensure that
    343   // all our types_to_download actually contain no data before we sync them.
    344   //
    345   // One common way to end up in this situation used to be types which
    346   // downloaded some or all of their data but have not applied it yet.  We avoid
    347   // problems with those types by purging the data of any such partially synced
    348   // types soon after we load the directory.
    349   //
    350   // Another possible scenario is that we have newly supported or newly enabled
    351   // data types being downloaded here but the nigori type, which is always
    352   // included in any GetUpdates request, requires migration.  The server has
    353   // code to detect this scenario based on the configure reason, the fact that
    354   // the nigori type is the only requested type which requires migration, and
    355   // that the requested types list includes at least one non-nigori type.  It
    356   // will not send a MIGRATION_DONE response in that case.  We still need to be
    357   // careful to not send progress markers for non-nigori types, though.  If a
    358   // non-nigori type in the request requires migration, a MIGRATION_DONE
    359   // response will be sent.
    360 
    361   syncer::ModelSafeRoutingInfo routing_info;
    362   registrar_->GetModelSafeRoutingInfo(&routing_info);
    363 
    364   syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
    365   syncer::ModelTypeSet types_to_purge =
    366       syncer::Difference(previous_types, current_types);
    367   syncer::ModelTypeSet inactive_types =
    368       GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
    369   types_to_purge.RemoveAll(inactive_types);
    370 
    371   // If a type has already been disabled and unapplied or journaled, it will
    372   // not be part of the |types_to_purge| set, and therefore does not need
    373   // to be acted on again.
    374   fatal_types.RetainAll(types_to_purge);
    375   syncer::ModelTypeSet unapply_types =
    376       syncer::Union(crypto_types, clean_first_types);
    377   unapply_types.RetainAll(types_to_purge);
    378 
    379   DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
    380   DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
    381   DCHECK(current_types.HasAll(types_to_download));
    382 
    383   SDVLOG(1) << "Types "
    384             << syncer::ModelTypeSetToString(types_to_download)
    385             << " added; calling DoConfigureSyncer";
    386   // Divide up the types into their corresponding actions (each is mutually
    387   // exclusive):
    388   // - Types which have just been added to the routing info (types_to_download):
    389   //   are downloaded.
    390   // - Types which have encountered a fatal error (fatal_types) are deleted
    391   //   from the directory and journaled in the delete journal.
    392   // - Types which have encountered a cryptographer error (crypto_types) are
    393   //   unapplied (local state is purged but sync state is not).
    394   // - All other types not in the routing info (types just disabled) are deleted
    395   //   from the directory.
    396   // - Everything else (enabled types and already disabled types) is not
    397   //   touched.
    398   RequestConfigureSyncer(reason,
    399                          types_to_download,
    400                          types_to_purge,
    401                          fatal_types,
    402                          unapply_types,
    403                          inactive_types,
    404                          routing_info,
    405                          ready_task,
    406                          retry_callback);
    407 }
    408 
    409 void SyncBackendHostImpl::EnableEncryptEverything() {
    410   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    411      base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
    412                 core_.get()));
    413 }
    414 
    415 void SyncBackendHostImpl::ActivateDataType(
    416     syncer::ModelType type, syncer::ModelSafeGroup group,
    417     ChangeProcessor* change_processor) {
    418   registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
    419 }
    420 
    421 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
    422   registrar_->DeactivateDataType(type);
    423 }
    424 
    425 syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
    426   return core_->sync_manager()->GetUserShare();
    427 }
    428 
    429 SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
    430   DCHECK(initialized());
    431   return core_->sync_manager()->GetDetailedStatus();
    432 }
    433 
    434 syncer::sessions::SyncSessionSnapshot
    435 SyncBackendHostImpl::GetLastSessionSnapshot() const {
    436   return last_snapshot_;
    437 }
    438 
    439 bool SyncBackendHostImpl::HasUnsyncedItems() const {
    440   DCHECK(initialized());
    441   return core_->sync_manager()->HasUnsyncedItems();
    442 }
    443 
    444 bool SyncBackendHostImpl::IsNigoriEnabled() const {
    445   return registrar_.get() && registrar_->IsNigoriEnabled();
    446 }
    447 
    448 syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
    449   return cached_passphrase_type_;
    450 }
    451 
    452 base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
    453   return cached_explicit_passphrase_time_;
    454 }
    455 
    456 bool SyncBackendHostImpl::IsCryptographerReady(
    457     const syncer::BaseTransaction* trans) const {
    458   return initialized() && trans->GetCryptographer()->is_ready();
    459 }
    460 
    461 void SyncBackendHostImpl::GetModelSafeRoutingInfo(
    462     syncer::ModelSafeRoutingInfo* out) const {
    463   if (initialized()) {
    464     CHECK(registrar_.get());
    465     registrar_->GetModelSafeRoutingInfo(out);
    466   } else {
    467     NOTREACHED();
    468   }
    469 }
    470 
    471 SyncedDeviceTracker* SyncBackendHostImpl::GetSyncedDeviceTracker() const {
    472   if (!initialized())
    473     return NULL;
    474   return core_->synced_device_tracker();
    475 }
    476 
    477 void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) {
    478   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    479       base::Bind(&SyncBackendHostCore::DoInitialize,
    480                  core_.get(), base::Passed(&options)));
    481 }
    482 
    483 void SyncBackendHostImpl::RequestConfigureSyncer(
    484     syncer::ConfigureReason reason,
    485     syncer::ModelTypeSet to_download,
    486     syncer::ModelTypeSet to_purge,
    487     syncer::ModelTypeSet to_journal,
    488     syncer::ModelTypeSet to_unapply,
    489     syncer::ModelTypeSet to_ignore,
    490     const syncer::ModelSafeRoutingInfo& routing_info,
    491     const base::Callback<void(syncer::ModelTypeSet,
    492                               syncer::ModelTypeSet)>& ready_task,
    493     const base::Closure& retry_callback) {
    494   DoConfigureSyncerTypes config_types;
    495   config_types.to_download = to_download;
    496   config_types.to_purge = to_purge;
    497   config_types.to_journal = to_journal;
    498   config_types.to_unapply = to_unapply;
    499   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    500        base::Bind(&SyncBackendHostCore::DoConfigureSyncer,
    501                   core_.get(),
    502                   reason,
    503                   config_types,
    504                   routing_info,
    505                   ready_task,
    506                   retry_callback));
    507 }
    508 
    509 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
    510     const syncer::ModelTypeSet enabled_types,
    511     const syncer::ModelTypeSet succeeded_configuration_types,
    512     const syncer::ModelTypeSet failed_configuration_types,
    513     const base::Callback<void(syncer::ModelTypeSet,
    514                               syncer::ModelTypeSet)>& ready_task) {
    515   if (!frontend_)
    516     return;
    517 
    518   invalidator_->UpdateRegisteredInvalidationIds(
    519       this,
    520       ModelTypeSetToObjectIdSet(enabled_types));
    521 
    522   if (!ready_task.is_null())
    523     ready_task.Run(succeeded_configuration_types, failed_configuration_types);
    524 }
    525 
    526 void SyncBackendHostImpl::Observe(
    527     int type,
    528     const content::NotificationSource& source,
    529     const content::NotificationDetails& details) {
    530   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    531   DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL);
    532 
    533   content::Details<const syncer::ModelTypeSet> state_details(details);
    534   const syncer::ModelTypeSet& types = *(state_details.ptr());
    535   registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
    536       base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types));
    537 }
    538 
    539 void SyncBackendHostImpl::AddExperimentalTypes() {
    540   CHECK(initialized());
    541   syncer::Experiments experiments;
    542   if (core_->sync_manager()->ReceivedExperiment(&experiments))
    543     frontend_->OnExperimentsChanged(experiments);
    544 }
    545 
    546 void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
    547   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    548   if (!frontend_)
    549     return;
    550 
    551   frontend_->OnSyncConfigureRetry();
    552 }
    553 
    554 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
    555     const syncer::WeakHandle<syncer::JsBackend> js_backend,
    556     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
    557         debug_info_listener) {
    558   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    559   if (!frontend_)
    560     return;
    561 
    562   initialized_ = true;
    563 
    564   invalidator_->RegisterInvalidationHandler(this);
    565   invalidation_handler_registered_ = true;
    566 
    567   // Fake a state change to initialize the SyncManager's cached invalidator
    568   // state.
    569   OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
    570 
    571   // Start forwarding refresh requests to the SyncManager
    572   notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
    573                               content::Source<Profile>(profile_));
    574 
    575   // Now that we've downloaded the control types, we can see if there are any
    576   // experimental types to enable. This should be done before we inform
    577   // the frontend to ensure they're visible in the customize screen.
    578   AddExperimentalTypes();
    579   frontend_->OnBackendInitialized(js_backend,
    580                                   debug_info_listener,
    581                                   true);
    582 }
    583 
    584 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
    585   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    586   if (!frontend_)
    587     return;
    588 
    589   frontend_->OnBackendInitialized(
    590       syncer::WeakHandle<syncer::JsBackend>(),
    591       syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
    592       false);
    593 }
    594 
    595 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
    596     const syncer::sessions::SyncSessionSnapshot& snapshot) {
    597   if (!frontend_)
    598     return;
    599   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    600 
    601   last_snapshot_ = snapshot;
    602 
    603   SDVLOG(1) << "Got snapshot " << snapshot.ToString();
    604 
    605   const syncer::ModelTypeSet to_migrate =
    606       snapshot.model_neutral_state().types_needing_local_migration;
    607   if (!to_migrate.Empty())
    608     frontend_->OnMigrationNeededForTypes(to_migrate);
    609 
    610   // Process any changes to the datatypes we're syncing.
    611   // TODO(sync): add support for removing types.
    612   if (initialized())
    613     AddExperimentalTypes();
    614 
    615   if (initialized())
    616     frontend_->OnSyncCycleCompleted();
    617 }
    618 
    619 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
    620     const base::Closure& retry_callback) {
    621   SDVLOG(1) << "Failed to complete configuration, informing of retry.";
    622   retry_callback.Run();
    623 }
    624 
    625 void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
    626     const std::string& token,
    627     syncer::BootstrapTokenType token_type) {
    628   CHECK(sync_prefs_.get());
    629   DCHECK(!token.empty());
    630   if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN)
    631     sync_prefs_->SetEncryptionBootstrapToken(token);
    632   else
    633     sync_prefs_->SetKeystoreEncryptionBootstrapToken(token);
    634 }
    635 
    636 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
    637     const syncer::SyncProtocolError& sync_error) {
    638   if (!frontend_)
    639     return;
    640   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    641   frontend_->OnActionableError(sync_error);
    642 }
    643 
    644 void SyncBackendHostImpl::OnInvalidatorStateChange(
    645     syncer::InvalidatorState state) {
    646   registrar_->sync_thread()->message_loop()->PostTask(
    647       FROM_HERE,
    648       base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
    649                  core_.get(),
    650                  state));
    651 }
    652 
    653 void SyncBackendHostImpl::OnIncomingInvalidation(
    654     const syncer::ObjectIdInvalidationMap& invalidation_map) {
    655   // TODO(rlarocque): Acknowledge these invalidations only after the syncer has
    656   // acted on them and saved the results to disk.
    657   invalidation_map.AcknowledgeAll();
    658   registrar_->sync_thread()->message_loop()->PostTask(
    659       FROM_HERE,
    660       base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
    661                  core_.get(),
    662                  invalidation_map));
    663 }
    664 
    665 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
    666     const std::string& passphrase) const {
    667   DCHECK(cached_pending_keys_.has_blob());
    668   DCHECK(!passphrase.empty());
    669   syncer::Nigori nigori;
    670   nigori.InitByDerivation("localhost", "dummy", passphrase);
    671   std::string plaintext;
    672   bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
    673   DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
    674   return result;
    675 }
    676 
    677 void SyncBackendHostImpl::NotifyPassphraseRequired(
    678     syncer::PassphraseRequiredReason reason,
    679     sync_pb::EncryptedData pending_keys) {
    680   if (!frontend_)
    681     return;
    682 
    683   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    684 
    685   // Update our cache of the cryptographer's pending keys.
    686   cached_pending_keys_ = pending_keys;
    687 
    688   frontend_->OnPassphraseRequired(reason, pending_keys);
    689 }
    690 
    691 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
    692   if (!frontend_)
    693     return;
    694 
    695   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    696 
    697   // Clear our cache of the cryptographer's pending keys.
    698   cached_pending_keys_.clear_blob();
    699   frontend_->OnPassphraseAccepted();
    700 }
    701 
    702 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
    703     syncer::ModelTypeSet encrypted_types,
    704     bool encrypt_everything) {
    705   if (!frontend_)
    706     return;
    707 
    708   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    709   frontend_->OnEncryptedTypesChanged(
    710       encrypted_types, encrypt_everything);
    711 }
    712 
    713 void SyncBackendHostImpl::NotifyEncryptionComplete() {
    714   if (!frontend_)
    715     return;
    716 
    717   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    718   frontend_->OnEncryptionComplete();
    719 }
    720 
    721 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
    722     syncer::PassphraseType type,
    723     base::Time explicit_passphrase_time) {
    724   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    725   DVLOG(1) << "Passphrase type changed to "
    726            << syncer::PassphraseTypeToString(type);
    727   cached_passphrase_type_ = type;
    728   cached_explicit_passphrase_time_ = explicit_passphrase_time;
    729 }
    730 
    731 void SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop() {
    732   if (!frontend_)
    733     return;
    734   frontend_->OnStopSyncingPermanently();
    735 }
    736 
    737 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
    738     syncer::ConnectionStatus status) {
    739   if (!frontend_)
    740     return;
    741 
    742   DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
    743 
    744   DVLOG(1) << "Connection status changed: "
    745            << syncer::ConnectionStatusToString(status);
    746   frontend_->OnConnectionStatusChange(status);
    747 }
    748 
    749 base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() {
    750   return registrar_->sync_thread()->message_loop();
    751 }
    752 
    753 }  // namespace browser_sync
    754 
    755 #undef SDVLOG
    756 
    757 #undef SLOG
    758 
    759