send_tab_to_self_bridge.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. // Copyright 2018 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/send_tab_to_self/send_tab_to_self_bridge.h"
  5. #include <algorithm>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/check_op.h"
  9. #include "base/containers/cxx20_erase_vector.h"
  10. #include "base/guid.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/observer_list.h"
  13. #include "base/strings/string_util.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "base/time/clock.h"
  16. #include "base/time/time.h"
  17. #include "components/history/core/browser/history_service.h"
  18. #include "components/send_tab_to_self/features.h"
  19. #include "components/send_tab_to_self/metrics_util.h"
  20. #include "components/send_tab_to_self/proto/send_tab_to_self.pb.h"
  21. #include "components/send_tab_to_self/target_device_info.h"
  22. #include "components/sync/model/entity_change.h"
  23. #include "components/sync/model/metadata_batch.h"
  24. #include "components/sync/model/metadata_change_list.h"
  25. #include "components/sync/model/model_type_change_processor.h"
  26. #include "components/sync/model/mutable_data_batch.h"
  27. #include "components/sync/protocol/model_type_state.pb.h"
  28. #include "components/sync_device_info/local_device_info_util.h"
  29. #include "third_party/abseil-cpp/absl/types/optional.h"
  30. namespace send_tab_to_self {
  31. namespace {
  32. using syncer::ModelTypeStore;
  33. const base::TimeDelta kDedupeTime = base::Seconds(5);
  34. const base::TimeDelta kDeviceExpiration = base::Days(10);
  35. // Converts a time field from sync protobufs to a time object.
  36. base::Time ProtoTimeToTime(int64_t proto_t) {
  37. return base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(proto_t));
  38. }
  39. // Allocate a EntityData and copies |specifics| into it.
  40. std::unique_ptr<syncer::EntityData> CopyToEntityData(
  41. const sync_pb::SendTabToSelfSpecifics& specifics) {
  42. auto entity_data = std::make_unique<syncer::EntityData>();
  43. *entity_data->specifics.mutable_send_tab_to_self() = specifics;
  44. entity_data->name = specifics.url();
  45. entity_data->creation_time = ProtoTimeToTime(specifics.shared_time_usec());
  46. return entity_data;
  47. }
  48. // Parses the content of |record_list| into |*initial_data|. The output
  49. // parameter is first for binding purposes.
  50. absl::optional<syncer::ModelError> ParseLocalEntriesOnBackendSequence(
  51. base::Time now,
  52. std::map<std::string, std::unique_ptr<SendTabToSelfEntry>>* entries,
  53. std::string* local_personalizable_device_name,
  54. std::unique_ptr<ModelTypeStore::RecordList> record_list) {
  55. DCHECK(entries);
  56. DCHECK(entries->empty());
  57. DCHECK(local_personalizable_device_name);
  58. DCHECK(record_list);
  59. *local_personalizable_device_name =
  60. syncer::GetPersonalizableDeviceNameBlocking();
  61. for (const syncer::ModelTypeStore::Record& r : *record_list) {
  62. auto specifics = std::make_unique<SendTabToSelfLocal>();
  63. if (specifics->ParseFromString(r.value)) {
  64. (*entries)[specifics->specifics().guid()] =
  65. SendTabToSelfEntry::FromLocalProto(*specifics, now);
  66. } else {
  67. return syncer::ModelError(FROM_HERE, "Failed to deserialize specifics.");
  68. }
  69. }
  70. return absl::nullopt;
  71. }
  72. } // namespace
  73. SendTabToSelfBridge::SendTabToSelfBridge(
  74. std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor,
  75. base::Clock* clock,
  76. syncer::OnceModelTypeStoreFactory create_store_callback,
  77. history::HistoryService* history_service,
  78. syncer::DeviceInfoTracker* device_info_tracker)
  79. : ModelTypeSyncBridge(std::move(change_processor)),
  80. clock_(clock),
  81. history_service_(history_service),
  82. device_info_tracker_(device_info_tracker),
  83. mru_entry_(nullptr) {
  84. DCHECK(clock_);
  85. DCHECK(device_info_tracker_);
  86. if (history_service) {
  87. history_service_observation_.Observe(history_service);
  88. }
  89. device_info_tracker_observation_.Observe(device_info_tracker);
  90. ComputeTargetDeviceInfoSortedList();
  91. std::move(create_store_callback)
  92. .Run(syncer::SEND_TAB_TO_SELF,
  93. base::BindOnce(&SendTabToSelfBridge::OnStoreCreated,
  94. weak_ptr_factory_.GetWeakPtr()));
  95. }
  96. SendTabToSelfBridge::~SendTabToSelfBridge() {
  97. if (history_service_) {
  98. history_service_observation_.Reset();
  99. }
  100. }
  101. std::unique_ptr<syncer::MetadataChangeList>
  102. SendTabToSelfBridge::CreateMetadataChangeList() {
  103. return ModelTypeStore::WriteBatch::CreateMetadataChangeList();
  104. }
  105. absl::optional<syncer::ModelError> SendTabToSelfBridge::MergeSyncData(
  106. std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
  107. syncer::EntityChangeList entity_data) {
  108. DCHECK(entries_.empty());
  109. return ApplySyncChanges(std::move(metadata_change_list),
  110. std::move(entity_data));
  111. }
  112. absl::optional<syncer::ModelError> SendTabToSelfBridge::ApplySyncChanges(
  113. std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
  114. syncer::EntityChangeList entity_changes) {
  115. std::vector<const SendTabToSelfEntry*> added;
  116. // The opened vector will accumulate both added entries that are already
  117. // opened as well as existing entries that have been updated to be marked as
  118. // opened.
  119. std::vector<const SendTabToSelfEntry*> opened;
  120. std::vector<std::string> removed;
  121. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  122. store_->CreateWriteBatch();
  123. for (const std::unique_ptr<syncer::EntityChange>& change : entity_changes) {
  124. const std::string& guid = change->storage_key();
  125. if (change->type() == syncer::EntityChange::ACTION_DELETE) {
  126. if (entries_.find(guid) != entries_.end()) {
  127. if (mru_entry_ && mru_entry_->GetGUID() == guid) {
  128. mru_entry_ = nullptr;
  129. }
  130. entries_.erase(change->storage_key());
  131. batch->DeleteData(guid);
  132. removed.push_back(change->storage_key());
  133. }
  134. } else {
  135. const sync_pb::SendTabToSelfSpecifics& specifics =
  136. change->data().specifics.send_tab_to_self();
  137. std::unique_ptr<SendTabToSelfEntry> remote_entry =
  138. SendTabToSelfEntry::FromProto(specifics, clock_->Now());
  139. if (!remote_entry) {
  140. continue; // Skip invalid entries.
  141. }
  142. if (remote_entry->IsExpired(clock_->Now())) {
  143. // Remove expired data from server.
  144. change_processor()->Delete(guid, batch->GetMetadataChangeList());
  145. } else {
  146. SendTabToSelfEntry* local_entry =
  147. GetMutableEntryByGUID(remote_entry->GetGUID());
  148. SendTabToSelfLocal remote_entry_pb = remote_entry->AsLocalProto();
  149. if (local_entry == nullptr) {
  150. // This remote_entry is new. Add it to the model.
  151. added.push_back(remote_entry.get());
  152. if (remote_entry->IsOpened()) {
  153. opened.push_back(remote_entry.get());
  154. }
  155. entries_[remote_entry->GetGUID()] = std::move(remote_entry);
  156. } else {
  157. // Update existing model if entries have been opened.
  158. if (remote_entry->IsOpened() && !local_entry->IsOpened()) {
  159. local_entry->MarkOpened();
  160. opened.push_back(local_entry);
  161. }
  162. }
  163. // Write to the store.
  164. batch->WriteData(guid, remote_entry_pb.SerializeAsString());
  165. }
  166. }
  167. }
  168. batch->TakeMetadataChangesFrom(std::move(metadata_change_list));
  169. Commit(std::move(batch));
  170. NotifyRemoteSendTabToSelfEntryDeleted(removed);
  171. NotifyRemoteSendTabToSelfEntryAdded(added);
  172. NotifyRemoteSendTabToSelfEntryOpened(opened);
  173. return absl::nullopt;
  174. }
  175. void SendTabToSelfBridge::GetData(StorageKeyList storage_keys,
  176. DataCallback callback) {
  177. auto batch = std::make_unique<syncer::MutableDataBatch>();
  178. for (const std::string& guid : storage_keys) {
  179. const SendTabToSelfEntry* entry = GetEntryByGUID(guid);
  180. if (!entry) {
  181. continue;
  182. }
  183. batch->Put(guid, CopyToEntityData(entry->AsLocalProto().specifics()));
  184. }
  185. std::move(callback).Run(std::move(batch));
  186. }
  187. void SendTabToSelfBridge::GetAllDataForDebugging(DataCallback callback) {
  188. auto batch = std::make_unique<syncer::MutableDataBatch>();
  189. for (const auto& it : entries_) {
  190. batch->Put(it.first,
  191. CopyToEntityData(it.second->AsLocalProto().specifics()));
  192. }
  193. std::move(callback).Run(std::move(batch));
  194. }
  195. std::string SendTabToSelfBridge::GetClientTag(
  196. const syncer::EntityData& entity_data) {
  197. return GetStorageKey(entity_data);
  198. }
  199. std::string SendTabToSelfBridge::GetStorageKey(
  200. const syncer::EntityData& entity_data) {
  201. return entity_data.specifics.send_tab_to_self().guid();
  202. }
  203. void SendTabToSelfBridge::ApplyStopSyncChanges(
  204. std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) {
  205. // If |delete_metadata_change_list| is null, it indicates that sync metadata
  206. // shouldn't be deleted, for example chrome is shutting down.
  207. if (!delete_metadata_change_list) {
  208. return;
  209. }
  210. DCHECK(store_);
  211. store_->DeleteAllDataAndMetadata(base::DoNothing());
  212. std::vector<std::string> all_guids = GetAllGuids();
  213. entries_.clear();
  214. mru_entry_ = nullptr;
  215. NotifyRemoteSendTabToSelfEntryDeleted(all_guids);
  216. }
  217. std::vector<std::string> SendTabToSelfBridge::GetAllGuids() const {
  218. std::vector<std::string> keys;
  219. for (const auto& it : entries_) {
  220. DCHECK_EQ(it.first, it.second->GetGUID());
  221. keys.push_back(it.first);
  222. }
  223. return keys;
  224. }
  225. const SendTabToSelfEntry* SendTabToSelfBridge::GetEntryByGUID(
  226. const std::string& guid) const {
  227. auto it = entries_.find(guid);
  228. if (it == entries_.end()) {
  229. return nullptr;
  230. }
  231. return it->second.get();
  232. }
  233. const SendTabToSelfEntry* SendTabToSelfBridge::AddEntry(
  234. const GURL& url,
  235. const std::string& title,
  236. const std::string& target_device_cache_guid) {
  237. if (!change_processor()->IsTrackingMetadata()) {
  238. // TODO(crbug.com/940512) handle failure case.
  239. return nullptr;
  240. }
  241. if (!url.is_valid()) {
  242. return nullptr;
  243. }
  244. // In the case where the user has attempted to send an identical URL
  245. // within the last |kDedupeTime| we think it is likely that user still
  246. // has the first sent tab in progress, and so we will not attempt to resend.
  247. base::Time shared_time = clock_->Now();
  248. if (mru_entry_ && url == mru_entry_->GetURL() &&
  249. shared_time - mru_entry_->GetSharedTime() < kDedupeTime) {
  250. send_tab_to_self::RecordNotificationThrottled();
  251. return mru_entry_;
  252. }
  253. std::string guid = base::GenerateGUID();
  254. // Assure that we don't have a guid collision.
  255. DCHECK_EQ(GetEntryByGUID(guid), nullptr);
  256. std::string trimmed_title = "";
  257. if (base::IsStringUTF8(title)) {
  258. trimmed_title = base::UTF16ToUTF8(
  259. base::CollapseWhitespace(base::UTF8ToUTF16(title), false));
  260. }
  261. auto entry = std::make_unique<SendTabToSelfEntry>(
  262. guid, url, trimmed_title, shared_time, local_device_name_,
  263. target_device_cache_guid);
  264. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  265. store_->CreateWriteBatch();
  266. // This entry is new. Add it to the store and model.
  267. auto entity_data = CopyToEntityData(entry->AsLocalProto().specifics());
  268. change_processor()->Put(guid, std::move(entity_data),
  269. batch->GetMetadataChangeList());
  270. const SendTabToSelfEntry* result =
  271. entries_.emplace(guid, std::move(entry)).first->second.get();
  272. batch->WriteData(guid, result->AsLocalProto().SerializeAsString());
  273. Commit(std::move(batch));
  274. mru_entry_ = result;
  275. return result;
  276. }
  277. void SendTabToSelfBridge::DeleteEntry(const std::string& guid) {
  278. // Assure that an entry with that guid exists.
  279. if (GetEntryByGUID(guid) == nullptr) {
  280. return;
  281. }
  282. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  283. store_->CreateWriteBatch();
  284. DeleteEntryWithBatch(guid, batch.get());
  285. Commit(std::move(batch));
  286. }
  287. void SendTabToSelfBridge::DismissEntry(const std::string& guid) {
  288. SendTabToSelfEntry* entry = GetMutableEntryByGUID(guid);
  289. // Assure that an entry with that guid exists.
  290. if (!entry) {
  291. return;
  292. }
  293. DCHECK(change_processor()->IsTrackingMetadata());
  294. entry->SetNotificationDismissed(true);
  295. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  296. store_->CreateWriteBatch();
  297. auto entity_data = CopyToEntityData(entry->AsLocalProto().specifics());
  298. change_processor()->Put(guid, std::move(entity_data),
  299. batch->GetMetadataChangeList());
  300. batch->WriteData(guid, entry->AsLocalProto().SerializeAsString());
  301. Commit(std::move(batch));
  302. }
  303. void SendTabToSelfBridge::MarkEntryOpened(const std::string& guid) {
  304. SendTabToSelfEntry* entry = GetMutableEntryByGUID(guid);
  305. // Assure that an entry with that guid exists.
  306. if (!entry) {
  307. return;
  308. }
  309. DCHECK(change_processor()->IsTrackingMetadata());
  310. entry->MarkOpened();
  311. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  312. store_->CreateWriteBatch();
  313. auto entity_data = CopyToEntityData(entry->AsLocalProto().specifics());
  314. change_processor()->Put(guid, std::move(entity_data),
  315. batch->GetMetadataChangeList());
  316. batch->WriteData(guid, entry->AsLocalProto().SerializeAsString());
  317. Commit(std::move(batch));
  318. }
  319. void SendTabToSelfBridge::OnURLsDeleted(
  320. history::HistoryService* history_service,
  321. const history::DeletionInfo& deletion_info) {
  322. // We only care about actual user (or sync) deletions.
  323. if (!change_processor()->IsTrackingMetadata()) {
  324. return; // Sync processor not yet ready, don't sync.
  325. }
  326. if (deletion_info.is_from_expiration())
  327. return;
  328. if (!deletion_info.IsAllHistory()) {
  329. std::vector<GURL> urls;
  330. for (const history::URLRow& row : deletion_info.deleted_rows()) {
  331. urls.push_back(row.url());
  332. }
  333. DeleteEntries(urls);
  334. return;
  335. }
  336. // All history was cleared: just delete all entries.
  337. DeleteAllEntries();
  338. }
  339. void SendTabToSelfBridge::OnDeviceInfoChange() {
  340. ComputeTargetDeviceInfoSortedList();
  341. }
  342. bool SendTabToSelfBridge::IsReady() {
  343. return change_processor()->IsTrackingMetadata();
  344. }
  345. bool SendTabToSelfBridge::HasValidTargetDevice() {
  346. return GetTargetDeviceInfoSortedList().size() > 0;
  347. }
  348. std::vector<TargetDeviceInfo>
  349. SendTabToSelfBridge::GetTargetDeviceInfoSortedList() {
  350. // Filter expired devices (some timestamps in the cached list may now be too
  351. // old). |target_device_info_sorted_list_| is copied here to avoid mutations
  352. // inside a getter.
  353. // TODO(crbug.com/1257573): Consider having a timer that fires on the next
  354. // expiry and removes the corresponding device(s) then.
  355. std::vector<TargetDeviceInfo> non_expired_devices =
  356. target_device_info_sorted_list_;
  357. const base::Time now = clock_->Now();
  358. base::EraseIf(non_expired_devices, [now](const TargetDeviceInfo& device) {
  359. return now - device.last_updated_timestamp > kDeviceExpiration;
  360. });
  361. return non_expired_devices;
  362. }
  363. // static
  364. std::unique_ptr<syncer::ModelTypeStore>
  365. SendTabToSelfBridge::DestroyAndStealStoreForTest(
  366. std::unique_ptr<SendTabToSelfBridge> bridge) {
  367. return std::move(bridge->store_);
  368. }
  369. void SendTabToSelfBridge::SetLocalDeviceNameForTest(
  370. const std::string& local_device_name) {
  371. local_device_name_ = local_device_name;
  372. }
  373. void SendTabToSelfBridge::NotifyRemoteSendTabToSelfEntryAdded(
  374. const std::vector<const SendTabToSelfEntry*>& new_entries) {
  375. if (new_entries.empty()) {
  376. return;
  377. }
  378. std::vector<const SendTabToSelfEntry*> new_local_entries;
  379. // Only pass along entries that are not dismissed or opened, and are
  380. // targeted at this device, which is determined by comparing the cache guid
  381. // associated with the entry to each device's local list of recently used
  382. // cache_guids
  383. DCHECK(!change_processor()->TrackedCacheGuid().empty());
  384. for (const SendTabToSelfEntry* entry : new_entries) {
  385. if (device_info_tracker_->IsRecentLocalCacheGuid(
  386. entry->GetTargetDeviceSyncCacheGuid()) &&
  387. !entry->GetNotificationDismissed() && !entry->IsOpened()) {
  388. new_local_entries.push_back(entry);
  389. }
  390. }
  391. for (SendTabToSelfModelObserver& observer : observers_) {
  392. observer.EntriesAddedRemotely(new_local_entries);
  393. }
  394. }
  395. void SendTabToSelfBridge::NotifyRemoteSendTabToSelfEntryDeleted(
  396. const std::vector<std::string>& guids) {
  397. if (guids.empty()) {
  398. return;
  399. }
  400. // TODO(crbug.com/956216): Only send the entries that targeted this device.
  401. for (SendTabToSelfModelObserver& observer : observers_) {
  402. observer.EntriesRemovedRemotely(guids);
  403. }
  404. }
  405. void SendTabToSelfBridge::NotifyRemoteSendTabToSelfEntryOpened(
  406. const std::vector<const SendTabToSelfEntry*>& opened_entries) {
  407. if (opened_entries.empty()) {
  408. return;
  409. }
  410. for (SendTabToSelfModelObserver& observer : observers_) {
  411. observer.EntriesOpenedRemotely(opened_entries);
  412. }
  413. }
  414. void SendTabToSelfBridge::NotifySendTabToSelfModelLoaded() {
  415. for (SendTabToSelfModelObserver& observer : observers_) {
  416. observer.SendTabToSelfModelLoaded();
  417. }
  418. }
  419. void SendTabToSelfBridge::OnStoreCreated(
  420. const absl::optional<syncer::ModelError>& error,
  421. std::unique_ptr<syncer::ModelTypeStore> store) {
  422. if (error) {
  423. change_processor()->ReportError(*error);
  424. return;
  425. }
  426. auto initial_entries = std::make_unique<SendTabToSelfEntries>();
  427. SendTabToSelfEntries* initial_entries_copy = initial_entries.get();
  428. auto local_device_name = std::make_unique<std::string>();
  429. std::string* local_device_name_copy = local_device_name.get();
  430. store_ = std::move(store);
  431. store_->ReadAllDataAndPreprocess(
  432. base::BindOnce(&ParseLocalEntriesOnBackendSequence, clock_->Now(),
  433. base::Unretained(initial_entries_copy),
  434. base::Unretained(local_device_name_copy)),
  435. base::BindOnce(&SendTabToSelfBridge::OnReadAllData,
  436. weak_ptr_factory_.GetWeakPtr(), std::move(initial_entries),
  437. std::move(local_device_name)));
  438. }
  439. void SendTabToSelfBridge::OnReadAllData(
  440. std::unique_ptr<SendTabToSelfEntries> initial_entries,
  441. std::unique_ptr<std::string> local_device_name,
  442. const absl::optional<syncer::ModelError>& error) {
  443. DCHECK(initial_entries);
  444. DCHECK(local_device_name);
  445. if (error) {
  446. change_processor()->ReportError(*error);
  447. return;
  448. }
  449. entries_ = std::move(*initial_entries);
  450. local_device_name_ = std::move(*local_device_name);
  451. store_->ReadAllMetadata(base::BindOnce(
  452. &SendTabToSelfBridge::OnReadAllMetadata, weak_ptr_factory_.GetWeakPtr()));
  453. }
  454. void SendTabToSelfBridge::OnReadAllMetadata(
  455. const absl::optional<syncer::ModelError>& error,
  456. std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
  457. if (error) {
  458. change_processor()->ReportError(*error);
  459. return;
  460. }
  461. change_processor()->ModelReadyToSync(std::move(metadata_batch));
  462. NotifySendTabToSelfModelLoaded();
  463. DoGarbageCollection();
  464. }
  465. void SendTabToSelfBridge::OnCommit(
  466. const absl::optional<syncer::ModelError>& error) {
  467. if (error) {
  468. change_processor()->ReportError(*error);
  469. }
  470. }
  471. void SendTabToSelfBridge::Commit(
  472. std::unique_ptr<ModelTypeStore::WriteBatch> batch) {
  473. store_->CommitWriteBatch(std::move(batch),
  474. base::BindOnce(&SendTabToSelfBridge::OnCommit,
  475. weak_ptr_factory_.GetWeakPtr()));
  476. }
  477. SendTabToSelfEntry* SendTabToSelfBridge::GetMutableEntryByGUID(
  478. const std::string& guid) const {
  479. auto it = entries_.find(guid);
  480. if (it == entries_.end()) {
  481. return nullptr;
  482. }
  483. return it->second.get();
  484. }
  485. void SendTabToSelfBridge::DoGarbageCollection() {
  486. std::vector<std::string> removed;
  487. auto entry = entries_.begin();
  488. while (entry != entries_.end()) {
  489. DCHECK_EQ(entry->first, entry->second->GetGUID());
  490. std::string guid = entry->first;
  491. bool expired = entry->second->IsExpired(clock_->Now());
  492. entry++;
  493. if (expired) {
  494. DeleteEntry(guid);
  495. removed.push_back(guid);
  496. }
  497. }
  498. NotifyRemoteSendTabToSelfEntryDeleted(removed);
  499. }
  500. void SendTabToSelfBridge::ComputeTargetDeviceInfoSortedList() {
  501. if (!device_info_tracker_->IsSyncing()) {
  502. return;
  503. }
  504. std::vector<std::unique_ptr<syncer::DeviceInfo>> all_devices =
  505. device_info_tracker_->GetAllDeviceInfo();
  506. // Sort the DeviceInfo vector so the most recently modified devices are first.
  507. std::stable_sort(all_devices.begin(), all_devices.end(),
  508. [](const std::unique_ptr<syncer::DeviceInfo>& device1,
  509. const std::unique_ptr<syncer::DeviceInfo>& device2) {
  510. return device1->last_updated_timestamp() >
  511. device2->last_updated_timestamp();
  512. });
  513. target_device_info_sorted_list_.clear();
  514. std::set<std::string> unique_device_names;
  515. std::unordered_map<std::string, int> short_names_counter;
  516. for (const auto& device : all_devices) {
  517. // If the current device is considered expired for our purposes, stop here
  518. // since the next devices in the vector are at least as expired than this
  519. // one.
  520. if (clock_->Now() - device->last_updated_timestamp() > kDeviceExpiration) {
  521. break;
  522. }
  523. // Don't include this device if it is the local device.
  524. if (device_info_tracker_->IsRecentLocalCacheGuid(device->guid())) {
  525. continue;
  526. }
  527. DCHECK_NE(device->guid(), change_processor()->TrackedCacheGuid());
  528. // Don't include devices that have disabled the send tab to self receiving
  529. // feature.
  530. if (!device->send_tab_to_self_receiving_enabled()) {
  531. continue;
  532. }
  533. SharingDeviceNames device_names = GetSharingDeviceNames(device.get());
  534. // Don't include this device if it has the same name as the local device.
  535. if (device_names.full_name == local_device_name_) {
  536. continue;
  537. }
  538. // Only keep one device per device name. We only keep the first occurrence
  539. // which is the most recent.
  540. if (unique_device_names.insert(device_names.full_name).second) {
  541. TargetDeviceInfo target_device_info(
  542. device_names.full_name, device_names.short_name, device->guid(),
  543. device->device_type(), device->last_updated_timestamp());
  544. target_device_info_sorted_list_.push_back(target_device_info);
  545. short_names_counter[device_names.short_name]++;
  546. }
  547. }
  548. for (auto& device_info : target_device_info_sorted_list_) {
  549. bool unique_short_name = short_names_counter[device_info.short_name] == 1;
  550. device_info.device_name =
  551. (unique_short_name ? device_info.short_name : device_info.full_name);
  552. }
  553. }
  554. void SendTabToSelfBridge::DeleteEntryWithBatch(
  555. const std::string& guid,
  556. ModelTypeStore::WriteBatch* batch) {
  557. // Assure that an entry with that guid exists.
  558. DCHECK(GetEntryByGUID(guid) != nullptr);
  559. DCHECK(change_processor()->IsTrackingMetadata());
  560. change_processor()->Delete(guid, batch->GetMetadataChangeList());
  561. if (mru_entry_ && mru_entry_->GetGUID() == guid) {
  562. mru_entry_ = nullptr;
  563. }
  564. entries_.erase(guid);
  565. batch->DeleteData(guid);
  566. }
  567. void SendTabToSelfBridge::DeleteEntries(const std::vector<GURL>& urls) {
  568. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  569. store_->CreateWriteBatch();
  570. std::vector<std::string> removed_guids;
  571. for (const GURL& url : urls) {
  572. auto entry = entries_.begin();
  573. while (entry != entries_.end()) {
  574. bool to_delete =
  575. (entry->second == nullptr || url == entry->second->GetURL());
  576. std::string guid = entry->first;
  577. entry++;
  578. if (to_delete) {
  579. removed_guids.push_back(guid);
  580. DeleteEntryWithBatch(guid, batch.get());
  581. }
  582. }
  583. }
  584. Commit(std::move(batch));
  585. // To err on the side of completeness this notifies all clients that these
  586. // entries have been removed. Regardless of if these entries were removed
  587. // "remotely".
  588. NotifyRemoteSendTabToSelfEntryDeleted(removed_guids);
  589. }
  590. void SendTabToSelfBridge::DeleteAllEntries() {
  591. if (!change_processor()->IsTrackingMetadata()) {
  592. DCHECK_EQ(0ul, entries_.size());
  593. return;
  594. }
  595. std::unique_ptr<ModelTypeStore::WriteBatch> batch =
  596. store_->CreateWriteBatch();
  597. std::vector<std::string> all_guids = GetAllGuids();
  598. for (const auto& guid : all_guids) {
  599. change_processor()->Delete(guid, batch->GetMetadataChangeList());
  600. batch->DeleteData(guid);
  601. }
  602. entries_.clear();
  603. mru_entry_ = nullptr;
  604. NotifyRemoteSendTabToSelfEntryDeleted(all_guids);
  605. }
  606. } // namespace send_tab_to_self