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