| // Copyright 2014 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. |
| |
| #ifndef COMPONENTS_SYNC_ENGINE_IMPL_MODEL_TYPE_WORKER_H_ |
| #define COMPONENTS_SYNC_ENGINE_IMPL_MODEL_TYPE_WORKER_H_ |
| |
| #include <stddef.h> |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "components/sync/base/cancelation_observer.h" |
| #include "components/sync/base/cryptographer.h" |
| #include "components/sync/base/model_type.h" |
| #include "components/sync/base/passphrase_enums.h" |
| #include "components/sync/engine/commit_queue.h" |
| #include "components/sync/engine/non_blocking_sync_common.h" |
| #include "components/sync/engine/sync_encryption_handler.h" |
| #include "components/sync/engine_impl/commit_contributor.h" |
| #include "components/sync/engine_impl/cycle/data_type_debug_info_emitter.h" |
| #include "components/sync/engine_impl/nudge_handler.h" |
| #include "components/sync/engine_impl/update_handler.h" |
| #include "components/sync/protocol/model_type_state.pb.h" |
| #include "components/sync/protocol/sync.pb.h" |
| |
| namespace syncer { |
| |
| class CancelationSignal; |
| class ModelTypeProcessor; |
| class WorkerEntityTracker; |
| |
| // A smart cache for sync types that use message passing (rather than |
| // transactions and the syncable::Directory) to communicate with the sync |
| // thread. |
| // |
| // When the non-blocking sync type wants to talk with the sync server, it will |
| // send a message from its thread to this object on the sync thread. This |
| // object ensures the appropriate sync server communication gets scheduled and |
| // executed. The response, if any, will be returned to the non-blocking sync |
| // type's thread eventually. |
| // |
| // This object also has a role to play in communications in the opposite |
| // direction. Sometimes the sync thread will receive changes from the sync |
| // server and deliver them here. This object will post this information back to |
| // the appropriate component on the model type's thread. |
| // |
| // This object does more than just pass along messages. It understands the sync |
| // protocol, and it can make decisions when it sees conflicting messages. For |
| // example, if the sync server sends down an update for a sync entity that is |
| // currently pending for commit, this object will detect this condition and |
| // cancel the pending commit. |
| class ModelTypeWorker : public UpdateHandler, |
| public CommitContributor, |
| public CommitQueue { |
| public: |
| // Public for testing. |
| enum DecryptionStatus { SUCCESS, DECRYPTION_PENDING, FAILED_TO_DECRYPT }; |
| |
| ModelTypeWorker(ModelType type, |
| const sync_pb::ModelTypeState& initial_state, |
| bool trigger_initial_sync, |
| std::unique_ptr<Cryptographer> cryptographer, |
| PassphraseType passphrase_type, |
| NudgeHandler* nudge_handler, |
| std::unique_ptr<ModelTypeProcessor> model_type_processor, |
| DataTypeDebugInfoEmitter* debug_info_emitter, |
| CancelationSignal* cancelation_signal); |
| ~ModelTypeWorker() override; |
| |
| // Public for testing. |
| // |cryptographer| can be null. |
| // |response_data| must be not null. |
| static DecryptionStatus PopulateUpdateResponseData( |
| const Cryptographer* cryptographer, |
| const sync_pb::SyncEntity& update_entity, |
| UpdateResponseData* response_data); |
| |
| ModelType GetModelType() const; |
| |
| void UpdateCryptographer(std::unique_ptr<Cryptographer> cryptographer); |
| void UpdatePassphraseType(PassphraseType type); |
| |
| // UpdateHandler implementation. |
| bool IsInitialSyncEnded() const override; |
| void GetDownloadProgress( |
| sync_pb::DataTypeProgressMarker* progress_marker) const override; |
| void GetDataTypeContext(sync_pb::DataTypeContext* context) const override; |
| SyncerError ProcessGetUpdatesResponse( |
| const sync_pb::DataTypeProgressMarker& progress_marker, |
| const sync_pb::DataTypeContext& mutated_context, |
| const SyncEntityList& applicable_updates, |
| StatusController* status) override; |
| void ApplyUpdates(StatusController* status) override; |
| void PassiveApplyUpdates(StatusController* status) override; |
| |
| // CommitQueue implementation. |
| void NudgeForCommit() override; |
| |
| // CommitContributor implementation. |
| std::unique_ptr<CommitContribution> GetContribution( |
| size_t max_entries) override; |
| |
| // Extended overload of ProcessGetUpdatesResponse() that allows specifying |
| // whether the updates are coming from the USS migrator, which influences how |
| // UMA metrics are logged. |
| SyncerError ProcessGetUpdatesResponse( |
| const sync_pb::DataTypeProgressMarker& progress_marker, |
| const sync_pb::DataTypeContext& mutated_context, |
| const SyncEntityList& applicable_updates, |
| bool from_uss_migrator, |
| StatusController* status); |
| |
| bool HasLocalChangesForTest() const; |
| |
| // An alternative way to drive sending data to the processor, that should be |
| // called when a new encryption mechanism is ready. |
| void EncryptionAcceptedMaybeApplyUpdates(); |
| |
| // Callback for when our contribution gets a response. |
| void OnCommitResponse(CommitResponseDataList* response_list); |
| |
| // If migration the directory encounters an error partway through, we need to |
| // clear the update data that has been added so far. |
| void AbortMigration(); |
| |
| // Returns the estimate of dynamically allocated memory in bytes. |
| size_t EstimateMemoryUsage() const; |
| |
| base::WeakPtr<ModelTypeWorker> AsWeakPtr(); |
| |
| private: |
| // Attempts to decrypt the given specifics and return them in the |out| |
| // parameter. The cryptographer must know the decryption key, i.e. |
| // cryptographer.CanDecrypt(specifics.encrypted()) must return true. |
| // |
| // Returns false if the decryption failed. There are no guarantees about the |
| // contents of |out| when that happens. |
| // |
| // In theory, this should never fail. Only corrupt or invalid entries could |
| // cause this to fail, and no clients are known to create such entries. The |
| // failure case is an attempt to be defensive against bad input. |
| static bool DecryptSpecifics(const Cryptographer& cryptographer, |
| const sync_pb::EntitySpecifics& in, |
| sync_pb::EntitySpecifics* out); |
| |
| // Attempts to decrypt the given password specifics and return them in the |
| // |out| parameter. The cryptographer must know the decryption key, i.e. |
| // cryptographer.CanDecrypt(in.password().encrypted()) must return true. |
| // |
| // Returns false if the decryption failed. There are no guarantees about the |
| // contents of |out| when that happens. |
| // |
| // In theory, this should never fail. Only corrupt or invalid entries could |
| // cause this to fail, and no clients are known to create such entries. The |
| // failure case is an attempt to be defensive against bad input. |
| static bool DecryptPasswordSpecifics(const Cryptographer& cryptographer, |
| const sync_pb::EntitySpecifics& in, |
| sync_pb::EntitySpecifics* out); |
| |
| // Helper function to actually send |pending_updates_| to the processor. |
| void ApplyPendingUpdates(); |
| |
| // Returns true if this type has successfully fetched all available updates |
| // from the server at least once. Our state may or may not be stale, but at |
| // least we know that it was valid at some point in the past. |
| bool IsTypeInitialized() const; |
| |
| // Returns true if this type is prepared to commit items. Currently, this |
| // depends on having downloaded the initial data and having the encryption |
| // settings in a good state. |
| bool CanCommitItems() const; |
| |
| // Returns true if this type should stop communicating because of outstanding |
| // encryption issues and must wait for keys to be updated. |
| bool BlockForEncryption() const; |
| |
| // Updates the encryption key name stored in |model_type_state_| if it differs |
| // from the default encryption key name in |cryptographer_|. Returns whether |
| // an update occurred. |
| bool UpdateEncryptionKeyName(); |
| |
| // Iterates through all elements in |entries_pending_decryption_| and tries to |
| // decrypt anything that has encrypted data. |
| // Should only be called during a GetUpdates cycle. |
| void DecryptStoredEntities(); |
| |
| // Returns the entity tracker for the given |tag_hash|, or nullptr. |
| WorkerEntityTracker* GetEntityTracker(const std::string& tag_hash); |
| |
| // Creates an entity tracker in the map using the given |data| and returns a |
| // pointer to it. Requires that one doesn't exist for data.client_tag_hash. |
| WorkerEntityTracker* CreateEntityTracker(const std::string& tag_hash); |
| |
| // Gets the entity tracker for |data| or creates one if it doesn't exist. |
| WorkerEntityTracker* GetOrCreateEntityTracker(const std::string& tag_hash); |
| |
| // Nudges nudge_handler_ when initial sync is done, processor has local |
| // changes and either encryption is disabled for the type or cryptographer is |
| // ready (doesn't have pending keys). |
| void NudgeIfReadyToCommit(); |
| |
| // Filters our duplicate updates from |pending_updates_| based on the server |
| // id. It discards all of them except the last one. |
| void DeduplicatePendingUpdatesBasedOnServerId(); |
| |
| // Filters our duplicate updates from |pending_updates_| based on the client |
| // tag hash. It discards all of them except the last one. |
| void DeduplicatePendingUpdatesBasedOnClientTagHash(); |
| |
| ModelType type_; |
| DataTypeDebugInfoEmitter* debug_info_emitter_; |
| |
| // State that applies to the entire model type. |
| sync_pb::ModelTypeState model_type_state_; |
| |
| // Pointer to the ModelTypeProcessor associated with this worker. Never null. |
| std::unique_ptr<ModelTypeProcessor> model_type_processor_; |
| |
| // A private copy of the most recent cryptographer known to sync. |
| // Initialized at construction time and updated with UpdateCryptographer(). |
| // null if encryption is not enabled for this type. |
| std::unique_ptr<Cryptographer> cryptographer_; |
| |
| // A private copy of the most recent passphrase type. Initialized at |
| // construction time and updated with UpdatePassphraseType(). |
| PassphraseType passphrase_type_; |
| |
| // Interface used to access and send nudges to the sync scheduler. Not owned. |
| NudgeHandler* nudge_handler_; |
| |
| // A map of update responses, keyed by server_id. |
| // Holds updates encrypted with pending keys. |
| std::map<std::string, UpdateResponseData> entries_pending_decryption_; |
| |
| // Accumulates all the updates from a single GetUpdates cycle in memory so |
| // they can all be sent to the processor at once. |
| UpdateResponseDataList pending_updates_; |
| |
| // Indicates if processor has local changes. Processor only nudges worker once |
| // and worker might not be ready to commit entities at the time. |
| bool has_local_changes_ = false; |
| |
| // Cancellation signal is used to cancel blocking operation on engine |
| // shutdown. |
| CancelationSignal* cancelation_signal_; |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| base::WeakPtrFactory<ModelTypeWorker> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ModelTypeWorker); |
| }; |
| |
| // GetLocalChangesRequest is a container for GetLocalChanges call response. It |
| // allows sync thread to block waiting for model thread to call SetResponse. |
| // This class supports canceling blocking call through CancelationSignal during |
| // sync engine shutdown. |
| // |
| // It should be used in the following manner: |
| // scoped_refptr<GetLocalChangesRequest> request = |
| // base::MakeRefCounted<GetLocalChangesRequest>(cancelation_signal_); |
| // model_type_processor_->GetLocalChanges( |
| // max_entries, |
| // base::Bind(&GetLocalChangesRequest::SetResponse, request)); |
| // request->WaitForResponse(); |
| // CommitRequestDataList response; |
| // if (!request->WasCancelled()) |
| // response = request->ExtractResponse(); |
| class GetLocalChangesRequest |
| : public base::RefCountedThreadSafe<GetLocalChangesRequest>, |
| public CancelationObserver { |
| public: |
| explicit GetLocalChangesRequest(CancelationSignal* cancelation_signal); |
| |
| // CancelationObserver implementation. |
| void OnSignalReceived() override; |
| |
| // Blocks current thread until either SetResponse is called or |
| // cancelation_signal_ is signaled. |
| void WaitForResponse(); |
| |
| // SetResponse takes ownership of |local_changes| and unblocks WaitForResponse |
| // call. It is called by model type through callback passed to |
| // GetLocalChanges. |
| void SetResponse(CommitRequestDataList&& local_changes); |
| |
| // Checks if WaitForResponse was canceled through CancelationSignal. When |
| // returns true calling ExtractResponse is unsafe. |
| bool WasCancelled(); |
| |
| // Returns response set by SetResponse(). |
| CommitRequestDataList&& ExtractResponse(); |
| |
| private: |
| friend class base::RefCountedThreadSafe<GetLocalChangesRequest>; |
| ~GetLocalChangesRequest() override; |
| |
| CancelationSignal* cancelation_signal_; |
| base::WaitableEvent response_accepted_; |
| CommitRequestDataList response_; |
| |
| DISALLOW_COPY_AND_ASSIGN(GetLocalChangesRequest); |
| }; |
| |
| } // namespace syncer |
| |
| #endif // COMPONENTS_SYNC_ENGINE_IMPL_MODEL_TYPE_WORKER_H_ |