Index: chrome/browser/sync/glue/sync_backend_host_core.cc |
diff --git a/chrome/browser/sync/glue/sync_backend_host_core.cc b/chrome/browser/sync/glue/sync_backend_host_core.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..50a8159bc43ef08e0c1d58255a63e97e908f4eff |
--- /dev/null |
+++ b/chrome/browser/sync/glue/sync_backend_host_core.cc |
@@ -0,0 +1,622 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/sync/glue/sync_backend_host_core.h" |
+ |
+#include "base/command_line.h" |
+#include "base/file_util.h" |
+#include "base/metrics/histogram.h" |
+#include "chrome/browser/sync/glue/device_info.h" |
+#include "chrome/browser/sync/glue/sync_backend_registrar.h" |
+#include "chrome/browser/sync/glue/synced_device_tracker.h" |
+#include "chrome/common/chrome_switches.h" |
+#include "chrome/common/chrome_version_info.h" |
+#include "sync/internal_api/public/http_post_provider_factory.h" |
+#include "sync/internal_api/public/internal_components_factory.h" |
+#include "sync/internal_api/public/sessions/sync_session_snapshot.h" |
+#include "sync/internal_api/public/sync_manager.h" |
+#include "sync/internal_api/public/sync_manager_factory.h" |
+ |
+// Helper macros to log with the syncer thread name; useful when there |
+// are multiple syncers involved. |
+ |
+#define SLOG(severity) LOG(severity) << name_ << ": " |
+ |
+#define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": " |
+ |
+static const int kSaveChangesIntervalSeconds = 10; |
+ |
+namespace syncer { |
+class InternalComponentsFactory; |
+} // namespace syncer |
+ |
+namespace { |
+ |
+// Enums for UMAs. |
+enum SyncBackendInitState { |
+ SETUP_COMPLETED_FOUND_RESTORED_TYPES = 0, |
+ SETUP_COMPLETED_NO_RESTORED_TYPES, |
+ FIRST_SETUP_NO_RESTORED_TYPES, |
+ FIRST_SETUP_RESTORED_TYPES, |
+ SYNC_BACKEND_INIT_STATE_COUNT |
+}; |
+ |
+} // namespace |
+ |
+namespace browser_sync { |
+ |
+DoInitializeOptions::DoInitializeOptions( |
+ base::MessageLoop* sync_loop, |
+ SyncBackendRegistrar* registrar, |
+ const syncer::ModelSafeRoutingInfo& routing_info, |
+ const std::vector<syncer::ModelSafeWorker*>& workers, |
+ const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity, |
+ const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, |
+ const GURL& service_url, |
+ scoped_ptr<syncer::HttpPostProviderFactory> http_bridge_factory, |
+ const syncer::SyncCredentials& credentials, |
+ const std::string& invalidator_client_id, |
+ scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory, |
+ bool delete_sync_data_folder, |
+ const std::string& restored_key_for_bootstrapping, |
+ const std::string& restored_keystore_key_for_bootstrapping, |
+ scoped_ptr<syncer::InternalComponentsFactory> internal_components_factory, |
+ scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler, |
+ syncer::ReportUnrecoverableErrorFunction |
+ report_unrecoverable_error_function) |
+ : sync_loop(sync_loop), |
+ registrar(registrar), |
+ routing_info(routing_info), |
+ workers(workers), |
+ extensions_activity(extensions_activity), |
+ event_handler(event_handler), |
+ service_url(service_url), |
+ http_bridge_factory(http_bridge_factory.Pass()), |
+ credentials(credentials), |
+ invalidator_client_id(invalidator_client_id), |
+ sync_manager_factory(sync_manager_factory.Pass()), |
+ delete_sync_data_folder(delete_sync_data_folder), |
+ restored_key_for_bootstrapping(restored_key_for_bootstrapping), |
+ restored_keystore_key_for_bootstrapping( |
+ restored_keystore_key_for_bootstrapping), |
+ internal_components_factory(internal_components_factory.Pass()), |
+ unrecoverable_error_handler(unrecoverable_error_handler.Pass()), |
+ report_unrecoverable_error_function( |
+ report_unrecoverable_error_function) { |
+} |
+ |
+DoInitializeOptions::~DoInitializeOptions() {} |
+ |
+DoConfigureSyncerTypes::DoConfigureSyncerTypes() {} |
+ |
+DoConfigureSyncerTypes::~DoConfigureSyncerTypes() {} |
+ |
+SyncBackendHostCore::SyncBackendHostCore( |
+ const std::string& name, |
+ const base::FilePath& sync_data_folder_path, |
+ bool has_sync_setup_completed, |
+ const base::WeakPtr<SyncBackendHostImpl>& backend) |
+ : name_(name), |
+ sync_data_folder_path_(sync_data_folder_path), |
+ host_(backend), |
+ sync_loop_(NULL), |
+ registrar_(NULL), |
+ has_sync_setup_completed_(has_sync_setup_completed), |
+ weak_ptr_factory_(this) { |
+ DCHECK(backend.get()); |
+} |
+ |
+SyncBackendHostCore::~SyncBackendHostCore() { |
+ DCHECK(!sync_manager_.get()); |
+} |
+ |
+void SyncBackendHostCore::OnSyncCycleCompleted( |
+ const syncer::sessions::SyncSessionSnapshot& snapshot) { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop, |
+ snapshot); |
+} |
+ |
+void SyncBackendHostCore::DoRefreshTypes(syncer::ModelTypeSet types) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->RefreshTypes(types); |
+} |
+ |
+void SyncBackendHostCore::OnControlTypesDownloadRetry() { |
+ host_.Call(FROM_HERE, |
+ &SyncBackendHostImpl::HandleControlTypesDownloadRetry); |
+} |
+ |
+void SyncBackendHostCore::OnInitializationComplete( |
+ const syncer::WeakHandle<syncer::JsBackend>& js_backend, |
+ const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>& |
+ debug_info_listener, |
+ bool success, |
+ const syncer::ModelTypeSet restored_types) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ |
+ if (!success) { |
+ DoDestroySyncManager(); |
+ host_.Call(FROM_HERE, |
+ &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop); |
+ return; |
+ } |
+ |
+ // Register for encryption related changes now. We have to do this before |
+ // the initializing downloading control types or initializing the encryption |
+ // handler in order to receive notifications triggered during encryption |
+ // startup. |
+ sync_manager_->GetEncryptionHandler()->AddObserver(this); |
+ |
+ // Sync manager initialization is complete, so we can schedule recurring |
+ // SaveChanges. |
+ sync_loop_->PostTask(FROM_HERE, |
+ base::Bind(&SyncBackendHostCore::StartSavingChanges, |
+ weak_ptr_factory_.GetWeakPtr())); |
+ |
+ // Hang on to these for a while longer. We're not ready to hand them back to |
+ // the UI thread yet. |
+ js_backend_ = js_backend; |
+ debug_info_listener_ = debug_info_listener; |
+ |
+ // Track whether or not sync DB and preferences were in sync. |
+ SyncBackendInitState backend_init_state; |
+ if (has_sync_setup_completed_ && !restored_types.Empty()) { |
+ backend_init_state = SETUP_COMPLETED_FOUND_RESTORED_TYPES; |
+ } else if (has_sync_setup_completed_ && restored_types.Empty()) { |
+ backend_init_state = SETUP_COMPLETED_NO_RESTORED_TYPES; |
+ } else if (!has_sync_setup_completed_ && restored_types.Empty()) { |
+ backend_init_state = FIRST_SETUP_NO_RESTORED_TYPES; |
+ } else { // (!has_sync_setup_completed_ && !restored_types.Empty()) |
+ backend_init_state = FIRST_SETUP_RESTORED_TYPES; |
+ } |
+ |
+ UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState", |
+ backend_init_state, |
+ SYNC_BACKEND_INIT_STATE_COUNT); |
+ |
+ // Before proceeding any further, we need to download the control types and |
+ // purge any partial data (ie. data downloaded for a type that was on its way |
+ // to being initially synced, but didn't quite make it.). The following |
+ // configure cycle will take care of this. It depends on the registrar state |
+ // which we initialize below to ensure that we don't perform any downloads if |
+ // all control types have already completed their initial sync. |
+ registrar_->SetInitialTypes(restored_types); |
+ |
+ syncer::ConfigureReason reason = |
+ restored_types.Empty() ? |
+ syncer::CONFIGURE_REASON_NEW_CLIENT : |
+ syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE; |
+ |
+ syncer::ModelTypeSet new_control_types = registrar_->ConfigureDataTypes( |
+ syncer::ControlTypes(), syncer::ModelTypeSet()); |
+ syncer::ModelSafeRoutingInfo routing_info; |
+ registrar_->GetModelSafeRoutingInfo(&routing_info); |
+ SDVLOG(1) << "Control Types " |
+ << syncer::ModelTypeSetToString(new_control_types) |
+ << " added; calling ConfigureSyncer"; |
+ |
+ syncer::ModelTypeSet types_to_purge = |
+ syncer::Difference(syncer::ModelTypeSet::All(), |
+ GetRoutingInfoTypes(routing_info)); |
+ |
+ sync_manager_->ConfigureSyncer( |
+ reason, |
+ new_control_types, |
+ types_to_purge, |
+ syncer::ModelTypeSet(), |
+ syncer::ModelTypeSet(), |
+ routing_info, |
+ base::Bind(&SyncBackendHostCore::DoInitialProcessControlTypes, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ base::Bind(&SyncBackendHostCore::OnControlTypesDownloadRetry, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void SyncBackendHostCore::OnConnectionStatusChange( |
+ syncer::ConnectionStatus status) { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop, status); |
+} |
+ |
+void SyncBackendHostCore::OnPassphraseRequired( |
+ syncer::PassphraseRequiredReason reason, |
+ const sync_pb::EncryptedData& pending_keys) { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::NotifyPassphraseRequired, reason, pending_keys); |
+} |
+ |
+void SyncBackendHostCore::OnPassphraseAccepted() { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::NotifyPassphraseAccepted); |
+} |
+ |
+void SyncBackendHostCore::OnBootstrapTokenUpdated( |
+ const std::string& bootstrap_token, |
+ syncer::BootstrapTokenType type) { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call(FROM_HERE, |
+ &SyncBackendHostImpl::PersistEncryptionBootstrapToken, |
+ bootstrap_token, |
+ type); |
+} |
+ |
+void SyncBackendHostCore::OnStopSyncingPermanently() { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop); |
+} |
+ |
+void SyncBackendHostCore::OnEncryptedTypesChanged( |
+ syncer::ModelTypeSet encrypted_types, |
+ bool encrypt_everything) { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ // NOTE: We're in a transaction. |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::NotifyEncryptedTypesChanged, |
+ encrypted_types, encrypt_everything); |
+} |
+ |
+void SyncBackendHostCore::OnEncryptionComplete() { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ // NOTE: We're in a transaction. |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::NotifyEncryptionComplete); |
+} |
+ |
+void SyncBackendHostCore::OnCryptographerStateChanged( |
+ syncer::Cryptographer* cryptographer) { |
+ // Do nothing. |
+} |
+ |
+void SyncBackendHostCore::OnPassphraseTypeChanged( |
+ syncer::PassphraseType type, base::Time passphrase_time) { |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop, |
+ type, passphrase_time); |
+} |
+ |
+void SyncBackendHostCore::OnActionableError( |
+ const syncer::SyncProtocolError& sync_error) { |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop, |
+ sync_error); |
+} |
+ |
+void SyncBackendHostCore::DoOnInvalidatorStateChange( |
+ syncer::InvalidatorState state) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->OnInvalidatorStateChange(state); |
+} |
+ |
+void SyncBackendHostCore::DoOnIncomingInvalidation( |
+ syncer::ObjectIdInvalidationMap invalidation_map) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->OnIncomingInvalidation(invalidation_map); |
+} |
+ |
+void SyncBackendHostCore::DoInitialize( |
+ scoped_ptr<DoInitializeOptions> options) { |
+ DCHECK(!sync_loop_); |
+ sync_loop_ = options->sync_loop; |
+ DCHECK(sync_loop_); |
+ |
+ // Finish initializing the HttpBridgeFactory. We do this here because |
+ // building the user agent may block on some platforms. |
+ chrome::VersionInfo version_info; |
+ options->http_bridge_factory->Init( |
+ DeviceInfo::MakeUserAgentForSyncApi(version_info)); |
+ |
+ // Blow away the partial or corrupt sync data folder before doing any more |
+ // initialization, if necessary. |
+ if (options->delete_sync_data_folder) { |
+ DeleteSyncDataFolder(); |
+ } |
+ |
+ // Make sure that the directory exists before initializing the backend. |
+ // If it already exists, this will do no harm. |
+ if (!file_util::CreateDirectory(sync_data_folder_path_)) { |
+ DLOG(FATAL) << "Sync Data directory creation failed."; |
+ } |
+ |
+ DCHECK(!registrar_); |
+ registrar_ = options->registrar; |
+ DCHECK(registrar_); |
+ |
+ sync_manager_ = options->sync_manager_factory->CreateSyncManager(name_); |
+ sync_manager_->AddObserver(this); |
+ sync_manager_->Init(sync_data_folder_path_, |
+ options->event_handler, |
+ options->service_url.host() + options->service_url.path(), |
+ options->service_url.EffectiveIntPort(), |
+ options->service_url.SchemeIsSecure(), |
+ options->http_bridge_factory.Pass(), |
+ options->workers, |
+ options->extensions_activity, |
+ options->registrar /* as SyncManager::ChangeDelegate */, |
+ options->credentials, |
+ options->invalidator_client_id, |
+ options->restored_key_for_bootstrapping, |
+ options->restored_keystore_key_for_bootstrapping, |
+ options->internal_components_factory.get(), |
+ &encryptor_, |
+ options->unrecoverable_error_handler.Pass(), |
+ options->report_unrecoverable_error_function, |
+ &stop_syncing_signal_); |
+ |
+ // |sync_manager_| may end up being NULL here in tests (in |
+ // synchronous initialization mode). |
+ // |
+ // TODO(akalin): Fix this behavior (see http://crbug.com/140354). |
+ if (sync_manager_) { |
+ // Now check the command line to see if we need to simulate an |
+ // unrecoverable error for testing purpose. Note the error is thrown |
+ // only if the initialization succeeded. Also it makes sense to use this |
+ // flag only when restarting the browser with an account already setup. If |
+ // you use this before setting up the setup would not succeed as an error |
+ // would be encountered. |
+ if (CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kSyncThrowUnrecoverableError)) { |
+ sync_manager_->ThrowUnrecoverableError(); |
+ } |
+ } |
+} |
+ |
+void SyncBackendHostCore::DoUpdateCredentials( |
+ const syncer::SyncCredentials& credentials) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ // UpdateCredentials can be called during backend initialization, possibly |
+ // when backend initialization has failed but hasn't notified the UI thread |
+ // yet. In that case, the sync manager may have been destroyed on the sync |
+ // thread before this task was executed, so we do nothing. |
+ if (sync_manager_) { |
+ sync_manager_->UpdateCredentials(credentials); |
+ } |
+} |
+ |
+void SyncBackendHostCore::DoStartSyncing( |
+ const syncer::ModelSafeRoutingInfo& routing_info) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->StartSyncingNormally(routing_info); |
+} |
+ |
+void SyncBackendHostCore::DoSetEncryptionPassphrase( |
+ const std::string& passphrase, |
+ bool is_explicit) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->GetEncryptionHandler()->SetEncryptionPassphrase( |
+ passphrase, is_explicit); |
+} |
+ |
+void SyncBackendHostCore::DoInitialProcessControlTypes() { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ |
+ DVLOG(1) << "Initilalizing Control Types"; |
+ |
+ // Initialize encryption. |
+ sync_manager_->GetEncryptionHandler()->Init(); |
+ |
+ // Note: experiments are currently handled via SBH::AddExperimentalTypes, |
+ // which is called at the end of every sync cycle. |
+ // TODO(zea): eventually add an experiment handler and initialize it here. |
+ |
+ if (!sync_manager_->GetUserShare()) { // NULL in some tests. |
+ DVLOG(1) << "Skipping initialization of DeviceInfo"; |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop); |
+ return; |
+ } |
+ |
+ if (!sync_manager_->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) { |
+ LOG(ERROR) << "Failed to download control types"; |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop); |
+ return; |
+ } |
+ |
+ // Initialize device info. This is asynchronous on some platforms, so we |
+ // provide a callback for when it finishes. |
+ synced_device_tracker_.reset( |
+ new SyncedDeviceTracker(sync_manager_->GetUserShare(), |
+ sync_manager_->cache_guid())); |
+ synced_device_tracker_->InitLocalDeviceInfo( |
+ base::Bind(&SyncBackendHostCore::DoFinishInitialProcessControlTypes, |
+ weak_ptr_factory_.GetWeakPtr())); |
+} |
+ |
+void SyncBackendHostCore::DoFinishInitialProcessControlTypes() { |
+ registrar_->ActivateDataType(syncer::DEVICE_INFO, |
+ syncer::GROUP_PASSIVE, |
+ synced_device_tracker_.get(), |
+ sync_manager_->GetUserShare()); |
+ |
+ host_.Call( |
+ FROM_HERE, |
+ &SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop, |
+ js_backend_, |
+ debug_info_listener_); |
+ |
+ js_backend_.Reset(); |
+ debug_info_listener_.Reset(); |
+} |
+ |
+void SyncBackendHostCore::DoSetDecryptionPassphrase( |
+ const std::string& passphrase) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase( |
+ passphrase); |
+} |
+ |
+void SyncBackendHostCore::DoEnableEncryptEverything() { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->GetEncryptionHandler()->EnableEncryptEverything(); |
+} |
+ |
+void SyncBackendHostCore::ShutdownOnUIThread() { |
+ // This will cut short any blocking network tasks, cut short any in-progress |
+ // sync cycles, and prevent the creation of new blocking network tasks and new |
+ // sync cycles. If there was an in-progress network request, it would have |
+ // had a reference to the RequestContextGetter. This reference will be |
+ // dropped by the time this function returns. |
+ // |
+ // It is safe to call this even if Sync's backend classes have not been |
+ // initialized yet. Those classes will receive the message when the sync |
+ // thread finally getes around to constructing them. |
+ stop_syncing_signal_.Signal(); |
+ |
+ // This will drop the HttpBridgeFactory's reference to the |
+ // RequestContextGetter. Once this has been called, the HttpBridgeFactory can |
+ // no longer be used to create new HttpBridge instances. We can get away with |
+ // this because the stop_syncing_signal_ has already been signalled, which |
+ // guarantees that the ServerConnectionManager will no longer attempt to |
+ // create new connections. |
+ release_request_context_signal_.Signal(); |
+} |
+ |
+void SyncBackendHostCore::DoShutdown(bool sync_disabled) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ |
+ // It's safe to do this even if the type was never activated. |
+ registrar_->DeactivateDataType(syncer::DEVICE_INFO); |
+ synced_device_tracker_.reset(); |
+ |
+ DoDestroySyncManager(); |
+ |
+ registrar_ = NULL; |
+ |
+ if (sync_disabled) |
+ DeleteSyncDataFolder(); |
+ |
+ host_.Reset(); |
+ weak_ptr_factory_.InvalidateWeakPtrs(); |
+} |
+ |
+void SyncBackendHostCore::DoDestroySyncManager() { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ if (sync_manager_) { |
+ save_changes_timer_.reset(); |
+ sync_manager_->RemoveObserver(this); |
+ sync_manager_->ShutdownOnSyncThread(); |
+ sync_manager_.reset(); |
+ } |
+} |
+ |
+void SyncBackendHostCore::DoConfigureSyncer( |
+ syncer::ConfigureReason reason, |
+ const DoConfigureSyncerTypes& config_types, |
+ const syncer::ModelSafeRoutingInfo routing_info, |
+ const base::Callback<void(syncer::ModelTypeSet, |
+ syncer::ModelTypeSet)>& ready_task, |
+ const base::Closure& retry_callback) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->ConfigureSyncer( |
+ reason, |
+ config_types.to_download, |
+ config_types.to_purge, |
+ config_types.to_journal, |
+ config_types.to_unapply, |
+ routing_info, |
+ base::Bind(&SyncBackendHostCore::DoFinishConfigureDataTypes, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ config_types.to_download, |
+ ready_task), |
+ base::Bind(&SyncBackendHostCore::DoRetryConfiguration, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ retry_callback)); |
+} |
+ |
+void SyncBackendHostCore::DoFinishConfigureDataTypes( |
+ syncer::ModelTypeSet types_to_config, |
+ const base::Callback<void(syncer::ModelTypeSet, |
+ syncer::ModelTypeSet)>& ready_task) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ |
+ // Update the enabled types for the bridge and sync manager. |
+ syncer::ModelSafeRoutingInfo routing_info; |
+ registrar_->GetModelSafeRoutingInfo(&routing_info); |
+ syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); |
+ enabled_types.RemoveAll(syncer::ProxyTypes()); |
+ |
+ const syncer::ModelTypeSet failed_configuration_types = |
+ Difference(types_to_config, sync_manager_->InitialSyncEndedTypes()); |
+ const syncer::ModelTypeSet succeeded_configuration_types = |
+ Difference(types_to_config, failed_configuration_types); |
+ host_.Call(FROM_HERE, |
+ &SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop, |
+ enabled_types, |
+ succeeded_configuration_types, |
+ failed_configuration_types, |
+ ready_task); |
+} |
+ |
+void SyncBackendHostCore::DoRetryConfiguration( |
+ const base::Closure& retry_callback) { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ host_.Call(FROM_HERE, |
+ &SyncBackendHostImpl::RetryConfigurationOnFrontendLoop, |
+ retry_callback); |
+} |
+ |
+void SyncBackendHostCore::DeleteSyncDataFolder() { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ if (base::DirectoryExists(sync_data_folder_path_)) { |
+ if (!base::DeleteFile(sync_data_folder_path_, true)) |
+ SLOG(DFATAL) << "Could not delete the Sync Data folder."; |
+ } |
+} |
+ |
+void SyncBackendHostCore::StartSavingChanges() { |
+ // We may already be shut down. |
+ if (!sync_loop_) |
+ return; |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ DCHECK(!save_changes_timer_.get()); |
+ save_changes_timer_.reset(new base::RepeatingTimer<SyncBackendHostCore>()); |
+ save_changes_timer_->Start(FROM_HERE, |
+ base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds), |
+ this, &SyncBackendHostCore::SaveChanges); |
+} |
+ |
+void SyncBackendHostCore::SaveChanges() { |
+ DCHECK_EQ(base::MessageLoop::current(), sync_loop_); |
+ sync_manager_->SaveChanges(); |
+} |
+ |
+} // namespace browser_sync |
+ |