Chromium Code Reviews| 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..829e6b8416dd61705eeaf899b07e003cf065d50e |
| --- /dev/null |
| +++ b/chrome/browser/sync/glue/sync_backend_host_core.cc |
| @@ -0,0 +1,621 @@ |
| +// 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/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 { |
| + |
| +// 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 syncer { |
|
Nicolas Zea
2013/11/06 18:03:21
nit: I think we typically have forward declaration
rlarocque
2013/11/06 21:48:47
Done.
|
| +class InternalComponentsFactory; |
| +} // namespace syncer |
| + |
| +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 |
| + |