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
28static const int kSaveChangesIntervalSeconds = 10;
29
30namespace syncer {
31class InternalComponentsFactory;
32}  // namespace syncer
33
34namespace {
35
36// Enums for UMAs.
37enum 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
47namespace browser_sync {
48
49DoInitializeOptions::DoInitializeOptions(
50    base::MessageLoop* sync_loop,
51    SyncBackendRegistrar* registrar,
52    const syncer::ModelSafeRoutingInfo& routing_info,
53    const std::vector<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
89DoInitializeOptions::~DoInitializeOptions() {}
90
91DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
92
93DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
94
95SyncBackendHostCore::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
110SyncBackendHostCore::~SyncBackendHostCore() {
111  DCHECK(!sync_manager_.get());
112}
113
114void 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
126void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types) {
127  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
128  sync_manager_->RefreshTypes(types);
129}
130
131void SyncBackendHostCore::OnControlTypesDownloadRetry() {
132  host_.Call(FROM_HERE,
133             &SyncBackendHostImpl::HandleControlTypesDownloadRetry);
134}
135
136void 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
222void 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
232void 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
243void 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
252void 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
264void 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
273void 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
286void 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
296void SyncBackendHostCore::OnCryptographerStateChanged(
297    syncer::Cryptographer* cryptographer) {
298  // Do nothing.
299}
300
301void 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
309void 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
320void SyncBackendHostCore::DoOnInvalidatorStateChange(
321    syncer::InvalidatorState state) {
322  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
323  sync_manager_->OnInvalidatorStateChange(state);
324}
325
326void SyncBackendHostCore::DoOnIncomingInvalidation(
327    const syncer::ObjectIdInvalidationMap& invalidation_map) {
328  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
329  sync_manager_->OnIncomingInvalidation(invalidation_map);
330}
331
332void 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
399void 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
411void SyncBackendHostCore::DoStartSyncing(
412    const syncer::ModelSafeRoutingInfo& routing_info) {
413  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
414  sync_manager_->StartSyncingNormally(routing_info);
415}
416
417void 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
425void 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
463void 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
479void SyncBackendHostCore::DoSetDecryptionPassphrase(
480    const std::string& passphrase) {
481  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
482  sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase(
483      passphrase);
484}
485
486void SyncBackendHostCore::DoEnableEncryptEverything() {
487  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
488  sync_manager_->GetEncryptionHandler()->EnableEncryptEverything();
489}
490
491void 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
512void 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
530void 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
540void 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
564void 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
588void 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
596void 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
604void 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
616void SyncBackendHostCore::SaveChanges() {
617  DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
618  sync_manager_->SaveChanges();
619}
620
621}  // namespace browser_sync
622
623