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

Unified Diff: chrome/browser/sync/internal_api/sync_manager.cc

Issue 10147003: [Sync] Move 'syncapi_core' and 'sync_unit_tests' targets to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Win update errors Created 8 years, 8 months 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/internal_api/sync_manager.cc
diff --git a/chrome/browser/sync/internal_api/sync_manager.cc b/chrome/browser/sync/internal_api/sync_manager.cc
deleted file mode 100644
index 6e6f17664eaebac9f8336f9fb3ad74c1feb10ae8..0000000000000000000000000000000000000000
--- a/chrome/browser/sync/internal_api/sync_manager.cc
+++ /dev/null
@@ -1,2575 +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 "chrome/browser/sync/internal_api/sync_manager.h"
-
-#include <string>
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/json/json_writer.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram.h"
-#include "base/observer_list.h"
-#include "base/string_number_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/sync/internal_api/all_status.h"
-#include "chrome/browser/sync/internal_api/base_node.h"
-#include "chrome/browser/sync/internal_api/change_reorder_buffer.h"
-#include "chrome/browser/sync/internal_api/configure_reason.h"
-#include "chrome/browser/sync/internal_api/debug_info_event_listener.h"
-#include "chrome/browser/sync/internal_api/js_mutation_event_observer.h"
-#include "chrome/browser/sync/internal_api/js_sync_manager_observer.h"
-#include "chrome/browser/sync/internal_api/read_node.h"
-#include "chrome/browser/sync/internal_api/read_transaction.h"
-#include "chrome/browser/sync/internal_api/syncapi_internal.h"
-#include "chrome/browser/sync/internal_api/syncapi_server_connection_manager.h"
-#include "chrome/browser/sync/internal_api/user_share.h"
-#include "chrome/browser/sync/internal_api/write_node.h"
-#include "chrome/browser/sync/internal_api/write_transaction.h"
-#include "net/base/network_change_notifier.h"
-#include "sync/engine/net/server_connection_manager.h"
-#include "sync/engine/nigori_util.h"
-#include "sync/engine/polling_constants.h"
-#include "sync/engine/sync_scheduler.h"
-#include "sync/engine/syncer_types.h"
-#include "sync/js/js_arg_list.h"
-#include "sync/js/js_backend.h"
-#include "sync/js/js_event_details.h"
-#include "sync/js/js_event_handler.h"
-#include "sync/js/js_reply_handler.h"
-#include "sync/notifier/sync_notifier.h"
-#include "sync/notifier/sync_notifier_observer.h"
-#include "sync/protocol/encryption.pb.h"
-#include "sync/protocol/proto_value_conversions.h"
-#include "sync/protocol/sync.pb.h"
-#include "sync/syncable/directory_change_delegate.h"
-#include "sync/syncable/model_type.h"
-#include "sync/syncable/model_type_payload_map.h"
-#include "sync/syncable/syncable.h"
-#include "sync/util/cryptographer.h"
-#include "sync/util/get_session_name.h"
-#include "sync/util/time.h"
-
-using base::TimeDelta;
-using browser_sync::AllStatus;
-using browser_sync::Cryptographer;
-using browser_sync::Encryptor;
-using browser_sync::JsArgList;
-using browser_sync::JsBackend;
-using browser_sync::JsEventDetails;
-using browser_sync::JsEventHandler;
-using browser_sync::JsEventHandler;
-using browser_sync::JsReplyHandler;
-using browser_sync::JsMutationEventObserver;
-using browser_sync::JsSyncManagerObserver;
-using browser_sync::ModelSafeWorkerRegistrar;
-using browser_sync::kNigoriTag;
-using browser_sync::KeyParams;
-using browser_sync::ModelSafeRoutingInfo;
-using browser_sync::ReportUnrecoverableErrorFunction;
-using browser_sync::ServerConnectionEvent;
-using browser_sync::ServerConnectionEventListener;
-using browser_sync::SyncEngineEvent;
-using browser_sync::SyncEngineEventListener;
-using browser_sync::SyncScheduler;
-using browser_sync::Syncer;
-using browser_sync::UnrecoverableErrorHandler;
-using browser_sync::WeakHandle;
-using browser_sync::sessions::SyncSessionContext;
-using syncable::ImmutableWriteTransactionInfo;
-using syncable::ModelType;
-using syncable::ModelTypeSet;
-using syncable::SPECIFICS;
-using sync_pb::GetUpdatesCallerInfo;
-
-namespace {
-
-// Delays for syncer nudges.
-static const int kSyncRefreshDelayMsec = 500;
-static const int kSyncSchedulerDelayMsec = 250;
-
-GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
- sync_api::ConfigureReason reason) {
- switch (reason) {
- case sync_api::CONFIGURE_REASON_RECONFIGURATION:
- return GetUpdatesCallerInfo::RECONFIGURATION;
- case sync_api::CONFIGURE_REASON_MIGRATION:
- return GetUpdatesCallerInfo::MIGRATION;
- case sync_api::CONFIGURE_REASON_NEW_CLIENT:
- return GetUpdatesCallerInfo::NEW_CLIENT;
- case sync_api::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE:
- return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE;
- default:
- NOTREACHED();
- }
-
- return GetUpdatesCallerInfo::UNKNOWN;
-}
-
-// The maximum number of times we will automatically overwrite the nigori node
-// because the encryption keys don't match (per chrome instantiation).
-static const int kNigoriOverwriteLimit = 10;
-
-} // namespace
-
-namespace sync_api {
-
-const int SyncManager::kDefaultNudgeDelayMilliseconds = 200;
-const int SyncManager::kPreferencesNudgeDelayMilliseconds = 2000;
-
-// Maximum count and size for traffic recorder.
-const unsigned int kMaxMessagesToRecord = 10;
-const unsigned int kMaxMessageSizeToRecord = 5 * 1024;
-
-//////////////////////////////////////////////////////////////////////////
-// SyncManager's implementation: SyncManager::SyncInternal
-class SyncManager::SyncInternal
- : public net::NetworkChangeNotifier::IPAddressObserver,
- public browser_sync::Cryptographer::Observer,
- public sync_notifier::SyncNotifierObserver,
- public JsBackend,
- public SyncEngineEventListener,
- public ServerConnectionEventListener,
- public syncable::DirectoryChangeDelegate {
- public:
- explicit SyncInternal(const std::string& name)
- : name_(name),
- weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
- enable_sync_tabs_for_other_clients_(false),
- registrar_(NULL),
- change_delegate_(NULL),
- initialized_(false),
- testing_mode_(NON_TEST),
- observing_ip_address_changes_(false),
- traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord),
- encryptor_(NULL),
- unrecoverable_error_handler_(NULL),
- report_unrecoverable_error_function_(NULL),
- created_on_loop_(MessageLoop::current()),
- nigori_overwrite_count_(0) {
- // Pre-fill |notification_info_map_|.
- for (int i = syncable::FIRST_REAL_MODEL_TYPE;
- i < syncable::MODEL_TYPE_COUNT; ++i) {
- notification_info_map_.insert(
- std::make_pair(syncable::ModelTypeFromInt(i), NotificationInfo()));
- }
-
- // Bind message handlers.
- BindJsMessageHandler(
- "getNotificationState",
- &SyncManager::SyncInternal::GetNotificationState);
- BindJsMessageHandler(
- "getNotificationInfo",
- &SyncManager::SyncInternal::GetNotificationInfo);
- BindJsMessageHandler(
- "getRootNodeDetails",
- &SyncManager::SyncInternal::GetRootNodeDetails);
- BindJsMessageHandler(
- "getNodeSummariesById",
- &SyncManager::SyncInternal::GetNodeSummariesById);
- BindJsMessageHandler(
- "getNodeDetailsById",
- &SyncManager::SyncInternal::GetNodeDetailsById);
- BindJsMessageHandler(
- "getAllNodes",
- &SyncManager::SyncInternal::GetAllNodes);
- BindJsMessageHandler(
- "getChildNodeIds",
- &SyncManager::SyncInternal::GetChildNodeIds);
- BindJsMessageHandler(
- "getClientServerTraffic",
- &SyncManager::SyncInternal::GetClientServerTraffic);
- }
-
- virtual ~SyncInternal() {
- CHECK(!initialized_);
- }
-
- bool Init(const FilePath& database_location,
- const WeakHandle<JsEventHandler>& event_handler,
- const std::string& sync_server_and_path,
- int port,
- bool use_ssl,
- const scoped_refptr<base::TaskRunner>& blocking_task_runner,
- HttpPostProviderFactory* post_factory,
- ModelSafeWorkerRegistrar* model_safe_worker_registrar,
- browser_sync::ExtensionsActivityMonitor*
- extensions_activity_monitor,
- ChangeDelegate* change_delegate,
- const std::string& user_agent,
- const SyncCredentials& credentials,
- bool enable_sync_tabs_for_other_clients,
- sync_notifier::SyncNotifier* sync_notifier,
- const std::string& restored_key_for_bootstrapping,
- TestingMode testing_mode,
- Encryptor* encryptor,
- UnrecoverableErrorHandler* unrecoverable_error_handler,
- ReportUnrecoverableErrorFunction
- report_unrecoverable_error_function);
-
- // Sign into sync with given credentials.
- // We do not verify the tokens given. After this call, the tokens are set
- // and the sync DB is open. True if successful, false if something
- // went wrong.
- bool SignIn(const SyncCredentials& credentials);
-
- // Update tokens that we're using in Sync. Email must stay the same.
- void UpdateCredentials(const SyncCredentials& credentials);
-
- // Called when the user disables or enables a sync type.
- void UpdateEnabledTypes();
-
- // Conditionally sets the flag in the Nigori node which instructs other
- // clients to start syncing tabs.
- void MaybeSetSyncTabsInNigoriNode(ModelTypeSet enabled_types);
-
- // Tell the sync engine to start the syncing process.
- void StartSyncingNormally();
-
- // Whether or not the Nigori node is encrypted using an explicit passphrase.
- bool IsUsingExplicitPassphrase();
-
- // Update the Cryptographer from the current nigori node and write back any
- // necessary changes to the nigori node. We also detect missing encryption
- // keys and write them into the nigori node.
- // Also updates or adds the device information into the nigori node.
- // Note: opens a transaction and can trigger an ON_PASSPHRASE_REQUIRED, so
- // should only be called after syncapi is fully initialized.
- // Calls the callback argument with true if cryptographer is ready, false
- // otherwise.
- void UpdateCryptographerAndNigori(
- const std::string& chrome_version,
- const base::Closure& done_callback);
-
- // Stores the current set of encryption keys (if the cryptographer is ready)
- // and encrypted types into the nigori node.
- void UpdateNigoriEncryptionState(Cryptographer* cryptographer,
- WriteNode* nigori_node);
-
- // Updates the nigori node with any new encrypted types and then
- // encrypts the nodes for those new data types as well as other
- // nodes that should be encrypted but aren't. Triggers
- // OnPassphraseRequired if the cryptographer isn't ready.
- void RefreshEncryption();
-
- // Re-encrypts the encrypted data types using the passed passphrase, and sets
- // a flag in the nigori node specifying whether the current passphrase is
- // explicit (custom passphrase) or non-explicit (GAIA). If the existing
- // encryption passphrase is "explicit", the data cannot be re-encrypted and
- // SetEncryptionPassphrase will do nothing.
- // If !is_explicit and there are pending keys, we will attempt to decrypt them
- // using this passphrase. If this fails, we will save this encryption key to
- // be applied later after the pending keys are resolved.
- // Calls FinishSetPassphrase at the end, which notifies observers of the
- // result of the set passphrase operation, updates the nigori node, and does
- // re-encryption.
- void SetEncryptionPassphrase(const std::string& passphrase, bool is_explicit);
-
- // Provides a passphrase for decrypting the user's existing sync data. Calls
- // FinishSetPassphrase at the end, which notifies observers of the result of
- // the set passphrase operation, updates the nigori node, and does
- // re-encryption.
- void SetDecryptionPassphrase(const std::string& passphrase);
-
- // The final step of SetEncryptionPassphrase and SetDecryptionPassphrase that
- // notifies observers of the result of the set passphrase operation, updates
- // the nigori node, and does re-encryption.
- // |success|: true if the operation was successful and false otherwise. If
- // success == false, we send an OnPassphraseRequired notification.
- // |bootstrap_token|: used to inform observers if the cryptographer's
- // bootstrap token was updated.
- // |is_explicit|: used to differentiate between a custom passphrase (true) and
- // a GAIA passphrase that is implicitly used for encryption
- // (false).
- // |trans| and |nigori_node|: used to access data in the cryptographer.
- void FinishSetPassphrase(
- bool success,
- const std::string& bootstrap_token,
- bool is_explicit,
- WriteTransaction* trans,
- WriteNode* nigori_node);
-
- // Call periodically from a database-safe thread to persist recent changes
- // to the syncapi model.
- void SaveChanges();
-
- // DirectoryChangeDelegate implementation.
- // This listener is called upon completion of a syncable transaction, and
- // builds the list of sync-engine initiated changes that will be forwarded to
- // the SyncManager's Observers.
- virtual void HandleTransactionCompleteChangeEvent(
- ModelTypeSet models_with_changes) OVERRIDE;
- virtual ModelTypeSet HandleTransactionEndingChangeEvent(
- const ImmutableWriteTransactionInfo& write_transaction_info,
- syncable::BaseTransaction* trans) OVERRIDE;
- virtual void HandleCalculateChangesChangeEventFromSyncApi(
- const ImmutableWriteTransactionInfo& write_transaction_info,
- syncable::BaseTransaction* trans) OVERRIDE;
- virtual void HandleCalculateChangesChangeEventFromSyncer(
- const ImmutableWriteTransactionInfo& write_transaction_info,
- syncable::BaseTransaction* trans) OVERRIDE;
-
- // Open the directory named with username_for_share
- bool OpenDirectory();
-
- // Cryptographer::Observer implementation.
- virtual void OnEncryptedTypesChanged(
- syncable::ModelTypeSet encrypted_types,
- bool encrypt_everything) OVERRIDE;
-
- // SyncNotifierObserver implementation.
- virtual void OnNotificationStateChange(
- bool notifications_enabled) OVERRIDE;
-
- virtual void OnIncomingNotification(
- const syncable::ModelTypePayloadMap& type_payloads,
- sync_notifier::IncomingNotificationSource source) OVERRIDE;
-
- virtual void StoreState(const std::string& cookie) OVERRIDE;
-
- void AddObserver(SyncManager::Observer* observer);
- void RemoveObserver(SyncManager::Observer* observer);
-
- // Accessors for the private members.
- syncable::Directory* directory() { return share_.directory.get(); }
- SyncAPIServerConnectionManager* connection_manager() {
- return connection_manager_.get();
- }
- SyncScheduler* scheduler() const { return scheduler_.get(); }
- UserShare* GetUserShare() {
- DCHECK(initialized_);
- return &share_;
- }
-
- // Return the currently active (validated) username for use with syncable
- // types.
- const std::string& username_for_share() const {
- return share_.name;
- }
-
- Status GetStatus();
-
- void RequestNudge(const tracked_objects::Location& nudge_location);
-
- void RequestNudgeForDataTypes(
- const tracked_objects::Location& nudge_location,
- ModelTypeSet type);
-
- TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type);
-
- void NotifyCryptographerState(Cryptographer* cryptographer);
-
- // See SyncManager::Shutdown* for information.
- void StopSyncingForShutdown(const base::Closure& callback);
- void ShutdownOnSyncThread();
-
- // If this is a deletion for a password, sets the legacy
- // ExtraPasswordChangeRecordData field of |buffer|. Otherwise sets
- // |buffer|'s specifics field to contain the unencrypted data.
- void SetExtraChangeRecordData(int64 id,
- syncable::ModelType type,
- ChangeReorderBuffer* buffer,
- Cryptographer* cryptographer,
- const syncable::EntryKernel& original,
- bool existed_before,
- bool exists_now);
-
- // Called only by our NetworkChangeNotifier.
- virtual void OnIPAddressChanged() OVERRIDE;
-
- bool InitialSyncEndedForAllEnabledTypes() {
- syncable::ModelTypeSet types;
- ModelSafeRoutingInfo enabled_types;
- registrar_->GetModelSafeRoutingInfo(&enabled_types);
- for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
- i != enabled_types.end(); ++i) {
- types.Put(i->first);
- }
-
- return InitialSyncEndedForTypes(types, &share_);
- }
-
- // SyncEngineEventListener implementation.
- virtual void OnSyncEngineEvent(const SyncEngineEvent& event) OVERRIDE;
-
- // ServerConnectionEventListener implementation.
- virtual void OnServerConnectionEvent(
- const ServerConnectionEvent& event) OVERRIDE;
-
- // JsBackend implementation.
- virtual void SetJsEventHandler(
- const WeakHandle<JsEventHandler>& event_handler) OVERRIDE;
- virtual void ProcessJsMessage(
- const std::string& name, const JsArgList& args,
- const WeakHandle<JsReplyHandler>& reply_handler) OVERRIDE;
-
- private:
- struct NotificationInfo {
- int total_count;
- std::string payload;
-
- NotificationInfo() : total_count(0) {}
-
- ~NotificationInfo() {}
-
- // Returned pointer owned by the caller.
- DictionaryValue* ToValue() const {
- DictionaryValue* value = new DictionaryValue();
- value->SetInteger("totalCount", total_count);
- value->SetString("payload", payload);
- return value;
- }
- };
-
- typedef std::map<syncable::ModelType, NotificationInfo> NotificationInfoMap;
- typedef JsArgList
- (SyncManager::SyncInternal::*UnboundJsMessageHandler)(const JsArgList&);
- typedef base::Callback<JsArgList(const JsArgList&)> JsMessageHandler;
- typedef std::map<std::string, JsMessageHandler> JsMessageHandlerMap;
-
- // Internal callback of UpdateCryptographerAndNigoriCallback.
- void UpdateCryptographerAndNigoriCallback(
- const std::string& chrome_version,
- const base::Closure& done_callback,
- const std::string& session_name);
-
- // Determine if the parents or predecessors differ between the old and new
- // versions of an entry stored in |a| and |b|. Note that a node's index may
- // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
- // the relative order is unchanged). To handle such cases, we rely on the
- // caller to treat a position update on any sibling as updating the positions
- // of all siblings.
- static bool VisiblePositionsDiffer(
- const syncable::EntryKernelMutation& mutation) {
- const syncable::EntryKernel& a = mutation.original;
- const syncable::EntryKernel& b = mutation.mutated;
- // If the datatype isn't one where the browser model cares about position,
- // don't bother notifying that data model of position-only changes.
- if (!ShouldMaintainPosition(
- syncable::GetModelTypeFromSpecifics(b.ref(SPECIFICS))))
- return false;
- if (a.ref(syncable::NEXT_ID) != b.ref(syncable::NEXT_ID))
- return true;
- if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID))
- return true;
- return false;
- }
-
- // Determine if any of the fields made visible to clients of the Sync API
- // differ between the versions of an entry stored in |a| and |b|. A return
- // value of false means that it should be OK to ignore this change.
- static bool VisiblePropertiesDiffer(
- const syncable::EntryKernelMutation& mutation,
- Cryptographer* cryptographer) {
- 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(syncable::GetModelTypeFromSpecifics(a_specifics),
- syncable::GetModelTypeFromSpecifics(b_specifics));
- syncable::ModelType model_type =
- syncable::GetModelTypeFromSpecifics(b_specifics);
- // Suppress updates to items that aren't tracked by any browser model.
- if (model_type < syncable::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;
- }
- // 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;
- }
-
- bool ChangeBuffersAreEmpty() {
- for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
- if (!change_buffers_[i].IsEmpty())
- return false;
- }
- return true;
- }
-
- void ReEncryptEverything(WriteTransaction* trans);
-
- // Called for every notification. This updates the notification statistics
- // to be displayed in about:sync.
- void UpdateNotificationInfo(
- const syncable::ModelTypePayloadMap& type_payloads);
-
- // Checks for server reachabilty and requests a nudge.
- void OnIPAddressChangedImpl();
-
- // Helper function used only by the constructor.
- void BindJsMessageHandler(
- const std::string& name, UnboundJsMessageHandler unbound_message_handler);
-
- // Returned pointer is owned by the caller.
- static DictionaryValue* NotificationInfoToValue(
- const NotificationInfoMap& notification_info);
-
- // JS message handlers.
- JsArgList GetNotificationState(const JsArgList& args);
- JsArgList GetNotificationInfo(const JsArgList& args);
- JsArgList GetRootNodeDetails(const JsArgList& args);
- JsArgList GetAllNodes(const JsArgList& args);
- JsArgList GetNodeSummariesById(const JsArgList& args);
- JsArgList GetNodeDetailsById(const JsArgList& args);
- JsArgList GetChildNodeIds(const JsArgList& args);
- JsArgList GetClientServerTraffic(const JsArgList& args);
-
- FilePath database_path_;
-
- const std::string name_;
-
- base::ThreadChecker thread_checker_;
-
- base::WeakPtrFactory<SyncInternal> weak_ptr_factory_;
-
- // Thread-safe handle used by
- // HandleCalculateChangesChangeEventFromSyncApi(), which can be
- // called from any thread. Valid only between between calls to
- // Init() and Shutdown().
- //
- // TODO(akalin): Ideally, we wouldn't need to store this; instead,
- // we'd have another worker class which implements
- // HandleCalculateChangesChangeEventFromSyncApi() and we'd pass it a
- // WeakHandle when we construct it.
- WeakHandle<SyncInternal> weak_handle_this_;
-
- // |blocking_task_runner| is a TaskRunner to be used for tasks that
- // may block on disk I/O.
- scoped_refptr<base::TaskRunner> blocking_task_runner_;
-
- // We give a handle to share_ to clients of the API for use when constructing
- // any transaction type.
- UserShare share_;
-
- // This can be called from any thread, but only between calls to
- // OpenDirectory() and ShutdownOnSyncThread().
- browser_sync::WeakHandle<SyncManager::ChangeObserver> change_observer_;
-
- ObserverList<SyncManager::Observer> observers_;
-
- // The ServerConnectionManager used to abstract communication between the
- // client (the Syncer) and the sync server.
- scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
-
- // The scheduler that runs the Syncer. Needs to be explicitly
- // Start()ed.
- scoped_ptr<SyncScheduler> scheduler_;
-
- bool enable_sync_tabs_for_other_clients_;
-
- // The SyncNotifier which notifies us when updates need to be downloaded.
- scoped_ptr<sync_notifier::SyncNotifier> sync_notifier_;
-
- // A multi-purpose status watch object that aggregates stats from various
- // sync components.
- AllStatus allstatus_;
-
- // Each element of this array is a store of change records produced by
- // HandleChangeEvent during the CALCULATE_CHANGES step. The changes are
- // segregated by model type, and are stored here to be processed and
- // forwarded to the observer slightly later, at the TRANSACTION_ENDING
- // step by HandleTransactionEndingChangeEvent. The list is cleared in the
- // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
- ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
-
- // The entity that provides us with information about which types to sync.
- // The instance is shared between the SyncManager and the Syncer.
- ModelSafeWorkerRegistrar* registrar_;
-
- SyncManager::ChangeDelegate* change_delegate_;
-
- // Set to true once Init has been called.
- bool initialized_;
-
- // Controls the disabling of certain SyncManager features.
- // Can be used to disable communication with the server and the use of an
- // on-disk file for maintaining syncer state.
- // TODO(117836): Clean up implementation of SyncManager unit tests.
- TestingMode testing_mode_;
-
- bool observing_ip_address_changes_;
-
- // Map used to store the notification info to be displayed in
- // about:sync page.
- NotificationInfoMap notification_info_map_;
-
- // These are for interacting with chrome://sync-internals.
- JsMessageHandlerMap js_message_handlers_;
- WeakHandle<JsEventHandler> js_event_handler_;
- JsSyncManagerObserver js_sync_manager_observer_;
- JsMutationEventObserver js_mutation_event_observer_;
-
- // This is for keeping track of client events to send to the server.
- DebugInfoEventListener debug_info_event_listener_;
-
- browser_sync::TrafficRecorder traffic_recorder_;
-
- Encryptor* encryptor_;
- UnrecoverableErrorHandler* unrecoverable_error_handler_;
- ReportUnrecoverableErrorFunction report_unrecoverable_error_function_;
-
- MessageLoop* const created_on_loop_;
-
- // The number of times we've automatically (i.e. not via SetPassphrase or
- // conflict resolver) updated the nigori's encryption keys in this chrome
- // instantiation.
- int nigori_overwrite_count_;
-};
-
-// A class to calculate nudge delays for types.
-class NudgeStrategy {
- public:
- static TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type,
- SyncManager::SyncInternal* core) {
- NudgeDelayStrategy delay_type = GetNudgeDelayStrategy(model_type);
- return GetNudgeDelayTimeDeltaFromType(delay_type,
- model_type,
- core);
- }
-
- private:
- // Possible types of nudge delay for datatypes.
- // Note: These are just hints. If a sync happens then all dirty entries
- // would be committed as part of the sync.
- enum NudgeDelayStrategy {
- // Sync right away.
- IMMEDIATE,
-
- // Sync this change while syncing another change.
- ACCOMPANY_ONLY,
-
- // The datatype does not use one of the predefined wait times but defines
- // its own wait time logic for nudge.
- CUSTOM,
- };
-
- static NudgeDelayStrategy GetNudgeDelayStrategy(const ModelType& type) {
- switch (type) {
- case syncable::AUTOFILL:
- return ACCOMPANY_ONLY;
- case syncable::PREFERENCES:
- case syncable::SESSIONS:
- return CUSTOM;
- default:
- return IMMEDIATE;
- }
- }
-
- static TimeDelta GetNudgeDelayTimeDeltaFromType(
- const NudgeDelayStrategy& delay_type, const ModelType& model_type,
- const SyncManager::SyncInternal* core) {
- CHECK(core);
- TimeDelta delay = TimeDelta::FromMilliseconds(
- SyncManager::kDefaultNudgeDelayMilliseconds);
- switch (delay_type) {
- case IMMEDIATE:
- delay = TimeDelta::FromMilliseconds(
- SyncManager::kDefaultNudgeDelayMilliseconds);
- break;
- case ACCOMPANY_ONLY:
- delay = TimeDelta::FromSeconds(
- browser_sync::kDefaultShortPollIntervalSeconds);
- break;
- case CUSTOM:
- switch (model_type) {
- case syncable::PREFERENCES:
- delay = TimeDelta::FromMilliseconds(
- SyncManager::kPreferencesNudgeDelayMilliseconds);
- break;
- case syncable::SESSIONS:
- delay = core->scheduler()->sessions_commit_delay();
- break;
- default:
- NOTREACHED();
- }
- break;
- default:
- NOTREACHED();
- }
- return delay;
- }
-};
-
-SyncManager::ChangeDelegate::~ChangeDelegate() {}
-
-SyncManager::ChangeObserver::~ChangeObserver() {}
-
-SyncManager::Observer::~Observer() {}
-
-SyncManager::SyncManager(const std::string& name)
- : data_(new SyncInternal(name)) {}
-
-SyncManager::Status::Status()
- : notifications_enabled(false),
- notifications_received(0),
- unsynced_count(0),
- encryption_conflicts(0),
- hierarchy_conflicts(0),
- simple_conflicts(0),
- server_conflicts(0),
- committed_count(0),
- syncing(false),
- initial_sync_ended(false),
- updates_available(0),
- updates_received(0),
- reflected_updates_received(0),
- tombstone_updates_received(0),
- num_local_overwrites_total(0),
- num_server_overwrites_total(0),
- nonempty_get_updates(0),
- empty_get_updates(0),
- sync_cycles_with_commits(0),
- sync_cycles_without_commits(0),
- useless_sync_cycles(0),
- useful_sync_cycles(0),
- cryptographer_ready(false),
- crypto_has_pending_keys(false) {
-}
-
-SyncManager::Status::~Status() {
-}
-
-bool SyncManager::Init(
- const FilePath& database_location,
- const WeakHandle<JsEventHandler>& event_handler,
- const std::string& sync_server_and_path,
- int sync_server_port,
- bool use_ssl,
- const scoped_refptr<base::TaskRunner>& blocking_task_runner,
- HttpPostProviderFactory* post_factory,
- ModelSafeWorkerRegistrar* registrar,
- browser_sync::ExtensionsActivityMonitor* extensions_activity_monitor,
- ChangeDelegate* change_delegate,
- const std::string& user_agent,
- const SyncCredentials& credentials,
- bool enable_sync_tabs_for_other_clients,
- sync_notifier::SyncNotifier* sync_notifier,
- const std::string& restored_key_for_bootstrapping,
- TestingMode testing_mode,
- Encryptor* encryptor,
- UnrecoverableErrorHandler* unrecoverable_error_handler,
- ReportUnrecoverableErrorFunction report_unrecoverable_error_function) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(post_factory);
- DVLOG(1) << "SyncManager starting Init...";
- std::string server_string(sync_server_and_path);
- return data_->Init(database_location,
- event_handler,
- server_string,
- sync_server_port,
- use_ssl,
- blocking_task_runner,
- post_factory,
- registrar,
- extensions_activity_monitor,
- change_delegate,
- user_agent,
- credentials,
- enable_sync_tabs_for_other_clients,
- sync_notifier,
- restored_key_for_bootstrapping,
- testing_mode,
- encryptor,
- unrecoverable_error_handler,
- report_unrecoverable_error_function);
-}
-
-void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->UpdateCredentials(credentials);
-}
-
-void SyncManager::UpdateEnabledTypes() {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->UpdateEnabledTypes();
-}
-
-void SyncManager::MaybeSetSyncTabsInNigoriNode(
- ModelTypeSet enabled_types) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->MaybeSetSyncTabsInNigoriNode(enabled_types);
-}
-
-void SyncManager::ThrowUnrecoverableError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- ReadTransaction trans(FROM_HERE, GetUserShare());
- trans.GetWrappedTrans()->OnUnrecoverableError(
- FROM_HERE, "Simulating unrecoverable error for testing purposes.");
-}
-
-bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
- return data_->InitialSyncEndedForAllEnabledTypes();
-}
-
-void SyncManager::StartSyncingNormally() {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->StartSyncingNormally();
-}
-
-void SyncManager::SetEncryptionPassphrase(const std::string& passphrase,
- bool is_explicit) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->SetEncryptionPassphrase(passphrase, is_explicit);
-}
-
-void SyncManager::SetDecryptionPassphrase(const std::string& passphrase) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->SetDecryptionPassphrase(passphrase);
-}
-
-void SyncManager::EnableEncryptEverything() {
- DCHECK(thread_checker_.CalledOnValidThread());
- {
- // Update the cryptographer to know we're now encrypting everything.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- // Only set encrypt everything if we know we can encrypt. This allows the
- // user to cancel encryption if they have forgotten their passphrase.
- if (cryptographer->is_ready())
- cryptographer->set_encrypt_everything();
- }
-
- // Reads from cryptographer so will automatically encrypt all
- // datatypes and update the nigori node as necessary. Will trigger
- // OnPassphraseRequired if necessary.
- data_->RefreshEncryption();
-}
-
-bool SyncManager::EncryptEverythingEnabledForTest() const {
- ReadTransaction trans(FROM_HERE, GetUserShare());
- return trans.GetCryptographer()->encrypt_everything();
-}
-
-bool SyncManager::IsUsingExplicitPassphrase() {
- return data_ && data_->IsUsingExplicitPassphrase();
-}
-
-void SyncManager::RequestCleanupDisabledTypes() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (data_->scheduler())
- data_->scheduler()->ScheduleCleanupDisabledTypes();
-}
-
-void SyncManager::RequestClearServerData() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (data_->scheduler())
- data_->scheduler()->ScheduleClearUserData();
-}
-
-void SyncManager::RequestConfig(
- ModelTypeSet types, ConfigureReason reason) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!data_->scheduler()) {
- LOG(INFO)
- << "SyncManager::RequestConfig: bailing out because scheduler is "
- << "null";
- return;
- }
- StartConfigurationMode(base::Closure());
- data_->scheduler()->ScheduleConfig(types, GetSourceFromReason(reason));
-}
-
-void SyncManager::StartConfigurationMode(const base::Closure& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!data_->scheduler()) {
- LOG(INFO)
- << "SyncManager::StartConfigurationMode: could not start "
- << "configuration mode because because scheduler is null";
- return;
- }
- data_->scheduler()->Start(
- browser_sync::SyncScheduler::CONFIGURATION_MODE, callback);
-}
-
-bool SyncManager::SyncInternal::Init(
- const FilePath& database_location,
- const WeakHandle<JsEventHandler>& event_handler,
- const std::string& sync_server_and_path,
- int port,
- bool use_ssl,
- const scoped_refptr<base::TaskRunner>& blocking_task_runner,
- HttpPostProviderFactory* post_factory,
- ModelSafeWorkerRegistrar* model_safe_worker_registrar,
- browser_sync::ExtensionsActivityMonitor* extensions_activity_monitor,
- ChangeDelegate* change_delegate,
- const std::string& user_agent,
- const SyncCredentials& credentials,
- bool enable_sync_tabs_for_other_clients,
- sync_notifier::SyncNotifier* sync_notifier,
- const std::string& restored_key_for_bootstrapping,
- TestingMode testing_mode,
- Encryptor* encryptor,
- UnrecoverableErrorHandler* unrecoverable_error_handler,
- ReportUnrecoverableErrorFunction report_unrecoverable_error_function) {
- CHECK(!initialized_);
-
- DCHECK(thread_checker_.CalledOnValidThread());
-
- DVLOG(1) << "Starting SyncInternal initialization.";
-
- weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
-
- blocking_task_runner_ = blocking_task_runner;
-
- registrar_ = model_safe_worker_registrar;
- change_delegate_ = change_delegate;
- testing_mode_ = testing_mode;
-
- enable_sync_tabs_for_other_clients_ = enable_sync_tabs_for_other_clients;
-
- sync_notifier_.reset(sync_notifier);
-
- AddObserver(&js_sync_manager_observer_);
- SetJsEventHandler(event_handler);
-
- AddObserver(&debug_info_event_listener_);
-
- database_path_ = database_location.Append(
- syncable::Directory::kSyncDatabaseFilename);
- encryptor_ = encryptor;
- unrecoverable_error_handler_ = unrecoverable_error_handler;
- report_unrecoverable_error_function_ = report_unrecoverable_error_function;
- share_.directory.reset(
- new syncable::Directory(encryptor_,
- unrecoverable_error_handler_,
- report_unrecoverable_error_function_));
-
- connection_manager_.reset(new SyncAPIServerConnectionManager(
- sync_server_and_path, port, use_ssl, user_agent, post_factory));
-
- net::NetworkChangeNotifier::AddIPAddressObserver(this);
- observing_ip_address_changes_ = true;
-
- connection_manager()->AddListener(this);
-
-
- // Test mode does not use a syncer context or syncer thread.
- if (testing_mode_ == NON_TEST) {
- // 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);
- SyncSessionContext* context = new SyncSessionContext(
- connection_manager_.get(),
- directory(),
- model_safe_worker_registrar,
- extensions_activity_monitor,
- listeners,
- &debug_info_event_listener_,
- &traffic_recorder_);
- context->set_account_name(credentials.email);
- // The SyncScheduler takes ownership of |context|.
- scheduler_.reset(new SyncScheduler(name_, context, new Syncer()));
- }
-
- bool signed_in = SignIn(credentials);
-
- if (signed_in) {
- if (scheduler()) {
- scheduler()->Start(
- browser_sync::SyncScheduler::CONFIGURATION_MODE, base::Closure());
- }
-
- initialized_ = true;
-
- // Cryptographer should only be accessed while holding a
- // transaction. Grabbing the user share for the transaction
- // checks the initialization state, so this must come after
- // |initialized_| is set to true.
- ReadTransaction trans(FROM_HERE, GetUserShare());
- trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping);
- trans.GetCryptographer()->AddObserver(this);
- }
-
- // Notify that initialization is complete. Note: This should be the last to
- // execute if |signed_in| is false. Reason being in that case we would
- // post a task to shutdown sync. But if this function posts any other tasks
- // on the UI thread and if shutdown wins then that tasks would execute on
- // a freed pointer. This is because UI thread is not shut down.
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnInitializationComplete(
- MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
- signed_in));
-
- if (!signed_in && testing_mode_ == NON_TEST)
- return false;
-
- sync_notifier_->AddObserver(this);
-
- return signed_in;
-}
-
-void SyncManager::SyncInternal::UpdateCryptographerAndNigori(
- const std::string& chrome_version,
- const base::Closure& done_callback) {
- DCHECK(initialized_);
- browser_sync::GetSessionName(
- blocking_task_runner_,
- base::Bind(
- &SyncManager::SyncInternal::UpdateCryptographerAndNigoriCallback,
- weak_ptr_factory_.GetWeakPtr(),
- chrome_version,
- done_callback));
-}
-
-void SyncManager::SyncInternal::UpdateNigoriEncryptionState(
- Cryptographer* cryptographer,
- WriteNode* nigori_node) {
- DCHECK(nigori_node);
- sync_pb::NigoriSpecifics nigori = nigori_node->GetNigoriSpecifics();
-
- if (cryptographer->is_ready() &&
- nigori_overwrite_count_ < kNigoriOverwriteLimit) {
- // Does not modify the encrypted blob if the unencrypted data already
- // matches what is about to be written.
- sync_pb::EncryptedData original_keys = nigori.encrypted();
- if (!cryptographer->GetKeys(nigori.mutable_encrypted()))
- NOTREACHED();
-
- if (nigori.encrypted().SerializeAsString() !=
- original_keys.SerializeAsString()) {
- // We've updated the nigori node's encryption keys. In order to prevent
- // a possible looping of two clients constantly overwriting each other,
- // we limit the absolute number of overwrites per client instantiation.
- nigori_overwrite_count_++;
- UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites",
- nigori_overwrite_count_);
- }
-
- // Note: we don't try to set using_explicit_passphrase here since if that
- // is lost the user can always set it again. The main point is to preserve
- // the encryption keys so all data remains decryptable.
- }
- cryptographer->UpdateNigoriFromEncryptedTypes(&nigori);
-
- // If nothing has changed, this is a no-op.
- nigori_node->SetNigoriSpecifics(nigori);
-}
-
-void SyncManager::SyncInternal::UpdateCryptographerAndNigoriCallback(
- const std::string& chrome_version,
- const base::Closure& done_callback,
- const std::string& session_name) {
- if (!directory()->initial_sync_ended_for_type(syncable::NIGORI)) {
- done_callback.Run(); // Should only happen during first time sync.
- return;
- }
-
- bool success = false;
- {
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- WriteNode node(&trans);
-
- if (node.InitByTagLookup(kNigoriTag) == sync_api::BaseNode::INIT_OK) {
- sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics());
- Cryptographer::UpdateResult result = cryptographer->Update(nigori);
- if (result == Cryptographer::NEEDS_PASSPHRASE) {
- sync_pb::EncryptedData pending_keys;
- if (cryptographer->has_pending_keys())
- pending_keys = cryptographer->GetPendingKeys();
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_DECRYPTION,
- pending_keys));
- }
-
-
- // Add or update device information.
- bool contains_this_device = false;
- for (int i = 0; i < nigori.device_information_size(); ++i) {
- const sync_pb::DeviceInformation& device_information =
- nigori.device_information(i);
- if (device_information.cache_guid() == directory()->cache_guid()) {
- // Update the version number in case it changed due to an update.
- if (device_information.chrome_version() != chrome_version) {
- sync_pb::DeviceInformation* mutable_device_information =
- nigori.mutable_device_information(i);
- mutable_device_information->set_chrome_version(
- chrome_version);
- }
- contains_this_device = true;
- }
- }
-
- if (!contains_this_device) {
- sync_pb::DeviceInformation* device_information =
- nigori.add_device_information();
- device_information->set_cache_guid(directory()->cache_guid());
-#if defined(OS_CHROMEOS)
- device_information->set_platform("ChromeOS");
-#elif defined(OS_LINUX)
- device_information->set_platform("Linux");
-#elif defined(OS_MACOSX)
- device_information->set_platform("Mac");
-#elif defined(OS_WIN)
- device_information->set_platform("Windows");
-#endif
- device_information->set_name(session_name);
- device_information->set_chrome_version(chrome_version);
- }
- // Disabled to avoid nigori races. TODO(zea): re-enable. crbug.com/122837
- // node.SetNigoriSpecifics(nigori);
-
- // Make sure the nigori node has the up to date encryption info.
- UpdateNigoriEncryptionState(cryptographer, &node);
-
- NotifyCryptographerState(cryptographer);
- allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
-
- success = cryptographer->is_ready();
- } else {
- NOTREACHED();
- }
- }
-
- if (success)
- RefreshEncryption();
- done_callback.Run();
-}
-
-void SyncManager::SyncInternal::NotifyCryptographerState(
- Cryptographer * cryptographer) {
- // TODO(lipalani): Explore the possibility of hooking this up to
- // SyncManager::Observer and making |AllStatus| a listener for that.
- allstatus_.SetCryptographerReady(cryptographer->is_ready());
- allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
- debug_info_event_listener_.SetCryptographerReady(cryptographer->is_ready());
- debug_info_event_listener_.SetCrytographerHasPendingKeys(
- cryptographer->has_pending_keys());
-}
-
-void SyncManager::SyncInternal::StartSyncingNormally() {
- // Start the sync scheduler.
- if (scheduler()) // NULL during certain unittests.
- scheduler()->Start(SyncScheduler::NORMAL_MODE, base::Closure());
-}
-
-bool SyncManager::SyncInternal::OpenDirectory() {
- DCHECK(!initialized_) << "Should only happen once";
-
- // Set before Open().
- change_observer_ =
- browser_sync::MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr());
- WeakHandle<syncable::TransactionObserver> transaction_observer(
- browser_sync::MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr()));
-
- syncable::DirOpenResult open_result = syncable::NOT_INITIALIZED;
- if (testing_mode_ == TEST_IN_MEMORY) {
- open_result = directory()->OpenInMemoryForTest(
- username_for_share(), this, transaction_observer);
- } else {
- open_result = directory()->Open(
- database_path_, username_for_share(), this, transaction_observer);
- }
- if (open_result != syncable::OPENED) {
- LOG(ERROR) << "Could not open share for:" << username_for_share();
- return false;
- }
-
- connection_manager()->set_client_id(directory()->cache_guid());
- return true;
-}
-
-bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(share_.name.empty());
- share_.name = credentials.email;
-
- DVLOG(1) << "Signing in user: " << username_for_share();
- if (!OpenDirectory())
- return false;
-
- // Retrieve and set the sync notifier state. This should be done
- // only after OpenDirectory is called.
- std::string unique_id = directory()->cache_guid();
- std::string state = directory()->GetNotificationState();
- DVLOG(1) << "Read notification unique ID: " << unique_id;
- if (VLOG_IS_ON(1)) {
- std::string encoded_state;
- base::Base64Encode(state, &encoded_state);
- DVLOG(1) << "Read notification state: " << encoded_state;
- }
- allstatus_.SetUniqueId(unique_id);
- sync_notifier_->SetUniqueId(unique_id);
- sync_notifier_->SetState(state);
-
- UpdateCredentials(credentials);
- UpdateEnabledTypes();
- return true;
-}
-
-void SyncManager::SyncInternal::UpdateCredentials(
- const SyncCredentials& credentials) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(credentials.email, share_.name);
- DCHECK(!credentials.email.empty());
- DCHECK(!credentials.sync_token.empty());
-
- observing_ip_address_changes_ = true;
- if (connection_manager()->set_auth_token(credentials.sync_token)) {
- sync_notifier_->UpdateCredentials(
- credentials.email, credentials.sync_token);
- if (testing_mode_ == NON_TEST && initialized_) {
- if (scheduler())
- scheduler()->OnCredentialsUpdated();
- }
- }
-}
-
-void SyncManager::SyncInternal::UpdateEnabledTypes() {
- DCHECK(thread_checker_.CalledOnValidThread());
- ModelSafeRoutingInfo routes;
- registrar_->GetModelSafeRoutingInfo(&routes);
- const ModelTypeSet enabled_types = GetRoutingInfoTypes(routes);
- sync_notifier_->UpdateEnabledTypes(enabled_types);
- if (enable_sync_tabs_for_other_clients_)
- MaybeSetSyncTabsInNigoriNode(enabled_types);
-}
-
-void SyncManager::SyncInternal::MaybeSetSyncTabsInNigoriNode(
- const ModelTypeSet enabled_types) {
- // The initialized_ check is to ensure that we don't CHECK in GetUserShare
- // when this is called on start-up. It's ok to ignore that case, since
- // presumably this would've run when the user originally enabled sessions.
- if (initialized_ && enabled_types.Has(syncable::SESSIONS)) {
- WriteTransaction trans(FROM_HERE, GetUserShare());
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
- LOG(WARNING) << "Unable to set 'sync_tabs' bit because Nigori node not "
- << "found.";
- return;
- }
-
- sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
- specifics.set_sync_tabs(true);
- node.SetNigoriSpecifics(specifics);
- }
-}
-
-void SyncManager::SyncInternal::SetEncryptionPassphrase(
- const std::string& passphrase,
- bool is_explicit) {
- // We do not accept empty passphrases.
- if (passphrase.empty()) {
- NOTREACHED() << "Cannot encrypt with an empty passphrase.";
- return;
- }
-
- // All accesses to the cryptographer are protected by a transaction.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- KeyParams key_params = {"localhost", "dummy", passphrase};
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
- // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
- NOTREACHED();
- return;
- }
-
- bool nigori_has_explicit_passphrase =
- node.GetNigoriSpecifics().using_explicit_passphrase();
- std::string bootstrap_token;
- sync_pb::EncryptedData pending_keys;
- if (cryptographer->has_pending_keys())
- pending_keys = cryptographer->GetPendingKeys();
- bool success = false;
-
-
- // There are six cases to handle here:
- // 1. The user has no pending keys and is setting their current GAIA password
- // as the encryption passphrase. This happens either during first time sync
- // with a clean profile, or after re-authenticating on a profile that was
- // already signed in with the cryptographer ready.
- // 2. The user has no pending keys, and is overwriting an (already provided)
- // implicit passphrase with an explicit (custom) passphrase.
- // 3. The user has pending keys for an explicit passphrase that is somehow set
- // to their current GAIA passphrase.
- // 4. The user has pending keys encrypted with their current GAIA passphrase
- // and the caller passes in the current GAIA passphrase.
- // 5. The user has pending keys encrypted with an older GAIA passphrase
- // and the caller passes in the current GAIA passphrase.
- // 6. The user has previously done encryption with an explicit passphrase.
- // Furthermore, we enforce the fact that the bootstrap encryption token will
- // always be derived from the newest GAIA password if the account is using
- // an implicit passphrase (even if the data is encrypted with an old GAIA
- // password). If the account is using an explicit (custom) passphrase, the
- // bootstrap token will be derived from the most recently provided explicit
- // passphrase (that was able to decrypt the data).
- if (!nigori_has_explicit_passphrase) {
- if (!cryptographer->has_pending_keys()) {
- if (cryptographer->AddKey(key_params)) {
- // Case 1 and 2. We set a new GAIA passphrase when there are no pending
- // keys (1), or overwriting an implicit passphrase with a new explicit
- // one (2) when there are no pending keys.
- DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" )
- << " passphrase for encryption.";
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- NOTREACHED() << "Failed to add key to cryptographer.";
- success = false;
- }
- } else { // cryptographer->has_pending_keys() == true
- if (is_explicit) {
- // This can only happen if the nigori node is updated with a new
- // implicit passphrase while a client is attempting to set a new custom
- // passphrase (race condition).
- DVLOG(1) << "Failing because an implicit passphrase is already set.";
- success = false;
- } else { // is_explicit == false
- if (cryptographer->DecryptPendingKeys(key_params)) {
- // Case 4. We successfully decrypted with the implicit GAIA passphrase
- // passed in.
- DVLOG(1) << "Implicit internal passphrase accepted for decryption.";
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- // Case 5. Encryption was done with an old GAIA password, but we were
- // provided with the current GAIA password. We need to generate a new
- // bootstrap token to preserve it. We build a temporary cryptographer
- // to allow us to extract these params without polluting our current
- // cryptographer.
- DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding "
- << "anyways as default passphrase and persisting via "
- << "bootstrap token.";
- Cryptographer temp_cryptographer(encryptor_);
- temp_cryptographer.AddKey(key_params);
- temp_cryptographer.GetBootstrapToken(&bootstrap_token);
- // We then set the new passphrase as the default passphrase of the
- // real cryptographer, even though we have pending keys. This is safe,
- // as although Cryptographer::is_initialized() will now be true,
- // is_ready() will remain false due to having pending keys.
- cryptographer->AddKey(key_params);
- success = false;
- }
- } // is_explicit
- } // cryptographer->has_pending_keys()
- } else { // nigori_has_explicit_passphrase == true
- // Case 6. We do not want to override a previously set explicit passphrase,
- // so we return a failure.
- DVLOG(1) << "Failing because an explicit passphrase is already set.";
- success = false;
- }
-
- DVLOG_IF(1, !success)
- << "Failure in SetEncryptionPassphrase; notifying and returning.";
- DVLOG_IF(1, success)
- << "Successfully set encryption passphrase; updating nigori and "
- "reencrypting.";
-
- FinishSetPassphrase(
- success, bootstrap_token, is_explicit, &trans, &node);
-}
-
-void SyncManager::SyncInternal::SetDecryptionPassphrase(
- const std::string& passphrase) {
- // We do not accept empty passphrases.
- if (passphrase.empty()) {
- NOTREACHED() << "Cannot decrypt with an empty passphrase.";
- return;
- }
-
- // All accesses to the cryptographer are protected by a transaction.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- KeyParams key_params = {"localhost", "dummy", passphrase};
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
- // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
- NOTREACHED();
- return;
- }
-
- if (!cryptographer->has_pending_keys()) {
- // Note that this *can* happen in a rare situation where data is
- // re-encrypted on another client while a SetDecryptionPassphrase() call is
- // in-flight on this client. It is rare enough that we choose to do nothing.
- NOTREACHED() << "Attempt to set decryption passphrase failed because there "
- << "were no pending keys.";
- return;
- }
-
- bool nigori_has_explicit_passphrase =
- node.GetNigoriSpecifics().using_explicit_passphrase();
- std::string bootstrap_token;
- sync_pb::EncryptedData pending_keys;
- pending_keys = cryptographer->GetPendingKeys();
- bool success = false;
-
- // There are three cases to handle here:
- // 7. We're using the current GAIA password to decrypt the pending keys. This
- // happens when signing in to an account with a previously set implicit
- // passphrase, where the data is already encrypted with the newest GAIA
- // password.
- // 8. The user is providing an old GAIA password to decrypt the pending keys.
- // In this case, the user is using an implicit passphrase, but has changed
- // their password since they last encrypted their data, and therefore
- // their current GAIA password was unable to decrypt the data. This will
- // happen when the user is setting up a new profile with a previously
- // encrypted account (after changing passwords).
- // 9. The user is providing a previously set explicit passphrase to decrypt
- // the pending keys.
- if (!nigori_has_explicit_passphrase) {
- if (cryptographer->is_initialized()) {
- // We only want to change the default encryption key to the pending
- // one if the pending keybag already contains the current default.
- // This covers the case where a different client re-encrypted
- // everything with a newer gaia passphrase (and hence the keybag
- // contains keys from all previously used gaia passphrases).
- // Otherwise, we're in a situation where the pending keys are
- // encrypted with an old gaia passphrase, while the default is the
- // current gaia passphrase. In that case, we preserve the default.
- Cryptographer temp_cryptographer(encryptor_);
- temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
- if (temp_cryptographer.DecryptPendingKeys(key_params)) {
- // Check to see if the pending bag of keys contains the current
- // default key.
- sync_pb::EncryptedData encrypted;
- cryptographer->GetKeys(&encrypted);
- if (temp_cryptographer.CanDecrypt(encrypted)) {
- DVLOG(1) << "Implicit user provided passphrase accepted for "
- << "decryption, overwriting default.";
- // Case 7. The pending keybag contains the current default. Go ahead
- // and update the cryptographer, letting the default change.
- cryptographer->DecryptPendingKeys(key_params);
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- // Case 8. The pending keybag does not contain the current default
- // encryption key. We decrypt the pending keys here, and in
- // FinishSetPassphrase, re-encrypt everything with the current GAIA
- // passphrase instead of the passphrase just provided by the user.
- DVLOG(1) << "Implicit user provided passphrase accepted for "
- << "decryption, restoring implicit internal passphrase "
- << "as default.";
- std::string bootstrap_token_from_current_key;
- cryptographer->GetBootstrapToken(
- &bootstrap_token_from_current_key);
- cryptographer->DecryptPendingKeys(key_params);
- // Overwrite the default from the pending keys.
- cryptographer->AddKeyFromBootstrapToken(
- bootstrap_token_from_current_key);
- success = true;
- }
- } else { // !temp_cryptographer.DecryptPendingKeys(..)
- DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
- success = false;
- } // temp_cryptographer.DecryptPendingKeys(...)
- } else { // cryptographer->is_initialized() == false
- if (cryptographer->DecryptPendingKeys(key_params)) {
- // This can happpen in two cases:
- // - First time sync on android, where we'll never have a
- // !user_provided passphrase.
- // - This is a restart for a client that lost their bootstrap token.
- // In both cases, we should go ahead and initialize the cryptographer
- // and persist the new bootstrap token.
- //
- // Note: at this point, we cannot distinguish between cases 7 and 8
- // above. This user provided passphrase could be the current or the
- // old. But, as long as we persist the token, there's nothing more
- // we can do.
- cryptographer->GetBootstrapToken(&bootstrap_token);
- DVLOG(1) << "Implicit user provided passphrase accepted, initializing"
- << " cryptographer.";
- success = true;
- } else {
- DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
- success = false;
- }
- } // cryptographer->is_initialized()
- } else { // nigori_has_explicit_passphrase == true
- // Case 9. Encryption was done with an explicit passphrase, and we decrypt
- // with the passphrase provided by the user.
- if (cryptographer->DecryptPendingKeys(key_params)) {
- DVLOG(1) << "Explicit passphrase accepted for decryption.";
- cryptographer->GetBootstrapToken(&bootstrap_token);
- success = true;
- } else {
- DVLOG(1) << "Explicit passphrase failed to decrypt.";
- success = false;
- }
- } // nigori_has_explicit_passphrase
-
- DVLOG_IF(1, !success)
- << "Failure in SetDecryptionPassphrase; notifying and returning.";
- DVLOG_IF(1, success)
- << "Successfully set decryption passphrase; updating nigori and "
- "reencrypting.";
-
- FinishSetPassphrase(success,
- bootstrap_token,
- nigori_has_explicit_passphrase,
- &trans,
- &node);
-}
-
-void SyncManager::SyncInternal::FinishSetPassphrase(
- bool success,
- const std::string& bootstrap_token,
- bool is_explicit,
- WriteTransaction* trans,
- WriteNode* nigori_node) {
- Cryptographer* cryptographer = trans->GetCryptographer();
- NotifyCryptographerState(cryptographer);
-
- // It's possible we need to change the bootstrap token even if we failed to
- // set the passphrase (for example if we need to preserve the new GAIA
- // passphrase).
- if (!bootstrap_token.empty()) {
- DVLOG(1) << "Bootstrap token updated.";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnBootstrapTokenUpdated(bootstrap_token));
- }
-
- if (!success) {
- if (cryptographer->is_ready()) {
- LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
- << "was ready.";
- } else if (cryptographer->has_pending_keys()) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_DECRYPTION,
- cryptographer->GetPendingKeys()));
- } else {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_ENCRYPTION,
- sync_pb::EncryptedData()));
- }
- return;
- }
-
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseAccepted());
- DCHECK(cryptographer->is_ready());
-
- // TODO(tim): Bug 58231. It would be nice if setting a passphrase didn't
- // require messing with the Nigori node, because we can't set a passphrase
- // until download conditions are met vs Cryptographer init. It seems like
- // it's safe to defer this work.
- sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics());
- // Does not modify specifics.encrypted() if the original decrypted data was
- // the same.
- if (!cryptographer->GetKeys(specifics.mutable_encrypted())) {
- NOTREACHED();
- return;
- }
- specifics.set_using_explicit_passphrase(is_explicit);
- nigori_node->SetNigoriSpecifics(specifics);
-
- // Does nothing if everything is already encrypted or the cryptographer has
- // pending keys.
- ReEncryptEverything(trans);
-}
-
-bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
- ReadTransaction trans(FROM_HERE, &share_);
- ReadNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
- // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
- NOTREACHED();
- return false;
- }
-
- return node.GetNigoriSpecifics().using_explicit_passphrase();
-}
-
-void SyncManager::SyncInternal::RefreshEncryption() {
- DCHECK(initialized_);
-
- WriteTransaction trans(FROM_HERE, GetUserShare());
- WriteNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
- NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not "
- << "found.";
- return;
- }
-
- Cryptographer* cryptographer = trans.GetCryptographer();
-
- if (!cryptographer->is_ready()) {
- DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not "
- << "initialized, prompting for passphrase.";
- // TODO(zea): this isn't really decryption, but that's the only way we have
- // to prompt the user for a passsphrase. See http://crbug.com/91379.
- sync_pb::EncryptedData pending_keys;
- if (cryptographer->has_pending_keys())
- pending_keys = cryptographer->GetPendingKeys();
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_DECRYPTION,
- pending_keys));
- return;
- }
-
- UpdateNigoriEncryptionState(cryptographer, &node);
-
- allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
-
- // We reencrypt everything regardless of whether the set of encrypted
- // types changed to ensure that any stray unencrypted entries are overwritten.
- ReEncryptEverything(&trans);
-}
-
-void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
- Cryptographer* cryptographer = trans->GetCryptographer();
- if (!cryptographer || !cryptographer->is_ready())
- return;
- syncable::ModelTypeSet encrypted_types = GetEncryptedTypes(trans);
- ModelSafeRoutingInfo routes;
- registrar_->GetModelSafeRoutingInfo(&routes);
- std::string tag;
- for (syncable::ModelTypeSet::Iterator iter = encrypted_types.First();
- iter.Good(); iter.Inc()) {
- if (iter.Get() == syncable::PASSWORDS ||
- iter.Get() == syncable::NIGORI ||
- routes.count(iter.Get()) == 0)
- continue;
- ReadNode type_root(trans);
- tag = syncable::ModelTypeToRootTag(iter.Get());
- if (type_root.InitByTagLookup(tag) != sync_api::BaseNode::INIT_OK) {
- // This can happen when we enable a datatype for the first time on restart
- // (for example when we upgrade) and therefore haven't done the initial
- // download for that type at the time we RefreshEncryption. There's
- // nothing we can do for now, so just move on to the next type.
- continue;
- }
-
- // Iterate through all children of this datatype.
- std::queue<int64> to_visit;
- int64 child_id = type_root.GetFirstChildId();
- to_visit.push(child_id);
- while (!to_visit.empty()) {
- child_id = to_visit.front();
- to_visit.pop();
- if (child_id == kInvalidId)
- continue;
-
- WriteNode child(trans);
- if (child.InitByIdLookup(child_id) != sync_api::BaseNode::INIT_OK) {
- NOTREACHED();
- continue;
- }
- if (child.GetIsFolder()) {
- to_visit.push(child.GetFirstChildId());
- }
- if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
- // Rewrite the specifics of the node with encrypted data if necessary
- // (only rewrite the non-unique folders).
- child.ResetFromSpecifics();
- }
- to_visit.push(child.GetSuccessorId());
- }
- }
-
- if (routes.count(syncable::PASSWORDS) > 0) {
- // Passwords are encrypted with their own legacy scheme.
- ReadNode passwords_root(trans);
- std::string passwords_tag =
- syncable::ModelTypeToRootTag(syncable::PASSWORDS);
- // It's possible we'll have the password routing info and not the password
- // root if we attempted to set a passphrase before passwords was enabled.
- if (passwords_root.InitByTagLookup(passwords_tag) ==
- sync_api::BaseNode::INIT_OK) {
- int64 child_id = passwords_root.GetFirstChildId();
- while (child_id != kInvalidId) {
- WriteNode child(trans);
- if (child.InitByIdLookup(child_id) != sync_api::BaseNode::INIT_OK) {
- NOTREACHED();
- return;
- }
- child.SetPasswordSpecifics(child.GetPasswordSpecifics());
- child_id = child.GetSuccessorId();
- }
- }
- }
-
- // NOTE: We notify from within a transaction.
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_, OnEncryptionComplete());
-}
-
-SyncManager::~SyncManager() {
- DCHECK(thread_checker_.CalledOnValidThread());
- delete data_;
-}
-
-void SyncManager::AddObserver(Observer* observer) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->AddObserver(observer);
-}
-
-void SyncManager::RemoveObserver(Observer* observer) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->RemoveObserver(observer);
-}
-
-void SyncManager::StopSyncingForShutdown(const base::Closure& callback) {
- data_->StopSyncingForShutdown(callback);
-}
-
-void SyncManager::SyncInternal::StopSyncingForShutdown(
- const base::Closure& callback) {
- DVLOG(2) << "StopSyncingForShutdown";
- if (scheduler()) // May be null in tests.
- scheduler()->RequestStop(callback);
- else
- created_on_loop_->PostTask(FROM_HERE, callback);
-
- if (connection_manager_.get())
- connection_manager_->TerminateAllIO();
-}
-
-void SyncManager::ShutdownOnSyncThread() {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->ShutdownOnSyncThread();
-}
-
-void SyncManager::SyncInternal::ShutdownOnSyncThread() {
- 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();
-
- SetJsEventHandler(WeakHandle<JsEventHandler>());
- RemoveObserver(&js_sync_manager_observer_);
-
- RemoveObserver(&debug_info_event_listener_);
-
- if (sync_notifier_.get()) {
- sync_notifier_->RemoveObserver(this);
- }
- sync_notifier_.reset();
-
- if (connection_manager_.get()) {
- connection_manager_->RemoveListener(this);
- }
- connection_manager_.reset();
-
- net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
- observing_ip_address_changes_ = false;
-
- if (initialized_ && directory()) {
- {
- // Cryptographer should only be accessed while holding a
- // transaction.
- ReadTransaction trans(FROM_HERE, GetUserShare());
- trans.GetCryptographer()->RemoveObserver(this);
- }
- directory()->SaveChanges();
- }
-
- share_.directory.reset();
-
- change_delegate_ = NULL;
- registrar_ = 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 SyncManager::SyncInternal::OnIPAddressChanged() {
- DVLOG(1) << "IP address change detected";
- if (!observing_ip_address_changes_) {
- DVLOG(1) << "IP address change dropped.";
- return;
- }
-
- OnIPAddressChangedImpl();
-}
-
-void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (scheduler())
- scheduler()->OnConnectionStatusChange();
-}
-
-void SyncManager::SyncInternal::OnServerConnectionEvent(
- const ServerConnectionEvent& event) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (event.connection_code ==
- browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnConnectionStatusChange(CONNECTION_OK));
- }
-
- if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
- observing_ip_address_changes_ = false;
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnConnectionStatusChange(CONNECTION_AUTH_ERROR));
- }
-
- if (event.connection_code ==
- browser_sync::HttpResponse::SYNC_SERVER_ERROR) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnConnectionStatusChange(CONNECTION_SERVER_ERROR));
- }
-}
-
-void SyncManager::SyncInternal::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
- SyncManager::SyncInternal::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_ || ChangeBuffersAreEmpty())
- 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 (int i = syncable::FIRST_REAL_MODEL_TYPE;
- i < syncable::MODEL_TYPE_COUNT; ++i) {
- const syncable::ModelType type = syncable::ModelTypeFromInt(i);
- if (change_buffers_[type].IsEmpty())
- continue;
-
- ImmutableChangeRecordList ordered_changes;
- // TODO(akalin): Propagate up the error further (see
- // http://crbug.com/100907).
- CHECK(change_buffers_[type].GetAllChangesInTreeOrder(&read_trans,
- &ordered_changes));
- if (!ordered_changes.Get().empty()) {
- change_delegate_->
- OnChangesApplied(type, &read_trans, ordered_changes);
- change_observer_.Call(FROM_HERE,
- &SyncManager::ChangeObserver::OnChangesApplied,
- type, write_transaction_info.Get().id, ordered_changes);
- models_with_changes.Put(type);
- }
- change_buffers_[i].Clear();
- }
- return models_with_changes;
-}
-
-void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
- const ImmutableWriteTransactionInfo& write_transaction_info,
- syncable::BaseTransaction* trans) {
- if (!scheduler()) {
- return;
- }
-
- // We have been notified about a user action changing a sync model.
- LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
- "CALCULATE_CHANGES called with unapplied old changes.";
-
- // The mutated model type, or UNSPECIFIED if nothing was mutated.
- syncable::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;
- }
-
- syncable::ModelType model_type =
- syncable::GetModelTypeFromSpecifics(
- it->second.mutated.ref(SPECIFICS));
- if (model_type < syncable::FIRST_REAL_MODEL_TYPE) {
- NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
- continue;
- }
-
- // Found real mutation.
- if (model_type != syncable::UNSPECIFIED) {
- mutated_model_types.Put(model_type);
- }
- }
-
- // Nudge if necessary.
- if (!mutated_model_types.Empty()) {
- if (weak_handle_this_.IsInitialized()) {
- weak_handle_this_.Call(FROM_HERE,
- &SyncInternal::RequestNudgeForDataTypes,
- FROM_HERE,
- mutated_model_types);
- } else {
- NOTREACHED();
- }
- }
-}
-
-void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
- syncable::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 == syncable::PASSWORDS) {
- // Passwords must use their own legacy ExtraPasswordChangeRecordData.
- scoped_ptr<sync_pb::PasswordSpecificsData> data(
- DecryptPasswordSpecifics(original_specifics, cryptographer));
- if (!data.get()) {
- 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 SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
- const ImmutableWriteTransactionInfo& write_transaction_info,
- syncable::BaseTransaction* trans) {
- // We only expect one notification per sync step, so change_buffers_ should
- // contain no pending entries.
- LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
- "CALCULATE_CHANGES called with unapplied old changes.";
-
- 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.
- syncable::ModelType type =
- syncable::GetModelTypeFromSpecifics(
- it->second.mutated.ref(SPECIFICS));
- if (type < syncable::FIRST_REAL_MODEL_TYPE)
- continue;
-
- int64 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, VisiblePositionsDiffer(it->second));
- }
-
- SetExtraChangeRecordData(handle, type, &change_buffers_[type], crypto,
- it->second.original, existed_before, exists_now);
- }
-}
-
-SyncManager::Status SyncManager::SyncInternal::GetStatus() {
- return allstatus_.status();
-}
-
-void SyncManager::SyncInternal::RequestNudge(
- const tracked_objects::Location& location) {
- if (scheduler()) {
- scheduler()->ScheduleNudge(
- TimeDelta::FromMilliseconds(0), browser_sync::NUDGE_SOURCE_LOCAL,
- ModelTypeSet(), location);
- }
-}
-
-TimeDelta SyncManager::SyncInternal::GetNudgeDelayTimeDelta(
- const ModelType& model_type) {
- return NudgeStrategy::GetNudgeDelayTimeDelta(model_type, this);
-}
-
-void SyncManager::SyncInternal::RequestNudgeForDataTypes(
- const tracked_objects::Location& nudge_location,
- ModelTypeSet types) {
- if (!scheduler()) {
- NOTREACHED();
- return;
- }
-
- debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get());
-
- // TODO(lipalani) : Calculate the nudge delay based on all types.
- base::TimeDelta nudge_delay = NudgeStrategy::GetNudgeDelayTimeDelta(
- types.First().Get(),
- this);
- scheduler()->ScheduleNudge(nudge_delay,
- browser_sync::NUDGE_SOURCE_LOCAL,
- types,
- nudge_location);
-}
-
-void SyncManager::SyncInternal::OnSyncEngineEvent(
- const SyncEngineEvent& 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 == SyncEngineEvent::SYNC_CYCLE_ENDED) {
- ModelSafeRoutingInfo enabled_types;
- registrar_->GetModelSafeRoutingInfo(&enabled_types);
- {
- // Check to see if we need to notify the frontend that we have newly
- // encrypted types or that we require a passphrase.
- ReadTransaction trans(FROM_HERE, GetUserShare());
- Cryptographer* cryptographer = trans.GetCryptographer();
- // If we've completed a sync cycle and the cryptographer isn't ready
- // yet, prompt the user for a passphrase.
- if (cryptographer->has_pending_keys()) {
- DVLOG(1) << "OnPassPhraseRequired Sent";
- sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_DECRYPTION,
- pending_keys));
- } else if (!cryptographer->is_ready() &&
- event.snapshot->initial_sync_ended.Has(syncable::NIGORI)) {
- DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
- << "ready";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_ENCRYPTION,
- sync_pb::EncryptedData()));
- }
-
- NotifyCryptographerState(cryptographer);
- allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
- }
-
- if (!initialized_) {
- LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
- << "initialized";
- return;
- }
-
- if (!event.snapshot->has_more_to_sync) {
- // To account for a nigori node arriving with stale/bad data, we ensure
- // that the nigori node is up to date at the end of each cycle.
- WriteTransaction trans(FROM_HERE, GetUserShare());
- WriteNode nigori_node(&trans);
- if (nigori_node.InitByTagLookup(kNigoriTag) ==
- sync_api::BaseNode::INIT_OK) {
- Cryptographer* cryptographer = trans.GetCryptographer();
- UpdateNigoriEncryptionState(cryptographer, &nigori_node);
- }
-
- DVLOG(1) << "Sending OnSyncCycleCompleted";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnSyncCycleCompleted(event.snapshot));
- }
-
- // This is here for tests, which are still using p2p notifications.
- //
- // TODO(chron): Consider changing this back to track has_more_to_sync
- // only notify peers if a successful commit has occurred.
- bool is_notifiable_commit =
- (event.snapshot->syncer_status.num_successful_commits > 0);
- if (is_notifiable_commit) {
- if (sync_notifier_.get()) {
- const ModelTypeSet changed_types =
- syncable::ModelTypePayloadMapToEnumSet(
- event.snapshot->source.types);
- sync_notifier_->SendNotification(changed_types);
- } else {
- DVLOG(1) << "Not sending notification: sync_notifier_ is NULL";
- }
- }
- }
-
- if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnStopSyncingPermanently());
- return;
- }
-
- if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnClearServerDataSucceeded());
- return;
- }
-
- if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnClearServerDataFailed());
- return;
- }
-
- if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnUpdatedToken(event.updated_token));
- return;
- }
-
- if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnActionableError(
- event.snapshot->errors.sync_protocol_error));
- return;
- }
-
-}
-
-void SyncManager::SyncInternal::SetJsEventHandler(
- const WeakHandle<JsEventHandler>& event_handler) {
- js_event_handler_ = event_handler;
- js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
- js_mutation_event_observer_.SetJsEventHandler(js_event_handler_);
-}
-
-void SyncManager::SyncInternal::ProcessJsMessage(
- const std::string& name, const JsArgList& args,
- const WeakHandle<JsReplyHandler>& reply_handler) {
- if (!initialized_) {
- NOTREACHED();
- return;
- }
-
- if (!reply_handler.IsInitialized()) {
- DVLOG(1) << "Uninitialized reply handler; dropping unknown message "
- << name << " with args " << args.ToString();
- return;
- }
-
- JsMessageHandler js_message_handler = js_message_handlers_[name];
- if (js_message_handler.is_null()) {
- DVLOG(1) << "Dropping unknown message " << name
- << " with args " << args.ToString();
- return;
- }
-
- reply_handler.Call(FROM_HERE,
- &JsReplyHandler::HandleJsReply,
- name, js_message_handler.Run(args));
-}
-
-void SyncManager::SyncInternal::BindJsMessageHandler(
- const std::string& name,
- UnboundJsMessageHandler unbound_message_handler) {
- js_message_handlers_[name] =
- base::Bind(unbound_message_handler, base::Unretained(this));
-}
-
-DictionaryValue* SyncManager::SyncInternal::NotificationInfoToValue(
- const NotificationInfoMap& notification_info) {
- DictionaryValue* value = new DictionaryValue();
-
- for (NotificationInfoMap::const_iterator it = notification_info.begin();
- it != notification_info.end(); ++it) {
- const std::string& model_type_str =
- syncable::ModelTypeToString(it->first);
- value->Set(model_type_str, it->second.ToValue());
- }
-
- return value;
-}
-
-JsArgList SyncManager::SyncInternal::GetNotificationState(
- const JsArgList& args) {
- bool notifications_enabled = allstatus_.status().notifications_enabled;
- ListValue return_args;
- return_args.Append(Value::CreateBooleanValue(notifications_enabled));
- return JsArgList(&return_args);
-}
-
-JsArgList SyncManager::SyncInternal::GetNotificationInfo(
- const JsArgList& args) {
- ListValue return_args;
- return_args.Append(NotificationInfoToValue(notification_info_map_));
- return JsArgList(&return_args);
-}
-
-JsArgList SyncManager::SyncInternal::GetRootNodeDetails(
- const JsArgList& args) {
- ReadTransaction trans(FROM_HERE, GetUserShare());
- ReadNode root(&trans);
- root.InitByRootLookup();
- ListValue return_args;
- return_args.Append(root.GetDetailsAsValue());
- return JsArgList(&return_args);
-}
-
-JsArgList SyncManager::SyncInternal::GetClientServerTraffic(
- const JsArgList& args) {
- ListValue return_args;
- ListValue* value = traffic_recorder_.ToValue();
- if (value != NULL)
- return_args.Append(value);
- return JsArgList(&return_args);
-}
-
-namespace {
-
-int64 GetId(const ListValue& ids, int i) {
- std::string id_str;
- if (!ids.GetString(i, &id_str)) {
- return kInvalidId;
- }
- int64 id = kInvalidId;
- if (!base::StringToInt64(id_str, &id)) {
- return kInvalidId;
- }
- return id;
-}
-
-JsArgList GetNodeInfoById(const JsArgList& args,
- UserShare* user_share,
- DictionaryValue* (BaseNode::*info_getter)() const) {
- CHECK(info_getter);
- ListValue return_args;
- ListValue* node_summaries = new ListValue();
- return_args.Append(node_summaries);
- ListValue* id_list = NULL;
- ReadTransaction trans(FROM_HERE, user_share);
- if (args.Get().GetList(0, &id_list)) {
- CHECK(id_list);
- for (size_t i = 0; i < id_list->GetSize(); ++i) {
- int64 id = GetId(*id_list, i);
- if (id == kInvalidId) {
- continue;
- }
- ReadNode node(&trans);
- if (node.InitByIdLookup(id) != sync_api::BaseNode::INIT_OK) {
- continue;
- }
- node_summaries->Append((node.*info_getter)());
- }
- }
- return JsArgList(&return_args);
-}
-
-} // namespace
-
-JsArgList SyncManager::SyncInternal::GetNodeSummariesById(
- const JsArgList& args) {
- return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetSummaryAsValue);
-}
-
-JsArgList SyncManager::SyncInternal::GetNodeDetailsById(
- const JsArgList& args) {
- return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetDetailsAsValue);
-}
-
-JsArgList SyncManager::SyncInternal::GetAllNodes(
- const JsArgList& args) {
- ListValue return_args;
- ListValue* result = new ListValue();
- return_args.Append(result);
-
- ReadTransaction trans(FROM_HERE, GetUserShare());
- std::vector<const syncable::EntryKernel*> entry_kernels;
- trans.GetDirectory()->GetAllEntryKernels(trans.GetWrappedTrans(),
- &entry_kernels);
-
- for (std::vector<const syncable::EntryKernel*>::const_iterator it =
- entry_kernels.begin(); it != entry_kernels.end(); ++it) {
- result->Append((*it)->ToValue());
- }
-
- return JsArgList(&return_args);
-}
-
-JsArgList SyncManager::SyncInternal::GetChildNodeIds(
- const JsArgList& args) {
- ListValue return_args;
- ListValue* child_ids = new ListValue();
- return_args.Append(child_ids);
- int64 id = GetId(args.Get(), 0);
- if (id != kInvalidId) {
- ReadTransaction trans(FROM_HERE, GetUserShare());
- syncable::Directory::ChildHandles child_handles;
- trans.GetDirectory()->GetChildHandlesByHandle(trans.GetWrappedTrans(),
- id, &child_handles);
- for (syncable::Directory::ChildHandles::const_iterator it =
- child_handles.begin(); it != child_handles.end(); ++it) {
- child_ids->Append(Value::CreateStringValue(
- base::Int64ToString(*it)));
- }
- }
- return JsArgList(&return_args);
-}
-
-void SyncManager::SyncInternal::OnEncryptedTypesChanged(
- syncable::ModelTypeSet encrypted_types,
- bool encrypt_everything) {
- // NOTE: We're in a transaction.
- FOR_EACH_OBSERVER(
- SyncManager::Observer, observers_,
- OnEncryptedTypesChanged(encrypted_types, encrypt_everything));
-}
-
-void SyncManager::SyncInternal::OnNotificationStateChange(
- bool notifications_enabled) {
- DVLOG(1) << "P2P: Notifications enabled = "
- << (notifications_enabled ? "true" : "false");
- allstatus_.SetNotificationsEnabled(notifications_enabled);
- if (scheduler()) {
- scheduler()->set_notifications_enabled(notifications_enabled);
- }
- if (js_event_handler_.IsInitialized()) {
- DictionaryValue details;
- details.Set("enabled", Value::CreateBooleanValue(notifications_enabled));
- js_event_handler_.Call(FROM_HERE,
- &JsEventHandler::HandleJsEvent,
- "onNotificationStateChange",
- JsEventDetails(&details));
- }
-}
-
-void SyncManager::SyncInternal::UpdateNotificationInfo(
- const syncable::ModelTypePayloadMap& type_payloads) {
- for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
- it != type_payloads.end(); ++it) {
- NotificationInfo* info = &notification_info_map_[it->first];
- info->total_count++;
- info->payload = it->second;
- }
-}
-
-void SyncManager::SyncInternal::OnIncomingNotification(
- const syncable::ModelTypePayloadMap& type_payloads,
- sync_notifier::IncomingNotificationSource source) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (source == sync_notifier::LOCAL_NOTIFICATION) {
- if (scheduler()) {
- scheduler()->ScheduleNudgeWithPayloads(
- TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
- browser_sync::NUDGE_SOURCE_LOCAL_REFRESH,
- type_payloads, FROM_HERE);
- }
- } else if (!type_payloads.empty()) {
- if (scheduler()) {
- scheduler()->ScheduleNudgeWithPayloads(
- TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
- browser_sync::NUDGE_SOURCE_NOTIFICATION,
- type_payloads, FROM_HERE);
- }
- allstatus_.IncrementNotificationsReceived();
- UpdateNotificationInfo(type_payloads);
- debug_info_event_listener_.OnIncomingNotification(type_payloads);
- } else {
- LOG(WARNING) << "Sync received notification without any type information.";
- }
-
- if (js_event_handler_.IsInitialized()) {
- DictionaryValue details;
- ListValue* changed_types = new ListValue();
- details.Set("changedTypes", changed_types);
- for (syncable::ModelTypePayloadMap::const_iterator
- it = type_payloads.begin();
- it != type_payloads.end(); ++it) {
- const std::string& model_type_str =
- syncable::ModelTypeToString(it->first);
- changed_types->Append(Value::CreateStringValue(model_type_str));
- }
- details.SetString("source", (source == sync_notifier::LOCAL_NOTIFICATION) ?
- "LOCAL_NOTIFICATION" : "REMOTE_NOTIFICATION");
- js_event_handler_.Call(FROM_HERE,
- &JsEventHandler::HandleJsEvent,
- "onIncomingNotification",
- JsEventDetails(&details));
- }
-}
-
-void SyncManager::SyncInternal::StoreState(
- const std::string& state) {
- if (!directory()) {
- LOG(ERROR) << "Could not write notification state";
- // TODO(akalin): Propagate result callback all the way to this
- // function and call it with "false" to signal failure.
- return;
- }
- if (VLOG_IS_ON(1)) {
- std::string encoded_state;
- base::Base64Encode(state, &encoded_state);
- DVLOG(1) << "Writing notification state: " << encoded_state;
- }
- directory()->SetNotificationState(state);
- directory()->SaveChanges();
-}
-
-void SyncManager::SyncInternal::AddObserver(
- SyncManager::Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void SyncManager::SyncInternal::RemoveObserver(
- SyncManager::Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-SyncManager::Status SyncManager::GetDetailedStatus() const {
- return data_->GetStatus();
-}
-
-void SyncManager::SaveChanges() {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->SaveChanges();
-}
-
-void SyncManager::SyncInternal::SaveChanges() {
- directory()->SaveChanges();
-}
-
-UserShare* SyncManager::GetUserShare() const {
- return data_->GetUserShare();
-}
-
-void SyncManager::RefreshNigori(const std::string& chrome_version,
- const base::Closure& done_callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->UpdateCryptographerAndNigori(
- chrome_version,
- done_callback);
-}
-
-TimeDelta SyncManager::GetNudgeDelayTimeDelta(
- const ModelType& model_type) {
- return data_->GetNudgeDelayTimeDelta(model_type);
-}
-
-syncable::ModelTypeSet SyncManager::GetEncryptedDataTypesForTest() const {
- ReadTransaction trans(FROM_HERE, GetUserShare());
- return GetEncryptedTypes(&trans);
-}
-
-bool SyncManager::ReceivedExperimentalTypes(syncable::ModelTypeSet* to_add)
- const {
- ReadTransaction trans(FROM_HERE, GetUserShare());
- ReadNode node(&trans);
- if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
- DVLOG(1) << "Couldn't find Nigori node.";
- return false;
- }
- if (node.GetNigoriSpecifics().sync_tabs()) {
- to_add->Put(syncable::SESSIONS);
- return true;
- }
- return false;
-}
-
-bool SyncManager::HasUnsyncedItems() const {
- sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
- return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
-}
-
-void SyncManager::TriggerOnNotificationStateChangeForTest(
- bool notifications_enabled) {
- DCHECK(thread_checker_.CalledOnValidThread());
- data_->OnNotificationStateChange(notifications_enabled);
-}
-
-void SyncManager::TriggerOnIncomingNotificationForTest(
- ModelTypeSet model_types) {
- DCHECK(thread_checker_.CalledOnValidThread());
- syncable::ModelTypePayloadMap model_types_with_payloads =
- syncable::ModelTypePayloadMapFromEnumSet(model_types,
- std::string());
-
- data_->OnIncomingNotification(model_types_with_payloads,
- sync_notifier::REMOTE_NOTIFICATION);
-}
-
-const char* ConnectionStatusToString(ConnectionStatus status) {
- switch (status) {
- case CONNECTION_OK:
- return "CONNECTION_OK";
- case CONNECTION_AUTH_ERROR:
- return "CONNECTION_AUTH_ERROR";
- case CONNECTION_SERVER_ERROR:
- return "CONNECTION_SERVER_ERROR";
- default:
- NOTREACHED();
- return "INVALID_CONNECTION_STATUS";
- }
-}
-
-// Helper function that converts a PassphraseRequiredReason value to a string.
-const char* PassphraseRequiredReasonToString(
- PassphraseRequiredReason reason) {
- switch (reason) {
- case REASON_PASSPHRASE_NOT_REQUIRED:
- return "REASON_PASSPHRASE_NOT_REQUIRED";
- case REASON_ENCRYPTION:
- return "REASON_ENCRYPTION";
- case REASON_DECRYPTION:
- return "REASON_DECRYPTION";
- default:
- NOTREACHED();
- return "INVALID_REASON";
- }
-}
-
-// Helper function to determine if initial sync had ended for types.
-bool InitialSyncEndedForTypes(syncable::ModelTypeSet types,
- sync_api::UserShare* share) {
- for (syncable::ModelTypeSet::Iterator i = types.First();
- i.Good(); i.Inc()) {
- if (!share->directory->initial_sync_ended_for_type(i.Get()))
- return false;
- }
- return true;
-}
-
-syncable::ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
- syncable::ModelTypeSet types,
- sync_api::UserShare* share) {
- syncable::ModelTypeSet result;
- for (syncable::ModelTypeSet::Iterator i = types.First();
- i.Good(); i.Inc()) {
- sync_pb::DataTypeProgressMarker marker;
- share->directory->GetDownloadProgress(i.Get(), &marker);
-
- if (marker.token().empty())
- result.Put(i.Get());
-
- }
- return result;
-}
-
-} // namespace sync_api
« no previous file with comments | « chrome/browser/sync/internal_api/sync_manager.h ('k') | chrome/browser/sync/internal_api/syncapi_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698