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_store.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
15 #include "chrome/browser/prefs/tracked/tracked_atomic_preference.h"
16 #include "chrome/browser/prefs/tracked/tracked_split_preference.h"
18 PrefHashFilter::PrefHashFilter(
19 scoped_ptr<PrefHashStore> pref_hash_store,
20 const TrackedPreferenceMetadata tracked_preferences[],
21 size_t tracked_preferences_size,
22 size_t reporting_ids_count,
23 EnforcementLevel enforcement_level,
24 const base::Closure& reset_callback)
25 : pref_hash_store_(pref_hash_store.Pass()),
26 reset_callback_(reset_callback) {
27 DCHECK(pref_hash_store_);
28 DCHECK_GE(reporting_ids_count, tracked_preferences_size);
30 for (size_t i = 0; i < tracked_preferences_size; ++i) {
31 const TrackedPreferenceMetadata& metadata = tracked_preferences[i];
33 EnforcementLevel enforcement_level_for_pref =
34 std::min(enforcement_level, metadata.max_enforcement_level);
36 scoped_ptr<TrackedPreference> tracked_preference;
37 switch (metadata.strategy) {
38 case TRACKING_STRATEGY_ATOMIC:
39 tracked_preference.reset(
40 new TrackedAtomicPreference(metadata.name, metadata.reporting_id,
42 enforcement_level_for_pref));
44 case TRACKING_STRATEGY_SPLIT:
45 tracked_preference.reset(
46 new TrackedSplitPreference(metadata.name, metadata.reporting_id,
48 enforcement_level_for_pref));
51 DCHECK(tracked_preference);
53 bool is_new = tracked_paths_.add(metadata.name,
54 tracked_preference.Pass()).second;
59 PrefHashFilter::~PrefHashFilter() {
60 // Ensure new values for all |changed_paths_| have been flushed to
61 // |pref_hash_store_| already.
62 DCHECK(changed_paths_.empty());
65 void PrefHashFilter::Initialize(const PrefStore& pref_store) {
66 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
67 pref_hash_store_->BeginTransaction());
68 for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
69 it != tracked_paths_.end(); ++it) {
70 const std::string& initialized_path = it->first;
71 const TrackedPreference* initialized_preference = it->second;
72 const base::Value* value = NULL;
73 pref_store.GetValue(initialized_path, &value);
74 initialized_preference->OnNewValue(value, hash_store_transaction.get());
78 // Validates loaded preference values according to stored hashes, reports
79 // validation results via UMA, and updates hashes in case of mismatch.
80 void PrefHashFilter::FilterOnLoad(base::DictionaryValue* pref_store_contents) {
81 DCHECK(pref_store_contents);
82 base::TimeTicks checkpoint = base::TimeTicks::Now();
84 bool did_reset = false;
86 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
87 pref_hash_store_->BeginTransaction());
88 for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
89 it != tracked_paths_.end(); ++it) {
90 if (it->second->EnforceAndReport(pref_store_contents,
91 hash_store_transaction.get())) {
98 reset_callback_.Run();
100 // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing
101 // data has been gathered from the wild to be confident this doesn't
102 // significantly affect startup.
103 UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime",
104 base::TimeTicks::Now() - checkpoint);
107 // Marks |path| has having changed if it is part of |tracked_paths_|. A new hash
108 // will be stored for it the next time FilterSerializeData() is invoked.
109 void PrefHashFilter::FilterUpdate(const std::string& path) {
110 TrackedPreferencesMap::const_iterator it = tracked_paths_.find(path);
111 if (it != tracked_paths_.end())
112 changed_paths_.insert(std::make_pair(path, it->second));
115 // Updates the stored hashes for |changed_paths_| before serializing data to
116 // disk. This is required as storing the hash everytime a pref's value changes
117 // is too expensive (see perf regression @ http://crbug.com/331273).
118 void PrefHashFilter::FilterSerializeData(
119 const base::DictionaryValue* pref_store_contents) {
120 if (!changed_paths_.empty()) {
121 base::TimeTicks checkpoint = base::TimeTicks::Now();
123 scoped_ptr<PrefHashStoreTransaction> hash_store_transaction(
124 pref_hash_store_->BeginTransaction());
125 for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
126 it != changed_paths_.end(); ++it) {
127 const std::string& changed_path = it->first;
128 const TrackedPreference* changed_preference = it->second;
129 const base::Value* value = NULL;
130 pref_store_contents->Get(changed_path, &value);
131 changed_preference->OnNewValue(value, hash_store_transaction.get());
133 changed_paths_.clear();
135 // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing
136 // data has been gathered from the wild to be confident this doesn't
137 // significantly affect performance on the UI thread.
138 UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime",
139 base::TimeTicks::Now() - checkpoint);