8d7d4a7ce4749844869833b104e7b5214de3fdbd
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / sync_backend_host_core.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_core.h"
6
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/sync/glue/device_info.h"
11 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
12 #include "chrome/browser/sync/glue/synced_device_tracker.h"
13 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/chrome_version_info.h"
15 #include "sync/internal_api/public/http_post_provider_factory.h"
16 #include "sync/internal_api/public/internal_components_factory.h"
17 #include "sync/internal_api/public/sessions/sync_session_snapshot.h"
18 #include "sync/internal_api/public/sync_manager.h"
19 #include "sync/internal_api/public/sync_manager_factory.h"
20
21 // Helper macros to log with the syncer thread name; useful when there
22 // are multiple syncers involved.
23
24 #define SLOG(severity) LOG(severity) << name_ << ": "
25
26 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
27
28 static const int kSaveChangesIntervalSeconds = 10;
29
30 namespace syncer {
31 class InternalComponentsFactory;
32 }  // namespace syncer
33
34 namespace {
35
36 // Enums for UMAs.
37 enum SyncBackendInitState {
38     SETUP_COMPLETED_FOUND_RESTORED_TYPES = 0,
39     SETUP_COMPLETED_NO_RESTORED_TYPES,
40     FIRST_SETUP_NO_RESTORED_TYPES,
41     FIRST_SETUP_RESTORED_TYPES,
42     SYNC_BACKEND_INIT_STATE_COUNT
43 };
44
45 }  // namespace
46
47 namespace browser_sync {
48
49 DoInitializeOptions::DoInitializeOptions(
50     base::MessageLoop* sync_loop,
51     SyncBackendRegistrar* registrar,
52     const syncer::ModelSafeRoutingInfo& routing_info,
53     const std::vector<scoped_refptr<syncer::ModelSafeWorker> >& workers,
54     const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity,
55     const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
56     const GURL& service_url,
57     scoped_ptr<syncer::HttpPostProviderFactory> http_bridge_factory,
58     const syncer::SyncCredentials& credentials,
59     const std::string& invalidator_client_id,
60     scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
61     bool delete_sync_data_folder,
62     const std::string& restored_key_for_bootstrapping,
63     const std::string& restored_keystore_key_for_bootstrapping,
64     scoped_ptr<syncer::InternalComponentsFactory> internal_components_factory,
65     scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
66     syncer::ReportUnrecoverableErrorFunction
67         report_unrecoverable_error_function)
68     : sync_loop(sync_loop),
69       registrar(registrar),
70       routing_info(routing_info),
71       workers(workers),
72       extensions_activity(extensions_activity),
73       event_handler(event_handler),
74       service_url(service_url),
75       http_bridge_factory(http_bridge_factory.Pass()),
76       credentials(credentials),
77       invalidator_client_id(invalidator_client_id),
78       sync_manager_factory(sync_manager_factory.Pass()),
79       delete_sync_data_folder(delete_sync_data_folder),
80       restored_key_for_bootstrapping(restored_key_for_bootstrapping),
81       restored_keystore_key_for_bootstrapping(
82           restored_keystore_key_for_bootstrapping),
83       internal_components_factory(internal_components_factory.Pass()),
84       unrecoverable_error_handler(unrecoverable_error_handler.Pass()),
85       report_unrecoverable_error_function(
86           report_unrecoverable_error_function) {
87 }
88
89 DoInitializeOptions::~DoInitializeOptions() {}
90
91 DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
92
93 DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
94
95 SyncBackendHostCore::SyncBackendHostCore(
96     const std::string& name,
97     const base::FilePath& sync_data_folder_path,
98     bool has_sync_setup_completed,
99     const base::WeakPtr<SyncBackendHostImpl>& backend)
100     : name_(name),
101       sync_data_folder_path_(sync_data_folder_path),
102       host_(backend),
103       sync_loop_(NULL),
104       registrar_(NULL),
105       has_sync_setup_completed_(has_sync_setup_completed),
106       weak_ptr_factory_(this) {
107   DCHECK(backend.get());
108 }
109
110 SyncBackendHostCore::~SyncBackendHostCore() {
111   DCHECK(!sync_manager_.get());
112 }
113
114 void SyncBackendHostCore::OnSyncCycleCompleted(
115     const syncer::sessions::SyncSessionSnapshot& snapshot) {
116   if (!sync_loop_)
117     return;
118   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
119
120   host_.Call(
121       FROM_HERE,
122       &SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop,
123       snapshot);
124 }
125
126 void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types) {
127   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
128   sync_manager_->RefreshTypes(types);
129 }
130
131 void SyncBackendHostCore::OnControlTypesDownloadRetry() {
132   host_.Call(FROM_HERE,
133              &SyncBackendHostImpl::HandleControlTypesDownloadRetry);
134 }
135
136 void SyncBackendHostCore::OnInitializationComplete(
137     const syncer::WeakHandle<syncer::JsBackend>& js_backend,
138     const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
139         debug_info_listener,
140     bool success,
141     const syncer::ModelTypeSet restored_types) {
142   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
143
144   if (!success) {
145     DoDestroySyncManager();
146     host_.Call(FROM_HERE,
147                &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
148     return;
149   }
150
151   // Register for encryption related changes now. We have to do this before
152   // the initializing downloading control types or initializing the encryption
153   // handler in order to receive notifications triggered during encryption
154   // startup.
155   sync_manager_->GetEncryptionHandler()->AddObserver(this);
156
157   // Sync manager initialization is complete, so we can schedule recurring
158   // SaveChanges.
159   sync_loop_->PostTask(FROM_HERE,
160                        base::Bind(&SyncBackendHostCore::StartSavingChanges,
161                                   weak_ptr_factory_.GetWeakPtr()));
162
163   // Hang on to these for a while longer.  We're not ready to hand them back to
164   // the UI thread yet.
165   js_backend_ = js_backend;
166   debug_info_listener_ = debug_info_listener;
167
168   // Track whether or not sync DB and preferences were in sync.
169   SyncBackendInitState backend_init_state;
170   if (has_sync_setup_completed_ && !restored_types.Empty()) {
171     backend_init_state = SETUP_COMPLETED_FOUND_RESTORED_TYPES;
172   } else if (has_sync_setup_completed_ && restored_types.Empty()) {
173     backend_init_state = SETUP_COMPLETED_NO_RESTORED_TYPES;
174   } else if (!has_sync_setup_completed_ && restored_types.Empty()) {
175     backend_init_state = FIRST_SETUP_NO_RESTORED_TYPES;
176   } else { // (!has_sync_setup_completed_ && !restored_types.Empty())
177     backend_init_state = FIRST_SETUP_RESTORED_TYPES;
178   }
179
180   UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState",
181                             backend_init_state,
182                             SYNC_BACKEND_INIT_STATE_COUNT);
183
184   // Before proceeding any further, we need to download the control types and
185   // purge any partial data (ie. data downloaded for a type that was on its way
186   // to being initially synced, but didn't quite make it.).  The following
187   // configure cycle will take care of this.  It depends on the registrar state
188   // which we initialize below to ensure that we don't perform any downloads if
189   // all control types have already completed their initial sync.
190   registrar_->SetInitialTypes(restored_types);
191
192   syncer::ConfigureReason reason =
193       restored_types.Empty() ?
194        syncer::CONFIGURE_REASON_NEW_CLIENT :
195        syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
196
197   syncer::ModelTypeSet new_control_types = registrar_->ConfigureDataTypes(
198       syncer::ControlTypes(), syncer::ModelTypeSet());
199   syncer::ModelSafeRoutingInfo routing_info;
200   registrar_->GetModelSafeRoutingInfo(&routing_info);
201   SDVLOG(1) << "Control Types "
202             << syncer::ModelTypeSetToString(new_control_types)
203             << " added; calling ConfigureSyncer";
204
205   syncer::ModelTypeSet types_to_purge =
206       syncer::Difference(syncer::ModelTypeSet::All(),
207                          GetRoutingInfoTypes(routing_info));
208
209   sync_manager_->ConfigureSyncer(
210       reason,
211       new_control_types,
212       types_to_purge,
213       syncer::ModelTypeSet(),
214       syncer::ModelTypeSet(),
215       routing_info,
216       base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes,
217                  weak_ptr_factory_.GetWeakPtr()),
218       base::Bind(&SyncBackendHostCore::OnControlTypesDownloadRetry,
219                  weak_ptr_factory_.GetWeakPtr()));
220 }
221
222 void SyncBackendHostCore::OnConnectionStatusChange(
223     syncer::ConnectionStatus status) {
224   if (!sync_loop_)
225     return;
226   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
227   host_.Call(
228       FROM_HERE,
229       &SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop, status);
230 }
231
232 void SyncBackendHostCore::OnPassphraseRequired(
233     syncer::PassphraseRequiredReason reason,
234     const sync_pb::EncryptedData& pending_keys) {
235   if (!sync_loop_)
236     return;
237   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
238   host_.Call(
239       FROM_HERE,
240       &SyncBackendHostImpl::NotifyPassphraseRequired, reason, pending_keys);
241 }
242
243 void SyncBackendHostCore::OnPassphraseAccepted() {
244   if (!sync_loop_)
245     return;
246   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
247   host_.Call(
248       FROM_HERE,
249       &SyncBackendHostImpl::NotifyPassphraseAccepted);
250 }
251
252 void SyncBackendHostCore::OnBootstrapTokenUpdated(
253     const std::string& bootstrap_token,
254     syncer::BootstrapTokenType type) {
255   if (!sync_loop_)
256     return;
257   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
258   host_.Call(FROM_HERE,
259              &SyncBackendHostImpl::PersistEncryptionBootstrapToken,
260              bootstrap_token,
261              type);
262 }
263
264 void SyncBackendHostCore::OnStopSyncingPermanently() {
265   if (!sync_loop_)
266     return;
267   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
268   host_.Call(
269       FROM_HERE,
270       &SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop);
271 }
272
273 void SyncBackendHostCore::OnEncryptedTypesChanged(
274     syncer::ModelTypeSet encrypted_types,
275     bool encrypt_everything) {
276   if (!sync_loop_)
277     return;
278   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
279   // NOTE: We're in a transaction.
280   host_.Call(
281       FROM_HERE,
282       &SyncBackendHostImpl::NotifyEncryptedTypesChanged,
283       encrypted_types, encrypt_everything);
284 }
285
286 void SyncBackendHostCore::OnEncryptionComplete() {
287   if (!sync_loop_)
288     return;
289   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
290   // NOTE: We're in a transaction.
291   host_.Call(
292       FROM_HERE,
293       &SyncBackendHostImpl::NotifyEncryptionComplete);
294 }
295
296 void SyncBackendHostCore::OnCryptographerStateChanged(
297     syncer::Cryptographer* cryptographer) {
298   // Do nothing.
299 }
300
301 void SyncBackendHostCore::OnPassphraseTypeChanged(
302     syncer::PassphraseType type, base::Time passphrase_time) {
303   host_.Call(
304       FROM_HERE,
305       &SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop,
306       type, passphrase_time);
307 }
308
309 void SyncBackendHostCore::OnActionableError(
310     const syncer::SyncProtocolError& sync_error) {
311   if (!sync_loop_)
312     return;
313   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
314   host_.Call(
315       FROM_HERE,
316       &SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop,
317       sync_error);
318 }
319
320 void SyncBackendHostCore::DoOnInvalidatorStateChange(
321     syncer::InvalidatorState state) {
322   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
323   sync_manager_->OnInvalidatorStateChange(state);
324 }
325
326 void SyncBackendHostCore::DoOnIncomingInvalidation(
327     const syncer::ObjectIdInvalidationMap& invalidation_map) {
328   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
329   sync_manager_->OnIncomingInvalidation(invalidation_map);
330 }
331
332 void SyncBackendHostCore::DoInitialize(
333     scoped_ptr<DoInitializeOptions> options) {
334   DCHECK(!sync_loop_);
335   sync_loop_ = options->sync_loop;
336   DCHECK(sync_loop_);
337
338   // Finish initializing the HttpBridgeFactory.  We do this here because
339   // building the user agent may block on some platforms.
340   chrome::VersionInfo version_info;
341   options->http_bridge_factory->Init(
342       DeviceInfo::MakeUserAgentForSyncApi(version_info));
343
344   // Blow away the partial or corrupt sync data folder before doing any more
345   // initialization, if necessary.
346   if (options->delete_sync_data_folder) {
347     DeleteSyncDataFolder();
348   }
349
350   // Make sure that the directory exists before initializing the backend.
351   // If it already exists, this will do no harm.
352   if (!base::CreateDirectory(sync_data_folder_path_)) {
353     DLOG(FATAL) << "Sync Data directory creation failed.";
354   }
355
356   DCHECK(!registrar_);
357   registrar_ = options->registrar;
358   DCHECK(registrar_);
359
360   sync_manager_ = options->sync_manager_factory->CreateSyncManager(name_);
361   sync_manager_->AddObserver(this);
362   sync_manager_->Init(sync_data_folder_path_,
363                       options->event_handler,
364                       options->service_url.host() + options->service_url.path(),
365                       options->service_url.EffectiveIntPort(),
366                       options->service_url.SchemeIsSecure(),
367                       options->http_bridge_factory.Pass(),
368                       options->workers,
369                       options->extensions_activity,
370                       options->registrar /* as SyncManager::ChangeDelegate */,
371                       options->credentials,
372                       options->invalidator_client_id,
373                       options->restored_key_for_bootstrapping,
374                       options->restored_keystore_key_for_bootstrapping,
375                       options->internal_components_factory.get(),
376                       &encryptor_,
377                       options->unrecoverable_error_handler.Pass(),
378                       options->report_unrecoverable_error_function,
379                       &stop_syncing_signal_);
380
381   // |sync_manager_| may end up being NULL here in tests (in
382   // synchronous initialization mode).
383   //
384   // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
385   if (sync_manager_) {
386     // Now check the command line to see if we need to simulate an
387     // unrecoverable error for testing purpose. Note the error is thrown
388     // only if the initialization succeeded. Also it makes sense to use this
389     // flag only when restarting the browser with an account already setup. If
390     // you use this before setting up the setup would not succeed as an error
391     // would be encountered.
392     if (CommandLine::ForCurrentProcess()->HasSwitch(
393             switches::kSyncThrowUnrecoverableError)) {
394       sync_manager_->ThrowUnrecoverableError();
395     }
396   }
397 }
398
399 void SyncBackendHostCore::DoUpdateCredentials(
400     const syncer::SyncCredentials& credentials) {
401   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
402   // UpdateCredentials can be called during backend initialization, possibly
403   // when backend initialization has failed but hasn't notified the UI thread
404   // yet. In that case, the sync manager may have been destroyed on the sync
405   // thread before this task was executed, so we do nothing.
406   if (sync_manager_) {
407     sync_manager_->UpdateCredentials(credentials);
408   }
409 }
410
411 void SyncBackendHostCore::DoStartSyncing(
412     const syncer::ModelSafeRoutingInfo& routing_info) {
413   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
414   sync_manager_->StartSyncingNormally(routing_info);
415 }
416
417 void SyncBackendHostCore::DoSetEncryptionPassphrase(
418     const std::string& passphrase,
419     bool is_explicit) {
420   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
421   sync_manager_->GetEncryptionHandler()->SetEncryptionPassphrase(
422       passphrase, is_explicit);
423 }
424
425 void SyncBackendHostCore::DoInitialProcessControlTypes() {
426   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
427
428   DVLOG(1) << "Initilalizing Control Types";
429
430   // Initialize encryption.
431   sync_manager_->GetEncryptionHandler()->Init();
432
433   // Note: experiments are currently handled via SBH::AddExperimentalTypes,
434   // which is called at the end of every sync cycle.
435   // TODO(zea): eventually add an experiment handler and initialize it here.
436
437   if (!sync_manager_->GetUserShare()) {  // NULL in some tests.
438     DVLOG(1) << "Skipping initialization of DeviceInfo";
439     host_.Call(
440         FROM_HERE,
441         &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
442     return;
443   }
444
445   if (!sync_manager_->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) {
446     LOG(ERROR) << "Failed to download control types";
447     host_.Call(
448         FROM_HERE,
449         &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
450     return;
451   }
452
453   // Initialize device info. This is asynchronous on some platforms, so we
454   // provide a callback for when it finishes.
455   synced_device_tracker_.reset(
456       new SyncedDeviceTracker(sync_manager_->GetUserShare(),
457                               sync_manager_->cache_guid()));
458   synced_device_tracker_->InitLocalDeviceInfo(
459       base::Bind(&SyncBackendHostCore::DoFinishInitialProcessControlTypes,
460                  weak_ptr_factory_.GetWeakPtr()));
461 }
462
463 void SyncBackendHostCore::DoFinishInitialProcessControlTypes() {
464   registrar_->ActivateDataType(syncer::DEVICE_INFO,
465                                syncer::GROUP_PASSIVE,
466                                synced_device_tracker_.get(),
467                                sync_manager_->GetUserShare());
468
469   host_.Call(
470       FROM_HERE,
471       &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop,
472       js_backend_,
473       debug_info_listener_);
474
475   js_backend_.Reset();
476   debug_info_listener_.Reset();
477 }
478
479 void SyncBackendHostCore::DoSetDecryptionPassphrase(
480     const std::string& passphrase) {
481   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
482   sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase(
483       passphrase);
484 }
485
486 void SyncBackendHostCore::DoEnableEncryptEverything() {
487   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
488   sync_manager_->GetEncryptionHandler()->EnableEncryptEverything();
489 }
490
491 void SyncBackendHostCore::ShutdownOnUIThread() {
492   // This will cut short any blocking network tasks, cut short any in-progress
493   // sync cycles, and prevent the creation of new blocking network tasks and new
494   // sync cycles.  If there was an in-progress network request, it would have
495   // had a reference to the RequestContextGetter.  This reference will be
496   // dropped by the time this function returns.
497   //
498   // It is safe to call this even if Sync's backend classes have not been
499   // initialized yet.  Those classes will receive the message when the sync
500   // thread finally getes around to constructing them.
501   stop_syncing_signal_.Signal();
502
503   // This will drop the HttpBridgeFactory's reference to the
504   // RequestContextGetter.  Once this has been called, the HttpBridgeFactory can
505   // no longer be used to create new HttpBridge instances.  We can get away with
506   // this because the stop_syncing_signal_ has already been signalled, which
507   // guarantees that the ServerConnectionManager will no longer attempt to
508   // create new connections.
509   release_request_context_signal_.Signal();
510 }
511
512 void SyncBackendHostCore::DoShutdown(bool sync_disabled) {
513   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
514
515   // It's safe to do this even if the type was never activated.
516   registrar_->DeactivateDataType(syncer::DEVICE_INFO);
517   synced_device_tracker_.reset();
518
519   DoDestroySyncManager();
520
521   registrar_ = NULL;
522
523   if (sync_disabled)
524     DeleteSyncDataFolder();
525
526   host_.Reset();
527   weak_ptr_factory_.InvalidateWeakPtrs();
528 }
529
530 void SyncBackendHostCore::DoDestroySyncManager() {
531   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
532   if (sync_manager_) {
533     save_changes_timer_.reset();
534     sync_manager_->RemoveObserver(this);
535     sync_manager_->ShutdownOnSyncThread();
536     sync_manager_.reset();
537   }
538 }
539
540 void SyncBackendHostCore::DoConfigureSyncer(
541     syncer::ConfigureReason reason,
542     const DoConfigureSyncerTypes& config_types,
543     const syncer::ModelSafeRoutingInfo routing_info,
544     const base::Callback<void(syncer::ModelTypeSet,
545                               syncer::ModelTypeSet)>& ready_task,
546     const base::Closure& retry_callback) {
547   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
548   sync_manager_->ConfigureSyncer(
549       reason,
550       config_types.to_download,
551       config_types.to_purge,
552       config_types.to_journal,
553       config_types.to_unapply,
554       routing_info,
555       base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes,
556                  weak_ptr_factory_.GetWeakPtr(),
557                  config_types.to_download,
558                  ready_task),
559       base::Bind(&SyncBackendHostCore::DoRetryConfiguration,
560                  weak_ptr_factory_.GetWeakPtr(),
561                  retry_callback));
562 }
563
564 void SyncBackendHostCore::DoFinishConfigureDataTypes(
565     syncer::ModelTypeSet types_to_config,
566     const base::Callback<void(syncer::ModelTypeSet,
567                               syncer::ModelTypeSet)>& ready_task) {
568   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
569
570   // Update the enabled types for the bridge and sync manager.
571   syncer::ModelSafeRoutingInfo routing_info;
572   registrar_->GetModelSafeRoutingInfo(&routing_info);
573   syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
574   enabled_types.RemoveAll(syncer::ProxyTypes());
575
576   const syncer::ModelTypeSet failed_configuration_types =
577       Difference(types_to_config, sync_manager_->InitialSyncEndedTypes());
578   const syncer::ModelTypeSet succeeded_configuration_types =
579       Difference(types_to_config, failed_configuration_types);
580   host_.Call(FROM_HERE,
581              &SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop,
582              enabled_types,
583              succeeded_configuration_types,
584              failed_configuration_types,
585              ready_task);
586 }
587
588 void SyncBackendHostCore::DoRetryConfiguration(
589     const base::Closure& retry_callback) {
590   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
591   host_.Call(FROM_HERE,
592              &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop,
593              retry_callback);
594 }
595
596 void SyncBackendHostCore::DeleteSyncDataFolder() {
597   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
598   if (base::DirectoryExists(sync_data_folder_path_)) {
599     if (!base::DeleteFile(sync_data_folder_path_, true))
600       SLOG(DFATAL) << "Could not delete the Sync Data folder.";
601   }
602 }
603
604 void SyncBackendHostCore::StartSavingChanges() {
605   // We may already be shut down.
606   if (!sync_loop_)
607     return;
608   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
609   DCHECK(!save_changes_timer_.get());
610   save_changes_timer_.reset(new base::RepeatingTimer<SyncBackendHostCore>());
611   save_changes_timer_->Start(FROM_HERE,
612       base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
613       this, &SyncBackendHostCore::SaveChanges);
614 }
615
616 void SyncBackendHostCore::SaveChanges() {
617   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
618   sync_manager_->SaveChanges();
619 }
620
621 }  // namespace browser_sync
622