Upstream version 5.34.104.0
[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::OnEncryptedTypesChanged(
265     syncer::ModelTypeSet encrypted_types,
266     bool encrypt_everything) {
267   if (!sync_loop_)
268     return;
269   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
270   // NOTE: We're in a transaction.
271   host_.Call(
272       FROM_HERE,
273       &SyncBackendHostImpl::NotifyEncryptedTypesChanged,
274       encrypted_types, encrypt_everything);
275 }
276
277 void SyncBackendHostCore::OnEncryptionComplete() {
278   if (!sync_loop_)
279     return;
280   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
281   // NOTE: We're in a transaction.
282   host_.Call(
283       FROM_HERE,
284       &SyncBackendHostImpl::NotifyEncryptionComplete);
285 }
286
287 void SyncBackendHostCore::OnCryptographerStateChanged(
288     syncer::Cryptographer* cryptographer) {
289   // Do nothing.
290 }
291
292 void SyncBackendHostCore::OnPassphraseTypeChanged(
293     syncer::PassphraseType type, base::Time passphrase_time) {
294   host_.Call(
295       FROM_HERE,
296       &SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop,
297       type, passphrase_time);
298 }
299
300 void SyncBackendHostCore::OnActionableError(
301     const syncer::SyncProtocolError& sync_error) {
302   if (!sync_loop_)
303     return;
304   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
305   host_.Call(
306       FROM_HERE,
307       &SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop,
308       sync_error);
309 }
310
311 void SyncBackendHostCore::OnMigrationRequested(syncer::ModelTypeSet types) {
312   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
313   host_.Call(
314       FROM_HERE,
315       &SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop,
316       types);
317 }
318
319 void SyncBackendHostCore::DoOnInvalidatorStateChange(
320     syncer::InvalidatorState state) {
321   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
322   sync_manager_->OnInvalidatorStateChange(state);
323 }
324
325 void SyncBackendHostCore::DoOnIncomingInvalidation(
326     const syncer::ObjectIdInvalidationMap& invalidation_map) {
327   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
328   sync_manager_->OnIncomingInvalidation(invalidation_map);
329 }
330
331 void SyncBackendHostCore::DoInitialize(
332     scoped_ptr<DoInitializeOptions> options) {
333   DCHECK(!sync_loop_);
334   sync_loop_ = options->sync_loop;
335   DCHECK(sync_loop_);
336
337   // Finish initializing the HttpBridgeFactory.  We do this here because
338   // building the user agent may block on some platforms.
339   chrome::VersionInfo version_info;
340   options->http_bridge_factory->Init(
341       DeviceInfo::MakeUserAgentForSyncApi(version_info));
342
343   // Blow away the partial or corrupt sync data folder before doing any more
344   // initialization, if necessary.
345   if (options->delete_sync_data_folder) {
346     DeleteSyncDataFolder();
347   }
348
349   // Make sure that the directory exists before initializing the backend.
350   // If it already exists, this will do no harm.
351   if (!base::CreateDirectory(sync_data_folder_path_)) {
352     DLOG(FATAL) << "Sync Data directory creation failed.";
353   }
354
355   DCHECK(!registrar_);
356   registrar_ = options->registrar;
357   DCHECK(registrar_);
358
359   sync_manager_ = options->sync_manager_factory->CreateSyncManager(name_);
360   sync_manager_->AddObserver(this);
361   sync_manager_->Init(sync_data_folder_path_,
362                       options->event_handler,
363                       options->service_url.host() + options->service_url.path(),
364                       options->service_url.EffectiveIntPort(),
365                       options->service_url.SchemeIsSecure(),
366                       options->http_bridge_factory.Pass(),
367                       options->workers,
368                       options->extensions_activity,
369                       options->registrar /* as SyncManager::ChangeDelegate */,
370                       options->credentials,
371                       options->invalidator_client_id,
372                       options->restored_key_for_bootstrapping,
373                       options->restored_keystore_key_for_bootstrapping,
374                       options->internal_components_factory.get(),
375                       &encryptor_,
376                       options->unrecoverable_error_handler.Pass(),
377                       options->report_unrecoverable_error_function,
378                       &stop_syncing_signal_);
379
380   // |sync_manager_| may end up being NULL here in tests (in
381   // synchronous initialization mode).
382   //
383   // TODO(akalin): Fix this behavior (see http://crbug.com/140354).
384   if (sync_manager_) {
385     // Now check the command line to see if we need to simulate an
386     // unrecoverable error for testing purpose. Note the error is thrown
387     // only if the initialization succeeded. Also it makes sense to use this
388     // flag only when restarting the browser with an account already setup. If
389     // you use this before setting up the setup would not succeed as an error
390     // would be encountered.
391     if (CommandLine::ForCurrentProcess()->HasSwitch(
392             switches::kSyncThrowUnrecoverableError)) {
393       sync_manager_->ThrowUnrecoverableError();
394     }
395   }
396 }
397
398 void SyncBackendHostCore::DoUpdateCredentials(
399     const syncer::SyncCredentials& credentials) {
400   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
401   // UpdateCredentials can be called during backend initialization, possibly
402   // when backend initialization has failed but hasn't notified the UI thread
403   // yet. In that case, the sync manager may have been destroyed on the sync
404   // thread before this task was executed, so we do nothing.
405   if (sync_manager_) {
406     sync_manager_->UpdateCredentials(credentials);
407   }
408 }
409
410 void SyncBackendHostCore::DoStartSyncing(
411     const syncer::ModelSafeRoutingInfo& routing_info) {
412   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
413   sync_manager_->StartSyncingNormally(routing_info);
414 }
415
416 void SyncBackendHostCore::DoSetEncryptionPassphrase(
417     const std::string& passphrase,
418     bool is_explicit) {
419   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
420   sync_manager_->GetEncryptionHandler()->SetEncryptionPassphrase(
421       passphrase, is_explicit);
422 }
423
424 void SyncBackendHostCore::DoInitialProcessControlTypes() {
425   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
426
427   DVLOG(1) << "Initilalizing Control Types";
428
429   // Initialize encryption.
430   sync_manager_->GetEncryptionHandler()->Init();
431
432   // Note: experiments are currently handled via SBH::AddExperimentalTypes,
433   // which is called at the end of every sync cycle.
434   // TODO(zea): eventually add an experiment handler and initialize it here.
435
436   if (!sync_manager_->GetUserShare()) {  // NULL in some tests.
437     DVLOG(1) << "Skipping initialization of DeviceInfo";
438     host_.Call(
439         FROM_HERE,
440         &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
441     return;
442   }
443
444   if (!sync_manager_->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) {
445     LOG(ERROR) << "Failed to download control types";
446     host_.Call(
447         FROM_HERE,
448         &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
449     return;
450   }
451
452   // Initialize device info. This is asynchronous on some platforms, so we
453   // provide a callback for when it finishes.
454   synced_device_tracker_.reset(
455       new SyncedDeviceTracker(sync_manager_->GetUserShare(),
456                               sync_manager_->cache_guid()));
457   synced_device_tracker_->InitLocalDeviceInfo(
458       base::Bind(&SyncBackendHostCore::DoFinishInitialProcessControlTypes,
459                  weak_ptr_factory_.GetWeakPtr()));
460 }
461
462 void SyncBackendHostCore::DoFinishInitialProcessControlTypes() {
463   registrar_->ActivateDataType(syncer::DEVICE_INFO,
464                                syncer::GROUP_PASSIVE,
465                                synced_device_tracker_.get(),
466                                sync_manager_->GetUserShare());
467
468   host_.Call(
469       FROM_HERE,
470       &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop,
471       js_backend_,
472       debug_info_listener_);
473
474   js_backend_.Reset();
475   debug_info_listener_.Reset();
476 }
477
478 void SyncBackendHostCore::DoSetDecryptionPassphrase(
479     const std::string& passphrase) {
480   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
481   sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase(
482       passphrase);
483 }
484
485 void SyncBackendHostCore::DoEnableEncryptEverything() {
486   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
487   sync_manager_->GetEncryptionHandler()->EnableEncryptEverything();
488 }
489
490 void SyncBackendHostCore::ShutdownOnUIThread() {
491   // This will cut short any blocking network tasks, cut short any in-progress
492   // sync cycles, and prevent the creation of new blocking network tasks and new
493   // sync cycles.  If there was an in-progress network request, it would have
494   // had a reference to the RequestContextGetter.  This reference will be
495   // dropped by the time this function returns.
496   //
497   // It is safe to call this even if Sync's backend classes have not been
498   // initialized yet.  Those classes will receive the message when the sync
499   // thread finally getes around to constructing them.
500   stop_syncing_signal_.Signal();
501
502   // This will drop the HttpBridgeFactory's reference to the
503   // RequestContextGetter.  Once this has been called, the HttpBridgeFactory can
504   // no longer be used to create new HttpBridge instances.  We can get away with
505   // this because the stop_syncing_signal_ has already been signalled, which
506   // guarantees that the ServerConnectionManager will no longer attempt to
507   // create new connections.
508   release_request_context_signal_.Signal();
509 }
510
511 void SyncBackendHostCore::DoShutdown(bool sync_disabled) {
512   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
513
514   // It's safe to do this even if the type was never activated.
515   registrar_->DeactivateDataType(syncer::DEVICE_INFO);
516   synced_device_tracker_.reset();
517
518   DoDestroySyncManager();
519
520   registrar_ = NULL;
521
522   if (sync_disabled)
523     DeleteSyncDataFolder();
524
525   host_.Reset();
526   weak_ptr_factory_.InvalidateWeakPtrs();
527 }
528
529 void SyncBackendHostCore::DoDestroySyncManager() {
530   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
531   if (sync_manager_) {
532     save_changes_timer_.reset();
533     sync_manager_->RemoveObserver(this);
534     sync_manager_->ShutdownOnSyncThread();
535     sync_manager_.reset();
536   }
537 }
538
539 void SyncBackendHostCore::DoConfigureSyncer(
540     syncer::ConfigureReason reason,
541     const DoConfigureSyncerTypes& config_types,
542     const syncer::ModelSafeRoutingInfo routing_info,
543     const base::Callback<void(syncer::ModelTypeSet,
544                               syncer::ModelTypeSet)>& ready_task,
545     const base::Closure& retry_callback) {
546   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
547   sync_manager_->ConfigureSyncer(
548       reason,
549       config_types.to_download,
550       config_types.to_purge,
551       config_types.to_journal,
552       config_types.to_unapply,
553       routing_info,
554       base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes,
555                  weak_ptr_factory_.GetWeakPtr(),
556                  config_types.to_download,
557                  ready_task),
558       base::Bind(&SyncBackendHostCore::DoRetryConfiguration,
559                  weak_ptr_factory_.GetWeakPtr(),
560                  retry_callback));
561 }
562
563 void SyncBackendHostCore::DoFinishConfigureDataTypes(
564     syncer::ModelTypeSet types_to_config,
565     const base::Callback<void(syncer::ModelTypeSet,
566                               syncer::ModelTypeSet)>& ready_task) {
567   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
568
569   // Update the enabled types for the bridge and sync manager.
570   syncer::ModelSafeRoutingInfo routing_info;
571   registrar_->GetModelSafeRoutingInfo(&routing_info);
572   syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
573   enabled_types.RemoveAll(syncer::ProxyTypes());
574
575   const syncer::ModelTypeSet failed_configuration_types =
576       Difference(types_to_config, sync_manager_->InitialSyncEndedTypes());
577   const syncer::ModelTypeSet succeeded_configuration_types =
578       Difference(types_to_config, failed_configuration_types);
579   host_.Call(FROM_HERE,
580              &SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop,
581              enabled_types,
582              succeeded_configuration_types,
583              failed_configuration_types,
584              ready_task);
585 }
586
587 void SyncBackendHostCore::DoRetryConfiguration(
588     const base::Closure& retry_callback) {
589   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
590   host_.Call(FROM_HERE,
591              &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop,
592              retry_callback);
593 }
594
595 void SyncBackendHostCore::DeleteSyncDataFolder() {
596   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
597   if (base::DirectoryExists(sync_data_folder_path_)) {
598     if (!base::DeleteFile(sync_data_folder_path_, true))
599       SLOG(DFATAL) << "Could not delete the Sync Data folder.";
600   }
601 }
602
603 void SyncBackendHostCore::StartSavingChanges() {
604   // We may already be shut down.
605   if (!sync_loop_)
606     return;
607   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
608   DCHECK(!save_changes_timer_.get());
609   save_changes_timer_.reset(new base::RepeatingTimer<SyncBackendHostCore>());
610   save_changes_timer_->Start(FROM_HERE,
611       base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
612       this, &SyncBackendHostCore::SaveChanges);
613 }
614
615 void SyncBackendHostCore::SaveChanges() {
616   DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
617   sync_manager_->SaveChanges();
618 }
619
620 }  // namespace browser_sync
621