Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(880)

Unified Diff: chrome/browser/sync/glue/sync_backend_host_impl.cc

Issue 61183003: Refactor SyncBackendHost (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix patch upload + fix some other issues Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
+
« no previous file with comments | « chrome/browser/sync/glue/sync_backend_host_impl.h ('k') | chrome/browser/sync/glue/sync_backend_host_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698