Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / glue / sync_backend_host_core.cc
blob8d7d4a7ce4749844869833b104e7b5214de3fdbd
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.
5 #include "chrome/browser/sync/glue/sync_backend_host_core.h"
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"
21 // Helper macros to log with the syncer thread name; useful when there
22 // are multiple syncers involved.
24 #define SLOG(severity) LOG(severity) << name_ << ": "
26 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": "
28 static const int kSaveChangesIntervalSeconds = 10;
30 namespace syncer {
31 class InternalComponentsFactory;
32 } // namespace syncer
34 namespace {
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
45 } // namespace
47 namespace browser_sync {
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) {
89 DoInitializeOptions::~DoInitializeOptions() {}
91 DoConfigureSyncerTypes::DoConfigureSyncerTypes() {}
93 DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {}
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());
110 SyncBackendHostCore::~SyncBackendHostCore() {
111 DCHECK(!sync_manager_.get());
114 void SyncBackendHostCore::OnSyncCycleCompleted(
115 const syncer::sessions::SyncSessionSnapshot& snapshot) {
116 if (!sync_loop_)
117 return;
118 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
120 host_.Call(
121 FROM_HERE,
122 &SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop,
123 snapshot);
126 void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types) {
127 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
128 sync_manager_->RefreshTypes(types);
131 void SyncBackendHostCore::OnControlTypesDownloadRetry() {
132 host_.Call(FROM_HERE,
133 &SyncBackendHostImpl::HandleControlTypesDownloadRetry);
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_);
144 if (!success) {
145 DoDestroySyncManager();
146 host_.Call(FROM_HERE,
147 &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop);
148 return;
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);
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()));
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;
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;
180 UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState",
181 backend_init_state,
182 SYNC_BACKEND_INIT_STATE_COUNT);
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);
192 syncer::ConfigureReason reason =
193 restored_types.Empty() ?
194 syncer::CONFIGURE_REASON_NEW_CLIENT :
195 syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
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";
205 syncer::ModelTypeSet types_to_purge =
206 syncer::Difference(syncer::ModelTypeSet::All(),
207 GetRoutingInfoTypes(routing_info));
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()));
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);
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);
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);
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);
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);
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);
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);
296 void SyncBackendHostCore::OnCryptographerStateChanged(
297 syncer::Cryptographer* cryptographer) {
298 // Do nothing.
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);
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);
320 void SyncBackendHostCore::DoOnInvalidatorStateChange(
321 syncer::InvalidatorState state) {
322 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
323 sync_manager_->OnInvalidatorStateChange(state);
326 void SyncBackendHostCore::DoOnIncomingInvalidation(
327 const syncer::ObjectIdInvalidationMap& invalidation_map) {
328 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
329 sync_manager_->OnIncomingInvalidation(invalidation_map);
332 void SyncBackendHostCore::DoInitialize(
333 scoped_ptr<DoInitializeOptions> options) {
334 DCHECK(!sync_loop_);
335 sync_loop_ = options->sync_loop;
336 DCHECK(sync_loop_);
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));
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();
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.";
356 DCHECK(!registrar_);
357 registrar_ = options->registrar;
358 DCHECK(registrar_);
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_);
381 // |sync_manager_| may end up being NULL here in tests (in
382 // synchronous initialization mode).
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();
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);
411 void SyncBackendHostCore::DoStartSyncing(
412 const syncer::ModelSafeRoutingInfo& routing_info) {
413 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
414 sync_manager_->StartSyncingNormally(routing_info);
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);
425 void SyncBackendHostCore::DoInitialProcessControlTypes() {
426 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
428 DVLOG(1) << "Initilalizing Control Types";
430 // Initialize encryption.
431 sync_manager_->GetEncryptionHandler()->Init();
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.
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;
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;
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()));
463 void SyncBackendHostCore::DoFinishInitialProcessControlTypes() {
464 registrar_->ActivateDataType(syncer::DEVICE_INFO,
465 syncer::GROUP_PASSIVE,
466 synced_device_tracker_.get(),
467 sync_manager_->GetUserShare());
469 host_.Call(
470 FROM_HERE,
471 &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop,
472 js_backend_,
473 debug_info_listener_);
475 js_backend_.Reset();
476 debug_info_listener_.Reset();
479 void SyncBackendHostCore::DoSetDecryptionPassphrase(
480 const std::string& passphrase) {
481 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
482 sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase(
483 passphrase);
486 void SyncBackendHostCore::DoEnableEncryptEverything() {
487 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
488 sync_manager_->GetEncryptionHandler()->EnableEncryptEverything();
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.
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();
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();
512 void SyncBackendHostCore::DoShutdown(bool sync_disabled) {
513 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
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();
519 DoDestroySyncManager();
521 registrar_ = NULL;
523 if (sync_disabled)
524 DeleteSyncDataFolder();
526 host_.Reset();
527 weak_ptr_factory_.InvalidateWeakPtrs();
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();
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));
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_);
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());
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);
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);
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.";
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);
616 void SyncBackendHostCore::SaveChanges() {
617 DCHECK_EQ(base::MessageLoop::current(), sync_loop_);
618 sync_manager_->SaveChanges();
621 } // namespace browser_sync