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