blob: 51aeee91d593a17dc8c2d57e4d13342555b710b2 [file] [log] [blame]
// 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 "components/sync/driver/glue/sync_backend_host_impl.h"
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/invalidation/public/invalidation_service.h"
#include "components/invalidation/public/object_id_invalidation_map.h"
#include "components/signin/core/browser/signin_client.h"
#include "components/sync/base/experiments.h"
#include "components/sync/base/invalidation_helper.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/glue/sync_backend_host_core.h"
#include "components/sync/driver/sync_client.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/engine/activation_context.h"
#include "components/sync/engine/engine_components_factory.h"
#include "components/sync/engine/engine_components_factory_impl.h"
#include "components/sync/engine/events/protocol_event.h"
#include "components/sync/engine/net/http_bridge.h"
#include "components/sync/engine/sync_backend_registrar.h"
#include "components/sync/engine/sync_engine_host.h"
#include "components/sync/engine/sync_manager_factory.h"
#include "components/sync/engine/sync_string_conversions.h"
#include "components/sync/syncable/base_transaction.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_ << ": "
namespace syncer {
SyncBackendHostImpl::SyncBackendHostImpl(
const std::string& name,
SyncClient* sync_client,
invalidation::InvalidationService* invalidator,
const base::WeakPtr<SyncPrefs>& sync_prefs,
const base::FilePath& sync_data_folder)
: sync_client_(sync_client),
name_(name),
sync_prefs_(sync_prefs),
invalidator_(invalidator),
weak_ptr_factory_(this) {
core_ = new SyncBackendHostCore(name_, sync_data_folder,
weak_ptr_factory_.GetWeakPtr());
}
SyncBackendHostImpl::~SyncBackendHostImpl() {
DCHECK(!core_.get() && !host_) << "Must call Shutdown before destructor.";
DCHECK(!registrar_);
}
void SyncBackendHostImpl::Initialize(InitParams params) {
CHECK(params.sync_task_runner);
DCHECK(params.host);
DCHECK(params.registrar);
sync_task_runner_ = params.sync_task_runner;
host_ = params.host;
registrar_ = params.registrar.get();
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoInitialize, core_,
base::Passed(&params)));
}
void SyncBackendHostImpl::TriggerRefresh(const ModelTypeSet& types) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_, types));
}
void SyncBackendHostImpl::UpdateCredentials(
const SyncCredentials& credentials) {
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoUpdateCredentials, core_,
credentials));
}
void SyncBackendHostImpl::StartConfiguration() {
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoStartConfiguration, core_));
}
void SyncBackendHostImpl::StartSyncingWithServer() {
SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called.";
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoStartSyncing, core_,
sync_prefs_->GetLastPollTime()));
}
void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
bool is_explicit) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase,
core_, passphrase, is_explicit));
}
void SyncBackendHostImpl::SetDecryptionPassphrase(
const std::string& passphrase) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase,
core_, passphrase));
}
void SyncBackendHostImpl::StopSyncingForShutdown() {
DCHECK(thread_checker_.CalledOnValidThread());
// Stop getting messages from the sync thread.
weak_ptr_factory_.InvalidateWeakPtrs();
// Immediately stop sending messages to the host.
host_ = nullptr;
registrar_->RequestWorkerStopOnUIThread();
core_->ShutdownOnUIThread();
}
void SyncBackendHostImpl::Shutdown(ShutdownReason reason) {
// StopSyncingForShutdown() (which nulls out |host_|) should be
// called first.
DCHECK(!host_);
if (invalidation_handler_registered_) {
CHECK(invalidator_->UpdateRegisteredInvalidationIds(this, ObjectIdSet()));
invalidator_->UnregisterInvalidationHandler(this);
invalidator_ = nullptr;
}
invalidation_handler_registered_ = false;
model_type_connector_.reset();
// Shut down and destroy SyncManager. SyncManager holds a pointer to
// |registrar_| so its destruction must be sequenced before the destruction of
// |registrar_|.
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoShutdown, core_, reason));
core_ = nullptr;
registrar_ = nullptr;
}
void SyncBackendHostImpl::ConfigureDataTypes(ConfigureParams params) {
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DoPurgeDisabledTypes, core_,
params.to_purge, params.to_journal, params.to_unapply));
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoConfigureSyncer, core_,
base::Passed(&params)));
}
void SyncBackendHostImpl::RegisterDirectoryDataType(ModelType type,
ModelSafeGroup group) {
model_type_connector_->RegisterDirectoryType(type, group);
}
void SyncBackendHostImpl::UnregisterDirectoryDataType(ModelType type) {
model_type_connector_->UnregisterDirectoryType(type);
}
void SyncBackendHostImpl::EnableEncryptEverything() {
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything, core_));
}
void SyncBackendHostImpl::ActivateDirectoryDataType(
ModelType type,
ModelSafeGroup group,
ChangeProcessor* change_processor) {
registrar_->ActivateDataType(type, group, change_processor, GetUserShare());
}
void SyncBackendHostImpl::DeactivateDirectoryDataType(ModelType type) {
registrar_->DeactivateDataType(type);
}
void SyncBackendHostImpl::ActivateNonBlockingDataType(
ModelType type,
std::unique_ptr<ActivationContext> activation_context) {
registrar_->RegisterNonBlockingType(type);
if (activation_context->model_type_state.initial_sync_done())
registrar_->AddRestoredNonBlockingType(type);
model_type_connector_->ConnectNonBlockingType(type,
std::move(activation_context));
}
void SyncBackendHostImpl::DeactivateNonBlockingDataType(ModelType type) {
model_type_connector_->DisconnectNonBlockingType(type);
}
UserShare* SyncBackendHostImpl::GetUserShare() const {
return core_->sync_manager()->GetUserShare();
}
SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() {
DCHECK(initialized());
return core_->sync_manager()->GetDetailedStatus();
}
bool SyncBackendHostImpl::HasUnsyncedItems() const {
DCHECK(initialized());
return core_->sync_manager()->HasUnsyncedItems();
}
bool SyncBackendHostImpl::IsCryptographerReady(
const BaseTransaction* trans) const {
return initialized() && trans->GetCryptographer() &&
trans->GetCryptographer()->is_ready();
}
void SyncBackendHostImpl::GetModelSafeRoutingInfo(
ModelSafeRoutingInfo* out) const {
if (initialized()) {
CHECK(registrar_);
registrar_->GetModelSafeRoutingInfo(out);
} else {
NOTREACHED();
}
}
void SyncBackendHostImpl::FlushDirectory() const {
DCHECK(initialized());
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::SaveChanges, core_));
}
void SyncBackendHostImpl::RequestBufferedProtocolEventsAndEnableForwarding() {
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(
&SyncBackendHostCore::SendBufferedProtocolEventsAndEnableForwarding,
core_));
}
void SyncBackendHostImpl::DisableProtocolEventForwarding() {
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DisableProtocolEventForwarding, core_));
}
void SyncBackendHostImpl::EnableDirectoryTypeDebugInfoForwarding() {
DCHECK(initialized());
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::EnableDirectoryTypeDebugInfoForwarding,
core_));
}
void SyncBackendHostImpl::DisableDirectoryTypeDebugInfoForwarding() {
DCHECK(initialized());
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DisableDirectoryTypeDebugInfoForwarding,
core_));
}
void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop(
const ModelTypeSet enabled_types,
const ModelTypeSet succeeded_configuration_types,
const ModelTypeSet failed_configuration_types,
const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task) {
if (invalidator_) {
CHECK(invalidator_->UpdateRegisteredInvalidationIds(
this, ModelTypeSetToObjectIdSet(enabled_types)));
}
if (!ready_task.is_null())
ready_task.Run(succeeded_configuration_types, failed_configuration_types);
}
void SyncBackendHostImpl::AddExperimentalTypes() {
CHECK(initialized());
Experiments experiments;
if (core_->sync_manager()->ReceivedExperiment(&experiments))
host_->OnExperimentsChanged(experiments);
}
void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
ModelTypeSet initial_types,
const WeakHandle<JsBackend> js_backend,
const WeakHandle<DataTypeDebugInfoListener> debug_info_listener,
std::unique_ptr<ModelTypeConnector> model_type_connector,
const std::string& cache_guid) {
DCHECK(thread_checker_.CalledOnValidThread());
model_type_connector_ = std::move(model_type_connector);
initialized_ = true;
if (invalidator_) {
invalidator_->RegisterInvalidationHandler(this);
invalidation_handler_registered_ = true;
// Fake a state change to initialize the SyncManager's cached invalidator
// state.
OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
}
// 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 host to ensure they're visible in the customize screen.
AddExperimentalTypes();
host_->OnEngineInitialized(initial_types, js_backend, debug_info_listener,
cache_guid, true);
}
void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnEngineInitialized(ModelTypeSet(), WeakHandle<JsBackend>(),
WeakHandle<DataTypeDebugInfoListener>(), "",
false);
}
void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
const SyncCycleSnapshot& snapshot) {
DCHECK(thread_checker_.CalledOnValidThread());
// Process any changes to the datatypes we're syncing.
// TODO(sync): add support for removing types.
if (initialized()) {
AddExperimentalTypes();
host_->OnSyncCycleCompleted(snapshot);
}
}
void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
const base::Closure& retry_callback) {
SDVLOG(1) << "Failed to complete configuration, informing of retry.";
retry_callback.Run();
}
void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
const SyncProtocolError& sync_error) {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnActionableError(sync_error);
}
void SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop(
ModelTypeSet types) {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnMigrationNeededForTypes(types);
}
void SyncBackendHostImpl::OnInvalidatorStateChange(InvalidatorState state) {
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange,
core_, state));
}
void SyncBackendHostImpl::OnIncomingInvalidation(
const ObjectIdInvalidationMap& invalidation_map) {
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation,
core_, invalidation_map));
}
std::string SyncBackendHostImpl::GetOwnerName() const {
return "SyncBackendHostImpl";
}
void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
ConnectionStatus status) {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "Connection status changed: " << ConnectionStatusToString(status);
host_->OnConnectionStatusChange(status);
}
void SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop(
std::unique_ptr<ProtocolEvent> event) {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnProtocolEvent(*event);
}
void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
ModelType type,
const CommitCounters& counters) {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnDirectoryTypeCommitCounterUpdated(type, counters);
}
void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
ModelType type,
const UpdateCounters& counters) {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
}
void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
ModelType type,
const StatusCounters& counters) {
DCHECK(thread_checker_.CalledOnValidThread());
host_->OnDatatypeStatusCounterUpdated(type, counters);
}
void SyncBackendHostImpl::UpdateInvalidationVersions(
const std::map<ModelType, int64_t>& invalidation_versions) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_prefs_->UpdateInvalidationVersions(invalidation_versions);
}
void SyncBackendHostImpl::RefreshTypesForTest(ModelTypeSet types) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_, types));
}
void SyncBackendHostImpl::ClearServerData(const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&SyncBackendHostCore::DoClearServerData, core_, callback));
}
void SyncBackendHostImpl::OnCookieJarChanged(bool account_mismatch,
bool empty_jar,
const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
sync_task_runner_->PostTask(
FROM_HERE, base::Bind(&SyncBackendHostCore::DoOnCookieJarChanged, core_,
account_mismatch, empty_jar, callback));
}
void SyncBackendHostImpl::ClearServerDataDoneOnFrontendLoop(
const base::Closure& frontend_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
frontend_callback.Run();
}
void SyncBackendHostImpl::OnCookieJarChangedDoneOnFrontendLoop(
const base::Closure& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
callback.Run();
}
} // namespace syncer
#undef SDVLOG
#undef SLOG