d0a398fbe97ab0f223987751f2ab88e592efe2ab
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / pref_hash_filter.cc
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/pref_hash_filter.h"
6
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_store.h"
10 #include "base/values.h"
11 #include "chrome/common/pref_names.h"
12
13 namespace {
14
15 void ReportValidationResult(PrefHashStore::ValueState value_state,
16                             size_t value_index,
17                             size_t num_values) {
18   switch (value_state) {
19     case PrefHashStore::UNCHANGED:
20       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceUnchanged",
21                                 value_index, num_values);
22       return;
23     case PrefHashStore::CLEARED:
24       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceCleared",
25                                 value_index, num_values);
26       return;
27     case PrefHashStore::MIGRATED:
28       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceMigrated",
29                                 value_index, num_values);
30       return;
31     case PrefHashStore::CHANGED:
32       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceChanged",
33                                 value_index, num_values);
34       return;
35     case PrefHashStore::UNTRUSTED_UNKNOWN_VALUE:
36       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceInitialized",
37                                 value_index, num_values);
38       return;
39     case PrefHashStore::TRUSTED_UNKNOWN_VALUE:
40       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceTrustedInitialized",
41                                 value_index, num_values);
42       return;
43   }
44   NOTREACHED() << "Unexpected PrefHashStore::ValueState: " << value_state;
45 }
46
47 }  // namespace
48
49 PrefHashFilter::PrefHashFilter(scoped_ptr<PrefHashStore> pref_hash_store,
50                                const TrackedPreference tracked_preferences[],
51                                size_t tracked_preferences_size,
52                                size_t reporting_ids_count,
53                                EnforcementLevel enforcement_level)
54     : pref_hash_store_(pref_hash_store.Pass()),
55       reporting_ids_count_(reporting_ids_count),
56       enforce_(enforcement_level >= ENFORCE),
57       no_seeding_(enforcement_level >= ENFORCE_NO_SEEDING),
58       no_migration_(enforcement_level >= ENFORCE_NO_SEEDING_NO_MIGRATION) {
59   DCHECK_GE(reporting_ids_count, tracked_preferences_size);
60
61   for (size_t i = 0; i < tracked_preferences_size; ++i) {
62     bool is_new = tracked_paths_.insert(std::make_pair(
63         std::string(tracked_preferences[i].name),
64         tracked_preferences[i])).second;
65     DCHECK(is_new);
66   }
67 }
68
69 PrefHashFilter::~PrefHashFilter() {
70   // Ensure new values for all |changed_paths_| have been flushed to
71   // |pref_hash_store_| already.
72   DCHECK(changed_paths_.empty());
73 }
74
75 void PrefHashFilter::Initialize(PrefStore* pref_store) {
76   UMA_HISTOGRAM_BOOLEAN(
77       "Settings.TrackedPreferencesInitializedForUnloadedProfile", true);
78
79   for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
80        it != tracked_paths_.end(); ++it) {
81     const base::Value* value = NULL;
82     pref_store->GetValue(it->first, &value);
83     pref_hash_store_->StoreHash(it->first, value);
84   }
85 }
86
87 // Validates loaded preference values according to stored hashes, reports
88 // validation results via UMA, and updates hashes in case of mismatch.
89 void PrefHashFilter::FilterOnLoad(base::DictionaryValue* pref_store_contents) {
90   DCHECK(pref_store_contents);
91   for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin();
92        it != tracked_paths_.end(); ++it) {
93     const std::string& pref_path = it->first;
94     const TrackedPreference& metadata = it->second;
95     const base::Value* value = NULL;
96     pref_store_contents->Get(pref_path, &value);
97
98     PrefHashStore::ValueState value_state =
99         pref_hash_store_->CheckValue(pref_path, value);
100     ReportValidationResult(value_state, metadata.reporting_id,
101                            reporting_ids_count_);
102
103     enum {
104       DONT_RESET,
105       WANTED_RESET,
106       DO_RESET,
107     } reset_state = DONT_RESET;
108     if (metadata.allow_enforcement) {
109       switch (value_state) {
110         case PrefHashStore::UNCHANGED:
111           // Desired case, nothing to do.
112           break;
113         case PrefHashStore::CLEARED:
114           // Unfortunate case, but there is nothing we can do.
115           break;
116         case PrefHashStore::TRUSTED_UNKNOWN_VALUE:
117           // It is okay to seed the hash in this case.
118           break;
119         case PrefHashStore::MIGRATED:
120           reset_state = no_migration_ ? DO_RESET : WANTED_RESET;
121           break;
122         case PrefHashStore::UNTRUSTED_UNKNOWN_VALUE:
123           reset_state = no_seeding_ ? DO_RESET : WANTED_RESET;
124           break;
125         case PrefHashStore::CHANGED:
126           reset_state = enforce_ ? DO_RESET : WANTED_RESET;
127           break;
128       }
129     }
130
131     if (reset_state == DO_RESET) {
132       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceReset",
133                                 metadata.reporting_id, reporting_ids_count_);
134       // TODO(gab): Store the |old_value| to provide an undo UI.
135       scoped_ptr<base::Value> old_value;
136       pref_store_contents->RemovePath(pref_path, &old_value);
137     } else if (reset_state == WANTED_RESET) {
138       UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceWantedReset",
139                                 metadata.reporting_id, reporting_ids_count_);
140     }
141
142     if (value_state != PrefHashStore::UNCHANGED) {
143       // Store the hash for the new value (whether it was reset or not).
144       const base::Value* new_value = NULL;
145       pref_store_contents->Get(pref_path, &new_value);
146       pref_hash_store_->StoreHash(pref_path, new_value);
147     }
148   }
149 }
150
151 // Marks |path| has having changed if it is part of |tracked_paths_|. A new hash
152 // will be stored for it the next time FilterSerializeData() is invoked.
153 void PrefHashFilter::FilterUpdate(const std::string& path) {
154   if (tracked_paths_.find(path) != tracked_paths_.end())
155     changed_paths_.insert(path);
156 }
157
158 // Updates the stored hashes for |changed_paths_| before serializing data to
159 // disk. This is required as storing the hash everytime a pref's value changes
160 // is too expensive (see perf regression @ http://crbug.com/331273).
161 void PrefHashFilter::FilterSerializeData(
162     const base::DictionaryValue* pref_store_contents) {
163   for (std::set<std::string>::const_iterator it = changed_paths_.begin();
164        it != changed_paths_.end(); ++it) {
165     const std::string& changed_path = *it;
166     const base::Value* value = NULL;
167     pref_store_contents->Get(changed_path, &value);
168     pref_hash_store_->StoreHash(changed_path, value);
169   }
170   changed_paths_.clear();
171 }