Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / prefs / pref_hash_store_impl.cc
blob096cbd9470b739d71403d929c9c5a1d745db16de
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_store_impl.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/values.h"
10 #include "chrome/browser/prefs/pref_hash_store_transaction.h"
11 #include "chrome/browser/prefs/tracked/hash_store_contents.h"
13 namespace {
15 // Returns true if the dictionary of hashes stored in |contents| is trusted
16 // (which implies unknown values can be trusted as newly tracked values).
17 bool IsHashDictionaryTrusted(const PrefHashCalculator& calculator,
18 const HashStoreContents& contents) {
19 const base::DictionaryValue* store_contents = contents.GetContents();
20 std::string super_mac = contents.GetSuperMac();
21 // The store must be initialized and have a valid super MAC to be trusted.
22 return store_contents && !super_mac.empty() &&
23 calculator.Validate(contents.hash_store_id(),
24 store_contents,
25 super_mac) == PrefHashCalculator::VALID;
28 } // namespace
30 class PrefHashStoreImpl::PrefHashStoreTransactionImpl
31 : public PrefHashStoreTransaction {
32 public:
33 // Constructs a PrefHashStoreTransactionImpl which can use the private
34 // members of its |outer| PrefHashStoreImpl.
35 explicit PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer);
36 virtual ~PrefHashStoreTransactionImpl();
38 // PrefHashStoreTransaction implementation.
39 virtual ValueState CheckValue(const std::string& path,
40 const base::Value* value) const OVERRIDE;
41 virtual void StoreHash(const std::string& path,
42 const base::Value* value) OVERRIDE;
43 virtual ValueState CheckSplitValue(
44 const std::string& path,
45 const base::DictionaryValue* initial_split_value,
46 std::vector<std::string>* invalid_keys) const OVERRIDE;
47 virtual void StoreSplitHash(
48 const std::string& path,
49 const base::DictionaryValue* split_value) OVERRIDE;
51 private:
52 bool GetSplitMacs(const std::string& path,
53 std::map<std::string, std::string>* split_macs) const;
54 PrefHashStoreImpl* outer_;
55 bool has_changed_;
57 DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl);
60 PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
61 const std::string& device_id,
62 scoped_ptr<HashStoreContents> contents)
63 : pref_hash_calculator_(seed, device_id),
64 contents_(contents.Pass()),
65 initial_hashes_dictionary_trusted_(
66 IsHashDictionaryTrusted(pref_hash_calculator_, *contents_)),
67 has_pending_write_(false) {
68 DCHECK(contents_);
69 UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted",
70 initial_hashes_dictionary_trusted_);
73 PrefHashStoreImpl::~PrefHashStoreImpl() {}
75 void PrefHashStoreImpl::Reset() {
76 contents_->Reset();
79 scoped_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction() {
80 return scoped_ptr<PrefHashStoreTransaction>(
81 new PrefHashStoreTransactionImpl(this));
84 PrefHashStoreImpl::StoreVersion PrefHashStoreImpl::GetCurrentVersion() const {
85 if (!contents_->IsInitialized())
86 return VERSION_UNINITIALIZED;
88 int current_version;
89 if (!contents_->GetVersion(&current_version)) {
90 return VERSION_PRE_MIGRATION;
93 DCHECK_GT(current_version, VERSION_PRE_MIGRATION);
94 return static_cast<StoreVersion>(current_version);
97 void PrefHashStoreImpl::CommitPendingWrite() {
98 if (has_pending_write_) {
99 contents_->CommitPendingWrite();
100 has_pending_write_ = false;
104 PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
105 PrefHashStoreImpl* outer) : outer_(outer), has_changed_(false) {
108 PrefHashStoreImpl::PrefHashStoreTransactionImpl::
109 ~PrefHashStoreTransactionImpl() {
110 // Update the super MAC if and only if the hashes dictionary has been
111 // modified in this transaction.
112 if (has_changed_) {
113 // Get the dictionary of hashes (or NULL if it doesn't exist).
114 const base::DictionaryValue* hashes_dict = outer_->contents_->GetContents();
115 outer_->contents_->SetSuperMac(outer_->pref_hash_calculator_.Calculate(
116 outer_->contents_->hash_store_id(), hashes_dict));
118 outer_->has_pending_write_ = true;
121 // Mark this hash store has having been updated to the latest version (in
122 // practice only initialization transactions will actually do this, but
123 // since they always occur before minor update transaction it's okay
124 // to unconditionally do this here). Only do this if this store's version
125 // isn't already at VERSION_LATEST (to avoid scheduling a write when
126 // unecessary). Note, this is outside of |if (has_changed)| to also seed
127 // version number of otherwise unchanged profiles.
128 int current_version;
129 if (!outer_->contents_->GetVersion(&current_version) ||
130 current_version != VERSION_LATEST) {
131 outer_->contents_->SetVersion(VERSION_LATEST);
132 outer_->has_pending_write_ = true;
136 PrefHashStoreTransaction::ValueState
137 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
138 const std::string& path, const base::Value* initial_value) const {
139 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents();
141 std::string last_hash;
142 if (hashed_prefs)
143 hashed_prefs->GetString(path, &last_hash);
145 if (last_hash.empty()) {
146 // In the absence of a hash for this pref, always trust a NULL value, but
147 // only trust an existing value if the initial hashes dictionary is trusted.
148 return (!initial_value || outer_->initial_hashes_dictionary_trusted_) ?
149 TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE;
152 PrefHashCalculator::ValidationResult validation_result =
153 outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash);
154 switch (validation_result) {
155 case PrefHashCalculator::VALID:
156 return UNCHANGED;
157 case PrefHashCalculator::VALID_WEAK_LEGACY:
158 return WEAK_LEGACY;
159 case PrefHashCalculator::VALID_SECURE_LEGACY:
160 return SECURE_LEGACY;
161 case PrefHashCalculator::INVALID:
162 return initial_value ? CHANGED : CLEARED;
164 NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
165 << validation_result;
166 return UNTRUSTED_UNKNOWN_VALUE;
169 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
170 const std::string& path, const base::Value* new_value) {
171 const std::string mac =
172 outer_->pref_hash_calculator_.Calculate(path, new_value);
173 (*outer_->contents_->GetMutableContents())->SetString(path, mac);
174 has_changed_ = true;
177 PrefHashStoreTransaction::ValueState
178 PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
179 const std::string& path,
180 const base::DictionaryValue* initial_split_value,
181 std::vector<std::string>* invalid_keys) const {
182 DCHECK(invalid_keys && invalid_keys->empty());
184 std::map<std::string, std::string> split_macs;
185 const bool has_hashes = GetSplitMacs(path, &split_macs);
187 // Treat NULL and empty the same; otherwise we would need to store a hash
188 // for the entire dictionary (or some other special beacon) to
189 // differentiate these two cases which are really the same for
190 // dictionaries.
191 if (!initial_split_value || initial_split_value->empty())
192 return has_hashes ? CLEARED : UNCHANGED;
194 if (!has_hashes) {
195 return outer_->initial_hashes_dictionary_trusted_ ?
196 TRUSTED_UNKNOWN_VALUE : UNTRUSTED_UNKNOWN_VALUE;
199 bool has_secure_legacy_id_hashes = false;
200 std::string keyed_path(path);
201 keyed_path.push_back('.');
202 const size_t common_part_length = keyed_path.length();
203 for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd();
204 it.Advance()) {
205 std::map<std::string, std::string>::iterator entry =
206 split_macs.find(it.key());
207 if (entry == split_macs.end()) {
208 invalid_keys->push_back(it.key());
209 } else {
210 // Keep the common part from the old |keyed_path| and replace the key to
211 // get the new |keyed_path|.
212 keyed_path.replace(common_part_length, std::string::npos, it.key());
213 switch (outer_->pref_hash_calculator_.Validate(
214 keyed_path, &it.value(), entry->second)) {
215 case PrefHashCalculator::VALID:
216 break;
217 case WEAK_LEGACY:
218 // Split tracked preferences were introduced after the migration from
219 // the weaker legacy algorithm started so no migration is expected,
220 // but declare it invalid in Release builds anyways.
221 NOTREACHED();
222 invalid_keys->push_back(it.key());
223 break;
224 case SECURE_LEGACY:
225 // Secure legacy device IDs based hashes are still accepted, but we
226 // should make sure to notify the caller for him to update the legacy
227 // hashes.
228 has_secure_legacy_id_hashes = true;
229 break;
230 case PrefHashCalculator::INVALID:
231 invalid_keys->push_back(it.key());
232 break;
234 // Remove processed MACs, remaining MACs at the end will also be
235 // considered invalid.
236 split_macs.erase(entry);
240 // Anything left in the map is missing from the data.
241 for (std::map<std::string, std::string>::const_iterator it =
242 split_macs.begin();
243 it != split_macs.end();
244 ++it) {
245 invalid_keys->push_back(it->first);
248 return invalid_keys->empty()
249 ? (has_secure_legacy_id_hashes ? SECURE_LEGACY : UNCHANGED)
250 : CHANGED;
253 void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
254 const std::string& path,
255 const base::DictionaryValue* split_value) {
256 scoped_ptr<HashStoreContents::MutableDictionary> mutable_dictionary =
257 outer_->contents_->GetMutableContents();
258 (*mutable_dictionary)->Remove(path, NULL);
260 if (split_value) {
261 std::string keyed_path(path);
262 keyed_path.push_back('.');
263 const size_t common_part_length = keyed_path.length();
264 for (base::DictionaryValue::Iterator it(*split_value); !it.IsAtEnd();
265 it.Advance()) {
266 // Keep the common part from the old |keyed_path| and replace the key to
267 // get the new |keyed_path|.
268 keyed_path.replace(common_part_length, std::string::npos, it.key());
269 (*mutable_dictionary)->SetString(
270 keyed_path,
271 outer_->pref_hash_calculator_.Calculate(keyed_path, &it.value()));
274 has_changed_ = true;
277 bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs(
278 const std::string& key,
279 std::map<std::string, std::string>* split_macs) const {
280 DCHECK(split_macs);
281 DCHECK(split_macs->empty());
283 const base::DictionaryValue* hashed_prefs = outer_->contents_->GetContents();
284 const base::DictionaryValue* split_mac_dictionary = NULL;
285 if (!hashed_prefs || !hashed_prefs->GetDictionary(key, &split_mac_dictionary))
286 return false;
287 for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd();
288 it.Advance()) {
289 std::string mac_string;
290 if (!it.value().GetAsString(&mac_string)) {
291 NOTREACHED();
292 continue;
294 split_macs->insert(make_pair(it.key(), mac_string));
296 return true;