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
44using syncer::InternalComponentsFactory;
45
46namespace browser_sync {
47
48namespace {
49
50void 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
58void 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
70SyncBackendHostImpl::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
93SyncBackendHostImpl::~SyncBackendHostImpl() {
94  DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
95  DCHECK(!registrar_.get());
96}
97
98void 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
163void 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
172void 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
183void 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
210bool 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
252void 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
271scoped_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
309void SyncBackendHostImpl::UnregisterInvalidationIds() {
310  if (invalidation_handler_registered_) {
311    invalidator_->UpdateRegisteredInvalidationIds(
312        this,
313        syncer::ObjectIdSet());
314  }
315}
316
317void 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
440void SyncBackendHostImpl::EnableEncryptEverything() {
441  registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
442     base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
443                core_.get()));
444}
445
446void 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
452void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
453  registrar_->DeactivateDataType(type);
454}
455
456syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
457  return core_->sync_manager()->GetUserShare();
458}
459
460scoped_ptr<syncer::SyncContextProxy>
461SyncBackendHostImpl::GetSyncContextProxy() {
462  return sync_context_proxy_.get() ? scoped_ptr<syncer::SyncContextProxy>(
463                                         sync_context_proxy_->Clone())
464                                   : scoped_ptr<syncer::SyncContextProxy>();
465}
466
467SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
468  DCHECK(initialized());
469  return core_->sync_manager()->GetDetailedStatus();
470}
471
472syncer::sessions::SyncSessionSnapshot
473SyncBackendHostImpl::GetLastSessionSnapshot() const {
474  return last_snapshot_;
475}
476
477bool SyncBackendHostImpl::HasUnsyncedItems() const {
478  DCHECK(initialized());
479  return core_->sync_manager()->HasUnsyncedItems();
480}
481
482bool SyncBackendHostImpl::IsNigoriEnabled() const {
483  return registrar_.get() && registrar_->IsNigoriEnabled();
484}
485
486syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
487  return cached_passphrase_type_;
488}
489
490base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
491  return cached_explicit_passphrase_time_;
492}
493
494bool SyncBackendHostImpl::IsCryptographerReady(
495    const syncer::BaseTransaction* trans) const {
496  return initialized() && trans->GetCryptographer() &&
497      trans->GetCryptographer()->is_ready();
498}
499
500void 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
510void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
511  registrar_->sync_thread()->message_loop()->PostTask(
512      FROM_HERE,
513      base::Bind(
514          &SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding,
515          core_));
516}
517
518void SyncBackendHostImpl::DisableProtocolEventForwarding() {
519  registrar_->sync_thread()->message_loop()->PostTask(
520      FROM_HERE,
521      base::Bind(
522          &SyncBackendHostCore::DisableProtocolEventForwarding,
523          core_));
524}
525
526void 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
535void 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
544void 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
558void 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
564void 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
590void 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
609void 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
622void SyncBackendHostImpl::AddExperimentalTypes() {
623  CHECK(initialized());
624  syncer::Experiments experiments;
625  if (core_->sync_manager()->ReceivedExperiment(&experiments))
626    frontend_->OnExperimentsChanged(experiments);
627}
628
629void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
630  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
631  if (!frontend_)
632    return;
633
634  frontend_->OnSyncConfigureRetry();
635}
636
637void 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
676void 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
688void 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
707void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
708    const base::Closure& retry_callback) {
709  SDVLOG(1) << "Failed to complete configuration, informing of retry.";
710  retry_callback.Run();
711}
712
713void 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
724void 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
732void 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
740void 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
749void 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
758std::string SyncBackendHostImpl::GetOwnerName() const {
759  return "SyncBackendHostImpl";
760}
761
762bool 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
774void 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
788void 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
799void 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
810void SyncBackendHostImpl::NotifyEncryptionComplete() {
811  if (!frontend_)
812    return;
813
814  DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
815  frontend_->OnEncryptionComplete();
816}
817
818void 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
828void 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
840void 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
848void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
849    syncer::ModelType type,
850    const syncer::CommitCounters& counters) {
851  if (!frontend_)
852    return;
853  frontend_->OnDirectoryTypeCommitCounterUpdated(type, counters);
854}
855
856void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
857    syncer::ModelType type,
858    const syncer::UpdateCounters& counters) {
859  if (!frontend_)
860    return;
861  frontend_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
862}
863
864void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
865    syncer::ModelType type,
866    const syncer::StatusCounters& counters) {
867  if (!frontend_)
868    return;
869  frontend_->OnDirectoryTypeStatusCounterUpdated(type, counters);
870}
871
872base::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