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.
5 #include "chrome/browser/prefs/pref_hash_filter.h"
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/pref_hash_store.h"
17 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
18 #include "chrome/browser/prefs/tracked/dictionary_hash_store_contents.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"
24 PrefHashFilter::PrefHashFilter(
25 scoped_ptr<PrefHashStore> pref_hash_store,
26 const std::vector<TrackedPreferenceMetadata>& tracked_preferences,
27 TrackedPreferenceValidationDelegate* delegate,
28 size_t reporting_ids_count,
29 bool report_super_mac_validity)
30 : pref_hash_store_(pref_hash_store.Pass()),
31 report_super_mac_validity_(report_super_mac_validity) {
32 DCHECK(pref_hash_store_);
33 DCHECK_GE(reporting_ids_count, tracked_preferences.size());
35 for (size_t i = 0; i < tracked_preferences.size(); ++i) {
36 const TrackedPreferenceMetadata& metadata = tracked_preferences[i];
38 scoped_ptr<TrackedPreference> tracked_preference;
39 switch (metadata.strategy) {
40 case TRACKING_STRATEGY_ATOMIC:
41 tracked_preference.reset(
42 new TrackedAtomicPreference(metadata.name,
43 metadata.reporting_id,
45 metadata.enforcement_level,
48 case TRACKING_STRATEGY_SPLIT:
49 tracked_preference.reset(
50 new TrackedSplitPreference(metadata.name,
51 metadata.reporting_id,
53 metadata.enforcement_level,
57 DCHECK(tracked_preference);
59 bool is_new = tracked_paths_.add(metadata.name,
60 tracked_preference.Pass()).second;
65 PrefHashFilter::~PrefHashFilter() {
66 // Ensure new values for all |changed_paths_| have been flushed to
67 // |pref_hash_store_| already.
68 DCHECK(changed_paths_.empty());
72 void PrefHashFilter::RegisterProfilePrefs(
73 user_prefs::PrefRegistrySyncable* registry) {
74 // See GetResetTime for why this is a StringPref and not Int64Pref.
75 registry->RegisterStringPref(
76 prefs::kPreferenceResetTime,
77 base::Int64ToString(base::Time().ToInternalValue()),
78 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
82 base::Time PrefHashFilter::GetResetTime(PrefService* user_prefs) {
83 // Provide our own implementation (identical to the PrefService::GetInt64) in
84 // order to ensure it remains consistent with the way we store this value
85 // (which we do via a PrefStore, preventing us from reusing
86 // PrefService::SetInt64).
87 int64 internal_value = base::Time().ToInternalValue();
88 if (!base::StringToInt64(
89 user_prefs->GetString(prefs::kPreferenceResetTime),
91 // Somehow the value stored on disk is not a valid int64.
95 return base::Time::FromInternalValue(internal_value);
99 void PrefHashFilter::ClearResetTime(PrefService* user_prefs) {
100 user_prefs->ClearPref(prefs::kPreferenceResetTime);
103 void PrefHashFilter::Initialize(base::DictionaryValue* pref_store_contents) {
104 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
105 pref_hash_store_->BeginTransaction(scoped_ptr<HashStoreContents>(
106 new DictionaryHashStoreContents(pref_store_contents))));
107 for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
108 it != tracked_paths_.end(); ++it) {
109 const std::string& initialized_path = it->first;
110 const TrackedPreference* initialized_preference = it->second;
111 const base::Value* value = NULL;
112 pref_store_contents->Get(initialized_path, &value);
113 initialized_preference->OnNewValue(value, hash_store_transaction.get());
117 // Marks |path| has having changed if it is part of |tracked_paths_|. A new hash
118 // will be stored for it the next time FilterSerializeData() is invoked.
119 void PrefHashFilter::FilterUpdate(const std::string& path) {
120 TrackedPreferencesMap::const_iterator it = tracked_paths_.find(path);
121 if (it != tracked_paths_.end())
122 changed_paths_.insert(std::make_pair(path, it->second));
125 // Updates the stored hashes for |changed_paths_| before serializing data to
126 // disk. This is required as storing the hash everytime a pref's value changes
127 // is too expensive (see perf regression @ http://crbug.com/331273).
128 void PrefHashFilter::FilterSerializeData(
129 base::DictionaryValue* pref_store_contents) {
130 if (!changed_paths_.empty()) {
131 base::TimeTicks checkpoint = base::TimeTicks::Now();
133 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
134 pref_hash_store_->BeginTransaction(scoped_ptr<HashStoreContents>(
135 new DictionaryHashStoreContents(pref_store_contents))));
136 for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
137 it != changed_paths_.end(); ++it) {
138 const std::string& changed_path = it->first;
139 const TrackedPreference* changed_preference = it->second;
140 const base::Value* value = NULL;
141 pref_store_contents->Get(changed_path, &value);
142 changed_preference->OnNewValue(value, hash_store_transaction.get());
144 changed_paths_.clear();
146 // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing
147 // data has been gathered from the wild to be confident this doesn't
148 // significantly affect performance on the UI thread.
149 UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime",
150 base::TimeTicks::Now() - checkpoint);
154 void PrefHashFilter::FinalizeFilterOnLoad(
155 const PostFilterOnLoadCallback& post_filter_on_load_callback,
156 scoped_ptr<base::DictionaryValue> pref_store_contents,
157 bool prefs_altered) {
158 DCHECK(pref_store_contents);
159 base::TimeTicks checkpoint = base::TimeTicks::Now();
161 bool did_reset = false;
163 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
164 pref_hash_store_->BeginTransaction(scoped_ptr<HashStoreContents>(
165 new DictionaryHashStoreContents(pref_store_contents.get()))));
166 if (report_super_mac_validity_) {
167 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted",
168 hash_store_transaction->IsSuperMACValid());
171 for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
172 it != tracked_paths_.end(); ++it) {
173 if (it->second->EnforceAndReport(pref_store_contents.get(),
174 hash_store_transaction.get())) {
176 prefs_altered = true;
179 if (hash_store_transaction->StampSuperMac())
180 prefs_altered = true;
184 pref_store_contents->Set(prefs::kPreferenceResetTime,
185 new base::StringValue(base::Int64ToString(
186 base::Time::Now().ToInternalValue())));
187 FilterUpdate(prefs::kPreferenceResetTime);
190 // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing
191 // data has been gathered from the wild to be confident this doesn't
192 // significantly affect startup.
193 UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime",
194 base::TimeTicks::Now() - checkpoint);
196 post_filter_on_load_callback.Run(pref_store_contents.Pass(), prefs_altered);