| Index: chrome/browser/sync/glue/sync_backend_host_impl.cc
|
| diff --git a/chrome/browser/sync/glue/sync_backend_host_impl.cc b/chrome/browser/sync/glue/sync_backend_host_impl.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f9e7ff4905d7c95ca1fe2c3644753022853f570a
|
| --- /dev/null
|
| +++ b/chrome/browser/sync/glue/sync_backend_host_impl.cc
|
| @@ -0,0 +1,763 @@
|
| +// 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_impl.h"
|
| +
|
| +#include "base/command_line.h"
|
| +#include "chrome/browser/chrome_notification_types.h"
|
| +#include "chrome/browser/invalidation/invalidation_service.h"
|
| +#include "chrome/browser/invalidation/invalidation_service_factory.h"
|
| +#include "chrome/browser/network_time/network_time_tracker.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/sync/glue/sync_backend_host_core.h"
|
| +#include "chrome/browser/sync/glue/sync_backend_registrar.h"
|
| +#include "chrome/browser/sync/glue/sync_frontend.h"
|
| +#include "chrome/browser/sync/sync_prefs.h"
|
| +#include "chrome/common/chrome_switches.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_source.h"
|
| +#include "sync/internal_api/public/base_transaction.h"
|
| +#include "sync/internal_api/public/http_bridge.h"
|
| +#include "sync/internal_api/public/internal_components_factory.h"
|
| +#include "sync/internal_api/public/internal_components_factory_impl.h"
|
| +#include "sync/internal_api/public/sync_manager.h"
|
| +#include "sync/internal_api/public/sync_manager_factory.h"
|
| +#include "sync/internal_api/public/util/experiments.h"
|
| +#include "sync/internal_api/public/util/sync_string_conversions.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_ << ": "
|
| +
|
| +using syncer::InternalComponentsFactory;
|
| +
|
| +static const base::FilePath::CharType kSyncDataFolderName[] =
|
| + FILE_PATH_LITERAL("Sync Data");
|
| +
|
| +namespace browser_sync {
|
| +
|
| +SyncBackendHostImpl::SyncBackendHostImpl(
|
| + const std::string& name,
|
| + Profile* profile,
|
| + const base::WeakPtr<SyncPrefs>& sync_prefs)
|
| + : frontend_loop_(base::MessageLoop::current()),
|
| + profile_(profile),
|
| + name_(name),
|
| + initialized_(false),
|
| + sync_prefs_(sync_prefs),
|
| + frontend_(NULL),
|
| + cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE),
|
| + invalidator_(
|
| + invalidation::InvalidationServiceFactory::GetForProfile(profile)),
|
| + invalidation_handler_registered_(false),
|
| + weak_ptr_factory_(this) {
|
| + core_ = new SyncBackendHostCore(
|
| + name_,
|
| + profile_->GetPath().Append(kSyncDataFolderName),
|
| + sync_prefs_->HasSyncSetupCompleted(),
|
| + weak_ptr_factory_.GetWeakPtr());
|
| +}
|
| +
|
| +SyncBackendHostImpl::~SyncBackendHostImpl() {
|
| + DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
|
| + DCHECK(!registrar_.get());
|
| +}
|
| +
|
| +void SyncBackendHostImpl::Initialize(
|
| + SyncFrontend* frontend,
|
| + scoped_ptr<base::Thread> sync_thread,
|
| + const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
|
| + const GURL& sync_service_url,
|
| + const syncer::SyncCredentials& credentials,
|
| + bool delete_sync_data_folder,
|
| + scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory,
|
| + scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler,
|
| + syncer::ReportUnrecoverableErrorFunction
|
| + report_unrecoverable_error_function) {
|
| + registrar_.reset(new browser_sync::SyncBackendRegistrar(name_,
|
| + profile_,
|
| + sync_thread.Pass()));
|
| + CHECK(registrar_->sync_thread());
|
| +
|
| + frontend_ = frontend;
|
| + DCHECK(frontend);
|
| +
|
| + syncer::ModelSafeRoutingInfo routing_info;
|
| + std::vector<syncer::ModelSafeWorker*> workers;
|
| + registrar_->GetModelSafeRoutingInfo(&routing_info);
|
| + registrar_->GetWorkers(&workers);
|
| +
|
| + InternalComponentsFactory::Switches factory_switches = {
|
| + InternalComponentsFactory::ENCRYPTION_KEYSTORE,
|
| + InternalComponentsFactory::BACKOFF_NORMAL
|
| + };
|
| +
|
| + CommandLine* cl = CommandLine::ForCurrentProcess();
|
| + if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
|
| + factory_switches.backoff_override =
|
| + InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
|
| + }
|
| + if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
|
| + factory_switches.pre_commit_updates_policy =
|
| + InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
|
| + }
|
| +
|
| + scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions(
|
| + registrar_->sync_thread()->message_loop(),
|
| + registrar_.get(),
|
| + routing_info,
|
| + workers,
|
| + extensions_activity_monitor_.GetExtensionsActivity(),
|
| + event_handler,
|
| + sync_service_url,
|
| + scoped_ptr<syncer::HttpPostProviderFactory>(
|
| + new syncer::HttpBridgeFactory(
|
| + make_scoped_refptr(profile_->GetRequestContext()),
|
| + NetworkTimeTracker::BuildNotifierUpdateCallback(),
|
| + core_->GetRequestContextCancelationSignal())),
|
| + credentials,
|
| + invalidator_->GetInvalidatorClientId(),
|
| + sync_manager_factory.Pass(),
|
| + delete_sync_data_folder,
|
| + sync_prefs_->GetEncryptionBootstrapToken(),
|
| + sync_prefs_->GetKeystoreEncryptionBootstrapToken(),
|
| + scoped_ptr<InternalComponentsFactory>(
|
| + new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(),
|
| + unrecoverable_error_handler.Pass(),
|
| + report_unrecoverable_error_function));
|
| + InitCore(init_opts.Pass());
|
| +}
|
| +
|
| +void SyncBackendHostImpl::UpdateCredentials(
|
| + const syncer::SyncCredentials& credentials) {
|
| + DCHECK(registrar_->sync_thread()->IsRunning());
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoUpdateCredentials,
|
| + core_.get(),
|
| + credentials));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::StartSyncingWithServer() {
|
| + SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
|
| +
|
| + syncer::ModelSafeRoutingInfo routing_info;
|
| + registrar_->GetModelSafeRoutingInfo(&routing_info);
|
| +
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoStartSyncing,
|
| + core_.get(), routing_info));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
|
| + bool is_explicit) {
|
| + DCHECK(registrar_->sync_thread()->IsRunning());
|
| + if (!IsNigoriEnabled()) {
|
| + NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
|
| + " is disabled.";
|
| + return;
|
| + }
|
| +
|
| + // We should never be called with an empty passphrase.
|
| + DCHECK(!passphrase.empty());
|
| +
|
| + // This should only be called by the frontend.
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + // SetEncryptionPassphrase should never be called if we are currently
|
| + // encrypted with an explicit passphrase.
|
| + DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE ||
|
| + cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE);
|
| +
|
| + // Post an encryption task on the syncer thread.
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
|
| + core_.get(),
|
| + passphrase, is_explicit));
|
| +}
|
| +
|
| +bool SyncBackendHostImpl::SetDecryptionPassphrase(
|
| + const std::string& passphrase) {
|
| + if (!IsNigoriEnabled()) {
|
| + NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
|
| + " is disabled.";
|
| + return false;
|
| + }
|
| +
|
| + // We should never be called with an empty passphrase.
|
| + DCHECK(!passphrase.empty());
|
| +
|
| + // This should only be called by the frontend.
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + // This should only be called when we have cached pending keys.
|
| + DCHECK(cached_pending_keys_.has_blob());
|
| +
|
| + // Check the passphrase that was provided against our local cache of the
|
| + // cryptographer's pending keys. If this was unsuccessful, the UI layer can
|
| + // immediately call OnPassphraseRequired without showing the user a spinner.
|
| + if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
|
| + return false;
|
| +
|
| + // Post a decryption task on the syncer thread.
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
|
| + core_.get(),
|
| + passphrase));
|
| +
|
| + // Since we were able to decrypt the cached pending keys with the passphrase
|
| + // provided, we immediately alert the UI layer that the passphrase was
|
| + // accepted. This will avoid the situation where a user enters a passphrase,
|
| + // clicks OK, immediately reopens the advanced settings dialog, and gets an
|
| + // unnecessary prompt for a passphrase.
|
| + // Note: It is not guaranteed that the passphrase will be accepted by the
|
| + // syncer thread, since we could receive a new nigori node while the task is
|
| + // pending. This scenario is a valid race, and SetDecryptionPassphrase can
|
| + // trigger a new OnPassphraseRequired if it needs to.
|
| + NotifyPassphraseAccepted();
|
| + return true;
|
| +}
|
| +
|
| +void SyncBackendHostImpl::StopSyncingForShutdown() {
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + // Immediately stop sending messages to the frontend.
|
| + frontend_ = NULL;
|
| +
|
| + // Stop listening for and forwarding locally-triggered sync refresh requests.
|
| + notification_registrar_.RemoveAll();
|
| +
|
| + DCHECK(registrar_->sync_thread()->IsRunning());
|
| +
|
| + registrar_->RequestWorkerStopOnUIThread();
|
| +
|
| + core_->ShutdownOnUIThread();
|
| +}
|
| +
|
| +scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(ShutdownOption option) {
|
| + // StopSyncingForShutdown() (which nulls out |frontend_|) should be
|
| + // called first.
|
| + DCHECK(!frontend_);
|
| + DCHECK(registrar_->sync_thread()->IsRunning());
|
| +
|
| + bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD);
|
| + bool sync_thread_claimed =
|
| + (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD);
|
| +
|
| + if (invalidation_handler_registered_) {
|
| + if (sync_disabled) {
|
| + UnregisterInvalidationIds();
|
| + }
|
| + invalidator_->UnregisterInvalidationHandler(this);
|
| + invalidator_ = NULL;
|
| + }
|
| + invalidation_handler_registered_ = false;
|
| +
|
| + // Shut down and destroy sync manager.
|
| + registrar_->sync_thread()->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoShutdown,
|
| + core_.get(), sync_disabled));
|
| + core_ = NULL;
|
| +
|
| + // Worker cleanup.
|
| + SyncBackendRegistrar* detached_registrar = registrar_.release();
|
| + detached_registrar->sync_thread()->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SyncBackendRegistrar::Shutdown,
|
| + base::Unretained(detached_registrar)));
|
| +
|
| + if (sync_thread_claimed)
|
| + return detached_registrar->ReleaseSyncThread();
|
| + else
|
| + return scoped_ptr<base::Thread>();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::UnregisterInvalidationIds() {
|
| + if (invalidation_handler_registered_) {
|
| + invalidator_->UpdateRegisteredInvalidationIds(
|
| + this,
|
| + syncer::ObjectIdSet());
|
| + }
|
| +}
|
| +
|
| +void SyncBackendHostImpl::ConfigureDataTypes(
|
| + syncer::ConfigureReason reason,
|
| + const DataTypeConfigStateMap& config_state_map,
|
| + const base::Callback<void(syncer::ModelTypeSet,
|
| + syncer::ModelTypeSet)>& ready_task,
|
| + const base::Callback<void()>& retry_callback) {
|
| + // Only one configure is allowed at a time. This is guaranteed by our
|
| + // callers. The SyncBackendHostImpl requests one configure as the backend is
|
| + // initializing and waits for it to complete. After initialization, all
|
| + // configurations will pass through the DataTypeManager, which is careful to
|
| + // never send a new configure request until the current request succeeds.
|
| +
|
| + // The SyncBackendRegistrar's routing info will be updated by adding the
|
| + // types_to_add to the list then removing types_to_remove. Any types which
|
| + // are not in either of those sets will remain untouched.
|
| + //
|
| + // Types which were not in the list previously are not fully downloaded, so we
|
| + // must ask the syncer to download them. Any newly supported datatypes will
|
| + // not have been in that routing info list, so they will be among the types
|
| + // downloaded if they are enabled.
|
| + //
|
| + // The SyncBackendRegistrar's state was initially derived from the types
|
| + // detected to have been downloaded in the database. Afterwards it is
|
| + // modified only by this function. We expect it to remain in sync with the
|
| + // backend because configuration requests are never aborted; they are retried
|
| + // until they succeed or the backend is shut down.
|
| +
|
| + syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes();
|
| +
|
| + syncer::ModelTypeSet disabled_types =
|
| + GetDataTypesInState(DISABLED, config_state_map);
|
| + syncer::ModelTypeSet fatal_types =
|
| + GetDataTypesInState(FATAL, config_state_map);
|
| + syncer::ModelTypeSet crypto_types =
|
| + GetDataTypesInState(CRYPTO, config_state_map);
|
| + disabled_types.PutAll(fatal_types);
|
| + disabled_types.PutAll(crypto_types);
|
| + syncer::ModelTypeSet active_types =
|
| + GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map);
|
| + syncer::ModelTypeSet clean_first_types =
|
| + GetDataTypesInState(CONFIGURE_CLEAN, config_state_map);
|
| + syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes(
|
| + syncer::Union(active_types, clean_first_types),
|
| + disabled_types);
|
| + types_to_download.PutAll(clean_first_types);
|
| + types_to_download.RemoveAll(syncer::ProxyTypes());
|
| + if (!types_to_download.Empty())
|
| + types_to_download.Put(syncer::NIGORI);
|
| +
|
| + // TODO(sync): crbug.com/137550.
|
| + // It's dangerous to configure types that have progress markers. Types with
|
| + // progress markers can trigger a MIGRATION_DONE response. We are not
|
| + // prepared to handle a migration during a configure, so we must ensure that
|
| + // all our types_to_download actually contain no data before we sync them.
|
| + //
|
| + // One common way to end up in this situation used to be types which
|
| + // downloaded some or all of their data but have not applied it yet. We avoid
|
| + // problems with those types by purging the data of any such partially synced
|
| + // types soon after we load the directory.
|
| + //
|
| + // Another possible scenario is that we have newly supported or newly enabled
|
| + // data types being downloaded here but the nigori type, which is always
|
| + // included in any GetUpdates request, requires migration. The server has
|
| + // code to detect this scenario based on the configure reason, the fact that
|
| + // the nigori type is the only requested type which requires migration, and
|
| + // that the requested types list includes at least one non-nigori type. It
|
| + // will not send a MIGRATION_DONE response in that case. We still need to be
|
| + // careful to not send progress markers for non-nigori types, though. If a
|
| + // non-nigori type in the request requires migration, a MIGRATION_DONE
|
| + // response will be sent.
|
| +
|
| + syncer::ModelSafeRoutingInfo routing_info;
|
| + registrar_->GetModelSafeRoutingInfo(&routing_info);
|
| +
|
| + syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes();
|
| + syncer::ModelTypeSet types_to_purge =
|
| + syncer::Difference(previous_types, current_types);
|
| + syncer::ModelTypeSet inactive_types =
|
| + GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map);
|
| + types_to_purge.RemoveAll(inactive_types);
|
| +
|
| + // If a type has already been disabled and unapplied or journaled, it will
|
| + // not be part of the |types_to_purge| set, and therefore does not need
|
| + // to be acted on again.
|
| + fatal_types.RetainAll(types_to_purge);
|
| + syncer::ModelTypeSet unapply_types =
|
| + syncer::Union(crypto_types, clean_first_types);
|
| + unapply_types.RetainAll(types_to_purge);
|
| +
|
| + DCHECK(syncer::Intersection(current_types, fatal_types).Empty());
|
| + DCHECK(syncer::Intersection(current_types, crypto_types).Empty());
|
| + DCHECK(current_types.HasAll(types_to_download));
|
| +
|
| + SDVLOG(1) << "Types "
|
| + << syncer::ModelTypeSetToString(types_to_download)
|
| + << " added; calling DoConfigureSyncer";
|
| + // Divide up the types into their corresponding actions (each is mutually
|
| + // exclusive):
|
| + // - Types which have just been added to the routing info (types_to_download):
|
| + // are downloaded.
|
| + // - Types which have encountered a fatal error (fatal_types) are deleted
|
| + // from the directory and journaled in the delete journal.
|
| + // - Types which have encountered a cryptographer error (crypto_types) are
|
| + // unapplied (local state is purged but sync state is not).
|
| + // - All other types not in the routing info (types just disabled) are deleted
|
| + // from the directory.
|
| + // - Everything else (enabled types and already disabled types) is not
|
| + // touched.
|
| + RequestConfigureSyncer(reason,
|
| + types_to_download,
|
| + types_to_purge,
|
| + fatal_types,
|
| + unapply_types,
|
| + inactive_types,
|
| + routing_info,
|
| + ready_task,
|
| + retry_callback);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::EnableEncryptEverything() {
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything,
|
| + core_.get()));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::ActivateDataType(
|
| + syncer::ModelType type, syncer::ModelSafeGroup group,
|
| + ChangeProcessor* change_processor) {
|
| + registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
|
| +}
|
| +
|
| +void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) {
|
| + registrar_->DeactivateDataType(type);
|
| +}
|
| +
|
| +syncer::UserShare* SyncBackendHostImpl::GetUserShare() const {
|
| + return core_->sync_manager()->GetUserShare();
|
| +}
|
| +
|
| +SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
|
| + DCHECK(initialized());
|
| + return core_->sync_manager()->GetDetailedStatus();
|
| +}
|
| +
|
| +syncer::sessions::SyncSessionSnapshot
|
| +SyncBackendHostImpl::GetLastSessionSnapshot() const {
|
| + return last_snapshot_;
|
| +}
|
| +
|
| +bool SyncBackendHostImpl::HasUnsyncedItems() const {
|
| + DCHECK(initialized());
|
| + return core_->sync_manager()->HasUnsyncedItems();
|
| +}
|
| +
|
| +bool SyncBackendHostImpl::IsNigoriEnabled() const {
|
| + return registrar_.get() && registrar_->IsNigoriEnabled();
|
| +}
|
| +
|
| +syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const {
|
| + return cached_passphrase_type_;
|
| +}
|
| +
|
| +base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const {
|
| + return cached_explicit_passphrase_time_;
|
| +}
|
| +
|
| +bool SyncBackendHostImpl::IsCryptographerReady(
|
| + const syncer::BaseTransaction* trans) const {
|
| + return initialized() && trans->GetCryptographer()->is_ready();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::GetModelSafeRoutingInfo(
|
| + syncer::ModelSafeRoutingInfo* out) const {
|
| + if (initialized()) {
|
| + CHECK(registrar_.get());
|
| + registrar_->GetModelSafeRoutingInfo(out);
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| +}
|
| +
|
| +SyncedDeviceTracker* SyncBackendHostImpl::GetSyncedDeviceTracker() const {
|
| + if (!initialized())
|
| + return NULL;
|
| + return core_->synced_device_tracker();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) {
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoInitialize,
|
| + core_.get(), base::Passed(&options)));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::RequestConfigureSyncer(
|
| + syncer::ConfigureReason reason,
|
| + syncer::ModelTypeSet to_download,
|
| + syncer::ModelTypeSet to_purge,
|
| + syncer::ModelTypeSet to_journal,
|
| + syncer::ModelTypeSet to_unapply,
|
| + syncer::ModelTypeSet to_ignore,
|
| + const syncer::ModelSafeRoutingInfo& routing_info,
|
| + const base::Callback<void(syncer::ModelTypeSet,
|
| + syncer::ModelTypeSet)>& ready_task,
|
| + const base::Closure& retry_callback) {
|
| + DoConfigureSyncerTypes config_types;
|
| + config_types.to_download = to_download;
|
| + config_types.to_purge = to_purge;
|
| + config_types.to_journal = to_journal;
|
| + config_types.to_unapply = to_unapply;
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoConfigureSyncer,
|
| + core_.get(),
|
| + reason,
|
| + config_types,
|
| + routing_info,
|
| + ready_task,
|
| + retry_callback));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
|
| + const syncer::ModelTypeSet enabled_types,
|
| + const syncer::ModelTypeSet succeeded_configuration_types,
|
| + const syncer::ModelTypeSet failed_configuration_types,
|
| + const base::Callback<void(syncer::ModelTypeSet,
|
| + syncer::ModelTypeSet)>& ready_task) {
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + invalidator_->UpdateRegisteredInvalidationIds(
|
| + this,
|
| + ModelTypeSetToObjectIdSet(enabled_types));
|
| +
|
| + if (!ready_task.is_null())
|
| + ready_task.Run(succeeded_configuration_types, failed_configuration_types);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::Observe(
|
| + int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL);
|
| +
|
| + content::Details<const syncer::ModelTypeSet> state_details(details);
|
| + const syncer::ModelTypeSet& types = *(state_details.ptr());
|
| + registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::AddExperimentalTypes() {
|
| + CHECK(initialized());
|
| + syncer::Experiments experiments;
|
| + if (core_->sync_manager()->ReceivedExperiment(&experiments))
|
| + frontend_->OnExperimentsChanged(experiments);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleControlTypesDownloadRetry() {
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + frontend_->OnSyncConfigureRetry();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
|
| + const syncer::WeakHandle<syncer::JsBackend> js_backend,
|
| + const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>
|
| + debug_info_listener) {
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + initialized_ = true;
|
| +
|
| + invalidator_->RegisterInvalidationHandler(this);
|
| + invalidation_handler_registered_ = true;
|
| +
|
| + // Fake a state change to initialize the SyncManager's cached invalidator
|
| + // state.
|
| + OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
|
| +
|
| + // Start forwarding refresh requests to the SyncManager
|
| + notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
|
| + content::Source<Profile>(profile_));
|
| +
|
| + // Now that we've downloaded the control types, we can see if there are any
|
| + // experimental types to enable. This should be done before we inform
|
| + // the frontend to ensure they're visible in the customize screen.
|
| + AddExperimentalTypes();
|
| + frontend_->OnBackendInitialized(js_backend,
|
| + debug_info_listener,
|
| + true);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + frontend_->OnBackendInitialized(
|
| + syncer::WeakHandle<syncer::JsBackend>(),
|
| + syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(),
|
| + false);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
|
| + const syncer::sessions::SyncSessionSnapshot& snapshot) {
|
| + if (!frontend_)
|
| + return;
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + last_snapshot_ = snapshot;
|
| +
|
| + SDVLOG(1) << "Got snapshot " << snapshot.ToString();
|
| +
|
| + const syncer::ModelTypeSet to_migrate =
|
| + snapshot.model_neutral_state().types_needing_local_migration;
|
| + if (!to_migrate.Empty())
|
| + frontend_->OnMigrationNeededForTypes(to_migrate);
|
| +
|
| + // Process any changes to the datatypes we're syncing.
|
| + // TODO(sync): add support for removing types.
|
| + if (initialized())
|
| + AddExperimentalTypes();
|
| +
|
| + if (initialized())
|
| + frontend_->OnSyncCycleCompleted();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
|
| + const base::Closure& retry_callback) {
|
| + SDVLOG(1) << "Failed to complete configuration, informing of retry.";
|
| + retry_callback.Run();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::PersistEncryptionBootstrapToken(
|
| + const std::string& token,
|
| + syncer::BootstrapTokenType token_type) {
|
| + CHECK(sync_prefs_.get());
|
| + DCHECK(!token.empty());
|
| + if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN)
|
| + sync_prefs_->SetEncryptionBootstrapToken(token);
|
| + else
|
| + sync_prefs_->SetKeystoreEncryptionBootstrapToken(token);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
|
| + const syncer::SyncProtocolError& sync_error) {
|
| + if (!frontend_)
|
| + return;
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + frontend_->OnActionableError(sync_error);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::OnInvalidatorStateChange(
|
| + syncer::InvalidatorState state) {
|
| + registrar_->sync_thread()->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
|
| + core_.get(),
|
| + state));
|
| +}
|
| +
|
| +void SyncBackendHostImpl::OnIncomingInvalidation(
|
| + const syncer::ObjectIdInvalidationMap& invalidation_map) {
|
| + // TODO(rlarocque): Acknowledge these invalidations only after the syncer has
|
| + // acted on them and saved the results to disk.
|
| + syncer::ObjectIdSet ids = invalidation_map.GetObjectIds();
|
| + for (syncer::ObjectIdSet::const_iterator it = ids.begin();
|
| + it != ids.end(); ++it) {
|
| + const syncer::AckHandle& handle =
|
| + invalidation_map.ForObject(*it).back().ack_handle();
|
| + invalidator_->AcknowledgeInvalidation(*it, handle);
|
| + }
|
| +
|
| + registrar_->sync_thread()->message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
|
| + core_.get(),
|
| + invalidation_map));
|
| +}
|
| +
|
| +bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys(
|
| + const std::string& passphrase) const {
|
| + DCHECK(cached_pending_keys_.has_blob());
|
| + DCHECK(!passphrase.empty());
|
| + syncer::Nigori nigori;
|
| + nigori.InitByDerivation("localhost", "dummy", passphrase);
|
| + std::string plaintext;
|
| + bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
|
| + DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
|
| + return result;
|
| +}
|
| +
|
| +void SyncBackendHostImpl::NotifyPassphraseRequired(
|
| + syncer::PassphraseRequiredReason reason,
|
| + sync_pb::EncryptedData pending_keys) {
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + // Update our cache of the cryptographer's pending keys.
|
| + cached_pending_keys_ = pending_keys;
|
| +
|
| + frontend_->OnPassphraseRequired(reason, pending_keys);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::NotifyPassphraseAccepted() {
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + // Clear our cache of the cryptographer's pending keys.
|
| + cached_pending_keys_.clear_blob();
|
| + frontend_->OnPassphraseAccepted();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
|
| + syncer::ModelTypeSet encrypted_types,
|
| + bool encrypt_everything) {
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + frontend_->OnEncryptedTypesChanged(
|
| + encrypted_types, encrypt_everything);
|
| +}
|
| +
|
| +void SyncBackendHostImpl::NotifyEncryptionComplete() {
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + frontend_->OnEncryptionComplete();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
|
| + syncer::PassphraseType type,
|
| + base::Time explicit_passphrase_time) {
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| + DVLOG(1) << "Passphrase type changed to "
|
| + << syncer::PassphraseTypeToString(type);
|
| + cached_passphrase_type_ = type;
|
| + cached_explicit_passphrase_time_ = explicit_passphrase_time;
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop() {
|
| + if (!frontend_)
|
| + return;
|
| + frontend_->OnStopSyncingPermanently();
|
| +}
|
| +
|
| +void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
|
| + syncer::ConnectionStatus status) {
|
| + if (!frontend_)
|
| + return;
|
| +
|
| + DCHECK_EQ(base::MessageLoop::current(), frontend_loop_);
|
| +
|
| + DVLOG(1) << "Connection status changed: "
|
| + << syncer::ConnectionStatusToString(status);
|
| + frontend_->OnConnectionStatusChange(status);
|
| +}
|
| +
|
| +base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() {
|
| + return registrar_->sync_thread()->message_loop();
|
| +}
|
| +
|
| +} // namespace browser_sync
|
| +
|
| +#undef SDVLOG
|
| +
|
| +#undef SLOG
|
| +
|
|
|