blob: 6df1fa537c94ff70d16acb7b021d629dc92ad680 [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.
29constexpr base::TimeDelta kMaxTimeDeltaLocalCacheGuidsStored =
30 base::TimeDelta::FromDays(10);
31
32// The max number of local device most recent cached GUIDs that will be stored
33// in preferences.
34constexpr int kMaxLocalCacheGuidsStored = 30;
35
36// Returns true iff |dict| is a dictionary with a cache GUID that is equal to
37// |cache_guid|.
38bool MatchesGuidInDictionary(const base::Value& dict,
39 const std::string& cache_guid) {
40 if (!dict.is_dict()) {
41 return false;
42 }
43 const std::string* v_cache_guid = dict.FindStringKey(kCacheGuidKey);
44 return v_cache_guid && *v_cache_guid == cache_guid;
45}
Jeffrey Cohen053be24d2019-07-23 23:44:0546
47} // namespace
48
49// static
50void DeviceInfoPrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) {
Mikel Astiz9637de22019-10-02 16:10:2751 registry->RegisterListPref(kDeviceInfoRecentGUIDsWithTimestamps);
Mikel Astiz9637de22019-10-02 16:10:2752}
53
54DeviceInfoPrefs::DeviceInfoPrefs(PrefService* pref_service,
55 const base::Clock* clock)
56 : pref_service_(pref_service), clock_(clock) {
57 DCHECK(pref_service_);
58 DCHECK(clock_);
Jeffrey Cohen053be24d2019-07-23 23:44:0559}
60
61DeviceInfoPrefs::~DeviceInfoPrefs() {}
62
63bool DeviceInfoPrefs::IsRecentLocalCacheGuid(
64 const std::string& cache_guid) const {
Jan Wilken Dörrie8d9034f12019-11-28 14:48:5765 base::Value::ConstListView recent_local_cache_guids =
Mikel Astiz9637de22019-10-02 16:10:2766 pref_service_->GetList(kDeviceInfoRecentGUIDsWithTimestamps)->GetList();
Jeffrey Cohen053be24d2019-07-23 23:44:0567
Mikel Astiz9637de22019-10-02 16:10:2768 for (const auto& v : recent_local_cache_guids) {
69 if (MatchesGuidInDictionary(v, cache_guid)) {
70 return true;
71 }
72 }
73
74 return false;
Jeffrey Cohen053be24d2019-07-23 23:44:0575}
76
77void DeviceInfoPrefs::AddLocalCacheGuid(const std::string& cache_guid) {
Mikel Astiz9637de22019-10-02 16:10:2778 ListPrefUpdate update_cache_guids(pref_service_,
79 kDeviceInfoRecentGUIDsWithTimestamps);
Jeffrey Cohen053be24d2019-07-23 23:44:0580
Jan Wilken Dörrie4badd7022019-10-30 21:36:2081 for (auto it = update_cache_guids->GetList().begin();
82 it != update_cache_guids->GetList().end(); it++) {
Mikel Astiz9637de22019-10-02 16:10:2783 if (MatchesGuidInDictionary(*it, cache_guid)) {
84 // Remove it from the list, to be reinserted below, in the first
85 // position.
Jan Wilken Dörrie4badd7022019-10-30 21:36:2086 update_cache_guids->EraseListIter(it);
Mikel Astiz9637de22019-10-02 16:10:2787 break;
88 }
Jeffrey Cohen053be24d2019-07-23 23:44:0589 }
90
Mikel Astiz9637de22019-10-02 16:10:2791 base::Value new_entry(base::Value::Type::DICTIONARY);
92 new_entry.SetKey(kCacheGuidKey, base::Value(cache_guid));
93 new_entry.SetKey(
94 kTimestampKey,
95 base::Value(clock_->Now().ToDeltaSinceWindowsEpoch().InDays()));
96
Jan Wilken Dörrie4badd7022019-10-30 21:36:2097 update_cache_guids->Insert(update_cache_guids->GetList().begin(),
98 std::move(new_entry));
Mikel Astiz9637de22019-10-02 16:10:2799
Jan Wilken Dörrie4badd7022019-10-30 21:36:20100 while (update_cache_guids->GetList().size() > kMaxLocalCacheGuidsStored) {
101 update_cache_guids->EraseListIter(update_cache_guids->GetList().end() - 1);
Jeffrey Cohen053be24d2019-07-23 23:44:05102 }
103}
104
Mikel Astiz9637de22019-10-02 16:10:27105void DeviceInfoPrefs::GarbageCollectExpiredCacheGuids() {
106 ListPrefUpdate update_cache_guids(pref_service_,
107 kDeviceInfoRecentGUIDsWithTimestamps);
Jan Wilken Dörrie4badd7022019-10-30 21:36:20108 update_cache_guids->EraseListValueIf([this](const auto& dict) {
Mikel Astizd55c5b02020-04-23 10:40:15109 // Avoid crashes if the preference contains corrupt entries that are not
110 // dictionaries, and meanwhile clean up these corrupt entries.
111 if (!dict.is_dict()) {
112 return true;
113 }
114
Anton Bikineev1156b5f2021-05-15 22:35:36115 absl::optional<int> days_since_epoch = dict.FindIntKey(kTimestampKey);
Mikel Astizd55c5b02020-04-23 10:40:15116
117 // Avoid crashes if the dictionary contains no timestamp and meanwhile clean
118 // up these corrupt entries.
119 if (!days_since_epoch.has_value()) {
120 return true;
121 }
122
123 const base::Time creation_time = base::Time::FromDeltaSinceWindowsEpoch(
124 base::TimeDelta::FromDays(*days_since_epoch));
Jan Wilken Dörrie4badd7022019-10-30 21:36:20125 return creation_time < clock_->Now() - kMaxTimeDeltaLocalCacheGuidsStored;
126 });
Mikel Astiz9637de22019-10-02 16:10:27127}
128
Jeffrey Cohen053be24d2019-07-23 23:44:05129} // namespace syncer