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