blob: b1b8f5a2d43a878fd6bcbd92e12696b6aa130324 [file] [log] [blame]
Jeffrey Cohen053be24d2019-07-23 23:44:051// Copyright 2019 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
5#include "components/sync_device_info/device_info_prefs.h"
6
7#include <algorithm>
Mikel Astiz9637de22019-10-02 16:10:278#include <utility>
Jeffrey Cohen053be24d2019-07-23 23:44:059
Mikel Astiz9637de22019-10-02 16:10:2710#include "base/time/clock.h"
11#include "base/time/default_clock.h"
Jeffrey Cohen053be24d2019-07-23 23:44:0512#include "components/prefs/pref_registry_simple.h"
13#include "components/prefs/pref_service.h"
14#include "components/prefs/scoped_user_pref_update.h"
15
16namespace syncer {
17namespace {
18
Mikel Astiz9637de22019-10-02 16:10:2719// Preference name for storing recently used cache GUIDs and their timestamps
20// in days since Windows epoch. Most recent first.
21const char kDeviceInfoRecentGUIDsWithTimestamps[] =
22 "sync.local_device_guids_with_timestamp";
23
24// Keys used in the dictionaries stored in prefs.
25const char kCacheGuidKey[] = "cache_guid";
26const char kTimestampKey[] = "timestamp";
27
28// The max time a local device's cached GUIDs will be stored.
Peter Kastinge5a38ed2021-10-02 03:06:3529constexpr base::TimeDelta kMaxTimeDeltaLocalCacheGuidsStored = base::Days(10);
Mikel Astiz9637de22019-10-02 16:10:2730
31// The max number of local device most recent cached GUIDs that will be stored
32// in preferences.
33constexpr int kMaxLocalCacheGuidsStored = 30;
34
35// Returns true iff |dict| is a dictionary with a cache GUID that is equal to
36// |cache_guid|.
37bool MatchesGuidInDictionary(const base::Value& dict,
38 const std::string& cache_guid) {
39 if (!dict.is_dict()) {
40 return false;
41 }
42 const std::string* v_cache_guid = dict.FindStringKey(kCacheGuidKey);
43 return v_cache_guid && *v_cache_guid == cache_guid;
44}
Jeffrey Cohen053be24d2019-07-23 23:44:0545
46} // namespace
47
48// static
49void DeviceInfoPrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) {
Mikel Astiz9637de22019-10-02 16:10:2750 registry->RegisterListPref(kDeviceInfoRecentGUIDsWithTimestamps);
Mikel Astiz9637de22019-10-02 16:10:2751}
52
53DeviceInfoPrefs::DeviceInfoPrefs(PrefService* pref_service,
54 const base::Clock* clock)
55 : pref_service_(pref_service), clock_(clock) {
56 DCHECK(pref_service_);
57 DCHECK(clock_);
Jeffrey Cohen053be24d2019-07-23 23:44:0558}
59
Victor Hugo Vianna Silva988fe7322021-09-23 18:16:5660DeviceInfoPrefs::~DeviceInfoPrefs() = default;
Jeffrey Cohen053be24d2019-07-23 23:44:0561
62bool DeviceInfoPrefs::IsRecentLocalCacheGuid(
63 const std::string& cache_guid) const {
Jan Wilken Dörrie8d9034f12019-11-28 14:48:5764 base::Value::ConstListView recent_local_cache_guids =
Mikel Astiz9637de22019-10-02 16:10:2765 pref_service_->GetList(kDeviceInfoRecentGUIDsWithTimestamps)->GetList();
Jeffrey Cohen053be24d2019-07-23 23:44:0566
Mikel Astiz9637de22019-10-02 16:10:2767 for (const auto& v : recent_local_cache_guids) {
68 if (MatchesGuidInDictionary(v, cache_guid)) {
69 return true;
70 }
71 }
72
73 return false;
Jeffrey Cohen053be24d2019-07-23 23:44:0574}
75
76void DeviceInfoPrefs::AddLocalCacheGuid(const std::string& cache_guid) {
Alex Turner259ff022022-01-18 16:17:0077 ListPrefUpdate update_cache_guids(pref_service_,
78 kDeviceInfoRecentGUIDsWithTimestamps);
Jeffrey Cohen053be24d2019-07-23 23:44:0579
Jan Wilken Dörrie4badd7022019-10-30 21:36:2080 for (auto it = update_cache_guids->GetList().begin();
81 it != update_cache_guids->GetList().end(); it++) {
Mikel Astiz9637de22019-10-02 16:10:2782 if (MatchesGuidInDictionary(*it, cache_guid)) {
83 // Remove it from the list, to be reinserted below, in the first
84 // position.
Jan Wilken Dörrie4badd7022019-10-30 21:36:2085 update_cache_guids->EraseListIter(it);
Mikel Astiz9637de22019-10-02 16:10:2786 break;
87 }
Jeffrey Cohen053be24d2019-07-23 23:44:0588 }
89
Mikel Astiz9637de22019-10-02 16:10:2790 base::Value new_entry(base::Value::Type::DICTIONARY);
91 new_entry.SetKey(kCacheGuidKey, base::Value(cache_guid));
92 new_entry.SetKey(
93 kTimestampKey,
94 base::Value(clock_->Now().ToDeltaSinceWindowsEpoch().InDays()));
95
Jan Wilken Dörrie4badd7022019-10-30 21:36:2096 update_cache_guids->Insert(update_cache_guids->GetList().begin(),
97 std::move(new_entry));
Mikel Astiz9637de22019-10-02 16:10:2798
Jan Wilken Dörrie4badd7022019-10-30 21:36:2099 while (update_cache_guids->GetList().size() > kMaxLocalCacheGuidsStored) {
100 update_cache_guids->EraseListIter(update_cache_guids->GetList().end() - 1);
Jeffrey Cohen053be24d2019-07-23 23:44:05101 }
102}
103
Mikel Astiz9637de22019-10-02 16:10:27104void DeviceInfoPrefs::GarbageCollectExpiredCacheGuids() {
Alex Turner259ff022022-01-18 16:17:00105 ListPrefUpdate update_cache_guids(pref_service_,
106 kDeviceInfoRecentGUIDsWithTimestamps);
Jan Wilken Dörrie4badd7022019-10-30 21:36:20107 update_cache_guids->EraseListValueIf([this](const auto& dict) {
Mikel Astizd55c5b02020-04-23 10:40:15108 // Avoid crashes if the preference contains corrupt entries that are not
109 // dictionaries, and meanwhile clean up these corrupt entries.
110 if (!dict.is_dict()) {
111 return true;
112 }
113
Anton Bikineev1156b5f2021-05-15 22:35:36114 absl::optional<int> days_since_epoch = dict.FindIntKey(kTimestampKey);
Mikel Astizd55c5b02020-04-23 10:40:15115
116 // Avoid crashes if the dictionary contains no timestamp and meanwhile clean
117 // up these corrupt entries.
118 if (!days_since_epoch.has_value()) {
119 return true;
120 }
121
Peter Kastinge5a38ed2021-10-02 03:06:35122 const base::Time creation_time =
123 base::Time::FromDeltaSinceWindowsEpoch(base::Days(*days_since_epoch));
Jan Wilken Dörrie4badd7022019-10-30 21:36:20124 return creation_time < clock_->Now() - kMaxTimeDeltaLocalCacheGuidsStored;
125 });
Mikel Astiz9637de22019-10-02 16:10:27126}
127
Jeffrey Cohen053be24d2019-07-23 23:44:05128} // namespace syncer