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