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