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