Index: sync/internal_api/sync_manager_impl.cc |
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc |
deleted file mode 100644 |
index cc59e645b06d03c999a4206cb3ea9d19bb22156a..0000000000000000000000000000000000000000 |
--- a/sync/internal_api/sync_manager_impl.cc |
+++ /dev/null |
@@ -1,1037 +0,0 @@ |
-// Copyright (c) 2012 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 "sync/internal_api/sync_manager_impl.h" |
- |
-#include <stddef.h> |
-#include <stdint.h> |
-#include <string> |
-#include <utility> |
- |
-#include "base/base64.h" |
-#include "base/bind.h" |
-#include "base/callback.h" |
-#include "base/compiler_specific.h" |
-#include "base/json/json_writer.h" |
-#include "base/memory/ptr_util.h" |
-#include "base/memory/ref_counted.h" |
-#include "base/metrics/histogram.h" |
-#include "base/observer_list.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/threading/thread_task_runner_handle.h" |
-#include "base/values.h" |
-#include "sync/engine/sync_scheduler.h" |
-#include "sync/engine/syncer_types.h" |
-#include "sync/internal_api/change_reorder_buffer.h" |
-#include "sync/internal_api/model_type_connector_proxy.h" |
-#include "sync/internal_api/public/base/cancelation_signal.h" |
-#include "sync/internal_api/public/base/invalidation_interface.h" |
-#include "sync/internal_api/public/base/model_type.h" |
-#include "sync/internal_api/public/base_node.h" |
-#include "sync/internal_api/public/configure_reason.h" |
-#include "sync/internal_api/public/engine/polling_constants.h" |
-#include "sync/internal_api/public/http_post_provider_factory.h" |
-#include "sync/internal_api/public/internal_components_factory.h" |
-#include "sync/internal_api/public/read_node.h" |
-#include "sync/internal_api/public/read_transaction.h" |
-#include "sync/internal_api/public/user_share.h" |
-#include "sync/internal_api/public/util/experiments.h" |
-#include "sync/internal_api/public/write_node.h" |
-#include "sync/internal_api/public/write_transaction.h" |
-#include "sync/internal_api/syncapi_internal.h" |
-#include "sync/internal_api/syncapi_server_connection_manager.h" |
-#include "sync/protocol/proto_value_conversions.h" |
-#include "sync/protocol/sync.pb.h" |
-#include "sync/sessions/directory_type_debug_info_emitter.h" |
-#include "sync/syncable/directory.h" |
-#include "sync/syncable/entry.h" |
-#include "sync/syncable/in_memory_directory_backing_store.h" |
-#include "sync/syncable/on_disk_directory_backing_store.h" |
- |
-using base::TimeDelta; |
-using sync_pb::GetUpdatesCallerInfo; |
- |
-class GURL; |
- |
-namespace syncer { |
- |
-using sessions::SyncSessionContext; |
-using syncable::ImmutableWriteTransactionInfo; |
-using syncable::SPECIFICS; |
-using syncable::UNIQUE_POSITION; |
- |
-namespace { |
- |
-GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason( |
- ConfigureReason reason) { |
- switch (reason) { |
- case CONFIGURE_REASON_RECONFIGURATION: |
- return GetUpdatesCallerInfo::RECONFIGURATION; |
- case CONFIGURE_REASON_MIGRATION: |
- return GetUpdatesCallerInfo::MIGRATION; |
- case CONFIGURE_REASON_NEW_CLIENT: |
- return GetUpdatesCallerInfo::NEW_CLIENT; |
- case CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE: |
- case CONFIGURE_REASON_CRYPTO: |
- case CONFIGURE_REASON_CATCH_UP: |
- return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE; |
- case CONFIGURE_REASON_PROGRAMMATIC: |
- return GetUpdatesCallerInfo::PROGRAMMATIC; |
- case CONFIGURE_REASON_UNKNOWN: |
- NOTREACHED(); |
- } |
- return GetUpdatesCallerInfo::UNKNOWN; |
-} |
- |
-} // namespace |
- |
-SyncManagerImpl::SyncManagerImpl(const std::string& name) |
- : name_(name), |
- change_delegate_(NULL), |
- initialized_(false), |
- observing_network_connectivity_changes_(false), |
- weak_ptr_factory_(this) { |
- // Pre-fill |notification_info_map_|. |
- for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { |
- notification_info_map_.insert( |
- std::make_pair(ModelTypeFromInt(i), NotificationInfo())); |
- } |
-} |
- |
-SyncManagerImpl::~SyncManagerImpl() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- CHECK(!initialized_); |
-} |
- |
-SyncManagerImpl::NotificationInfo::NotificationInfo() : total_count(0) {} |
-SyncManagerImpl::NotificationInfo::~NotificationInfo() {} |
- |
-base::DictionaryValue* SyncManagerImpl::NotificationInfo::ToValue() const { |
- base::DictionaryValue* value = new base::DictionaryValue(); |
- value->SetInteger("totalCount", total_count); |
- value->SetString("payload", payload); |
- return value; |
-} |
- |
-bool SyncManagerImpl::VisiblePositionsDiffer( |
- const syncable::EntryKernelMutation& mutation) const { |
- const syncable::EntryKernel& a = mutation.original; |
- const syncable::EntryKernel& b = mutation.mutated; |
- if (!b.ShouldMaintainPosition()) |
- return false; |
- if (!a.ref(UNIQUE_POSITION).Equals(b.ref(UNIQUE_POSITION))) |
- return true; |
- if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID)) |
- return true; |
- return false; |
-} |
- |
-bool SyncManagerImpl::VisiblePropertiesDiffer( |
- const syncable::EntryKernelMutation& mutation, |
- Cryptographer* cryptographer) const { |
- const syncable::EntryKernel& a = mutation.original; |
- const syncable::EntryKernel& b = mutation.mutated; |
- const sync_pb::EntitySpecifics& a_specifics = a.ref(SPECIFICS); |
- const sync_pb::EntitySpecifics& b_specifics = b.ref(SPECIFICS); |
- DCHECK_EQ(GetModelTypeFromSpecifics(a_specifics), |
- GetModelTypeFromSpecifics(b_specifics)); |
- ModelType model_type = GetModelTypeFromSpecifics(b_specifics); |
- // Suppress updates to items that aren't tracked by any browser model. |
- if (model_type < FIRST_REAL_MODEL_TYPE || |
- !a.ref(syncable::UNIQUE_SERVER_TAG).empty()) { |
- return false; |
- } |
- if (a.ref(syncable::IS_DIR) != b.ref(syncable::IS_DIR)) |
- return true; |
- if (!AreSpecificsEqual(cryptographer, |
- a.ref(syncable::SPECIFICS), |
- b.ref(syncable::SPECIFICS))) { |
- return true; |
- } |
- if (!AreAttachmentMetadataEqual(a.ref(syncable::ATTACHMENT_METADATA), |
- b.ref(syncable::ATTACHMENT_METADATA))) { |
- return true; |
- } |
- // We only care if the name has changed if neither specifics is encrypted |
- // (encrypted nodes blow away the NON_UNIQUE_NAME). |
- if (!a_specifics.has_encrypted() && !b_specifics.has_encrypted() && |
- a.ref(syncable::NON_UNIQUE_NAME) != b.ref(syncable::NON_UNIQUE_NAME)) |
- return true; |
- if (VisiblePositionsDiffer(mutation)) |
- return true; |
- return false; |
-} |
- |
-ModelTypeSet SyncManagerImpl::InitialSyncEndedTypes() { |
- DCHECK(initialized_); |
- return model_type_registry_->GetInitialSyncEndedTypes(); |
-} |
- |
-ModelTypeSet SyncManagerImpl::GetTypesWithEmptyProgressMarkerToken( |
- ModelTypeSet types) { |
- ModelTypeSet result; |
- for (ModelTypeSet::Iterator i = types.First(); i.Good(); i.Inc()) { |
- sync_pb::DataTypeProgressMarker marker; |
- directory()->GetDownloadProgress(i.Get(), &marker); |
- |
- if (marker.token().empty()) |
- result.Put(i.Get()); |
- } |
- return result; |
-} |
- |
-void SyncManagerImpl::ConfigureSyncer( |
- ConfigureReason reason, |
- ModelTypeSet to_download, |
- ModelTypeSet to_purge, |
- ModelTypeSet to_journal, |
- ModelTypeSet to_unapply, |
- const ModelSafeRoutingInfo& new_routing_info, |
- const base::Closure& ready_task, |
- const base::Closure& retry_task) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(!ready_task.is_null()); |
- DCHECK(initialized_); |
- |
- DVLOG(1) << "Configuring -" |
- << "\n\t" << "current types: " |
- << ModelTypeSetToString(GetRoutingInfoTypes(new_routing_info)) |
- << "\n\t" << "types to download: " |
- << ModelTypeSetToString(to_download) |
- << "\n\t" << "types to purge: " |
- << ModelTypeSetToString(to_purge) |
- << "\n\t" << "types to journal: " |
- << ModelTypeSetToString(to_journal) |
- << "\n\t" << "types to unapply: " |
- << ModelTypeSetToString(to_unapply); |
- if (!PurgeDisabledTypes(to_purge, |
- to_journal, |
- to_unapply)) { |
- // We failed to cleanup the types. Invoke the ready task without actually |
- // configuring any types. The caller should detect this as a configuration |
- // failure and act appropriately. |
- ready_task.Run(); |
- return; |
- } |
- |
- ConfigurationParams params(GetSourceFromReason(reason), |
- to_download, |
- new_routing_info, |
- ready_task, |
- retry_task); |
- |
- scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time()); |
- scheduler_->ScheduleConfiguration(params); |
-} |
- |
-void SyncManagerImpl::Init(InitArgs* args) { |
- CHECK(!initialized_); |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(args->post_factory.get()); |
- DCHECK(!args->credentials.account_id.empty()); |
- DCHECK(!args->credentials.sync_token.empty()); |
- DCHECK(!args->credentials.scope_set.empty()); |
- DCHECK(args->cancelation_signal); |
- DVLOG(1) << "SyncManager starting Init..."; |
- |
- weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()); |
- |
- change_delegate_ = args->change_delegate; |
- |
- AddObserver(&js_sync_manager_observer_); |
- SetJsEventHandler(args->event_handler); |
- |
- AddObserver(&debug_info_event_listener_); |
- |
- database_path_ = args->database_location.Append( |
- syncable::Directory::kSyncDatabaseFilename); |
- report_unrecoverable_error_function_ = |
- args->report_unrecoverable_error_function; |
- |
- allstatus_.SetHasKeystoreKey( |
- !args->restored_keystore_key_for_bootstrapping.empty()); |
- sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl( |
- &share_, args->encryptor, args->restored_key_for_bootstrapping, |
- args->restored_keystore_key_for_bootstrapping)); |
- sync_encryption_handler_->AddObserver(this); |
- sync_encryption_handler_->AddObserver(&debug_info_event_listener_); |
- sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_); |
- |
- base::FilePath absolute_db_path = database_path_; |
- DCHECK(absolute_db_path.IsAbsolute()); |
- |
- std::unique_ptr<syncable::DirectoryBackingStore> backing_store = |
- args->internal_components_factory->BuildDirectoryBackingStore( |
- InternalComponentsFactory::STORAGE_ON_DISK, |
- args->credentials.account_id, absolute_db_path); |
- |
- DCHECK(backing_store.get()); |
- share_.directory.reset( |
- new syncable::Directory( |
- backing_store.release(), |
- args->unrecoverable_error_handler, |
- report_unrecoverable_error_function_, |
- sync_encryption_handler_.get(), |
- sync_encryption_handler_->GetCryptographerUnsafe())); |
- share_.sync_credentials = args->credentials; |
- |
- // UserShare is accessible to a lot of code that doesn't need access to the |
- // sync token so clear sync_token from the UserShare. |
- share_.sync_credentials.sync_token = ""; |
- |
- DVLOG(1) << "Username: " << args->credentials.email; |
- DVLOG(1) << "AccountId: " << args->credentials.account_id; |
- if (!OpenDirectory(args->credentials.account_id)) { |
- NotifyInitializationFailure(); |
- LOG(ERROR) << "Sync manager initialization failed!"; |
- return; |
- } |
- |
- // Now that we have opened the Directory we can restore any previously saved |
- // nigori specifics. |
- if (args->saved_nigori_state) { |
- sync_encryption_handler_->RestoreNigori(*args->saved_nigori_state); |
- args->saved_nigori_state.reset(); |
- } |
- |
- connection_manager_.reset(new SyncAPIServerConnectionManager( |
- args->service_url.host() + args->service_url.path(), |
- args->service_url.EffectiveIntPort(), |
- args->service_url.SchemeIsCryptographic(), args->post_factory.release(), |
- args->cancelation_signal)); |
- connection_manager_->set_client_id(directory()->cache_guid()); |
- connection_manager_->AddListener(this); |
- |
- std::string sync_id = directory()->cache_guid(); |
- |
- DVLOG(1) << "Setting sync client ID: " << sync_id; |
- allstatus_.SetSyncId(sync_id); |
- DVLOG(1) << "Setting invalidator client ID: " << args->invalidator_client_id; |
- allstatus_.SetInvalidatorClientId(args->invalidator_client_id); |
- |
- model_type_registry_.reset( |
- new ModelTypeRegistry(args->workers, directory(), this)); |
- sync_encryption_handler_->AddObserver(model_type_registry_.get()); |
- |
- // Build a SyncSessionContext and store the worker in it. |
- DVLOG(1) << "Sync is bringing up SyncSessionContext."; |
- std::vector<SyncEngineEventListener*> listeners; |
- listeners.push_back(&allstatus_); |
- listeners.push_back(this); |
- session_context_ = args->internal_components_factory->BuildContext( |
- connection_manager_.get(), directory(), args->extensions_activity, |
- listeners, &debug_info_event_listener_, model_type_registry_.get(), |
- args->invalidator_client_id); |
- scheduler_ = args->internal_components_factory->BuildScheduler( |
- name_, session_context_.get(), args->cancelation_signal); |
- |
- scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time()); |
- |
- initialized_ = true; |
- |
- net::NetworkChangeNotifier::AddIPAddressObserver(this); |
- net::NetworkChangeNotifier::AddConnectionTypeObserver(this); |
- observing_network_connectivity_changes_ = true; |
- |
- UpdateCredentials(args->credentials); |
- |
- NotifyInitializationSuccess(); |
-} |
- |
-void SyncManagerImpl::NotifyInitializationSuccess() { |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnInitializationComplete( |
- MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()), |
- MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()), |
- true, InitialSyncEndedTypes())); |
-} |
- |
-void SyncManagerImpl::NotifyInitializationFailure() { |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnInitializationComplete( |
- MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()), |
- MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()), |
- false, ModelTypeSet())); |
-} |
- |
-void SyncManagerImpl::OnPassphraseRequired( |
- PassphraseRequiredReason reason, |
- const sync_pb::EncryptedData& pending_keys) { |
- // Does nothing. |
-} |
- |
-void SyncManagerImpl::OnPassphraseAccepted() { |
- // Does nothing. |
-} |
- |
-void SyncManagerImpl::OnBootstrapTokenUpdated( |
- const std::string& bootstrap_token, |
- BootstrapTokenType type) { |
- if (type == KEYSTORE_BOOTSTRAP_TOKEN) |
- allstatus_.SetHasKeystoreKey(true); |
-} |
- |
-void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types, |
- bool encrypt_everything) { |
- allstatus_.SetEncryptedTypes(encrypted_types); |
-} |
- |
-void SyncManagerImpl::OnEncryptionComplete() { |
- // Does nothing. |
-} |
- |
-void SyncManagerImpl::OnCryptographerStateChanged( |
- Cryptographer* cryptographer) { |
- allstatus_.SetCryptographerReady(cryptographer->is_ready()); |
- allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys()); |
- allstatus_.SetKeystoreMigrationTime( |
- sync_encryption_handler_->migration_time()); |
-} |
- |
-void SyncManagerImpl::OnPassphraseTypeChanged( |
- PassphraseType type, |
- base::Time explicit_passphrase_time) { |
- allstatus_.SetPassphraseType(type); |
- allstatus_.SetKeystoreMigrationTime( |
- sync_encryption_handler_->migration_time()); |
-} |
- |
-void SyncManagerImpl::OnLocalSetPassphraseEncryption( |
- const SyncEncryptionHandler::NigoriState& nigori_state) { |
-} |
- |
-void SyncManagerImpl::StartSyncingNormally( |
- const ModelSafeRoutingInfo& routing_info, |
- base::Time last_poll_time) { |
- // Start the sync scheduler. |
- // TODO(sync): We always want the newest set of routes when we switch back |
- // to normal mode. Figure out how to enforce set_routing_info is always |
- // appropriately set and that it's only modified when switching to normal |
- // mode. |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- session_context_->SetRoutingInfo(routing_info); |
- scheduler_->Start(SyncScheduler::NORMAL_MODE, |
- last_poll_time); |
-} |
- |
-syncable::Directory* SyncManagerImpl::directory() { |
- return share_.directory.get(); |
-} |
- |
-const SyncScheduler* SyncManagerImpl::scheduler() const { |
- return scheduler_.get(); |
-} |
- |
-bool SyncManagerImpl::GetHasInvalidAuthTokenForTest() const { |
- return connection_manager_->HasInvalidAuthToken(); |
-} |
- |
-bool SyncManagerImpl::OpenDirectory(const std::string& username) { |
- DCHECK(!initialized_) << "Should only happen once"; |
- |
- // Set before Open(). |
- change_observer_ = MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr()); |
- WeakHandle<syncable::TransactionObserver> transaction_observer( |
- MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr())); |
- |
- syncable::DirOpenResult open_result = syncable::NOT_INITIALIZED; |
- open_result = directory()->Open(username, this, transaction_observer); |
- if (open_result != syncable::OPENED) { |
- LOG(ERROR) << "Could not open share for:" << username; |
- return false; |
- } |
- |
- // Unapplied datatypes (those that do not have initial sync ended set) get |
- // re-downloaded during any configuration. But, it's possible for a datatype |
- // to have a progress marker but not have initial sync ended yet, making |
- // it a candidate for migration. This is a problem, as the DataTypeManager |
- // does not support a migration while it's already in the middle of a |
- // configuration. As a result, any partially synced datatype can stall the |
- // DTM, waiting for the configuration to complete, which it never will due |
- // to the migration error. In addition, a partially synced nigori will |
- // trigger the migration logic before the backend is initialized, resulting |
- // in crashes. We therefore detect and purge any partially synced types as |
- // part of initialization. |
- if (!PurgePartiallySyncedTypes()) |
- return false; |
- |
- return true; |
-} |
- |
-bool SyncManagerImpl::PurgePartiallySyncedTypes() { |
- ModelTypeSet partially_synced_types = ModelTypeSet::All(); |
- partially_synced_types.RemoveAll(directory()->InitialSyncEndedTypes()); |
- partially_synced_types.RemoveAll(GetTypesWithEmptyProgressMarkerToken( |
- ModelTypeSet::All())); |
- |
- DVLOG(1) << "Purging partially synced types " |
- << ModelTypeSetToString(partially_synced_types); |
- UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes", |
- partially_synced_types.Size()); |
- if (partially_synced_types.Empty()) |
- return true; |
- return directory()->PurgeEntriesWithTypeIn(partially_synced_types, |
- ModelTypeSet(), |
- ModelTypeSet()); |
-} |
- |
-bool SyncManagerImpl::PurgeDisabledTypes( |
- ModelTypeSet to_purge, |
- ModelTypeSet to_journal, |
- ModelTypeSet to_unapply) { |
- if (to_purge.Empty()) |
- return true; |
- DVLOG(1) << "Purging disabled types " << ModelTypeSetToString(to_purge); |
- DCHECK(to_purge.HasAll(to_journal)); |
- DCHECK(to_purge.HasAll(to_unapply)); |
- return directory()->PurgeEntriesWithTypeIn(to_purge, to_journal, to_unapply); |
-} |
- |
-void SyncManagerImpl::UpdateCredentials(const SyncCredentials& credentials) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(initialized_); |
- DCHECK(!credentials.account_id.empty()); |
- DCHECK(!credentials.sync_token.empty()); |
- DCHECK(!credentials.scope_set.empty()); |
- session_context_->set_account_name(credentials.email); |
- |
- observing_network_connectivity_changes_ = true; |
- if (!connection_manager_->SetAuthToken(credentials.sync_token)) |
- return; // Auth token is known to be invalid, so exit early. |
- |
- scheduler_->OnCredentialsUpdated(); |
- |
- // TODO(zea): pass the credential age to the debug info event listener. |
-} |
- |
-void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- observers_.AddObserver(observer); |
-} |
- |
-void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- observers_.RemoveObserver(observer); |
-} |
- |
-void SyncManagerImpl::ShutdownOnSyncThread(ShutdownReason reason) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- // Prevent any in-flight method calls from running. Also |
- // invalidates |weak_handle_this_| and |change_observer_|. |
- weak_ptr_factory_.InvalidateWeakPtrs(); |
- js_mutation_event_observer_.InvalidateWeakPtrs(); |
- |
- scheduler_.reset(); |
- session_context_.reset(); |
- |
- if (model_type_registry_) |
- sync_encryption_handler_->RemoveObserver(model_type_registry_.get()); |
- |
- model_type_registry_.reset(); |
- |
- if (sync_encryption_handler_) { |
- sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_); |
- sync_encryption_handler_->RemoveObserver(this); |
- } |
- |
- SetJsEventHandler(WeakHandle<JsEventHandler>()); |
- RemoveObserver(&js_sync_manager_observer_); |
- |
- RemoveObserver(&debug_info_event_listener_); |
- |
- // |connection_manager_| may end up being NULL here in tests (in synchronous |
- // initialization mode). |
- // |
- // TODO(akalin): Fix this behavior. |
- if (connection_manager_) |
- connection_manager_->RemoveListener(this); |
- connection_manager_.reset(); |
- |
- net::NetworkChangeNotifier::RemoveIPAddressObserver(this); |
- net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
- observing_network_connectivity_changes_ = false; |
- |
- if (initialized_ && directory()) { |
- directory()->SaveChanges(); |
- } |
- |
- share_.directory.reset(); |
- |
- change_delegate_ = NULL; |
- |
- initialized_ = false; |
- |
- // We reset these here, since only now we know they will not be |
- // accessed from other threads (since we shut down everything). |
- change_observer_.Reset(); |
- weak_handle_this_.Reset(); |
-} |
- |
-void SyncManagerImpl::OnIPAddressChanged() { |
- if (!observing_network_connectivity_changes_) { |
- DVLOG(1) << "IP address change dropped."; |
- return; |
- } |
- DVLOG(1) << "IP address change detected."; |
- OnNetworkConnectivityChangedImpl(); |
-} |
- |
-void SyncManagerImpl::OnConnectionTypeChanged( |
- net::NetworkChangeNotifier::ConnectionType) { |
- if (!observing_network_connectivity_changes_) { |
- DVLOG(1) << "Connection type change dropped."; |
- return; |
- } |
- DVLOG(1) << "Connection type change detected."; |
- OnNetworkConnectivityChangedImpl(); |
-} |
- |
-void SyncManagerImpl::OnNetworkConnectivityChangedImpl() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- scheduler_->OnConnectionStatusChange(); |
-} |
- |
-void SyncManagerImpl::OnServerConnectionEvent( |
- const ServerConnectionEvent& event) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (event.connection_code == |
- HttpResponse::SERVER_CONNECTION_OK) { |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnConnectionStatusChange(CONNECTION_OK)); |
- } |
- |
- if (event.connection_code == HttpResponse::SYNC_AUTH_ERROR) { |
- observing_network_connectivity_changes_ = false; |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnConnectionStatusChange(CONNECTION_AUTH_ERROR)); |
- } |
- |
- if (event.connection_code == HttpResponse::SYNC_SERVER_ERROR) { |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnConnectionStatusChange(CONNECTION_SERVER_ERROR)); |
- } |
-} |
- |
-void SyncManagerImpl::HandleTransactionCompleteChangeEvent( |
- ModelTypeSet models_with_changes) { |
- // This notification happens immediately after the transaction mutex is |
- // released. This allows work to be performed without blocking other threads |
- // from acquiring a transaction. |
- if (!change_delegate_) |
- return; |
- |
- // Call commit. |
- for (ModelTypeSet::Iterator it = models_with_changes.First(); |
- it.Good(); it.Inc()) { |
- change_delegate_->OnChangesComplete(it.Get()); |
- change_observer_.Call( |
- FROM_HERE, |
- &SyncManager::ChangeObserver::OnChangesComplete, |
- it.Get()); |
- } |
-} |
- |
-ModelTypeSet |
-SyncManagerImpl::HandleTransactionEndingChangeEvent( |
- const ImmutableWriteTransactionInfo& write_transaction_info, |
- syncable::BaseTransaction* trans) { |
- // This notification happens immediately before a syncable WriteTransaction |
- // falls out of scope. It happens while the channel mutex is still held, |
- // and while the transaction mutex is held, so it cannot be re-entrant. |
- if (!change_delegate_ || change_records_.empty()) |
- return ModelTypeSet(); |
- |
- // This will continue the WriteTransaction using a read only wrapper. |
- // This is the last chance for read to occur in the WriteTransaction |
- // that's closing. This special ReadTransaction will not close the |
- // underlying transaction. |
- ReadTransaction read_trans(GetUserShare(), trans); |
- |
- ModelTypeSet models_with_changes; |
- for (ChangeRecordMap::const_iterator it = change_records_.begin(); |
- it != change_records_.end(); ++it) { |
- DCHECK(!it->second.Get().empty()); |
- ModelType type = ModelTypeFromInt(it->first); |
- change_delegate_-> |
- OnChangesApplied(type, trans->directory()->GetTransactionVersion(type), |
- &read_trans, it->second); |
- change_observer_.Call(FROM_HERE, |
- &SyncManager::ChangeObserver::OnChangesApplied, |
- type, write_transaction_info.Get().id, it->second); |
- models_with_changes.Put(type); |
- } |
- change_records_.clear(); |
- return models_with_changes; |
-} |
- |
-void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncApi( |
- const ImmutableWriteTransactionInfo& write_transaction_info, |
- syncable::BaseTransaction* trans, |
- std::vector<int64_t>* entries_changed) { |
- // We have been notified about a user action changing a sync model. |
- LOG_IF(WARNING, !change_records_.empty()) << |
- "CALCULATE_CHANGES called with unapplied old changes."; |
- |
- // The mutated model type, or UNSPECIFIED if nothing was mutated. |
- ModelTypeSet mutated_model_types; |
- |
- const syncable::ImmutableEntryKernelMutationMap& mutations = |
- write_transaction_info.Get().mutations; |
- for (syncable::EntryKernelMutationMap::const_iterator it = |
- mutations.Get().begin(); it != mutations.Get().end(); ++it) { |
- if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) { |
- continue; |
- } |
- |
- ModelType model_type = |
- GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS)); |
- if (model_type < FIRST_REAL_MODEL_TYPE) { |
- NOTREACHED() << "Permanent or underspecified item changed via syncapi."; |
- continue; |
- } |
- |
- // Found real mutation. |
- if (model_type != UNSPECIFIED) { |
- mutated_model_types.Put(model_type); |
- entries_changed->push_back(it->second.mutated.ref(syncable::META_HANDLE)); |
- } |
- } |
- |
- // Nudge if necessary. |
- if (!mutated_model_types.Empty()) { |
- if (weak_handle_this_.IsInitialized()) { |
- weak_handle_this_.Call(FROM_HERE, |
- &SyncManagerImpl::RequestNudgeForDataTypes, |
- FROM_HERE, |
- mutated_model_types); |
- } else { |
- NOTREACHED(); |
- } |
- } |
-} |
- |
-void SyncManagerImpl::SetExtraChangeRecordData( |
- int64_t id, |
- ModelType type, |
- ChangeReorderBuffer* buffer, |
- Cryptographer* cryptographer, |
- const syncable::EntryKernel& original, |
- bool existed_before, |
- bool exists_now) { |
- // If this is a deletion and the datatype was encrypted, we need to decrypt it |
- // and attach it to the buffer. |
- if (!exists_now && existed_before) { |
- sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS)); |
- if (type == PASSWORDS) { |
- // Passwords must use their own legacy ExtraPasswordChangeRecordData. |
- std::unique_ptr<sync_pb::PasswordSpecificsData> data( |
- DecryptPasswordSpecifics(original_specifics, cryptographer)); |
- if (!data) { |
- NOTREACHED(); |
- return; |
- } |
- buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data)); |
- } else if (original_specifics.has_encrypted()) { |
- // All other datatypes can just create a new unencrypted specifics and |
- // attach it. |
- const sync_pb::EncryptedData& encrypted = original_specifics.encrypted(); |
- if (!cryptographer->Decrypt(encrypted, &original_specifics)) { |
- NOTREACHED(); |
- return; |
- } |
- } |
- buffer->SetSpecificsForId(id, original_specifics); |
- } |
-} |
- |
-void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncer( |
- const ImmutableWriteTransactionInfo& write_transaction_info, |
- syncable::BaseTransaction* trans, |
- std::vector<int64_t>* entries_changed) { |
- // We only expect one notification per sync step, so change_buffers_ should |
- // contain no pending entries. |
- LOG_IF(WARNING, !change_records_.empty()) << |
- "CALCULATE_CHANGES called with unapplied old changes."; |
- |
- ChangeReorderBuffer change_buffers[MODEL_TYPE_COUNT]; |
- |
- Cryptographer* crypto = directory()->GetCryptographer(trans); |
- const syncable::ImmutableEntryKernelMutationMap& mutations = |
- write_transaction_info.Get().mutations; |
- for (syncable::EntryKernelMutationMap::const_iterator it = |
- mutations.Get().begin(); it != mutations.Get().end(); ++it) { |
- bool existed_before = !it->second.original.ref(syncable::IS_DEL); |
- bool exists_now = !it->second.mutated.ref(syncable::IS_DEL); |
- |
- // Omit items that aren't associated with a model. |
- ModelType type = |
- GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS)); |
- if (type < FIRST_REAL_MODEL_TYPE) |
- continue; |
- |
- int64_t handle = it->first; |
- if (exists_now && !existed_before) |
- change_buffers[type].PushAddedItem(handle); |
- else if (!exists_now && existed_before) |
- change_buffers[type].PushDeletedItem(handle); |
- else if (exists_now && existed_before && |
- VisiblePropertiesDiffer(it->second, crypto)) |
- change_buffers[type].PushUpdatedItem(handle); |
- |
- SetExtraChangeRecordData(handle, type, &change_buffers[type], crypto, |
- it->second.original, existed_before, exists_now); |
- } |
- |
- ReadTransaction read_trans(GetUserShare(), trans); |
- for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) { |
- if (!change_buffers[i].IsEmpty()) { |
- if (change_buffers[i].GetAllChangesInTreeOrder(&read_trans, |
- &(change_records_[i]))) { |
- for (size_t j = 0; j < change_records_[i].Get().size(); ++j) |
- entries_changed->push_back((change_records_[i].Get())[j].id); |
- } |
- if (change_records_[i].Get().empty()) |
- change_records_.erase(i); |
- } |
- } |
-} |
- |
-void SyncManagerImpl::RequestNudgeForDataTypes( |
- const tracked_objects::Location& nudge_location, |
- ModelTypeSet types) { |
- debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get()); |
- |
- scheduler_->ScheduleLocalNudge(types, nudge_location); |
-} |
- |
-void SyncManagerImpl::NudgeForInitialDownload(syncer::ModelType type) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- scheduler_->ScheduleInitialSyncNudge(type); |
-} |
- |
-void SyncManagerImpl::NudgeForCommit(syncer::ModelType type) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- RequestNudgeForDataTypes(FROM_HERE, ModelTypeSet(type)); |
-} |
- |
-void SyncManagerImpl::NudgeForRefresh(syncer::ModelType type) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- RefreshTypes(ModelTypeSet(type)); |
-} |
- |
-void SyncManagerImpl::OnSyncCycleEvent(const SyncCycleEvent& event) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- // Only send an event if this is due to a cycle ending and this cycle |
- // concludes a canonical "sync" process; that is, based on what is known |
- // locally we are "all happy" and up to date. There may be new changes on |
- // the server, but we'll get them on a subsequent sync. |
- // |
- // Notifications are sent at the end of every sync cycle, regardless of |
- // whether we should sync again. |
- if (event.what_happened == SyncCycleEvent::SYNC_CYCLE_ENDED) { |
- if (!initialized_) { |
- DVLOG(1) << "OnSyncCycleCompleted not sent because sync api is not " |
- << "initialized"; |
- return; |
- } |
- |
- DVLOG(1) << "Sending OnSyncCycleCompleted"; |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnSyncCycleCompleted(event.snapshot)); |
- } |
-} |
- |
-void SyncManagerImpl::OnActionableError(const SyncProtocolError& error) { |
- FOR_EACH_OBSERVER( |
- SyncManager::Observer, observers_, |
- OnActionableError(error)); |
-} |
- |
-void SyncManagerImpl::OnRetryTimeChanged(base::Time) {} |
- |
-void SyncManagerImpl::OnThrottledTypesChanged(ModelTypeSet) {} |
- |
-void SyncManagerImpl::OnMigrationRequested(ModelTypeSet types) { |
- FOR_EACH_OBSERVER( |
- SyncManager::Observer, observers_, |
- OnMigrationRequested(types)); |
-} |
- |
-void SyncManagerImpl::OnProtocolEvent(const ProtocolEvent& event) { |
- protocol_event_buffer_.RecordProtocolEvent(event); |
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, |
- OnProtocolEvent(event)); |
-} |
- |
-void SyncManagerImpl::SetJsEventHandler( |
- const WeakHandle<JsEventHandler>& event_handler) { |
- js_sync_manager_observer_.SetJsEventHandler(event_handler); |
- js_mutation_event_observer_.SetJsEventHandler(event_handler); |
- js_sync_encryption_handler_observer_.SetJsEventHandler(event_handler); |
-} |
- |
-std::unique_ptr<base::ListValue> SyncManagerImpl::GetAllNodesForType( |
- syncer::ModelType type) { |
- DirectoryTypeDebugInfoEmitterMap* emitter_map = |
- model_type_registry_->directory_type_debug_info_emitter_map(); |
- DirectoryTypeDebugInfoEmitterMap::iterator it = emitter_map->find(type); |
- |
- if (it == emitter_map->end()) { |
- // This can happen in some cases. The UI thread makes requests of us |
- // when it doesn't really know which types are enabled or disabled. |
- DLOG(WARNING) << "Asked to return debug info for invalid type " |
- << ModelTypeToString(type); |
- return std::unique_ptr<base::ListValue>(new base::ListValue()); |
- } |
- |
- return it->second->GetAllNodes(); |
-} |
- |
-void SyncManagerImpl::SetInvalidatorEnabled(bool invalidator_enabled) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- DVLOG(1) << "Invalidator enabled state is now: " << invalidator_enabled; |
- allstatus_.SetNotificationsEnabled(invalidator_enabled); |
- scheduler_->SetNotificationsEnabled(invalidator_enabled); |
-} |
- |
-void SyncManagerImpl::OnIncomingInvalidation( |
- syncer::ModelType type, |
- std::unique_ptr<InvalidationInterface> invalidation) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- |
- allstatus_.IncrementNotificationsReceived(); |
- scheduler_->ScheduleInvalidationNudge(type, std::move(invalidation), |
- FROM_HERE); |
-} |
- |
-void SyncManagerImpl::RefreshTypes(ModelTypeSet types) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- if (types.Empty()) { |
- LOG(WARNING) << "Sync received refresh request with no types specified."; |
- } else { |
- scheduler_->ScheduleLocalRefreshRequest( |
- types, FROM_HERE); |
- } |
-} |
- |
-SyncStatus SyncManagerImpl::GetDetailedStatus() const { |
- return allstatus_.status(); |
-} |
- |
-void SyncManagerImpl::SaveChanges() { |
- directory()->SaveChanges(); |
-} |
- |
-UserShare* SyncManagerImpl::GetUserShare() { |
- DCHECK(initialized_); |
- return &share_; |
-} |
- |
-std::unique_ptr<syncer_v2::ModelTypeConnector> |
-SyncManagerImpl::GetModelTypeConnectorProxy() { |
- DCHECK(initialized_); |
- return base::WrapUnique(new syncer_v2::ModelTypeConnectorProxy( |
- base::ThreadTaskRunnerHandle::Get(), model_type_registry_->AsWeakPtr())); |
-} |
- |
-const std::string SyncManagerImpl::cache_guid() { |
- DCHECK(initialized_); |
- return directory()->cache_guid(); |
-} |
- |
-bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) { |
- ReadTransaction trans(FROM_HERE, GetUserShare()); |
- ReadNode nigori_node(&trans); |
- if (nigori_node.InitTypeRoot(NIGORI) != BaseNode::INIT_OK) { |
- DVLOG(1) << "Couldn't find Nigori node."; |
- return false; |
- } |
- bool found_experiment = false; |
- |
- ReadNode favicon_sync_node(&trans); |
- if (favicon_sync_node.InitByClientTagLookup( |
- syncer::EXPERIMENTS, |
- syncer::kFaviconSyncTag) == BaseNode::INIT_OK) { |
- experiments->favicon_sync_limit = |
- favicon_sync_node.GetExperimentsSpecifics().favicon_sync(). |
- favicon_sync_limit(); |
- found_experiment = true; |
- } |
- |
- ReadNode pre_commit_update_avoidance_node(&trans); |
- if (pre_commit_update_avoidance_node.InitByClientTagLookup( |
- syncer::EXPERIMENTS, |
- syncer::kPreCommitUpdateAvoidanceTag) == BaseNode::INIT_OK) { |
- session_context_->set_server_enabled_pre_commit_update_avoidance( |
- pre_commit_update_avoidance_node.GetExperimentsSpecifics(). |
- pre_commit_update_avoidance().enabled()); |
- // We don't bother setting found_experiment. The frontend doesn't need to |
- // know about this. |
- } |
- |
- ReadNode gcm_invalidations_node(&trans); |
- if (gcm_invalidations_node.InitByClientTagLookup( |
- syncer::EXPERIMENTS, syncer::kGCMInvalidationsTag) == |
- BaseNode::INIT_OK) { |
- const sync_pb::GcmInvalidationsFlags& gcm_invalidations = |
- gcm_invalidations_node.GetExperimentsSpecifics().gcm_invalidations(); |
- if (gcm_invalidations.has_enabled()) { |
- experiments->gcm_invalidations_enabled = gcm_invalidations.enabled(); |
- found_experiment = true; |
- } |
- } |
- |
- return found_experiment; |
-} |
- |
-bool SyncManagerImpl::HasUnsyncedItems() { |
- ReadTransaction trans(FROM_HERE, GetUserShare()); |
- return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); |
-} |
- |
-SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() { |
- return sync_encryption_handler_.get(); |
-} |
- |
-ScopedVector<syncer::ProtocolEvent> |
- SyncManagerImpl::GetBufferedProtocolEvents() { |
- return protocol_event_buffer_.GetBufferedProtocolEvents(); |
-} |
- |
-void SyncManagerImpl::RegisterDirectoryTypeDebugInfoObserver( |
- syncer::TypeDebugInfoObserver* observer) { |
- model_type_registry_->RegisterDirectoryTypeDebugInfoObserver(observer); |
-} |
- |
-void SyncManagerImpl::UnregisterDirectoryTypeDebugInfoObserver( |
- syncer::TypeDebugInfoObserver* observer) { |
- model_type_registry_->UnregisterDirectoryTypeDebugInfoObserver(observer); |
-} |
- |
-bool SyncManagerImpl::HasDirectoryTypeDebugInfoObserver( |
- syncer::TypeDebugInfoObserver* observer) { |
- return model_type_registry_->HasDirectoryTypeDebugInfoObserver(observer); |
-} |
- |
-void SyncManagerImpl::RequestEmitDebugInfo() { |
- model_type_registry_->RequestEmitDebugInfo(); |
-} |
- |
-void SyncManagerImpl::ClearServerData(const ClearServerDataCallback& callback) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- scheduler_->Start(SyncScheduler::CLEAR_SERVER_DATA_MODE, base::Time()); |
- ClearParams params(callback); |
- scheduler_->ScheduleClearServerData(params); |
-} |
- |
-void SyncManagerImpl::OnCookieJarChanged(bool account_mismatch, |
- bool empty_jar) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- session_context_->set_cookie_jar_mismatch(account_mismatch); |
- session_context_->set_cookie_jar_empty(empty_jar); |
-} |
- |
-} // namespace syncer |