8bdf99444065a662e03baf3479fdd0c8c586ea5b
[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 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());
34
35   for (size_t i = 0; i < tracked_preferences.size(); ++i) {
36     const TrackedPreferenceMetadata& metadata = tracked_preferences[i];
37
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,
44                                         reporting_ids_count,
45                                         metadata.enforcement_level,
46                                         delegate));
47         break;
48       case TRACKING_STRATEGY_SPLIT:
49         tracked_preference.reset(
50             new TrackedSplitPreference(metadata.name,
51                                        metadata.reporting_id,
52                                        reporting_ids_count,
53                                        metadata.enforcement_level,
54                                        delegate));
55         break;
56     }
57     DCHECK(tracked_preference);
58
59     bool is_new = tracked_paths_.add(metadata.name,
60                                      tracked_preference.Pass()).second;
61     DCHECK(is_new);
62   }
63 }
64
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());
69 }
70
71 // static
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);
79 }
80
81 // static
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),
90           &internal_value)) {
91     // Somehow the value stored on disk is not a valid int64.
92     NOTREACHED();
93     return base::Time();
94   }
95   return base::Time::FromInternalValue(internal_value);
96 }
97
98 // static
99 void PrefHashFilter::ClearResetTime(PrefService* user_prefs) {
100   user_prefs->ClearPref(prefs::kPreferenceResetTime);
101 }
102
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());
114   }
115 }
116
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));
123 }
124
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();
132     {
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());
143       }
144       changed_paths_.clear();
145     }
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);
151   }
152 }
153
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();
160
161   bool did_reset = false;
162   {
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());
169     }
170
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())) {
175         did_reset = true;
176         prefs_altered = true;
177       }
178     }
179     if (hash_store_transaction->StampSuperMac())
180       prefs_altered = true;
181   }
182
183   if (did_reset) {
184     pref_store_contents->Set(prefs::kPreferenceResetTime,
185                              new base::StringValue(base::Int64ToString(
186                                  base::Time::Now().ToInternalValue())));
187     FilterUpdate(prefs::kPreferenceResetTime);
188   }
189
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);
195
196   post_filter_on_load_callback.Run(pref_store_contents.Pass(), prefs_altered);
197 }