model_type_worker.cc 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/sync/engine/model_type_worker.h"
  5. #include <stdint.h>
  6. #include <set>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/containers/contains.h"
  10. #include "base/containers/cxx20_erase.h"
  11. #include "base/format_macros.h"
  12. #include "base/guid.h"
  13. #include "base/logging.h"
  14. #include "base/metrics/field_trial_params.h"
  15. #include "base/metrics/histogram_functions.h"
  16. #include "base/strings/strcat.h"
  17. #include "base/strings/string_util.h"
  18. #include "base/strings/stringprintf.h"
  19. #include "base/synchronization/waitable_event.h"
  20. #include "base/threading/sequenced_task_runner_handle.h"
  21. #include "base/threading/thread_restrictions.h"
  22. #include "base/trace_event/memory_usage_estimator.h"
  23. #include "components/sync/base/client_tag_hash.h"
  24. #include "components/sync/base/data_type_histogram.h"
  25. #include "components/sync/base/features.h"
  26. #include "components/sync/base/hash_util.h"
  27. #include "components/sync/base/model_type.h"
  28. #include "components/sync/base/time.h"
  29. #include "components/sync/base/unique_position.h"
  30. #include "components/sync/engine/bookmark_update_preprocessing.h"
  31. #include "components/sync/engine/cancelation_signal.h"
  32. #include "components/sync/engine/commit_contribution.h"
  33. #include "components/sync/engine/commit_contribution_impl.h"
  34. #include "components/sync/engine/cycle/entity_change_metric_recording.h"
  35. #include "components/sync/engine/model_type_processor.h"
  36. #include "components/sync/protocol/data_type_progress_marker.pb.h"
  37. #include "components/sync/protocol/entity_specifics.pb.h"
  38. #include "components/sync/protocol/proto_memory_estimations.h"
  39. #include "components/sync/protocol/sync_entity.pb.h"
  40. namespace syncer {
  41. namespace {
  42. const char kTimeUntilEncryptionKeyFoundHistogramName[] =
  43. "Sync.ModelTypeTimeUntilEncryptionKeyFound2";
  44. const char kUndecryptablePendingUpdatesDroppedHistogramName[] =
  45. "Sync.ModelTypeUndecryptablePendingUpdatesDropped";
  46. const char kBlockedByUndecryptableUpdateHistogramName[] =
  47. "Sync.ModelTypeBlockedDueToUndecryptableUpdate";
  48. const char kPasswordNotesStateHistogramName[] =
  49. "Sync.PasswordNotesStateInUpdate";
  50. void LogPasswordNotesState(PasswordNotesStateForUMA state) {
  51. base::UmaHistogramEnumeration(kPasswordNotesStateHistogramName, state);
  52. }
  53. // A proxy which can be called from any sequence and delegates the work to the
  54. // commit queue injected on construction.
  55. class CommitQueueProxy : public CommitQueue {
  56. public:
  57. // Must be called from the sequence where |commit_queue| lives.
  58. explicit CommitQueueProxy(const base::WeakPtr<CommitQueue>& commit_queue)
  59. : commit_queue_(commit_queue) {}
  60. ~CommitQueueProxy() override = default;
  61. void NudgeForCommit() override {
  62. commit_queue_thread_->PostTask(
  63. FROM_HERE, base::BindOnce(&CommitQueue::NudgeForCommit, commit_queue_));
  64. }
  65. private:
  66. const base::WeakPtr<CommitQueue> commit_queue_;
  67. const scoped_refptr<base::SequencedTaskRunner> commit_queue_thread_ =
  68. base::SequencedTaskRunnerHandle::Get();
  69. };
  70. void AdaptClientTagForFullUpdateData(ModelType model_type,
  71. syncer::EntityData* data) {
  72. // Server does not send any client tags for wallet data entities or offer data
  73. // entities. This code manually asks the bridge to create the client tags for
  74. // each entity, so that we can use ClientTagBasedModelTypeProcessor for
  75. // AUTOFILL_WALLET_DATA or AUTOFILL_WALLET_OFFER.
  76. if (data->legacy_parent_id == "0") {
  77. // Ignore the permanent root node as that one should have no client tag
  78. // hash.
  79. return;
  80. }
  81. DCHECK(!data->specifics.has_encrypted());
  82. if (model_type == AUTOFILL_WALLET_DATA) {
  83. DCHECK(data->specifics.has_autofill_wallet());
  84. data->client_tag_hash = ClientTagHash::FromUnhashed(
  85. AUTOFILL_WALLET_DATA, GetUnhashedClientTagFromAutofillWalletSpecifics(
  86. data->specifics.autofill_wallet()));
  87. } else if (model_type == AUTOFILL_WALLET_OFFER) {
  88. DCHECK(data->specifics.has_autofill_offer());
  89. data->client_tag_hash = ClientTagHash::FromUnhashed(
  90. AUTOFILL_WALLET_OFFER, GetUnhashedClientTagFromAutofillOfferSpecifics(
  91. data->specifics.autofill_offer()));
  92. } else {
  93. NOTREACHED();
  94. }
  95. }
  96. // Returns empty string if |entity| is not encrypted.
  97. // TODO(crbug.com/1109221): Consider moving this to a util file and converting
  98. // UpdateResponseData::encryption_key_name into a method that calls it. Consider
  99. // returning a struct containing also the encrypted blob, which would make the
  100. // code of PopulateUpdateResponseData() simpler.
  101. std::string GetEncryptionKeyName(const sync_pb::SyncEntity& entity) {
  102. if (entity.deleted()) {
  103. return std::string();
  104. }
  105. // Passwords use their own legacy encryption scheme.
  106. if (entity.specifics().password().has_encrypted()) {
  107. return entity.specifics().password().encrypted().key_name();
  108. }
  109. if (entity.specifics().has_encrypted()) {
  110. return entity.specifics().encrypted().key_name();
  111. }
  112. return std::string();
  113. }
  114. // Attempts to decrypt the given specifics and return them in the |out|
  115. // parameter. The cryptographer must know the decryption key, i.e.
  116. // cryptographer.CanDecrypt(specifics.encrypted()) must return true.
  117. //
  118. // Returns false if the decryption failed. There are no guarantees about the
  119. // contents of |out| when that happens.
  120. //
  121. // In theory, this should never fail. Only corrupt or invalid entries could
  122. // cause this to fail, and no clients are known to create such entries. The
  123. // failure case is an attempt to be defensive against bad input.
  124. bool DecryptSpecifics(const Cryptographer& cryptographer,
  125. const sync_pb::EntitySpecifics& in,
  126. sync_pb::EntitySpecifics* out) {
  127. DCHECK(!in.has_password());
  128. DCHECK(in.has_encrypted());
  129. DCHECK(cryptographer.CanDecrypt(in.encrypted()));
  130. if (!cryptographer.Decrypt(in.encrypted(), out)) {
  131. DLOG(ERROR) << "Failed to decrypt a decryptable specifics";
  132. return false;
  133. }
  134. return true;
  135. }
  136. // Attempts to decrypt the given password specifics and return them in the
  137. // |out| parameter. The cryptographer must know the decryption key, i.e.
  138. // cryptographer.CanDecrypt(in.password().encrypted()) must return true.
  139. //
  140. // Returns false if the decryption failed. There are no guarantees about the
  141. // contents of |out| when that happens.
  142. //
  143. // In theory, this should never fail. Only corrupt or invalid entries could
  144. // cause this to fail, and no clients are known to create such entries. The
  145. // failure case is an attempt to be defensive against bad input.
  146. bool DecryptPasswordSpecifics(const Cryptographer& cryptographer,
  147. const sync_pb::EntitySpecifics& in,
  148. sync_pb::EntitySpecifics* out) {
  149. DCHECK(in.has_password());
  150. DCHECK(in.password().has_encrypted());
  151. DCHECK(cryptographer.CanDecrypt(in.password().encrypted()));
  152. if (!cryptographer.Decrypt(
  153. in.password().encrypted(),
  154. out->mutable_password()->mutable_client_only_encrypted_data())) {
  155. DLOG(ERROR) << "Failed to decrypt a decryptable password";
  156. return false;
  157. }
  158. // The `notes` field in the PasswordSpecificsData is the authoritative value.
  159. // When set, it disregards whatever `encrypted_notes_backup` contains.
  160. if (out->password().client_only_encrypted_data().has_notes()) {
  161. LogPasswordNotesState(PasswordNotesStateForUMA::kSetInSpecificsData);
  162. return true;
  163. }
  164. if (!in.password().has_encrypted_notes_backup()) {
  165. LogPasswordNotesState(PasswordNotesStateForUMA::kUnset);
  166. return true;
  167. }
  168. if (!base::FeatureList::IsEnabled(
  169. syncer::kReadWritePasswordNotesBackupField)) {
  170. return true;
  171. }
  172. // It is guaranteed that if `encrypted()` is decryptable, then
  173. // `encrypted_notes_backup()` must be decryptable too. Failure to decrypt
  174. // `encrypted_notes_backup()` indicates a data corruption.
  175. if (!cryptographer.Decrypt(in.password().encrypted_notes_backup(),
  176. out->mutable_password()
  177. ->mutable_client_only_encrypted_data()
  178. ->mutable_notes())) {
  179. LogPasswordNotesState(
  180. PasswordNotesStateForUMA::kSetOnlyInBackupButCorrupted);
  181. return false;
  182. }
  183. LogPasswordNotesState(PasswordNotesStateForUMA::kSetOnlyInBackup);
  184. // TODO(crbug.com/1326554): Properly handle the case when both blobs are
  185. // decryptable but with different keys. Ideally the password should be
  186. // re-uploaded potentially by setting needs_reupload boolean in
  187. // UpdateResponseData or EntityData.
  188. return true;
  189. }
  190. } // namespace
  191. ModelTypeWorker::ModelTypeWorker(ModelType type,
  192. const sync_pb::ModelTypeState& initial_state,
  193. Cryptographer* cryptographer,
  194. bool encryption_enabled,
  195. PassphraseType passphrase_type,
  196. NudgeHandler* nudge_handler,
  197. CancelationSignal* cancelation_signal)
  198. : type_(type),
  199. cryptographer_(cryptographer),
  200. nudge_handler_(nudge_handler),
  201. cancelation_signal_(cancelation_signal),
  202. model_type_state_(initial_state),
  203. encryption_enabled_(encryption_enabled),
  204. passphrase_type_(passphrase_type),
  205. min_get_updates_to_ignore_key_(kMinGuResponsesToIgnoreKey.Get()) {
  206. DCHECK(cryptographer_);
  207. DCHECK(!AlwaysEncryptedUserTypes().Has(type_) || encryption_enabled_);
  208. if (!CommitOnlyTypes().Has(GetModelType())) {
  209. DCHECK_EQ(type, GetModelTypeFromSpecificsFieldNumber(
  210. initial_state.progress_marker().data_type_id()));
  211. }
  212. }
  213. ModelTypeWorker::~ModelTypeWorker() {
  214. if (model_type_processor_) {
  215. // This will always be the case in production today.
  216. model_type_processor_->DisconnectSync();
  217. }
  218. }
  219. void ModelTypeWorker::ConnectSync(
  220. std::unique_ptr<ModelTypeProcessor> model_type_processor) {
  221. DCHECK(!model_type_processor_);
  222. DCHECK(model_type_processor);
  223. model_type_processor_ = std::move(model_type_processor);
  224. // TODO(victorvianna): CommitQueueProxy is only needed by the
  225. // ModelTypeProcessorProxy implementation, so it could possibly be moved
  226. // there % changing ConnectSync() to take a raw pointer. This then allows
  227. // removing base::test::SingleThreadTaskEnvironment from the unit test.
  228. model_type_processor_->ConnectSync(
  229. std::make_unique<CommitQueueProxy>(weak_ptr_factory_.GetWeakPtr()));
  230. if (!model_type_state_.initial_sync_done()) {
  231. nudge_handler_->NudgeForInitialDownload(type_);
  232. }
  233. // |model_type_state_| might have an outdated encryption key name, e.g.
  234. // because |cryptographer_| was updated before this worker was constructed.
  235. // OnCryptographerChange() might never be called, so update the key manually
  236. // here and push it to the processor. Only push if initial sync is done,
  237. // otherwise this violates some of the processor assumptions; if initial sync
  238. // isn't done, the now-updated key will be pushed on the first ApplyUpdates()
  239. // call anyway.
  240. bool had_outdated_key_name = UpdateTypeEncryptionKeyName();
  241. if (had_outdated_key_name && model_type_state_.initial_sync_done()) {
  242. SendPendingUpdatesToProcessorIfReady();
  243. }
  244. }
  245. ModelType ModelTypeWorker::GetModelType() const {
  246. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  247. return type_;
  248. }
  249. void ModelTypeWorker::EnableEncryption() {
  250. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  251. if (encryption_enabled_) {
  252. // No-op.
  253. return;
  254. }
  255. encryption_enabled_ = true;
  256. // UpdateTypeEncryptionKeyName() might return false if the cryptographer does
  257. // not have a default key yet.
  258. if (UpdateTypeEncryptionKeyName()) {
  259. // Push the new key name to the processor.
  260. SendPendingUpdatesToProcessorIfReady();
  261. }
  262. }
  263. void ModelTypeWorker::OnCryptographerChange() {
  264. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  265. // Always try to decrypt, regardless of |encryption_enabled_|. This might
  266. // add some elements to |pending_updates_|.
  267. DecryptStoredEntities();
  268. bool had_oudated_key_name = UpdateTypeEncryptionKeyName();
  269. if (had_oudated_key_name || !pending_updates_.empty()) {
  270. // Push the newly decrypted updates and/or the new key name to the
  271. // processor.
  272. SendPendingUpdatesToProcessorIfReady();
  273. }
  274. // If the worker couldn't commit before due to BlockForEncryption(), this
  275. // might now be resolved. The call is a no-op if there's nothing to commit.
  276. NudgeIfReadyToCommit();
  277. }
  278. void ModelTypeWorker::UpdatePassphraseType(PassphraseType type) {
  279. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  280. passphrase_type_ = type;
  281. }
  282. bool ModelTypeWorker::IsInitialSyncEnded() const {
  283. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  284. return model_type_state_.initial_sync_done();
  285. }
  286. const sync_pb::DataTypeProgressMarker& ModelTypeWorker::GetDownloadProgress()
  287. const {
  288. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  289. return model_type_state_.progress_marker();
  290. }
  291. const sync_pb::DataTypeContext& ModelTypeWorker::GetDataTypeContext() const {
  292. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  293. return model_type_state_.type_context();
  294. }
  295. void ModelTypeWorker::ProcessGetUpdatesResponse(
  296. const sync_pb::DataTypeProgressMarker& progress_marker,
  297. const sync_pb::DataTypeContext& mutated_context,
  298. const SyncEntityList& applicable_updates,
  299. StatusController* status) {
  300. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  301. const bool is_initial_sync = !model_type_state_.initial_sync_done();
  302. // TODO(rlarocque): Handle data type context conflicts.
  303. *model_type_state_.mutable_type_context() = mutated_context;
  304. *model_type_state_.mutable_progress_marker() = progress_marker;
  305. for (const sync_pb::SyncEntity* update_entity : applicable_updates) {
  306. RecordEntityChangeMetrics(
  307. type_, is_initial_sync
  308. ? ModelTypeEntityChange::kRemoteInitialUpdate
  309. : ModelTypeEntityChange::kRemoteNonInitialUpdate);
  310. if (update_entity->deleted()) {
  311. status->increment_num_tombstone_updates_downloaded_by(1);
  312. if (!is_initial_sync) {
  313. RecordEntityChangeMetrics(type_,
  314. ModelTypeEntityChange::kRemoteDeletion);
  315. }
  316. }
  317. UpdateResponseData response_data;
  318. switch (PopulateUpdateResponseData(*cryptographer_, type_, *update_entity,
  319. &response_data)) {
  320. case SUCCESS:
  321. pending_updates_.push_back(std::move(response_data));
  322. // Override any previously undecryptable update for the same id.
  323. entries_pending_decryption_.erase(update_entity->id_string());
  324. break;
  325. case DECRYPTION_PENDING: {
  326. SyncRecordModelTypeUpdateDropReason(
  327. UpdateDropReason::kDecryptionPending, type_);
  328. const std::string& key_name = response_data.encryption_key_name;
  329. DCHECK(!key_name.empty());
  330. // If there's no entry for this unknown encryption key, create one.
  331. unknown_encryption_keys_by_name_.emplace(key_name,
  332. UnknownEncryptionKeyInfo());
  333. const std::string& server_id = update_entity->id_string();
  334. if (ShouldIgnoreUpdatesEncryptedWith(key_name)) {
  335. // Don't queue the incoming update. If there's a queued entry for
  336. // |server_id|, don't clear it: outdated data is better than nothing.
  337. // Such entry should be encrypted with another key, since |key_name|'s
  338. // queued updates would've have been dropped by now.
  339. DCHECK(!base::Contains(entries_pending_decryption_, server_id) ||
  340. GetEncryptionKeyName(entries_pending_decryption_[server_id]) !=
  341. key_name);
  342. SyncRecordModelTypeUpdateDropReason(
  343. UpdateDropReason::kDecryptionPendingForTooLong, type_);
  344. break;
  345. }
  346. // Copy the sync entity for later decryption.
  347. // TODO(crbug.com/1270734): Any write to |entries_pending_decryption_|
  348. // should do like DeduplicatePendingUpdatesBasedOnServerId() and honor
  349. // entity version. Additionally, it should look up the same server id
  350. // in |pending_updates_| and compare versions. In fact, the 2 containers
  351. // should probably be moved to a separate class with unit tests.
  352. entries_pending_decryption_[server_id] = *update_entity;
  353. break;
  354. }
  355. case FAILED_TO_DECRYPT:
  356. // Failed to decrypt the entity. Likely it is corrupt. Move on.
  357. SyncRecordModelTypeUpdateDropReason(UpdateDropReason::kFailedToDecrypt,
  358. type_);
  359. break;
  360. }
  361. }
  362. // Some updates pending decryption might have been overwritten by decryptable
  363. // ones. So some encryption keys may no longer fit the definition of unknown.
  364. RemoveKeysNoLongerUnknown();
  365. if (!entries_pending_decryption_.empty() &&
  366. (!encryption_enabled_ || cryptographer_->CanEncrypt())) {
  367. base::UmaHistogramEnumeration(kBlockedByUndecryptableUpdateHistogramName,
  368. ModelTypeHistogramValue(type_));
  369. }
  370. }
  371. // static
  372. // |response_data| must be not null.
  373. ModelTypeWorker::DecryptionStatus ModelTypeWorker::PopulateUpdateResponseData(
  374. const Cryptographer& cryptographer,
  375. ModelType model_type,
  376. const sync_pb::SyncEntity& update_entity,
  377. UpdateResponseData* response_data) {
  378. syncer::EntityData data;
  379. // Deleted entities must use the default instance of EntitySpecifics in
  380. // order for EntityData to correctly reflect that they are deleted.
  381. const sync_pb::EntitySpecifics& specifics =
  382. update_entity.deleted() ? sync_pb::EntitySpecifics::default_instance()
  383. : update_entity.specifics();
  384. bool specifics_were_encrypted = false;
  385. response_data->encryption_key_name = GetEncryptionKeyName(update_entity);
  386. // Try to decrypt any encrypted data. Per crbug.com/1178418, in rare cases
  387. // ModelTypeWorker receives some even though its type doesn't use encryption.
  388. // If so, still try to decrypt with the available keys regardless.
  389. if (specifics.password().has_encrypted()) {
  390. // Passwords use their own legacy encryption scheme.
  391. if (!cryptographer.CanDecrypt(specifics.password().encrypted())) {
  392. return DECRYPTION_PENDING;
  393. }
  394. if (!DecryptPasswordSpecifics(cryptographer, specifics, &data.specifics)) {
  395. return FAILED_TO_DECRYPT;
  396. }
  397. specifics_were_encrypted = true;
  398. } else if (specifics.has_encrypted()) {
  399. DCHECK(!update_entity.deleted()) << "Tombstones shouldn't be encrypted";
  400. if (!cryptographer.CanDecrypt(specifics.encrypted())) {
  401. return DECRYPTION_PENDING;
  402. }
  403. if (!DecryptSpecifics(cryptographer, specifics, &data.specifics)) {
  404. return FAILED_TO_DECRYPT;
  405. }
  406. specifics_were_encrypted = true;
  407. } else {
  408. // No encryption.
  409. data.specifics = specifics;
  410. }
  411. response_data->response_version = update_entity.version();
  412. // Prepare the message for the model thread.
  413. data.id = update_entity.id_string();
  414. data.client_tag_hash =
  415. ClientTagHash::FromHashed(update_entity.client_defined_unique_tag());
  416. data.creation_time = ProtoTimeToTime(update_entity.ctime());
  417. data.modification_time = ProtoTimeToTime(update_entity.mtime());
  418. data.name = update_entity.name();
  419. data.legacy_parent_id = update_entity.parent_id_string();
  420. data.server_defined_unique_tag = update_entity.server_defined_unique_tag();
  421. // Populate |originator_cache_guid| and |originator_client_item_id|. This is
  422. // currently relevant only for bookmarks.
  423. data.originator_cache_guid = update_entity.originator_cache_guid();
  424. data.originator_client_item_id = update_entity.originator_client_item_id();
  425. // Adapt the update for compatibility.
  426. if (model_type == BOOKMARKS) {
  427. data.is_bookmark_unique_position_in_specifics_preprocessed =
  428. AdaptUniquePositionForBookmark(update_entity, &data.specifics);
  429. AdaptTypeForBookmark(update_entity, &data.specifics);
  430. AdaptTitleForBookmark(update_entity, &data.specifics,
  431. specifics_were_encrypted);
  432. AdaptGuidForBookmark(update_entity, &data.specifics);
  433. // Note that the parent GUID in specifics cannot be adapted/populated here,
  434. // because the logic requires access to tracked entities. Hence, it is
  435. // done by BookmarkModelTypeProcessor, with logic implemented in
  436. // components/sync_bookmarks/parent_guid_preprocessing.cc.
  437. } else if (model_type == AUTOFILL_WALLET_DATA ||
  438. model_type == AUTOFILL_WALLET_OFFER) {
  439. AdaptClientTagForFullUpdateData(model_type, &data);
  440. }
  441. response_data->entity = std::move(data);
  442. return SUCCESS;
  443. }
  444. void ModelTypeWorker::ApplyUpdates(StatusController* status) {
  445. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  446. // Indicate to the processor that the initial download is done. The initial
  447. // sync technically isn't done yet but by the time this value is persisted to
  448. // disk on the model thread it will be.
  449. model_type_state_.set_initial_sync_done(true);
  450. if (!entries_pending_decryption_.empty() &&
  451. (!encryption_enabled_ || cryptographer_->CanEncrypt())) {
  452. DCHECK(BlockForEncryption());
  453. for (auto& [key, info] : unknown_encryption_keys_by_name_) {
  454. info.get_updates_while_should_have_been_known++;
  455. // If the key is now missing for too long, drop pending updates encrypted
  456. // with it. This eventually unblocks a worker having undecryptable data.
  457. MaybeDropPendingUpdatesEncryptedWith(key);
  458. }
  459. }
  460. if (HasNonDeletionUpdates()) {
  461. status->add_updated_type(type_);
  462. }
  463. // Download cycle is done, pass all updates to the processor.
  464. SendPendingUpdatesToProcessorIfReady();
  465. }
  466. void ModelTypeWorker::SendPendingUpdatesToProcessorIfReady() {
  467. DCHECK(model_type_processor_);
  468. if (!model_type_state_.initial_sync_done()) {
  469. return;
  470. }
  471. if (BlockForEncryption()) {
  472. return;
  473. }
  474. DCHECK(!AlwaysEncryptedUserTypes().Has(type_) || encryption_enabled_);
  475. DCHECK(!encryption_enabled_ ||
  476. !model_type_state_.encryption_key_name().empty());
  477. DCHECK(entries_pending_decryption_.empty());
  478. DVLOG(1) << ModelTypeToDebugString(type_) << ": "
  479. << base::StringPrintf("Delivering %" PRIuS " applicable updates.",
  480. pending_updates_.size());
  481. // Deduplicate updates first based on server ids, which is the only legit
  482. // source of duplicates, specially due to pagination.
  483. DeduplicatePendingUpdatesBasedOnServerId();
  484. // As extra precaution, and although it shouldn't be necessary without a
  485. // misbehaving server, deduplicate based on client tags and originator item
  486. // IDs. This allows further code to use DCHECKs without relying on external
  487. // behavior.
  488. DeduplicatePendingUpdatesBasedOnClientTagHash();
  489. DeduplicatePendingUpdatesBasedOnOriginatorClientItemId();
  490. model_type_processor_->OnUpdateReceived(model_type_state_,
  491. std::move(pending_updates_));
  492. pending_updates_.clear();
  493. }
  494. void ModelTypeWorker::NudgeForCommit() {
  495. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  496. has_local_changes_state_ = kNewlyNudgedLocalChanges;
  497. NudgeIfReadyToCommit();
  498. }
  499. void ModelTypeWorker::NudgeIfReadyToCommit() {
  500. // TODO(crbug.com/1188034): |kNoNudgedLocalChanges| is used to keep the
  501. // existing behaviour. But perhaps there is no need to nudge for commit if all
  502. // known changes are already in flight.
  503. if (has_local_changes_state_ != kNoNudgedLocalChanges && CanCommitItems()) {
  504. nudge_handler_->NudgeForCommit(type_);
  505. }
  506. }
  507. std::unique_ptr<CommitContribution> ModelTypeWorker::GetContribution(
  508. size_t max_entries) {
  509. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  510. DCHECK(model_type_state_.initial_sync_done());
  511. DCHECK(model_type_processor_);
  512. // Early return if type is not ready to commit (initial sync isn't done or
  513. // cryptographer has pending keys).
  514. if (!CanCommitItems()) {
  515. return nullptr;
  516. }
  517. // Client shouldn't be committing data to server when it hasn't processed all
  518. // updates it received.
  519. DCHECK(entries_pending_decryption_.empty());
  520. // Pull local changes from the processor (in the model thread/sequence). Note
  521. // that this takes place independently of nudges (i.e.
  522. // |has_local_changes_state_|), in case the processor decided a local change
  523. // was not worth a nudge.
  524. scoped_refptr<GetLocalChangesRequest> request =
  525. base::MakeRefCounted<GetLocalChangesRequest>(cancelation_signal_);
  526. model_type_processor_->GetLocalChanges(
  527. max_entries,
  528. base::BindOnce(&GetLocalChangesRequest::SetResponse, request));
  529. request->WaitForResponseOrCancelation();
  530. CommitRequestDataList response;
  531. if (!request->WasCancelled()) {
  532. response = request->ExtractResponse();
  533. }
  534. if (response.empty()) {
  535. has_local_changes_state_ = kNoNudgedLocalChanges;
  536. return nullptr;
  537. }
  538. DCHECK(response.size() <= max_entries);
  539. if (response.size() < max_entries) {
  540. // In case when response.size() equals to |max_entries|, there will be
  541. // another commit request (see CommitProcessor::GatherCommitContributions).
  542. // Hence, in general it should be normal if |has_local_changes_state_| is
  543. // |kNewlyNudgedLocalChanges| (even if there are no more items in the
  544. // processor). In other words, |kAllNudgedLocalChangesInFlight| means that
  545. // there might not be another commit request in the current sync cycle (but
  546. // still possible if some other data type contributes |max_entities|).
  547. has_local_changes_state_ = kAllNudgedLocalChangesInFlight;
  548. }
  549. DCHECK(!AlwaysEncryptedUserTypes().Has(type_) || encryption_enabled_);
  550. DCHECK(!encryption_enabled_ ||
  551. (model_type_state_.encryption_key_name() ==
  552. cryptographer_->GetDefaultEncryptionKeyName()));
  553. return std::make_unique<CommitContributionImpl>(
  554. type_, model_type_state_.type_context(), std::move(response),
  555. base::BindOnce(&ModelTypeWorker::OnCommitResponse,
  556. weak_ptr_factory_.GetWeakPtr()),
  557. base::BindOnce(&ModelTypeWorker::OnFullCommitFailure,
  558. weak_ptr_factory_.GetWeakPtr()),
  559. encryption_enabled_ ? cryptographer_.get() : nullptr, passphrase_type_,
  560. CommitOnlyTypes().Has(type_));
  561. }
  562. bool ModelTypeWorker::HasLocalChangesForTest() const {
  563. return has_local_changes_state_ != kNoNudgedLocalChanges;
  564. }
  565. void ModelTypeWorker::OnCommitResponse(
  566. const CommitResponseDataList& committed_response_list,
  567. const FailedCommitResponseDataList& error_response_list) {
  568. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  569. // Send the responses back to the model thread. It needs to know which
  570. // items have been successfully committed (it can save that information in
  571. // permanent storage) and which failed (it can e.g. notify the user).
  572. model_type_processor_->OnCommitCompleted(
  573. model_type_state_, committed_response_list, error_response_list);
  574. if (has_local_changes_state_ == kAllNudgedLocalChangesInFlight) {
  575. // There are no new nudged changes since last commit.
  576. has_local_changes_state_ = kNoNudgedLocalChanges;
  577. }
  578. }
  579. void ModelTypeWorker::OnFullCommitFailure(SyncCommitError commit_error) {
  580. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  581. model_type_processor_->OnCommitFailed(commit_error);
  582. }
  583. size_t ModelTypeWorker::EstimateMemoryUsage() const {
  584. using base::trace_event::EstimateMemoryUsage;
  585. size_t memory_usage = 0;
  586. memory_usage += EstimateMemoryUsage(model_type_state_);
  587. memory_usage += EstimateMemoryUsage(entries_pending_decryption_);
  588. memory_usage += EstimateMemoryUsage(pending_updates_);
  589. return memory_usage;
  590. }
  591. bool ModelTypeWorker::IsTypeInitialized() const {
  592. return model_type_state_.initial_sync_done();
  593. }
  594. bool ModelTypeWorker::CanCommitItems() const {
  595. // We can only commit if we've received the initial update response and aren't
  596. // blocked by missing encryption keys.
  597. return IsTypeInitialized() && !BlockForEncryption();
  598. }
  599. bool ModelTypeWorker::BlockForEncryption() const {
  600. if (!entries_pending_decryption_.empty()) {
  601. return true;
  602. }
  603. // Should be using encryption, but we do not have the keys.
  604. return encryption_enabled_ && !cryptographer_->CanEncrypt();
  605. }
  606. bool ModelTypeWorker::UpdateTypeEncryptionKeyName() {
  607. if (!encryption_enabled_) {
  608. // The type encryption key is expected to be empty.
  609. if (model_type_state_.encryption_key_name().empty()) {
  610. return false;
  611. }
  612. DLOG(WARNING) << ModelTypeToDebugString(type_)
  613. << " : Had encryption disabled but non-empty encryption key "
  614. << model_type_state_.encryption_key_name()
  615. << ". Setting key to empty.";
  616. model_type_state_.clear_encryption_key_name();
  617. return true;
  618. }
  619. if (!cryptographer_->CanEncrypt()) {
  620. // There's no selected default key. Let's wait for one to be selected before
  621. // updating.
  622. return false;
  623. }
  624. std::string default_key_name = cryptographer_->GetDefaultEncryptionKeyName();
  625. DCHECK(!default_key_name.empty());
  626. DVLOG(1) << ModelTypeToDebugString(type_) << ": Updating encryption key "
  627. << model_type_state_.encryption_key_name() << " -> "
  628. << default_key_name;
  629. model_type_state_.set_encryption_key_name(default_key_name);
  630. return true;
  631. }
  632. void ModelTypeWorker::DecryptStoredEntities() {
  633. for (auto it = entries_pending_decryption_.begin();
  634. it != entries_pending_decryption_.end();) {
  635. const sync_pb::SyncEntity& encrypted_update = it->second;
  636. UpdateResponseData response_data;
  637. switch (PopulateUpdateResponseData(*cryptographer_, type_, encrypted_update,
  638. &response_data)) {
  639. case SUCCESS:
  640. pending_updates_.push_back(std::move(response_data));
  641. it = entries_pending_decryption_.erase(it);
  642. break;
  643. case DECRYPTION_PENDING:
  644. // Still cannot decrypt, move on and keep this one for later.
  645. ++it;
  646. break;
  647. case FAILED_TO_DECRYPT:
  648. // Decryption error should be permanent (e.g. corrupt data), since
  649. // decryption keys are up-to-date. Let's ignore this update to avoid
  650. // blocking other updates.
  651. it = entries_pending_decryption_.erase(it);
  652. break;
  653. }
  654. }
  655. // Note this can perfectly contain keys that were encrypting corrupt updates
  656. // (FAILED_TO_DECRYPT above); all that matters is the key was found.
  657. const std::vector<UnknownEncryptionKeyInfo> newly_found_keys =
  658. RemoveKeysNoLongerUnknown();
  659. for (const UnknownEncryptionKeyInfo& newly_found_key : newly_found_keys) {
  660. // Don't record UMA for the dominant case where the key was only unknown
  661. // while the cryptographer was pending external interaction.
  662. if (newly_found_key.get_updates_while_should_have_been_known > 0) {
  663. base::UmaHistogramCounts1000(
  664. kTimeUntilEncryptionKeyFoundHistogramName,
  665. newly_found_key.get_updates_while_should_have_been_known);
  666. base::UmaHistogramCounts1000(
  667. base::StrCat({kTimeUntilEncryptionKeyFoundHistogramName, ".",
  668. ModelTypeToHistogramSuffix(type_)}),
  669. newly_found_key.get_updates_while_should_have_been_known);
  670. }
  671. }
  672. }
  673. void ModelTypeWorker::DeduplicatePendingUpdatesBasedOnServerId() {
  674. UpdateResponseDataList candidates;
  675. pending_updates_.swap(candidates);
  676. pending_updates_.reserve(candidates.size());
  677. std::map<std::string, size_t> id_to_index;
  678. for (UpdateResponseData& candidate : candidates) {
  679. if (candidate.entity.id.empty()) {
  680. continue;
  681. }
  682. // Try to insert. If we already saw an item with the same server id,
  683. // this will fail but give us its iterator.
  684. auto [it, success] =
  685. id_to_index.emplace(candidate.entity.id, pending_updates_.size());
  686. if (success) {
  687. // New server id, append at the end. Note that we already inserted
  688. // the correct index (|pending_updates_.size()|) above.
  689. pending_updates_.push_back(std::move(candidate));
  690. continue;
  691. }
  692. // Duplicate! Overwrite the existing update if |candidate| has a more recent
  693. // version.
  694. const size_t existing_index = it->second;
  695. UpdateResponseData& existing_update = pending_updates_[existing_index];
  696. if (candidate.response_version >= existing_update.response_version) {
  697. existing_update = std::move(candidate);
  698. }
  699. }
  700. }
  701. void ModelTypeWorker::DeduplicatePendingUpdatesBasedOnClientTagHash() {
  702. UpdateResponseDataList candidates;
  703. pending_updates_.swap(candidates);
  704. pending_updates_.reserve(candidates.size());
  705. std::map<ClientTagHash, size_t> tag_to_index;
  706. for (UpdateResponseData& candidate : candidates) {
  707. // Items with empty client tag hash just get passed through.
  708. if (candidate.entity.client_tag_hash.value().empty()) {
  709. pending_updates_.push_back(std::move(candidate));
  710. continue;
  711. }
  712. // Try to insert. If we already saw an item with the same client tag hash,
  713. // this will fail but give us its iterator.
  714. auto [it, success] = tag_to_index.emplace(candidate.entity.client_tag_hash,
  715. pending_updates_.size());
  716. if (success) {
  717. // New client tag hash, append at the end. Note that we already inserted
  718. // the correct index (|pending_updates_.size()|) above.
  719. pending_updates_.push_back(std::move(candidate));
  720. continue;
  721. }
  722. // Duplicate! Overwrite the existing update if |candidate| has a more recent
  723. // version.
  724. const size_t existing_index = it->second;
  725. UpdateResponseData& existing_update = pending_updates_[existing_index];
  726. if (candidate.response_version >= existing_update.response_version) {
  727. existing_update = std::move(candidate);
  728. }
  729. }
  730. }
  731. void ModelTypeWorker::DeduplicatePendingUpdatesBasedOnOriginatorClientItemId() {
  732. UpdateResponseDataList candidates;
  733. pending_updates_.swap(candidates);
  734. pending_updates_.reserve(candidates.size());
  735. std::map<std::string, size_t> id_to_index;
  736. for (UpdateResponseData& candidate : candidates) {
  737. // Entities with an item ID that is not a GUID just get passed through
  738. // without deduplication, which is the case for all datatypes except
  739. // bookmarks, as well as bookmarks created before 2015, when the item ID was
  740. // not globally unique across clients.
  741. if (!base::IsValidGUID(candidate.entity.originator_client_item_id)) {
  742. pending_updates_.push_back(std::move(candidate));
  743. continue;
  744. }
  745. // Try to insert. If we already saw an item with the same originator item
  746. // ID, this will fail but give us its iterator.
  747. auto [it, success] = id_to_index.emplace(
  748. base::ToLowerASCII(candidate.entity.originator_client_item_id),
  749. pending_updates_.size());
  750. if (success) {
  751. // New item ID, append at the end. Note that we already inserted the
  752. // correct index (|pending_updates_.size()|) above.
  753. pending_updates_.push_back(std::move(candidate));
  754. continue;
  755. }
  756. // Duplicate! Overwrite the existing update if |candidate| has a more recent
  757. // version.
  758. const size_t existing_index = it->second;
  759. UpdateResponseData& existing_update = pending_updates_[existing_index];
  760. if (candidate.response_version >= existing_update.response_version) {
  761. existing_update = std::move(candidate);
  762. }
  763. }
  764. }
  765. bool ModelTypeWorker::ShouldIgnoreUpdatesEncryptedWith(
  766. const std::string& key_name) {
  767. if (!base::Contains(unknown_encryption_keys_by_name_, key_name)) {
  768. return false;
  769. }
  770. if (unknown_encryption_keys_by_name_.at(key_name)
  771. .get_updates_while_should_have_been_known <
  772. min_get_updates_to_ignore_key_) {
  773. return false;
  774. }
  775. return base::FeatureList::IsEnabled(kIgnoreSyncEncryptionKeysLongMissing);
  776. }
  777. void ModelTypeWorker::MaybeDropPendingUpdatesEncryptedWith(
  778. const std::string& key_name) {
  779. if (!ShouldIgnoreUpdatesEncryptedWith(key_name)) {
  780. return;
  781. }
  782. size_t updates_before_dropping = entries_pending_decryption_.size();
  783. base::EraseIf(entries_pending_decryption_, [&](const auto& id_and_update) {
  784. return key_name == GetEncryptionKeyName(id_and_update.second);
  785. });
  786. // If updates were dropped, record how many.
  787. const size_t dropped_updates =
  788. updates_before_dropping - entries_pending_decryption_.size();
  789. if (dropped_updates > 0) {
  790. base::UmaHistogramCounts1000(
  791. kUndecryptablePendingUpdatesDroppedHistogramName, dropped_updates);
  792. base::UmaHistogramCounts1000(
  793. base::StrCat({kUndecryptablePendingUpdatesDroppedHistogramName, ".",
  794. ModelTypeToHistogramSuffix(type_)}),
  795. dropped_updates);
  796. }
  797. }
  798. std::vector<ModelTypeWorker::UnknownEncryptionKeyInfo>
  799. ModelTypeWorker::RemoveKeysNoLongerUnknown() {
  800. std::set<std::string> keys_blocking_updates;
  801. for (const auto& [id, update] : entries_pending_decryption_) {
  802. const std::string key_name = GetEncryptionKeyName(update);
  803. DCHECK(!key_name.empty());
  804. keys_blocking_updates.insert(key_name);
  805. }
  806. std::vector<ModelTypeWorker::UnknownEncryptionKeyInfo> removed_keys;
  807. base::EraseIf(
  808. unknown_encryption_keys_by_name_, [&](const auto& key_and_info) {
  809. if (base::Contains(keys_blocking_updates, key_and_info.first)) {
  810. return false;
  811. }
  812. removed_keys.push_back(key_and_info.second);
  813. return true;
  814. });
  815. return removed_keys;
  816. }
  817. bool ModelTypeWorker::HasNonDeletionUpdates() const {
  818. for (const UpdateResponseData& update : pending_updates_) {
  819. if (!update.entity.is_deleted()) {
  820. return true;
  821. }
  822. }
  823. return false;
  824. }
  825. GetLocalChangesRequest::GetLocalChangesRequest(
  826. CancelationSignal* cancelation_signal)
  827. : cancelation_signal_(cancelation_signal),
  828. response_accepted_(base::WaitableEvent::ResetPolicy::MANUAL,
  829. base::WaitableEvent::InitialState::NOT_SIGNALED) {}
  830. GetLocalChangesRequest::~GetLocalChangesRequest() = default;
  831. void GetLocalChangesRequest::OnCancelationSignalReceived() {
  832. response_accepted_.Signal();
  833. }
  834. void GetLocalChangesRequest::WaitForResponseOrCancelation() {
  835. if (!cancelation_signal_->TryRegisterHandler(this)) {
  836. return;
  837. }
  838. {
  839. base::ScopedAllowBaseSyncPrimitives allow_wait;
  840. response_accepted_.Wait();
  841. }
  842. cancelation_signal_->UnregisterHandler(this);
  843. }
  844. void GetLocalChangesRequest::SetResponse(
  845. CommitRequestDataList&& local_changes) {
  846. response_ = std::move(local_changes);
  847. response_accepted_.Signal();
  848. }
  849. bool GetLocalChangesRequest::WasCancelled() {
  850. return cancelation_signal_->IsSignalled();
  851. }
  852. CommitRequestDataList&& GetLocalChangesRequest::ExtractResponse() {
  853. return std::move(response_);
  854. }
  855. } // namespace syncer