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<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 623