OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "chrome/browser/prefs/tracked/pref_hash_filter.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/metrics/histogram.h" | |
11 #include "base/prefs/pref_service.h" | |
12 #include "base/prefs/pref_store.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/time/time.h" | |
15 #include "base/values.h" | |
16 #include "chrome/browser/prefs/tracked/dictionary_hash_store_contents.h" | |
17 #include "chrome/browser/prefs/tracked/pref_hash_store.h" | |
18 #include "chrome/browser/prefs/tracked/pref_hash_store_transaction.h" | |
19 #include "chrome/browser/prefs/tracked/tracked_atomic_preference.h" | |
20 #include "chrome/browser/prefs/tracked/tracked_split_preference.h" | |
21 #include "chrome/common/pref_names.h" | |
22 #include "components/pref_registry/pref_registry_syncable.h" | |
23 | |
24 namespace { | |
25 | |
26 void CleanupDeprecatedTrackedPreferences( | |
27 base::DictionaryValue* pref_store_contents, | |
28 PrefHashStoreTransaction* hash_store_transaction) { | |
29 // Add deprecated previously tracked preferences below for them to be cleaned | |
30 // up from both the pref files and the hash store. | |
31 static const char* const kDeprecatedTrackedPreferences[] = { | |
32 // TODO(grt): Remove in M44+. | |
33 "safebrowsing.incident_report_sent", | |
34 // TODO(mad): Remove in M48+. | |
35 "software_reporter.prompt_reason", | |
36 }; | |
37 | |
38 for (size_t i = 0; i < arraysize(kDeprecatedTrackedPreferences); ++i) { | |
39 const char* key = kDeprecatedTrackedPreferences[i]; | |
40 pref_store_contents->Remove(key, NULL); | |
41 hash_store_transaction->ClearHash(key); | |
42 } | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 PrefHashFilter::PrefHashFilter( | |
48 scoped_ptr<PrefHashStore> pref_hash_store, | |
49 const std::vector<TrackedPreferenceMetadata>& tracked_preferences, | |
50 const base::Closure& on_reset_on_load, | |
51 TrackedPreferenceValidationDelegate* delegate, | |
52 size_t reporting_ids_count, | |
53 bool report_super_mac_validity) | |
54 : pref_hash_store_(pref_hash_store.Pass()), | |
55 on_reset_on_load_(on_reset_on_load), | |
56 report_super_mac_validity_(report_super_mac_validity) { | |
57 DCHECK(pref_hash_store_); | |
58 DCHECK_GE(reporting_ids_count, tracked_preferences.size()); | |
59 | |
60 for (size_t i = 0; i < tracked_preferences.size(); ++i) { | |
61 const TrackedPreferenceMetadata& metadata = tracked_preferences[i]; | |
62 | |
63 scoped_ptr<TrackedPreference> tracked_preference; | |
64 switch (metadata.strategy) { | |
65 case TRACKING_STRATEGY_ATOMIC: | |
66 tracked_preference.reset( | |
67 new TrackedAtomicPreference(metadata.name, | |
68 metadata.reporting_id, | |
69 reporting_ids_count, | |
70 metadata.enforcement_level, | |
71 metadata.value_type, | |
72 delegate)); | |
73 break; | |
74 case TRACKING_STRATEGY_SPLIT: | |
75 tracked_preference.reset( | |
76 new TrackedSplitPreference(metadata.name, | |
77 metadata.reporting_id, | |
78 reporting_ids_count, | |
79 metadata.enforcement_level, | |
80 metadata.value_type, | |
81 delegate)); | |
82 break; | |
83 } | |
84 DCHECK(tracked_preference); | |
85 | |
86 bool is_new = tracked_paths_.add(metadata.name, | |
87 tracked_preference.Pass()).second; | |
88 DCHECK(is_new); | |
89 } | |
90 } | |
91 | |
92 PrefHashFilter::~PrefHashFilter() { | |
93 // Ensure new values for all |changed_paths_| have been flushed to | |
94 // |pref_hash_store_| already. | |
95 DCHECK(changed_paths_.empty()); | |
96 } | |
97 | |
98 // static | |
99 void PrefHashFilter::RegisterProfilePrefs( | |
100 user_prefs::PrefRegistrySyncable* registry) { | |
101 // See GetResetTime for why this is a StringPref and not Int64Pref. | |
102 registry->RegisterStringPref( | |
103 prefs::kPreferenceResetTime, | |
104 base::Int64ToString(base::Time().ToInternalValue())); | |
105 } | |
106 | |
107 // static | |
108 base::Time PrefHashFilter::GetResetTime(PrefService* user_prefs) { | |
109 // Provide our own implementation (identical to the PrefService::GetInt64) in | |
110 // order to ensure it remains consistent with the way we store this value | |
111 // (which we do via a PrefStore, preventing us from reusing | |
112 // PrefService::SetInt64). | |
113 int64 internal_value = base::Time().ToInternalValue(); | |
114 if (!base::StringToInt64( | |
115 user_prefs->GetString(prefs::kPreferenceResetTime), | |
116 &internal_value)) { | |
117 // Somehow the value stored on disk is not a valid int64. | |
118 NOTREACHED(); | |
119 return base::Time(); | |
120 } | |
121 return base::Time::FromInternalValue(internal_value); | |
122 } | |
123 | |
124 // static | |
125 void PrefHashFilter::ClearResetTime(PrefService* user_prefs) { | |
126 user_prefs->ClearPref(prefs::kPreferenceResetTime); | |
127 } | |
128 | |
129 void PrefHashFilter::Initialize(base::DictionaryValue* pref_store_contents) { | |
130 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction( | |
131 pref_hash_store_->BeginTransaction(scoped_ptr<HashStoreContents>( | |
132 new DictionaryHashStoreContents(pref_store_contents)))); | |
133 for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin(); | |
134 it != tracked_paths_.end(); ++it) { | |
135 const std::string& initialized_path = it->first; | |
136 const TrackedPreference* initialized_preference = it->second; | |
137 const base::Value* value = NULL; | |
138 pref_store_contents->Get(initialized_path, &value); | |
139 initialized_preference->OnNewValue(value, hash_store_transaction.get()); | |
140 } | |
141 } | |
142 | |
143 // Marks |path| has having changed if it is part of |tracked_paths_|. A new hash | |
144 // will be stored for it the next time FilterSerializeData() is invoked. | |
145 void PrefHashFilter::FilterUpdate(const std::string& path) { | |
146 TrackedPreferencesMap::const_iterator it = tracked_paths_.find(path); | |
147 if (it != tracked_paths_.end()) | |
148 changed_paths_.insert(std::make_pair(path, it->second)); | |
149 } | |
150 | |
151 // Updates the stored hashes for |changed_paths_| before serializing data to | |
152 // disk. This is required as storing the hash everytime a pref's value changes | |
153 // is too expensive (see perf regression @ http://crbug.com/331273). | |
154 void PrefHashFilter::FilterSerializeData( | |
155 base::DictionaryValue* pref_store_contents) { | |
156 if (!changed_paths_.empty()) { | |
157 base::TimeTicks checkpoint = base::TimeTicks::Now(); | |
158 { | |
159 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction( | |
160 pref_hash_store_->BeginTransaction(scoped_ptr<HashStoreContents>( | |
161 new DictionaryHashStoreContents(pref_store_contents)))); | |
162 for (ChangedPathsMap::const_iterator it = changed_paths_.begin(); | |
163 it != changed_paths_.end(); ++it) { | |
164 const std::string& changed_path = it->first; | |
165 const TrackedPreference* changed_preference = it->second; | |
166 const base::Value* value = NULL; | |
167 pref_store_contents->Get(changed_path, &value); | |
168 changed_preference->OnNewValue(value, hash_store_transaction.get()); | |
169 } | |
170 changed_paths_.clear(); | |
171 } | |
172 // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing | |
173 // data has been gathered from the wild to be confident this doesn't | |
174 // significantly affect performance on the UI thread. | |
175 UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime", | |
176 base::TimeTicks::Now() - checkpoint); | |
177 } | |
178 } | |
179 | |
180 void PrefHashFilter::FinalizeFilterOnLoad( | |
181 const PostFilterOnLoadCallback& post_filter_on_load_callback, | |
182 scoped_ptr<base::DictionaryValue> pref_store_contents, | |
183 bool prefs_altered) { | |
184 DCHECK(pref_store_contents); | |
185 base::TimeTicks checkpoint = base::TimeTicks::Now(); | |
186 | |
187 bool did_reset = false; | |
188 { | |
189 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction( | |
190 pref_hash_store_->BeginTransaction(scoped_ptr<HashStoreContents>( | |
191 new DictionaryHashStoreContents(pref_store_contents.get())))); | |
192 | |
193 CleanupDeprecatedTrackedPreferences( | |
194 pref_store_contents.get(), hash_store_transaction.get()); | |
195 | |
196 if (report_super_mac_validity_) { | |
197 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted", | |
198 hash_store_transaction->IsSuperMACValid()); | |
199 } | |
200 | |
201 for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin(); | |
202 it != tracked_paths_.end(); ++it) { | |
203 if (it->second->EnforceAndReport(pref_store_contents.get(), | |
204 hash_store_transaction.get())) { | |
205 did_reset = true; | |
206 prefs_altered = true; | |
207 } | |
208 } | |
209 if (hash_store_transaction->StampSuperMac()) | |
210 prefs_altered = true; | |
211 } | |
212 | |
213 if (did_reset) { | |
214 pref_store_contents->Set(prefs::kPreferenceResetTime, | |
215 new base::StringValue(base::Int64ToString( | |
216 base::Time::Now().ToInternalValue()))); | |
217 FilterUpdate(prefs::kPreferenceResetTime); | |
218 | |
219 if (!on_reset_on_load_.is_null()) | |
220 on_reset_on_load_.Run(); | |
221 } | |
222 | |
223 // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing | |
224 // data has been gathered from the wild to be confident this doesn't | |
225 // significantly affect startup. | |
226 UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime", | |
227 base::TimeTicks::Now() - checkpoint); | |
228 | |
229 post_filter_on_load_callback.Run(pref_store_contents.Pass(), prefs_altered); | |
230 } | |
OLD | NEW |