diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-04 14:17:57 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-01-05 10:05:06 +0000 |
commit | 39d357e3248f80abea0159765ff39554affb40db (patch) | |
tree | aba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/components/user_prefs | |
parent | 87778abf5a1f89266f37d1321b92a21851d8244d (diff) | |
download | qtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz |
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2
Change-Id: I20d43c737f82764d857ada9a55586901b18b9243
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/user_prefs')
36 files changed, 1447 insertions, 975 deletions
diff --git a/chromium/components/user_prefs/tracked/BUILD.gn b/chromium/components/user_prefs/tracked/BUILD.gn index 3afd2bc7744..d2108c61762 100644 --- a/chromium/components/user_prefs/tracked/BUILD.gn +++ b/chromium/components/user_prefs/tracked/BUILD.gn @@ -23,8 +23,8 @@ static_library("user_prefs_tracked") { "pref_hash_store_transaction.h", "pref_names.cc", "pref_names.h", - "pref_service_hash_store_contents.cc", - "pref_service_hash_store_contents.h", + "registry_hash_store_contents_win.cc", + "registry_hash_store_contents_win.h", "segregated_pref_store.cc", "segregated_pref_store.h", "tracked_atomic_preference.cc", @@ -56,7 +56,7 @@ static_library("user_prefs_tracked") { ] } -source_set("user_prefs_tracked_test_support") { +static_library("user_prefs_tracked_test_support") { testonly = true sources = [ "mock_validation_delegate.cc", @@ -76,7 +76,7 @@ source_set("unit_tests") { "pref_hash_calculator_unittest.cc", "pref_hash_filter_unittest.cc", "pref_hash_store_impl_unittest.cc", - "pref_service_hash_store_contents_unittest.cc", + "registry_hash_store_contents_win_unittest.cc", "segregated_pref_store_unittest.cc", "tracked_preferences_migration_unittest.cc", ] @@ -85,6 +85,7 @@ source_set("unit_tests") { ":user_prefs_tracked", ":user_prefs_tracked_test_support", "//base:base", + "//base/test:test_support", "//components/prefs:test_support", "//testing/gtest", ] diff --git a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc index 899cafabec1..288c1bf45db 100644 --- a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc +++ b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.cc @@ -12,42 +12,10 @@ #include "components/prefs/persistent_pref_store.h" namespace { - const char kPreferenceMACs[] = "protection.macs"; const char kSuperMACPref[] = "protection.super_mac"; - -class MutablePreferenceMacDictionary - : public HashStoreContents::MutableDictionary { - public: - explicit MutablePreferenceMacDictionary(base::DictionaryValue* storage); - - // MutableDictionary implementation - base::DictionaryValue* operator->() override; - - private: - base::DictionaryValue* storage_; - - DISALLOW_COPY_AND_ASSIGN(MutablePreferenceMacDictionary); -}; - -MutablePreferenceMacDictionary::MutablePreferenceMacDictionary( - base::DictionaryValue* storage) - : storage_(storage) { } -base::DictionaryValue* MutablePreferenceMacDictionary::operator->() { - base::DictionaryValue* mac_dictionary = NULL; - - if (!storage_->GetDictionary(kPreferenceMACs, &mac_dictionary)) { - mac_dictionary = new base::DictionaryValue; - storage_->Set(kPreferenceMACs, mac_dictionary); - } - - return mac_dictionary; -} - -} // namespace - DictionaryHashStoreContents::DictionaryHashStoreContents( base::DictionaryValue* storage) : storage_(storage) { @@ -60,28 +28,82 @@ void DictionaryHashStoreContents::RegisterProfilePrefs( registry->RegisterStringPref(kSuperMACPref, std::string()); } -std::string DictionaryHashStoreContents::hash_store_id() const { - return ""; +bool DictionaryHashStoreContents::IsCopyable() const { + return false; +} + +std::unique_ptr<HashStoreContents> DictionaryHashStoreContents::MakeCopy() + const { + NOTREACHED() << "DictionaryHashStoreContents does not support MakeCopy"; + return nullptr; +} + +base::StringPiece DictionaryHashStoreContents::GetUMASuffix() const { + // To stay consistent with existing reported data, do not append a suffix + // when reporting UMA stats for this content. + return base::StringPiece(); } void DictionaryHashStoreContents::Reset() { storage_->Remove(kPreferenceMACs, NULL); } -bool DictionaryHashStoreContents::IsInitialized() const { - return storage_->GetDictionary(kPreferenceMACs, NULL); +bool DictionaryHashStoreContents::GetMac(const std::string& path, + std::string* out_value) { + const base::DictionaryValue* macs_dict = GetContents(); + if (macs_dict) + return macs_dict->GetString(path, out_value); + + return false; } -const base::DictionaryValue* DictionaryHashStoreContents::GetContents() const { - const base::DictionaryValue* mac_dictionary = NULL; - storage_->GetDictionary(kPreferenceMACs, &mac_dictionary); - return mac_dictionary; +bool DictionaryHashStoreContents::GetSplitMacs( + const std::string& path, + std::map<std::string, std::string>* split_macs) { + DCHECK(split_macs); + DCHECK(split_macs->empty()); + + const base::DictionaryValue* macs_dict = GetContents(); + const base::DictionaryValue* split_macs_dict = NULL; + if (!macs_dict || !macs_dict->GetDictionary(path, &split_macs_dict)) + return false; + for (base::DictionaryValue::Iterator it(*split_macs_dict); !it.IsAtEnd(); + it.Advance()) { + std::string mac_string; + if (!it.value().GetAsString(&mac_string)) { + NOTREACHED(); + continue; + } + split_macs->insert(make_pair(it.key(), mac_string)); + } + return true; } -std::unique_ptr<HashStoreContents::MutableDictionary> -DictionaryHashStoreContents::GetMutableContents() { - return std::unique_ptr<MutableDictionary>( - new MutablePreferenceMacDictionary(storage_)); +void DictionaryHashStoreContents::SetMac(const std::string& path, + const std::string& value) { + base::DictionaryValue* macs_dict = GetMutableContents(true); + macs_dict->SetString(path, value); +} + +void DictionaryHashStoreContents::SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) { + // DictionaryValue handles a '.' delimiter. + SetMac(path + '.' + split_path, value); +} + +void DictionaryHashStoreContents::ImportEntry(const std::string& path, + const base::Value* in_value) { + base::DictionaryValue* macs_dict = GetMutableContents(true); + macs_dict->Set(path, in_value->DeepCopy()); +} + +bool DictionaryHashStoreContents::RemoveEntry(const std::string& path) { + base::DictionaryValue* macs_dict = GetMutableContents(false); + if (macs_dict) + return macs_dict->RemovePath(path, NULL); + + return false; } std::string DictionaryHashStoreContents::GetSuperMac() const { @@ -93,3 +115,20 @@ std::string DictionaryHashStoreContents::GetSuperMac() const { void DictionaryHashStoreContents::SetSuperMac(const std::string& super_mac) { storage_->SetString(kSuperMACPref, super_mac); } + +const base::DictionaryValue* DictionaryHashStoreContents::GetContents() const { + const base::DictionaryValue* macs_dict = NULL; + storage_->GetDictionary(kPreferenceMACs, &macs_dict); + return macs_dict; +} + +base::DictionaryValue* DictionaryHashStoreContents::GetMutableContents( + bool create_if_null) { + base::DictionaryValue* macs_dict = NULL; + storage_->GetDictionary(kPreferenceMACs, &macs_dict); + if (!macs_dict && create_if_null) { + macs_dict = new base::DictionaryValue; + storage_->Set(kPreferenceMACs, macs_dict); + } + return macs_dict; +} diff --git a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h index b47d0e0bce4..f231c257bdd 100644 --- a/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h +++ b/chromium/components/user_prefs/tracked/dictionary_hash_store_contents.h @@ -5,12 +5,12 @@ #ifndef COMPONENTS_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_ #define COMPONENTS_USER_PREFS_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_ -#include "base/compiler_specific.h" #include "base/macros.h" #include "components/user_prefs/tracked/hash_store_contents.h" namespace base { class DictionaryValue; +class Value; } // namespace base namespace user_prefs { @@ -31,17 +31,31 @@ class DictionaryHashStoreContents : public HashStoreContents { static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); // HashStoreContents implementation - std::string hash_store_id() const override; + bool IsCopyable() const override; + std::unique_ptr<HashStoreContents> MakeCopy() const override; + base::StringPiece GetUMASuffix() const override; void Reset() override; - bool IsInitialized() const override; + bool GetMac(const std::string& path, std::string* out_value) override; + bool GetSplitMacs(const std::string& path, + std::map<std::string, std::string>* split_macs) override; + void SetMac(const std::string& path, const std::string& value) override; + void SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) override; + void ImportEntry(const std::string& path, + const base::Value* in_value) override; + bool RemoveEntry(const std::string& path) override; const base::DictionaryValue* GetContents() const override; - std::unique_ptr<MutableDictionary> GetMutableContents() override; std::string GetSuperMac() const override; void SetSuperMac(const std::string& super_mac) override; private: base::DictionaryValue* storage_; + // Helper function to get a mutable version of the macs from |storage_|, + // creating it if needed and |create_if_null| is true. + base::DictionaryValue* GetMutableContents(bool create_if_null); + DISALLOW_COPY_AND_ASSIGN(DictionaryHashStoreContents); }; diff --git a/chromium/components/user_prefs/tracked/hash_store_contents.h b/chromium/components/user_prefs/tracked/hash_store_contents.h index 94323843cc1..9cc8abba090 100644 --- a/chromium/components/user_prefs/tracked/hash_store_contents.h +++ b/chromium/components/user_prefs/tracked/hash_store_contents.h @@ -5,12 +5,15 @@ #ifndef COMPONENTS_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_ #define COMPONENTS_USER_PREFS_TRACKED_HASH_STORE_CONTENTS_H_ +#include <map> #include <memory> #include <string> +#include "base/strings/string_piece.h" namespace base { class DictionaryValue; +class Value; } // namespace base // Provides access to the contents of a preference hash store. The store @@ -19,41 +22,65 @@ class DictionaryValue; // MACs. // Version: a client-defined version number for the format of Contents. // Super MAC: a MAC that authenticates the entirety of Contents. -// Legacy hash stores may have an ID that was incorporated into MAC -// calculations. The ID, if any, is available via |hash_store_id()|. class HashStoreContents { public: - // Used to modify a DictionaryValue stored in the preference hash store. The - // MutableDictionary should be destroyed when modifications are complete in - // order to allow them to be committed to the underlying storage. - class MutableDictionary { - public: - virtual ~MutableDictionary() {} - // Returns the DictionaryValue, which will be created if it does not already - // exist. - virtual base::DictionaryValue* operator->() = 0; - }; - virtual ~HashStoreContents() {} - // Returns the hash-store ID. May be empty. - virtual std::string hash_store_id() const = 0; + // Returns true if this implementation of HashStoreContents can be copied via + // MakeCopy(). + virtual bool IsCopyable() const = 0; + + // Returns a copy of this HashStoreContents. Must only be called on + // lightweight implementations (which return true from IsCopyable()) and only + // in scenarios where a copy cannot be avoided. + virtual std::unique_ptr<HashStoreContents> MakeCopy() const = 0; + + // Returns the suffix to be appended to UMA histograms for this store type. + // The returned value must either be an empty string or one of the values in + // histograms.xml's TrackedPreferencesExternalValidators. + virtual base::StringPiece GetUMASuffix() const = 0; // Discards all data related to this hash store. virtual void Reset() = 0; - // Indicates whether any data is currently stored for this hash store. - virtual bool IsInitialized() const = 0; + // Outputs the MAC validating the preference at path. Returns true if a MAC + // was successfully read and false otherwise. + virtual bool GetMac(const std::string& path, std::string* out_value) = 0; - // Retrieves the contents of this hash store. May return NULL if the hash - // store has not been initialized. - virtual const base::DictionaryValue* GetContents() const = 0; + // Outputs the MACS validating the split preference at path. Returns true if + // MACS were successfully read and false otherwise. + virtual bool GetSplitMacs(const std::string& path, + std::map<std::string, std::string>* out_value) = 0; + + // Set the MAC validating the preference at path. + virtual void SetMac(const std::string& path, const std::string& value) = 0; - // Provides mutable access to the contents of this hash store. - virtual std::unique_ptr<MutableDictionary> GetMutableContents() = 0; + // Set the MAC validating the split preference at path and split_path. + // For example, |path| is 'extension' and |split_path| is some extenson id. + virtual void SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) = 0; + + // Sets the MAC for the preference at |path|. + // If |path| is a split preference |in_value| must be a DictionaryValue whose + // keys are keys in the split preference and whose values are MACs of the + // corresponding values in the split preference. + // If |path| is an atomic preference |in_value| must be a StringValue + // containing a MAC of the preference value. + virtual void ImportEntry(const std::string& path, + const base::Value* in_value) = 0; + + // Removes the MAC (for atomic preferences) or MACs (for split preferences) + // at |path|. Returns true if there was an entry at |path| which was + // successfully removed. + virtual bool RemoveEntry(const std::string& path) = 0; + + // Only needed if this store supports super MACs. + virtual const base::DictionaryValue* GetContents() const = 0; // Retrieves the super MAC value previously stored by SetSuperMac. May be - // empty if no super MAC has been stored. + // empty if no super MAC has been stored or if this store does not support + // super MACs. virtual std::string GetSuperMac() const = 0; // Stores a super MAC value for this hash store. diff --git a/chromium/components/user_prefs/tracked/mock_validation_delegate.cc b/chromium/components/user_prefs/tracked/mock_validation_delegate.cc index d2936af55be..e0e88283c48 100644 --- a/chromium/components/user_prefs/tracked/mock_validation_delegate.cc +++ b/chromium/components/user_prefs/tracked/mock_validation_delegate.cc @@ -20,6 +20,16 @@ size_t MockValidationDelegate::CountValidationsOfState( return count; } +size_t MockValidationDelegate::CountExternalValidationsOfState( + PrefHashStoreTransaction::ValueState value_state) const { + size_t count = 0; + for (size_t i = 0; i < validations_.size(); ++i) { + if (validations_[i].external_validation_value_state == value_state) + ++count; + } + return count; +} + const MockValidationDelegate::ValidationEvent* MockValidationDelegate::GetEventForPath(const std::string& pref_path) const { for (size_t i = 0; i < validations_.size(); ++i) { @@ -33,26 +43,31 @@ void MockValidationDelegate::OnAtomicPreferenceValidation( const std::string& pref_path, const base::Value* value, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal) { - RecordValidation(pref_path, value_state, is_personal, - PrefHashFilter::TRACKING_STRATEGY_ATOMIC); + RecordValidation(pref_path, value_state, external_validation_value_state, + is_personal, PrefHashFilter::TRACKING_STRATEGY_ATOMIC); } void MockValidationDelegate::OnSplitPreferenceValidation( const std::string& pref_path, const base::DictionaryValue* dict_value, const std::vector<std::string>& invalid_keys, + const std::vector<std::string>& external_validation_invalid_keys, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal) { - RecordValidation(pref_path, value_state, is_personal, - PrefHashFilter::TRACKING_STRATEGY_SPLIT); + RecordValidation(pref_path, value_state, external_validation_value_state, + is_personal, PrefHashFilter::TRACKING_STRATEGY_SPLIT); } void MockValidationDelegate::RecordValidation( const std::string& pref_path, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal, PrefHashFilter::PrefTrackingStrategy strategy) { - validations_.push_back( - ValidationEvent(pref_path, value_state, is_personal, strategy)); + validations_.push_back(ValidationEvent(pref_path, value_state, + external_validation_value_state, + is_personal, strategy)); } diff --git a/chromium/components/user_prefs/tracked/mock_validation_delegate.h b/chromium/components/user_prefs/tracked/mock_validation_delegate.h index 0b8cb12ce43..de95f0599ed 100644 --- a/chromium/components/user_prefs/tracked/mock_validation_delegate.h +++ b/chromium/components/user_prefs/tracked/mock_validation_delegate.h @@ -20,17 +20,21 @@ class MockValidationDelegate : public TrackedPreferenceValidationDelegate { public: struct ValidationEvent { - ValidationEvent(const std::string& path, - PrefHashStoreTransaction::ValueState state, - bool is_personal, - PrefHashFilter::PrefTrackingStrategy tracking_strategy) + ValidationEvent( + const std::string& path, + PrefHashStoreTransaction::ValueState state, + PrefHashStoreTransaction::ValueState external_validation_state, + bool is_personal, + PrefHashFilter::PrefTrackingStrategy tracking_strategy) : pref_path(path), value_state(state), + external_validation_value_state(external_validation_state), is_personal(is_personal), strategy(tracking_strategy) {} std::string pref_path; PrefHashStoreTransaction::ValueState value_state; + PrefHashStoreTransaction::ValueState external_validation_value_state; bool is_personal; PrefHashFilter::PrefTrackingStrategy strategy; }; @@ -45,6 +49,10 @@ class MockValidationDelegate : public TrackedPreferenceValidationDelegate { size_t CountValidationsOfState( PrefHashStoreTransaction::ValueState value_state) const; + // Returns the number of external validations of a given value state. + size_t CountExternalValidationsOfState( + PrefHashStoreTransaction::ValueState value_state) const; + // Returns the event for the preference with a given path. const ValidationEvent* GetEventForPath(const std::string& pref_path) const; @@ -53,20 +61,25 @@ class MockValidationDelegate : public TrackedPreferenceValidationDelegate { const std::string& pref_path, const base::Value* value, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal) override; void OnSplitPreferenceValidation( const std::string& pref_path, const base::DictionaryValue* dict_value, const std::vector<std::string>& invalid_keys, + const std::vector<std::string>& external_validation_invalid_keys, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal) override; private: // Adds a new validation event. - void RecordValidation(const std::string& pref_path, - PrefHashStoreTransaction::ValueState value_state, - bool is_personal, - PrefHashFilter::PrefTrackingStrategy strategy); + void RecordValidation( + const std::string& pref_path, + PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, + bool is_personal, + PrefHashFilter::PrefTrackingStrategy strategy); std::vector<ValidationEvent> validations_; diff --git a/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc index a2de0466ef2..1b3ecd793f5 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc +++ b/chromium/components/user_prefs/tracked/pref_hash_calculator_unittest.cc @@ -8,6 +8,7 @@ #include <string> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "base/values.h" #include "testing/gtest/include/gtest/gtest.h" @@ -91,9 +92,9 @@ TEST(PrefHashCalculatorTest, CatchHashChanges) { nested_empty_dict->Set("a", new base::DictionaryValue); nested_empty_dict->Set("b", new base::ListValue); std::unique_ptr<base::ListValue> nested_empty_list(new base::ListValue); - nested_empty_list->Append(new base::DictionaryValue); - nested_empty_list->Append(new base::ListValue); - nested_empty_list->Append(nested_empty_dict->DeepCopy()); + nested_empty_list->Append(base::MakeUnique<base::DictionaryValue>()); + nested_empty_list->Append(base::MakeUnique<base::ListValue>()); + nested_empty_list->Append(nested_empty_dict->CreateDeepCopy()); // A dictionary with an empty dictionary, an empty list, and nested empty // dictionaries/lists in it. diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter.cc b/chromium/components/user_prefs/tracked/pref_hash_filter.cc index 2f0c6e71f5f..1101080cd76 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_filter.cc +++ b/chromium/components/user_prefs/tracked/pref_hash_filter.cc @@ -8,9 +8,11 @@ #include <algorithm> #include <utility> +#include "base/bind.h" #include "base/logging.h" #include "base/macros.h" -#include "base/metrics/histogram.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "base/values.h" @@ -51,16 +53,27 @@ void CleanupDeprecatedTrackedPreferences( PrefHashFilter::PrefHashFilter( std::unique_ptr<PrefHashStore> pref_hash_store, + StoreContentsPair external_validation_hash_store_pair, const std::vector<TrackedPreferenceMetadata>& tracked_preferences, const base::Closure& on_reset_on_load, TrackedPreferenceValidationDelegate* delegate, size_t reporting_ids_count, bool report_super_mac_validity) : pref_hash_store_(std::move(pref_hash_store)), + external_validation_hash_store_pair_( + external_validation_hash_store_pair.first + ? base::make_optional( + std::move(external_validation_hash_store_pair)) + : base::nullopt), on_reset_on_load_(on_reset_on_load), report_super_mac_validity_(report_super_mac_validity) { DCHECK(pref_hash_store_); DCHECK_GE(reporting_ids_count, tracked_preferences.size()); + // Verify that, if |external_validation_hash_store_pair_| is present, both its + // items are non-null. + DCHECK(!external_validation_hash_store_pair_.has_value() || + (external_validation_hash_store_pair_->first && + external_validation_hash_store_pair_->second)); for (size_t i = 0; i < tracked_preferences.size(); ++i) { const TrackedPreferenceMetadata& metadata = tracked_preferences[i]; @@ -132,14 +145,14 @@ void PrefHashFilter::ClearResetTime(PrefService* user_prefs) { } void PrefHashFilter::Initialize(base::DictionaryValue* pref_store_contents) { + DictionaryHashStoreContents dictionary_contents(pref_store_contents); std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction( - pref_hash_store_->BeginTransaction(std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(pref_store_contents)))); + pref_hash_store_->BeginTransaction(&dictionary_contents)); for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin(); it != tracked_paths_.end(); ++it) { const std::string& initialized_path = it->first; const TrackedPreference* initialized_preference = it->second; - const base::Value* value = NULL; + const base::Value* value = nullptr; pref_store_contents->Get(initialized_path, &value); initialized_preference->OnNewValue(value, hash_store_transaction.get()); } @@ -156,30 +169,42 @@ void PrefHashFilter::FilterUpdate(const std::string& path) { // Updates the stored hashes for |changed_paths_| before serializing data to // disk. This is required as storing the hash everytime a pref's value changes // is too expensive (see perf regression @ http://crbug.com/331273). -void PrefHashFilter::FilterSerializeData( +PrefFilter::OnWriteCallbackPair PrefHashFilter::FilterSerializeData( base::DictionaryValue* pref_store_contents) { + // Generate the callback pair before clearing |changed_paths_|. + PrefFilter::OnWriteCallbackPair callback_pair = + GetOnWriteSynchronousCallbacks(pref_store_contents); + if (!changed_paths_.empty()) { base::TimeTicks checkpoint = base::TimeTicks::Now(); { + DictionaryHashStoreContents dictionary_contents(pref_store_contents); std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction( - pref_hash_store_->BeginTransaction(std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(pref_store_contents)))); + pref_hash_store_->BeginTransaction(&dictionary_contents)); + + std::unique_ptr<PrefHashStoreTransaction> + external_validation_hash_store_transaction; + if (external_validation_hash_store_pair_) { + external_validation_hash_store_transaction = + external_validation_hash_store_pair_->first->BeginTransaction( + external_validation_hash_store_pair_->second.get()); + } + for (ChangedPathsMap::const_iterator it = changed_paths_.begin(); it != changed_paths_.end(); ++it) { const std::string& changed_path = it->first; const TrackedPreference* changed_preference = it->second; - const base::Value* value = NULL; + const base::Value* value = nullptr; pref_store_contents->Get(changed_path, &value); changed_preference->OnNewValue(value, hash_store_transaction.get()); } changed_paths_.clear(); } - // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing - // data has been gathered from the wild to be confident this doesn't - // significantly affect performance on the UI thread. UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime", base::TimeTicks::Now() - checkpoint); } + + return callback_pair; } void PrefHashFilter::FinalizeFilterOnLoad( @@ -191,9 +216,17 @@ void PrefHashFilter::FinalizeFilterOnLoad( bool did_reset = false; { + DictionaryHashStoreContents dictionary_contents(pref_store_contents.get()); std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction( - pref_hash_store_->BeginTransaction(std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(pref_store_contents.get())))); + pref_hash_store_->BeginTransaction(&dictionary_contents)); + + std::unique_ptr<PrefHashStoreTransaction> + external_validation_hash_store_transaction; + if (external_validation_hash_store_pair_) { + external_validation_hash_store_transaction = + external_validation_hash_store_pair_->first->BeginTransaction( + external_validation_hash_store_pair_->second.get()); + } CleanupDeprecatedTrackedPreferences( pref_store_contents.get(), hash_store_transaction.get()); @@ -205,8 +238,9 @@ void PrefHashFilter::FinalizeFilterOnLoad( for (TrackedPreferencesMap::const_iterator it = tracked_paths_.begin(); it != tracked_paths_.end(); ++it) { - if (it->second->EnforceAndReport(pref_store_contents.get(), - hash_store_transaction.get())) { + if (it->second->EnforceAndReport( + pref_store_contents.get(), hash_store_transaction.get(), + external_validation_hash_store_transaction.get())) { did_reset = true; prefs_altered = true; } @@ -225,12 +259,114 @@ void PrefHashFilter::FinalizeFilterOnLoad( on_reset_on_load_.Run(); } - // TODO(gab): Remove this histogram by Feb 21 2014; after sufficient timing - // data has been gathered from the wild to be confident this doesn't - // significantly affect startup. UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime", base::TimeTicks::Now() - checkpoint); post_filter_on_load_callback.Run(std::move(pref_store_contents), prefs_altered); } + +// static +void PrefHashFilter::ClearFromExternalStore( + HashStoreContents* external_validation_hash_store_contents, + const base::DictionaryValue* changed_paths_and_macs) { + DCHECK(!changed_paths_and_macs->empty()); + + for (base::DictionaryValue::Iterator it(*changed_paths_and_macs); + !it.IsAtEnd(); it.Advance()) { + external_validation_hash_store_contents->RemoveEntry(it.key()); + } +} + +// static +void PrefHashFilter::FlushToExternalStore( + std::unique_ptr<HashStoreContents> external_validation_hash_store_contents, + std::unique_ptr<base::DictionaryValue> changed_paths_and_macs, + bool write_success) { + DCHECK(!changed_paths_and_macs->empty()); + DCHECK(external_validation_hash_store_contents); + if (!write_success) + return; + + for (base::DictionaryValue::Iterator it(*changed_paths_and_macs); + !it.IsAtEnd(); it.Advance()) { + const std::string& changed_path = it.key(); + + const base::DictionaryValue* split_values = nullptr; + if (it.value().GetAsDictionary(&split_values)) { + for (base::DictionaryValue::Iterator inner_it(*split_values); + !inner_it.IsAtEnd(); inner_it.Advance()) { + std::string mac; + bool is_string = inner_it.value().GetAsString(&mac); + DCHECK(is_string); + + external_validation_hash_store_contents->SetSplitMac( + changed_path, inner_it.key(), mac); + } + } else { + const base::StringValue* value_as_string; + bool is_string = it.value().GetAsString(&value_as_string); + DCHECK(is_string); + + external_validation_hash_store_contents->SetMac( + changed_path, value_as_string->GetString()); + } + } +} + +PrefFilter::OnWriteCallbackPair PrefHashFilter::GetOnWriteSynchronousCallbacks( + base::DictionaryValue* pref_store_contents) { + if (changed_paths_.empty() || !external_validation_hash_store_pair_) { + return std::make_pair(base::Closure(), + base::Callback<void(bool success)>()); + } + + std::unique_ptr<base::DictionaryValue> changed_paths_macs = + base::MakeUnique<base::DictionaryValue>(); + + for (ChangedPathsMap::const_iterator it = changed_paths_.begin(); + it != changed_paths_.end(); ++it) { + const std::string& changed_path = it->first; + const TrackedPreference* changed_preference = it->second; + + switch (changed_preference->GetType()) { + case TrackedPreferenceType::ATOMIC: { + const base::Value* new_value = nullptr; + pref_store_contents->Get(changed_path, &new_value); + changed_paths_macs->SetStringWithoutPathExpansion( + changed_path, + external_validation_hash_store_pair_->first->ComputeMac( + changed_path, new_value)); + break; + } + case TrackedPreferenceType::SPLIT: { + const base::DictionaryValue* dict_value = nullptr; + pref_store_contents->GetDictionary(changed_path, &dict_value); + changed_paths_macs->SetWithoutPathExpansion( + changed_path, + external_validation_hash_store_pair_->first->ComputeSplitMacs( + changed_path, dict_value)); + break; + } + } + } + + DCHECK(external_validation_hash_store_pair_->second->IsCopyable()) + << "External HashStoreContents must be copyable as it needs to be used " + "off-thread"; + + std::unique_ptr<HashStoreContents> hash_store_contents_copy = + external_validation_hash_store_pair_->second->MakeCopy(); + + // We can use raw pointers for the first callback instead of making more + // copies as it will be executed in sequence before the second callback, + // which owns the pointers. + HashStoreContents* raw_contents = hash_store_contents_copy.get(); + base::DictionaryValue* raw_changed_paths_macs = changed_paths_macs.get(); + + return std::make_pair( + base::Bind(&ClearFromExternalStore, base::Unretained(raw_contents), + base::Unretained(raw_changed_paths_macs)), + base::Bind(&FlushToExternalStore, base::Passed(&hash_store_contents_copy), + base::Passed(&changed_paths_macs))); +} diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter.h b/chromium/components/user_prefs/tracked/pref_hash_filter.h index 8652a7f817c..07c92db9506 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_filter.h +++ b/chromium/components/user_prefs/tracked/pref_hash_filter.h @@ -15,7 +15,10 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/containers/scoped_ptr_hash_map.h" +#include "base/files/file_path.h" #include "base/macros.h" +#include "base/optional.h" +#include "components/user_prefs/tracked/hash_store_contents.h" #include "components/user_prefs/tracked/interceptable_pref_filter.h" #include "components/user_prefs/tracked/tracked_preference.h" @@ -64,6 +67,9 @@ class PrefHashFilter : public InterceptablePrefFilter { ValueType value_type; }; + using StoreContentsPair = std::pair<std::unique_ptr<PrefHashStore>, + std::unique_ptr<HashStoreContents>>; + // Constructs a PrefHashFilter tracking the specified |tracked_preferences| // using |pref_hash_store| to check/store hashes. An optional |delegate| is // notified of the status of each preference as it is checked. @@ -73,8 +79,11 @@ class PrefHashFilter : public InterceptablePrefFilter { // than |tracked_preferences.size()|). If |report_super_mac_validity| is true, // the state of the super MAC will be reported via UMA during // FinalizeFilterOnLoad. + // |external_validation_hash_store_pair_| will be used (if non-null) to + // perform extra validations without triggering resets. PrefHashFilter( std::unique_ptr<PrefHashStore> pref_hash_store, + StoreContentsPair external_validation_hash_store_pair_, const std::vector<TrackedPreferenceMetadata>& tracked_preferences, const base::Closure& on_reset_on_load, TrackedPreferenceValidationDelegate* delegate, @@ -101,7 +110,8 @@ class PrefHashFilter : public InterceptablePrefFilter { // PrefFilter remaining implementation. void FilterUpdate(const std::string& path) override; - void FilterSerializeData(base::DictionaryValue* pref_store_contents) override; + OnWriteCallbackPair FilterSerializeData( + base::DictionaryValue* pref_store_contents) override; private: // InterceptablePrefFilter implementation. @@ -110,6 +120,25 @@ class PrefHashFilter : public InterceptablePrefFilter { std::unique_ptr<base::DictionaryValue> pref_store_contents, bool prefs_altered) override; + // Helper function to generate FilterSerializeData()'s pre-write and + // post-write callbacks. The returned callbacks are thread-safe. + OnWriteCallbackPair GetOnWriteSynchronousCallbacks( + base::DictionaryValue* pref_store_contents); + + // Clears the MACs contained in |external_validation_hash_store_contents| + // which are present in |paths_to_clear|. + static void ClearFromExternalStore( + HashStoreContents* external_validation_hash_store_contents, + const base::DictionaryValue* changed_paths_and_macs); + + // Flushes the MACs contained in |changed_paths_and_mac| to + // external_hash_store_contents if |write_success|, otherwise discards the + // changes. + static void FlushToExternalStore( + std::unique_ptr<HashStoreContents> external_hash_store_contents, + std::unique_ptr<base::DictionaryValue> changed_paths_and_macs, + bool write_success); + // Callback to be invoked only once (and subsequently reset) on the next // FilterOnLoad event. It will be allowed to modify the |prefs| handed to // FilterOnLoad before handing them back to this PrefHashFilter. @@ -120,12 +149,18 @@ class PrefHashFilter : public InterceptablePrefFilter { typedef base::ScopedPtrHashMap<std::string, std::unique_ptr<TrackedPreference>> TrackedPreferencesMap; + // A map from changed paths to their corresponding TrackedPreferences (which // aren't owned by this map). typedef std::map<std::string, const TrackedPreference*> ChangedPathsMap; std::unique_ptr<PrefHashStore> pref_hash_store_; + // A store and contents on which to perform extra validations without + // triggering resets. + // Will be null if the platform does not support external validation. + const base::Optional<StoreContentsPair> external_validation_hash_store_pair_; + // Invoked if a reset occurs in a call to FilterOnLoad. const base::Closure on_reset_on_load_; diff --git a/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc index 97201b5a1e6..1d3afd4b9fc 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc +++ b/chromium/components/user_prefs/tracked/pref_hash_filter_unittest.cc @@ -18,7 +18,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/macros.h" -#include "base/memory/ref_counted.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_base.h" #include "base/metrics/histogram_samples.h" #include "base/metrics/statistics_recorder.h" @@ -157,7 +157,12 @@ class MockPrefHashStore : public PrefHashStore { // PrefHashStore implementation. std::unique_ptr<PrefHashStoreTransaction> BeginTransaction( - std::unique_ptr<HashStoreContents> storage) override; + HashStoreContents* storage) override; + std::string ComputeMac(const std::string& path, + const base::Value* new_value) override; + std::unique_ptr<base::DictionaryValue> ComputeSplitMacs( + const std::string& path, + const base::DictionaryValue* split_values) override; private: // A MockPrefHashStoreTransaction is handed to the caller on @@ -175,6 +180,7 @@ class MockPrefHashStore : public PrefHashStore { } // PrefHashStoreTransaction implementation. + base::StringPiece GetStoreUMASuffix() const override; PrefHashStoreTransaction::ValueState CheckValue( const std::string& path, const base::Value* value) const override; @@ -247,12 +253,29 @@ void MockPrefHashStore::SetInvalidKeysResult( } std::unique_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction( - std::unique_ptr<HashStoreContents> storage) { + HashStoreContents* storage) { EXPECT_FALSE(transaction_active_); return std::unique_ptr<PrefHashStoreTransaction>( new MockPrefHashStoreTransaction(this)); } +std::string MockPrefHashStore::ComputeMac(const std::string& path, + const base::Value* new_value) { + return "atomic mac for: " + path; +}; + +std::unique_ptr<base::DictionaryValue> MockPrefHashStore::ComputeSplitMacs( + const std::string& path, + const base::DictionaryValue* split_values) { + std::unique_ptr<base::DictionaryValue> macs_dict(new base::DictionaryValue); + for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd(); + it.Advance()) { + macs_dict->SetStringWithoutPathExpansion( + it.key(), "split mac for: " + path + "/" + it.key()); + } + return macs_dict; +}; + PrefHashStoreTransaction::ValueState MockPrefHashStore::RecordCheckValue( const std::string& path, const base::Value* value, @@ -279,6 +302,11 @@ void MockPrefHashStore::RecordStoreHash( .second); } +base::StringPiece +MockPrefHashStore::MockPrefHashStoreTransaction::GetStoreUMASuffix() const { + return "unused"; +} + PrefHashStoreTransaction::ValueState MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue( const std::string& path, @@ -359,6 +387,189 @@ std::vector<PrefHashFilter::TrackedPreferenceMetadata> GetConfiguration( return configuration; } +class MockHashStoreContents : public HashStoreContents { + public: + MockHashStoreContents(){}; + + // Returns the number of hashes stored. + size_t stored_hashes_count() const { return dictionary_.size(); } + + // Returns the number of paths cleared. + size_t cleared_paths_count() const { return removed_entries_.size(); } + + // Returns the stored MAC for an Atomic preference. + std::string GetStoredMac(const std::string& path) const; + // Returns the stored MAC for a Split preference. + std::string GetStoredSplitMac(const std::string& path, + const std::string& split_path) const; + + // HashStoreContents implementation. + bool IsCopyable() const override; + std::unique_ptr<HashStoreContents> MakeCopy() const override; + base::StringPiece GetUMASuffix() const override; + void Reset() override; + bool GetMac(const std::string& path, std::string* out_value) override; + bool GetSplitMacs(const std::string& path, + std::map<std::string, std::string>* split_macs) override; + void SetMac(const std::string& path, const std::string& value) override; + void SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) override; + void ImportEntry(const std::string& path, + const base::Value* in_value) override; + bool RemoveEntry(const std::string& path) override; + const base::DictionaryValue* GetContents() const override; + std::string GetSuperMac() const override; + void SetSuperMac(const std::string& super_mac) override; + + private: + MockHashStoreContents(MockHashStoreContents* origin_mock); + + // Records calls to this mock's SetMac/SetSplitMac methods. + void RecordSetMac(const std::string& path, const std::string& mac) { + dictionary_.SetStringWithoutPathExpansion(path, mac); + } + void RecordSetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& mac) { + base::DictionaryValue* mac_dict = nullptr; + dictionary_.GetDictionaryWithoutPathExpansion(path, &mac_dict); + if (!mac_dict) { + mac_dict = new base::DictionaryValue; + dictionary_.SetWithoutPathExpansion(path, mac_dict); + } + mac_dict->SetStringWithoutPathExpansion(split_path, mac); + } + + // Records a call to this mock's RemoveEntry method. + void RecordRemoveEntry(const std::string& path) { + // Don't expect the same pref to be cleared more than once. + EXPECT_EQ(removed_entries_.end(), removed_entries_.find(path)); + removed_entries_.insert(path); + } + + base::DictionaryValue dictionary_; + std::set<std::string> removed_entries_; + + // The code being tested copies its HashStoreContents for use in a callback + // which can be executed during shutdown. To be able to capture the behavior + // of the copy, we make it forward calls to the mock it was created from. + // Once set, |origin_mock_| must outlive this instance. + MockHashStoreContents* origin_mock_; + + DISALLOW_COPY_AND_ASSIGN(MockHashStoreContents); +}; + +std::string MockHashStoreContents::GetStoredMac(const std::string& path) const { + const base::Value* out_value; + if (dictionary_.GetWithoutPathExpansion(path, &out_value)) { + const base::StringValue* value_as_string; + EXPECT_TRUE(out_value->GetAsString(&value_as_string)); + + return value_as_string->GetString(); + } + + return std::string(); +} + +std::string MockHashStoreContents::GetStoredSplitMac( + const std::string& path, + const std::string& split_path) const { + const base::Value* out_value; + if (dictionary_.GetWithoutPathExpansion(path, &out_value)) { + const base::DictionaryValue* value_as_dict; + EXPECT_TRUE(out_value->GetAsDictionary(&value_as_dict)); + + if (value_as_dict->GetWithoutPathExpansion(split_path, &out_value)) { + const base::StringValue* value_as_string; + EXPECT_TRUE(out_value->GetAsString(&value_as_string)); + + return value_as_string->GetString(); + } + } + + return std::string(); +} + +MockHashStoreContents::MockHashStoreContents(MockHashStoreContents* origin_mock) + : origin_mock_(origin_mock) {} + +bool MockHashStoreContents::IsCopyable() const { + return true; +} + +std::unique_ptr<HashStoreContents> MockHashStoreContents::MakeCopy() const { + // Return a new MockHashStoreContents which forwards all requests to this + // mock instance. + return std::unique_ptr<HashStoreContents>( + new MockHashStoreContents(const_cast<MockHashStoreContents*>(this))); +} + +base::StringPiece MockHashStoreContents::GetUMASuffix() const { + return "Unused"; +} + +void MockHashStoreContents::Reset() { + ADD_FAILURE() << "Unexpected call."; +} + +bool MockHashStoreContents::GetMac(const std::string& path, + std::string* out_value) { + ADD_FAILURE() << "Unexpected call."; + return false; +} + +bool MockHashStoreContents::GetSplitMacs( + const std::string& path, + std::map<std::string, std::string>* split_macs) { + ADD_FAILURE() << "Unexpected call."; + return false; +} + +void MockHashStoreContents::SetMac(const std::string& path, + const std::string& value) { + if (origin_mock_) + origin_mock_->RecordSetMac(path, value); + else + RecordSetMac(path, value); +} + +void MockHashStoreContents::SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) { + if (origin_mock_) + origin_mock_->RecordSetSplitMac(path, split_path, value); + else + RecordSetSplitMac(path, split_path, value); +} + +void MockHashStoreContents::ImportEntry(const std::string& path, + const base::Value* in_value) { + ADD_FAILURE() << "Unexpected call."; +} + +bool MockHashStoreContents::RemoveEntry(const std::string& path) { + if (origin_mock_) + origin_mock_->RecordRemoveEntry(path); + else + RecordRemoveEntry(path); + return true; +} + +const base::DictionaryValue* MockHashStoreContents::GetContents() const { + ADD_FAILURE() << "Unexpected call."; + return nullptr; +} + +std::string MockHashStoreContents::GetSuperMac() const { + ADD_FAILURE() << "Unexpected call."; + return std::string(); +} + +void MockHashStoreContents::SetSuperMac(const std::string& super_mac) { + ADD_FAILURE() << "Unexpected call."; +} + class PrefHashFilterTest : public testing::TestWithParam<PrefHashFilter::EnforcementLevel> { public: @@ -386,9 +597,22 @@ class PrefHashFilterTest PrefHashFilter::TrackedPreferenceMetadata>& configuration) { std::unique_ptr<MockPrefHashStore> temp_mock_pref_hash_store( new MockPrefHashStore); + std::unique_ptr<MockPrefHashStore> + temp_mock_external_validation_pref_hash_store(new MockPrefHashStore); + std::unique_ptr<MockHashStoreContents> + temp_mock_external_validation_hash_store_contents( + new MockHashStoreContents); mock_pref_hash_store_ = temp_mock_pref_hash_store.get(); + mock_external_validation_pref_hash_store_ = + temp_mock_external_validation_pref_hash_store.get(); + mock_external_validation_hash_store_contents_ = + temp_mock_external_validation_hash_store_contents.get(); pref_hash_filter_.reset(new PrefHashFilter( - std::move(temp_mock_pref_hash_store), configuration, + std::move(temp_mock_pref_hash_store), + PrefHashFilter::StoreContentsPair( + std::move(temp_mock_external_validation_pref_hash_store), + std::move(temp_mock_external_validation_hash_store_contents)), + configuration, base::Bind(&PrefHashFilterTest::RecordReset, base::Unretained(this)), &mock_validation_delegate_, arraysize(kTestTrackedPrefs), true)); } @@ -414,6 +638,8 @@ class PrefHashFilterTest } MockPrefHashStore* mock_pref_hash_store_; + MockPrefHashStore* mock_external_validation_pref_hash_store_; + MockHashStoreContents* mock_external_validation_hash_store_contents_; std::unique_ptr<base::DictionaryValue> pref_store_contents_; MockValidationDelegate mock_validation_delegate_; std::unique_ptr<PrefHashFilter> pref_hash_filter_; @@ -1035,6 +1261,132 @@ TEST_P(PrefHashFilterTest, DontResetReportOnly) { } } +TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacks) { + base::DictionaryValue root_dict; + // Ownership of the following values is transfered to |root_dict|. + base::Value* int_value1 = new base::FundamentalValue(1); + base::Value* int_value2 = new base::FundamentalValue(2); + base::DictionaryValue* dict_value = new base::DictionaryValue; + dict_value->Set("a", new base::FundamentalValue(true)); + root_dict.Set(kAtomicPref, int_value1); + root_dict.Set(kAtomicPref2, int_value2); + root_dict.Set(kSplitPref, dict_value); + + // Skip updating kAtomicPref2. + pref_hash_filter_->FilterUpdate(kAtomicPref); + pref_hash_filter_->FilterUpdate(kSplitPref); + + PrefHashFilter::OnWriteCallbackPair callbacks = + pref_hash_filter_->FilterSerializeData(&root_dict); + + ASSERT_FALSE(callbacks.first.is_null()); + + // Prefs should be cleared from the external validation store only once the + // before-write callback is run. + ASSERT_EQ( + 0u, mock_external_validation_hash_store_contents_->cleared_paths_count()); + callbacks.first.Run(); + ASSERT_EQ( + 2u, mock_external_validation_hash_store_contents_->cleared_paths_count()); + + // No pref write should occur before the after-write callback is run. + ASSERT_EQ( + 0u, mock_external_validation_hash_store_contents_->stored_hashes_count()); + + callbacks.second.Run(true); + + ASSERT_EQ( + 2u, mock_external_validation_hash_store_contents_->stored_hashes_count()); + ASSERT_EQ( + "atomic mac for: atomic_pref", + mock_external_validation_hash_store_contents_->GetStoredMac(kAtomicPref)); + ASSERT_EQ("split mac for: split_pref/a", + mock_external_validation_hash_store_contents_->GetStoredSplitMac( + kSplitPref, "a")); + + // The callbacks should write directly to the contents without going through + // a pref hash store. + ASSERT_EQ(0u, + mock_external_validation_pref_hash_store_->stored_paths_count()); +} + +TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacksWithFailure) { + base::DictionaryValue root_dict; + // Ownership of the following values is transfered to |root_dict|. + base::Value* int_value1 = new base::FundamentalValue(1); + root_dict.Set(kAtomicPref, int_value1); + + // Only update kAtomicPref. + pref_hash_filter_->FilterUpdate(kAtomicPref); + + PrefHashFilter::OnWriteCallbackPair callbacks = + pref_hash_filter_->FilterSerializeData(&root_dict); + + ASSERT_FALSE(callbacks.first.is_null()); + + callbacks.first.Run(); + + // The pref should have been cleared from the external validation store. + ASSERT_EQ( + 1u, mock_external_validation_hash_store_contents_->cleared_paths_count()); + + callbacks.second.Run(false); + + // Expect no writes to the external validation hash store contents. + ASSERT_EQ(0u, + mock_external_validation_pref_hash_store_->stored_paths_count()); + ASSERT_EQ( + 0u, mock_external_validation_hash_store_contents_->stored_hashes_count()); +} + +TEST_P(PrefHashFilterTest, ExternalValidationValueChanged) { + // Ownership of this value is transfered to |pref_store_contents_|. + base::Value* int_value = new base::FundamentalValue(1234); + pref_store_contents_->Set(kAtomicPref, int_value); + + base::DictionaryValue* dict_value = new base::DictionaryValue; + dict_value->SetString("a", "foo"); + dict_value->SetInteger("b", 1234); + dict_value->SetInteger("c", 56); + dict_value->SetBoolean("d", false); + pref_store_contents_->Set(kSplitPref, dict_value); + + mock_external_validation_pref_hash_store_->SetCheckResult( + kAtomicPref, PrefHashStoreTransaction::CHANGED); + mock_external_validation_pref_hash_store_->SetCheckResult( + kSplitPref, PrefHashStoreTransaction::CHANGED); + + std::vector<std::string> mock_invalid_keys; + mock_invalid_keys.push_back("a"); + mock_invalid_keys.push_back("c"); + mock_external_validation_pref_hash_store_->SetInvalidKeysResult( + kSplitPref, mock_invalid_keys); + + DoFilterOnLoad(false); + + ASSERT_EQ(arraysize(kTestTrackedPrefs), + mock_external_validation_pref_hash_store_->checked_paths_count()); + ASSERT_EQ(2u, + mock_external_validation_pref_hash_store_->stored_paths_count()); + ASSERT_EQ( + 1u, mock_external_validation_pref_hash_store_->transactions_performed()); + + ASSERT_EQ(arraysize(kTestTrackedPrefs), + mock_validation_delegate_.recorded_validations_count()); + + // Regular validation should not have any CHANGED prefs. + ASSERT_EQ(arraysize(kTestTrackedPrefs), + mock_validation_delegate_.CountValidationsOfState( + PrefHashStoreTransaction::UNCHANGED)); + + // External validation should have two CHANGED prefs (kAtomic and kSplit). + ASSERT_EQ(2u, mock_validation_delegate_.CountExternalValidationsOfState( + PrefHashStoreTransaction::CHANGED)); + ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u, + mock_validation_delegate_.CountExternalValidationsOfState( + PrefHashStoreTransaction::UNCHANGED)); +} + INSTANTIATE_TEST_CASE_P(PrefHashFilterTestInstance, PrefHashFilterTest, testing::Values(PrefHashFilter::NO_ENFORCEMENT, diff --git a/chromium/components/user_prefs/tracked/pref_hash_store.h b/chromium/components/user_prefs/tracked/pref_hash_store.h index 2fdc617301a..67808fd3939 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_store.h +++ b/chromium/components/user_prefs/tracked/pref_hash_store.h @@ -6,6 +6,10 @@ #define COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_ #include <memory> +#include <string> + +#include "base/values.h" +#include "components/user_prefs/tracked/pref_hash_store_transaction.h" class HashStoreContents; class PrefHashStoreTransaction; @@ -21,8 +25,24 @@ class PrefHashStore { // of operations on the hash store. |storage| MAY be used as the backing store // depending on the implementation. Therefore the HashStoreContents used for // related transactions should correspond to the same underlying data store. + // |storage| must outlive the returned transaction. virtual std::unique_ptr<PrefHashStoreTransaction> BeginTransaction( - std::unique_ptr<HashStoreContents> storage) = 0; + HashStoreContents* storage) = 0; + + // Computes the MAC to be associated with |path| and |value| in this store. + // PrefHashStoreTransaction typically uses this internally but it's also + // exposed for users that want to compute MACs ahead of time for asynchronous + // operations. + virtual std::string ComputeMac(const std::string& path, + const base::Value* value) = 0; + + // Computes the MAC to be associated with |path| and |split_values| in this + // store. PrefHashStoreTransaction typically uses this internally but it's + // also exposed for users that want to compute MACs ahead of time for + // asynchronous operations. + virtual std::unique_ptr<base::DictionaryValue> ComputeSplitMacs( + const std::string& path, + const base::DictionaryValue* split_values) = 0; }; #endif // COMPONENTS_PREFS_TRACKED_PREF_HASH_STORE_H_ diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc b/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc index c756d6f28f7..80438d6954a 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc +++ b/chromium/components/user_prefs/tracked/pref_hash_store_impl.cc @@ -10,9 +10,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram.h" -#include "base/values.h" #include "components/user_prefs/tracked/hash_store_contents.h" -#include "components/user_prefs/tracked/pref_hash_store_transaction.h" class PrefHashStoreImpl::PrefHashStoreTransactionImpl : public PrefHashStoreTransaction { @@ -20,10 +18,11 @@ class PrefHashStoreImpl::PrefHashStoreTransactionImpl // Constructs a PrefHashStoreTransactionImpl which can use the private // members of its |outer| PrefHashStoreImpl. PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer, - std::unique_ptr<HashStoreContents> storage); + HashStoreContents* storage); ~PrefHashStoreTransactionImpl() override; // PrefHashStoreTransaction implementation. + base::StringPiece GetStoreUMASuffix() const override; ValueState CheckValue(const std::string& path, const base::Value* value) const override; void StoreHash(const std::string& path, const base::Value* value) override; @@ -40,23 +39,8 @@ class PrefHashStoreImpl::PrefHashStoreTransactionImpl bool StampSuperMac() override; private: - bool GetSplitMacs(const std::string& path, - std::map<std::string, std::string>* split_macs) const; - - HashStoreContents* contents() { - return outer_->legacy_hash_store_contents_ - ? outer_->legacy_hash_store_contents_.get() - : contents_.get(); - } - - const HashStoreContents* contents() const { - return outer_->legacy_hash_store_contents_ - ? outer_->legacy_hash_store_contents_.get() - : contents_.get(); - } - PrefHashStoreImpl* outer_; - std::unique_ptr<HashStoreContents> contents_; + HashStoreContents* contents_; bool super_mac_valid_; bool super_mac_dirty_; @@ -73,20 +57,44 @@ PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed, PrefHashStoreImpl::~PrefHashStoreImpl() { } -void PrefHashStoreImpl::set_legacy_hash_store_contents( - std::unique_ptr<HashStoreContents> legacy_hash_store_contents) { - legacy_hash_store_contents_ = std::move(legacy_hash_store_contents); -} - std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction( - std::unique_ptr<HashStoreContents> storage) { + HashStoreContents* storage) { return std::unique_ptr<PrefHashStoreTransaction>( new PrefHashStoreTransactionImpl(this, std::move(storage))); } +std::string PrefHashStoreImpl::ComputeMac(const std::string& path, + const base::Value* value) { + return pref_hash_calculator_.Calculate(path, value); +} + +std::unique_ptr<base::DictionaryValue> PrefHashStoreImpl::ComputeSplitMacs( + const std::string& path, + const base::DictionaryValue* split_values) { + DCHECK(split_values); + + std::string keyed_path(path); + keyed_path.push_back('.'); + const size_t common_part_length = keyed_path.length(); + + std::unique_ptr<base::DictionaryValue> split_macs(new base::DictionaryValue); + + for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd(); + it.Advance()) { + // Keep the common part from the old |keyed_path| and replace the key to + // get the new |keyed_path|. + keyed_path.replace(common_part_length, std::string::npos, it.key()); + + split_macs->SetStringWithoutPathExpansion( + it.key(), ComputeMac(keyed_path, &it.value())); + } + + return split_macs; +} + PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl( PrefHashStoreImpl* outer, - std::unique_ptr<HashStoreContents> storage) + HashStoreContents* storage) : outer_(outer), contents_(std::move(storage)), super_mac_valid_(false), @@ -94,40 +102,36 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl( if (!outer_->use_super_mac_) return; - // The store must be initialized and have a valid super MAC to be trusted. - - const base::DictionaryValue* store_contents = contents()->GetContents(); - if (!store_contents) - return; - - std::string super_mac = contents()->GetSuperMac(); + // The store must have a valid super MAC to be trusted. + std::string super_mac = contents_->GetSuperMac(); if (super_mac.empty()) return; - super_mac_valid_ = outer_->pref_hash_calculator_.Validate( - contents()->hash_store_id(), store_contents, - super_mac) == PrefHashCalculator::VALID; + super_mac_valid_ = + outer_->pref_hash_calculator_.Validate( + "", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID; } PrefHashStoreImpl::PrefHashStoreTransactionImpl:: ~PrefHashStoreTransactionImpl() { if (super_mac_dirty_ && outer_->use_super_mac_) { // Get the dictionary of hashes (or NULL if it doesn't exist). - const base::DictionaryValue* hashes_dict = contents()->GetContents(); - contents()->SetSuperMac(outer_->pref_hash_calculator_.Calculate( - contents()->hash_store_id(), hashes_dict)); + const base::DictionaryValue* hashes_dict = contents_->GetContents(); + contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict)); } } +base::StringPiece +PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const { + return contents_->GetUMASuffix(); +} + PrefHashStoreTransaction::ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( const std::string& path, const base::Value* initial_value) const { - const base::DictionaryValue* hashes_dict = contents()->GetContents(); - std::string last_hash; - if (hashes_dict) - hashes_dict->GetString(path, &last_hash); + contents_->GetMac(path, &last_hash); if (last_hash.empty()) { // In the absence of a hash for this pref, always trust a NULL value, but @@ -158,9 +162,8 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue( void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash( const std::string& path, const base::Value* new_value) { - const std::string mac = - outer_->pref_hash_calculator_.Calculate(path, new_value); - (*contents()->GetMutableContents())->SetString(path, mac); + const std::string mac = outer_->ComputeMac(path, new_value); + contents_->SetMac(path, mac); super_mac_dirty_ = true; } @@ -172,7 +175,7 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( DCHECK(invalid_keys && invalid_keys->empty()); std::map<std::string, std::string> split_macs; - const bool has_hashes = GetSplitMacs(path, &split_macs); + const bool has_hashes = contents_->GetSplitMacs(path, &split_macs); // Treat NULL and empty the same; otherwise we would need to store a hash for // the entire dictionary (or some other special beacon) to differentiate these @@ -232,53 +235,30 @@ PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue( void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash( const std::string& path, const base::DictionaryValue* split_value) { - std::unique_ptr<HashStoreContents::MutableDictionary> mutable_dictionary = - contents()->GetMutableContents(); - (*mutable_dictionary)->Remove(path, NULL); + contents_->RemoveEntry(path); if (split_value) { - std::string keyed_path(path); - keyed_path.push_back('.'); - const size_t common_part_length = keyed_path.length(); - for (base::DictionaryValue::Iterator it(*split_value); !it.IsAtEnd(); - it.Advance()) { - // Keep the common part from the old |keyed_path| and replace the key to - // get the new |keyed_path|. - keyed_path.replace(common_part_length, std::string::npos, it.key()); - (*mutable_dictionary) - ->SetString(keyed_path, outer_->pref_hash_calculator_.Calculate( - keyed_path, &it.value())); - } - } - super_mac_dirty_ = true; -} + std::unique_ptr<base::DictionaryValue> split_macs = + outer_->ComputeSplitMacs(path, split_value); -bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitMacs( - const std::string& key, - std::map<std::string, std::string>* split_macs) const { - DCHECK(split_macs); - DCHECK(split_macs->empty()); + for (base::DictionaryValue::Iterator it(*split_macs); !it.IsAtEnd(); + it.Advance()) { + const base::StringValue* value_as_string; + bool is_string = it.value().GetAsString(&value_as_string); + DCHECK(is_string); - const base::DictionaryValue* hashes_dict = contents()->GetContents(); - const base::DictionaryValue* split_mac_dictionary = NULL; - if (!hashes_dict || !hashes_dict->GetDictionary(key, &split_mac_dictionary)) - return false; - for (base::DictionaryValue::Iterator it(*split_mac_dictionary); !it.IsAtEnd(); - it.Advance()) { - std::string mac_string; - if (!it.value().GetAsString(&mac_string)) { - NOTREACHED(); - continue; + contents_->SetSplitMac(path, it.key(), value_as_string->GetString()); } - split_macs->insert(make_pair(it.key(), mac_string)); } - return true; + super_mac_dirty_ = true; } bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash( const std::string& path) const { - const base::DictionaryValue* hashes_dict = contents()->GetContents(); - return hashes_dict && hashes_dict->Get(path, NULL); + std::string out_value; + std::map<std::string, std::string> out_values; + return contents_->GetMac(path, &out_value) || + contents_->GetSplitMacs(path, &out_values); } void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash( @@ -286,7 +266,7 @@ void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash( const base::Value* hash) { DCHECK(hash); - (*contents()->GetMutableContents())->Set(path, hash->DeepCopy()); + contents_->ImportEntry(path, hash); if (super_mac_valid_) super_mac_dirty_ = true; @@ -294,8 +274,7 @@ void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash( void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash( const std::string& path) { - if ((*contents()->GetMutableContents())->RemovePath(path, NULL) && - super_mac_valid_) { + if (contents_->RemoveEntry(path) && super_mac_valid_) { super_mac_dirty_ = true; } } diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl.h b/chromium/components/user_prefs/tracked/pref_hash_store_impl.h index 254d8f3f89f..1b5682eed4e 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_store_impl.h +++ b/chromium/components/user_prefs/tracked/pref_hash_store_impl.h @@ -5,17 +5,11 @@ #ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_ #define COMPONENTS_USER_PREFS_TRACKED_PREF_HASH_STORE_IMPL_H_ -#include <memory> -#include <string> - #include "base/compiler_specific.h" #include "base/macros.h" #include "components/user_prefs/tracked/pref_hash_calculator.h" #include "components/user_prefs/tracked/pref_hash_store.h" -class HashStoreContents; -class PrefHashStoreTransaction; - // Implements PrefHashStoreImpl by storing preference hashes in a // HashStoreContents. class PrefHashStoreImpl : public PrefHashStore { @@ -41,24 +35,24 @@ class PrefHashStoreImpl : public PrefHashStore { ~PrefHashStoreImpl() override; - // Provides an external HashStoreContents implementation to be used. - // BeginTransaction() will ignore |storage| if this is provided. - void set_legacy_hash_store_contents( - std::unique_ptr<HashStoreContents> legacy_hash_store_contents); - // Clears the contents of this PrefHashStore. |IsInitialized()| will return // false after this call. void Reset(); // PrefHashStore implementation. std::unique_ptr<PrefHashStoreTransaction> BeginTransaction( - std::unique_ptr<HashStoreContents> storage) override; + HashStoreContents* storage) override; + + std::string ComputeMac(const std::string& path, + const base::Value* new_value) override; + std::unique_ptr<base::DictionaryValue> ComputeSplitMacs( + const std::string& path, + const base::DictionaryValue* split_values) override; private: class PrefHashStoreTransactionImpl; const PrefHashCalculator pref_hash_calculator_; - std::unique_ptr<HashStoreContents> legacy_hash_store_contents_; bool use_super_mac_; DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImpl); diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc b/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc index 10867e66d45..f5d92182a53 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc +++ b/chromium/components/user_prefs/tracked/pref_hash_store_impl_unittest.cc @@ -15,16 +15,60 @@ #include "testing/gtest/include/gtest/gtest.h" class PrefHashStoreImplTest : public testing::Test { + public: + PrefHashStoreImplTest() : contents_(&pref_store_contents_) {} + protected: - std::unique_ptr<HashStoreContents> CreateHashStoreContents() { - return std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(&pref_store_contents_)); - } + HashStoreContents* GetHashStoreContents() { return &contents_; } private: base::DictionaryValue pref_store_contents_; + // Must be declared after |pref_store_contents_| as it needs to be outlived + // by it. + DictionaryHashStoreContents contents_; + + DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImplTest); }; +TEST_F(PrefHashStoreImplTest, ComputeMac) { + base::StringValue string_1("string1"); + base::StringValue string_2("string2"); + PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); + + std::string computed_mac_1 = pref_hash_store.ComputeMac("path1", &string_1); + std::string computed_mac_2 = pref_hash_store.ComputeMac("path1", &string_2); + std::string computed_mac_3 = pref_hash_store.ComputeMac("path2", &string_1); + + // Quick sanity checks here, see pref_hash_calculator_unittest.cc for more + // complete tests. + EXPECT_EQ(computed_mac_1, pref_hash_store.ComputeMac("path1", &string_1)); + EXPECT_NE(computed_mac_1, computed_mac_2); + EXPECT_NE(computed_mac_1, computed_mac_3); + EXPECT_EQ(64U, computed_mac_1.size()); +} + +TEST_F(PrefHashStoreImplTest, ComputeSplitMacs) { + base::DictionaryValue dict; + dict.Set("a", new base::StringValue("string1")); + dict.Set("b", new base::StringValue("string2")); + PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); + + std::unique_ptr<base::DictionaryValue> computed_macs = + pref_hash_store.ComputeSplitMacs("foo.bar", &dict); + + std::string mac_1; + std::string mac_2; + ASSERT_TRUE(computed_macs->GetString("a", &mac_1)); + ASSERT_TRUE(computed_macs->GetString("b", &mac_2)); + + EXPECT_EQ(2U, computed_macs->size()); + + base::StringValue string_1("string1"); + base::StringValue string_2("string2"); + EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.a", &string_1), mac_1); + EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.b", &string_2), mac_2); +} + TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) { base::StringValue string_1("string1"); base::StringValue string_2("string2"); @@ -33,7 +77,7 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) { // 32 NULL bytes is the seed that was used to generate the legacy hash. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); // Only NULL should be trusted in the absence of a hash. EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE, @@ -63,14 +107,14 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) { transaction->CheckValue("path1", &dict)); } - ASSERT_FALSE(CreateHashStoreContents()->GetSuperMac().empty()); + ASSERT_FALSE(GetHashStoreContents()->GetSuperMac().empty()); { // |pref_hash_store2| should trust its initial hashes dictionary and thus // trust new unknown values. PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store2.BeginTransaction(CreateHashStoreContents())); + pref_hash_store2.BeginTransaction(GetHashStoreContents())); EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE, transaction->CheckValue("new_path", &string_1)); EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE, @@ -80,14 +124,14 @@ TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) { } // Manually corrupt the super MAC. - CreateHashStoreContents()->SetSuperMac(std::string(64, 'A')); + GetHashStoreContents()->SetSuperMac(std::string(64, 'A')); { // |pref_hash_store3| should no longer trust its initial hashes dictionary // and thus shouldn't trust non-NULL unknown values. PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store3.BeginTransaction(CreateHashStoreContents())); + pref_hash_store3.BeginTransaction(GetHashStoreContents())); EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE, transaction->CheckValue("new_path", &string_1)); EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE, @@ -105,7 +149,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_FALSE(transaction->IsSuperMACValid()); ASSERT_FALSE(transaction->HasHash("path1")); @@ -122,7 +166,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { // Make a copy of the stored hash for future use. const base::Value* hash = NULL; - ASSERT_TRUE(CreateHashStoreContents()->GetContents()->Get("path1", &hash)); + ASSERT_TRUE(GetHashStoreContents()->GetContents()->Get("path1", &hash)); std::unique_ptr<base::Value> path_1_string_1_hash_copy(hash->DeepCopy()); hash = NULL; @@ -130,7 +174,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_TRUE(transaction->IsSuperMACValid()); ASSERT_TRUE(transaction->HasHash("path1")); @@ -149,18 +193,18 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_TRUE(transaction->IsSuperMACValid()); ASSERT_FALSE(transaction->HasHash("path1")); } // Invalidate the super MAC. - CreateHashStoreContents()->SetSuperMac(std::string()); + GetHashStoreContents()->SetSuperMac(std::string()); { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_FALSE(transaction->IsSuperMACValid()); ASSERT_FALSE(transaction->HasHash("path1")); @@ -178,7 +222,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_FALSE(transaction->IsSuperMACValid()); ASSERT_TRUE(transaction->HasHash("path1")); EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED, @@ -196,7 +240,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_FALSE(transaction->IsSuperMACValid()); // Test StampSuperMac. @@ -207,7 +251,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_TRUE(transaction->IsSuperMACValid()); // Store the hash of a different value to test an "over-import". @@ -221,7 +265,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_TRUE(transaction->IsSuperMACValid()); // "Over-import". An import should preserve validity. @@ -236,7 +280,7 @@ TEST_F(PrefHashStoreImplTest, ImportExportOperations) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); ASSERT_TRUE(transaction->IsSuperMACValid()); EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED, transaction->CheckValue("path1", &string_1)); @@ -253,19 +297,19 @@ TEST_F(PrefHashStoreImplTest, SuperMACDisabled) { // Pass |use_super_mac| => false. PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", false); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); transaction->StoreHash("path1", &string_2); EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED, transaction->CheckValue("path1", &string_2)); } - ASSERT_TRUE(CreateHashStoreContents()->GetSuperMac().empty()); + ASSERT_TRUE(GetHashStoreContents()->GetSuperMac().empty()); { PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", false); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store2.BeginTransaction(CreateHashStoreContents())); + pref_hash_store2.BeginTransaction(GetHashStoreContents())); EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE, transaction->CheckValue("new_path", &string_1)); } @@ -289,7 +333,7 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); // No hashes stored yet and hashes dictionary is empty (and thus not // trusted). @@ -359,21 +403,21 @@ TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) { // trust new unknown values. PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store2.BeginTransaction(CreateHashStoreContents())); + pref_hash_store2.BeginTransaction(GetHashStoreContents())); EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE, transaction->CheckSplitValue("new_path", &dict, &invalid_keys)); EXPECT_TRUE(invalid_keys.empty()); } // Manually corrupt the super MAC. - CreateHashStoreContents()->SetSuperMac(std::string(64, 'A')); + GetHashStoreContents()->SetSuperMac(std::string(64, 'A')); { // |pref_hash_store3| should no longer trust its initial hashes dictionary // and thus shouldn't trust unknown values. PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store3.BeginTransaction(CreateHashStoreContents())); + pref_hash_store3.BeginTransaction(GetHashStoreContents())); EXPECT_EQ(PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE, transaction->CheckSplitValue("new_path", &dict, &invalid_keys)); EXPECT_TRUE(invalid_keys.empty()); @@ -388,7 +432,7 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); // Store hashes for a random dict to be overwritten below. base::DictionaryValue initial_dict; @@ -424,7 +468,7 @@ TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) { // update the stored hash of hashes). PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store2.BeginTransaction(CreateHashStoreContents())); + pref_hash_store2.BeginTransaction(GetHashStoreContents())); base::DictionaryValue tested_dict; tested_dict.Set("a", new base::StringValue("foo")); @@ -454,7 +498,7 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) { { PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store.BeginTransaction(CreateHashStoreContents())); + pref_hash_store.BeginTransaction(GetHashStoreContents())); transaction->StoreHash("path1", &string); EXPECT_EQ(PrefHashStoreTransaction::UNCHANGED, @@ -465,7 +509,7 @@ TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) { // Load a new |pref_hash_store2| in which the hashes dictionary is trusted. PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true); std::unique_ptr<PrefHashStoreTransaction> transaction( - pref_hash_store2.BeginTransaction(CreateHashStoreContents())); + pref_hash_store2.BeginTransaction(GetHashStoreContents())); std::vector<std::string> invalid_keys; EXPECT_EQ(PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE, transaction->CheckSplitValue("path1", &dict, &invalid_keys)); diff --git a/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h b/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h index b8e2cf75e75..55d99d2d03f 100644 --- a/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h +++ b/chromium/components/user_prefs/tracked/pref_hash_store_transaction.h @@ -8,6 +8,8 @@ #include <string> #include <vector> +#include "base/strings/string_piece.h" + namespace base { class DictionaryValue; class Value; @@ -36,11 +38,17 @@ class PrefHashStoreTransaction { TRUSTED_UNKNOWN_VALUE, // NULL values are inherently trusted. TRUSTED_NULL_VALUE, + // This transaction's store type is not supported. + UNSUPPORTED, }; // Finalizes any remaining work after the transaction has been performed. virtual ~PrefHashStoreTransaction() {} + // Returns the suffix to be appended to UMA histograms for the store contained + // in this transaction. + virtual base::StringPiece GetStoreUMASuffix() const = 0; + // Checks |initial_value| against the existing stored value hash. virtual ValueState CheckValue(const std::string& path, const base::Value* initial_value) const = 0; diff --git a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc b/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc deleted file mode 100644 index d175541281f..00000000000 --- a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.cc +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/user_prefs/tracked/pref_service_hash_store_contents.h" - -#include "base/values.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/scoped_user_pref_update.h" - -namespace { - -// Implements get-or-create of a dictionary value and holds a -// DictionaryPrefUpdate. -class PrefServiceMutableDictionary - : public HashStoreContents::MutableDictionary { - public: - // Creates an instance that provides mutable access to a dictionary value - // named |key| that is a child of |kProfilePreferenceHashes| in - // |prefs|. - PrefServiceMutableDictionary(const std::string& key, - PrefService* pref_service); - - // HashStoreContents::MutableDictionary implementation - base::DictionaryValue* operator->() override; - - private: - const std::string key_; - DictionaryPrefUpdate update_; -}; - -PrefServiceMutableDictionary::PrefServiceMutableDictionary( - const std::string& key, - PrefService* pref_service) - : key_(key), - update_(pref_service, - PrefServiceHashStoreContents::kProfilePreferenceHashes) { - DCHECK(!key_.empty()); -} - -base::DictionaryValue* PrefServiceMutableDictionary::operator->() { - base::DictionaryValue* dictionary = NULL; - if (!update_->GetDictionaryWithoutPathExpansion(key_, &dictionary)) { - dictionary = new base::DictionaryValue; - update_->SetWithoutPathExpansion(key_, dictionary); - } - return dictionary; -} - -} // namespace - -// static -const char PrefServiceHashStoreContents::kProfilePreferenceHashes[] = - "profile.preference_hashes"; - -// static -const char PrefServiceHashStoreContents::kHashOfHashesDict[] = "hash_of_hashes"; - -// static -const char PrefServiceHashStoreContents::kStoreVersionsDict[] = - "store_versions"; - -PrefServiceHashStoreContents::PrefServiceHashStoreContents( - const std::string& hash_store_id, - PrefService* pref_service) - : hash_store_id_(hash_store_id), pref_service_(pref_service) { - // TODO(erikwright): Remove in M40+. - DictionaryPrefUpdate update(pref_service_, kProfilePreferenceHashes); - update->RemovePath(kStoreVersionsDict, NULL); -} - -// static -void PrefServiceHashStoreContents::RegisterPrefs(PrefRegistrySimple* registry) { - // Register the top level dictionary to map profile names to dictionaries of - // tracked preferences. - registry->RegisterDictionaryPref(kProfilePreferenceHashes); -} - -// static -void PrefServiceHashStoreContents::ResetAllPrefHashStores( - PrefService* pref_service) { - pref_service->ClearPref(kProfilePreferenceHashes); -} - -std::string PrefServiceHashStoreContents::hash_store_id() const { - return hash_store_id_; -} - -void PrefServiceHashStoreContents::Reset() { - DictionaryPrefUpdate update(pref_service_, kProfilePreferenceHashes); - - update->RemoveWithoutPathExpansion(hash_store_id_, NULL); - - // Remove this store's entry in the kHashOfHashesDict. - base::DictionaryValue* hash_of_hashes_dict; - if (update->GetDictionaryWithoutPathExpansion(kHashOfHashesDict, - &hash_of_hashes_dict)) { - hash_of_hashes_dict->RemoveWithoutPathExpansion(hash_store_id_, NULL); - if (hash_of_hashes_dict->empty()) - update->RemovePath(kHashOfHashesDict, NULL); - } - - if (update->empty()) - pref_service_->ClearPref(kProfilePreferenceHashes); -} - -bool PrefServiceHashStoreContents::IsInitialized() const { - const base::DictionaryValue* pref_hash_dicts = - pref_service_->GetDictionary(kProfilePreferenceHashes); - return pref_hash_dicts->GetDictionaryWithoutPathExpansion(hash_store_id_, - NULL); -} - -const base::DictionaryValue* PrefServiceHashStoreContents::GetContents() const { - const base::DictionaryValue* pref_hash_dicts = - pref_service_->GetDictionary(kProfilePreferenceHashes); - const base::DictionaryValue* hashes_dict = NULL; - pref_hash_dicts->GetDictionaryWithoutPathExpansion(hash_store_id_, - &hashes_dict); - return hashes_dict; -} - -std::unique_ptr<HashStoreContents::MutableDictionary> -PrefServiceHashStoreContents::GetMutableContents() { - return std::unique_ptr<HashStoreContents::MutableDictionary>( - new PrefServiceMutableDictionary(hash_store_id_, pref_service_)); -} - -std::string PrefServiceHashStoreContents::GetSuperMac() const { - const base::DictionaryValue* pref_hash_dicts = - pref_service_->GetDictionary(kProfilePreferenceHashes); - const base::DictionaryValue* hash_of_hashes_dict = NULL; - std::string hash_of_hashes; - if (pref_hash_dicts->GetDictionaryWithoutPathExpansion( - kHashOfHashesDict, &hash_of_hashes_dict)) { - hash_of_hashes_dict->GetStringWithoutPathExpansion(hash_store_id_, - &hash_of_hashes); - } - return hash_of_hashes; -} - -void PrefServiceHashStoreContents::SetSuperMac(const std::string& super_mac) { - PrefServiceMutableDictionary(kHashOfHashesDict, pref_service_) - ->SetStringWithoutPathExpansion(hash_store_id_, super_mac); -} diff --git a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h b/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h deleted file mode 100644 index 05417d81c8e..00000000000 --- a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_SERVICE_HASH_STORE_CONTENTS_H_ -#define COMPONENTS_USER_PREFS_TRACKED_PREF_SERVICE_HASH_STORE_CONTENTS_H_ - -#include <string> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "components/user_prefs/tracked/hash_store_contents.h" - -class PrefRegistrySimple; -class PrefService; - -// Implements HashStoreContents by storing hashes in a PrefService. Multiple -// separate hash stores may coexist in the PrefService by using distinct hash -// store IDs. -// TODO(erikwright): This class is only used to recreate preference state as in -// M35, to test migration behaviour. Remove this class when -// ProfilePrefStoreManagerTest no longer depends on it. -class PrefServiceHashStoreContents : public HashStoreContents { - public: - // Constructs a HashStoreContents that stores hashes in |pref_service|. - // Multiple hash stores can use the same |pref_service| with distinct - // |hash_store_id|s. - // - // |pref_service| must have previously been configured using |RegisterPrefs|. - PrefServiceHashStoreContents(const std::string& hash_store_id, - PrefService* pref_service); - - // A dictionary pref which maps profile names to dictionary values which hold - // hashes of profile prefs that we track to detect changes that happen outside - // of Chrome. - static const char kProfilePreferenceHashes[]; - - // The name of a dict that is stored as a child of - // |prefs::kProfilePreferenceHashes|. Each child node is a string whose name - // is a hash store ID and whose value is the super MAC for the corresponding - // hash store. - static const char kHashOfHashesDict[]; - - // The name of a dict that is stored as a child of - // |prefs::kProfilePreferenceHashes|. Each child node is a number whose name - // is a hash store ID and whose value is the version of the corresponding - // hash store. - static const char kStoreVersionsDict[]; - - // Registers required preferences. - static void RegisterPrefs(PrefRegistrySimple* registry); - - // Deletes stored hashes for all profiles from |pref_service|. - static void ResetAllPrefHashStores(PrefService* pref_service); - - // HashStoreContents implementation - std::string hash_store_id() const override; - void Reset() override; - bool IsInitialized() const override; - const base::DictionaryValue* GetContents() const override; - std::unique_ptr<MutableDictionary> GetMutableContents() override; - std::string GetSuperMac() const override; - void SetSuperMac(const std::string& super_mac) override; - - private: - const std::string hash_store_id_; - PrefService* pref_service_; - - DISALLOW_COPY_AND_ASSIGN(PrefServiceHashStoreContents); -}; - -#endif // COMPONENTS_PREFS_TRACKED_PREF_SERVICE_HASH_STORE_CONTENTS_H_ diff --git a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc b/chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc deleted file mode 100644 index 3cfb10542af..00000000000 --- a/chromium/components/user_prefs/tracked/pref_service_hash_store_contents_unittest.cc +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/user_prefs/tracked/pref_service_hash_store_contents.h" - -#include <string> - -#include "base/values.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/testing_pref_service.h" -#include "testing/gtest/include/gtest/gtest.h" - -class PrefServiceHashStoreContentsTest : public testing::Test { - public: - void SetUp() override { - PrefServiceHashStoreContents::RegisterPrefs(local_state_.registry()); - } - - protected: - TestingPrefServiceSimple local_state_; -}; - -TEST_F(PrefServiceHashStoreContentsTest, hash_store_id) { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_EQ("store_id", contents.hash_store_id()); -} - -TEST_F(PrefServiceHashStoreContentsTest, IsInitialized) { - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_FALSE(contents.IsInitialized()); - (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar")); - ASSERT_TRUE(contents.IsInitialized()); - } - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_TRUE(contents.IsInitialized()); - PrefServiceHashStoreContents other_contents("other_store_id", - &local_state_); - ASSERT_FALSE(other_contents.IsInitialized()); - } -} - -TEST_F(PrefServiceHashStoreContentsTest, Reset) { - ASSERT_FALSE(local_state_.GetUserPrefValue( - PrefServiceHashStoreContents::kProfilePreferenceHashes)); - - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_FALSE(contents.IsInitialized()); - (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar")); - ASSERT_TRUE(contents.IsInitialized()); - PrefServiceHashStoreContents other_contents("other_store_id", - &local_state_); - (*other_contents.GetMutableContents()) - ->Set("foo", new base::StringValue("bar")); - } - - ASSERT_TRUE(local_state_.GetUserPrefValue( - PrefServiceHashStoreContents::kProfilePreferenceHashes)); - - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_TRUE(contents.IsInitialized()); - contents.Reset(); - ASSERT_FALSE(contents.IsInitialized()); - } - - ASSERT_TRUE(local_state_.GetUserPrefValue( - PrefServiceHashStoreContents::kProfilePreferenceHashes)); - - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_FALSE(contents.IsInitialized()); - PrefServiceHashStoreContents other_contents("other_store_id", - &local_state_); - ASSERT_TRUE(other_contents.IsInitialized()); - } - - { - PrefServiceHashStoreContents other_contents("other_store_id", - &local_state_); - other_contents.Reset(); - } - - ASSERT_FALSE(local_state_.GetUserPrefValue( - PrefServiceHashStoreContents::kProfilePreferenceHashes)); -} - -TEST_F(PrefServiceHashStoreContentsTest, GetAndSetContents) { - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_EQ(NULL, contents.GetContents()); - (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar")); - ASSERT_FALSE(contents.GetContents() == NULL); - std::string actual_value; - ASSERT_TRUE(contents.GetContents()->GetString("foo", &actual_value)); - ASSERT_EQ("bar", actual_value); - PrefServiceHashStoreContents other_contents("other_store_id", - &local_state_); - ASSERT_EQ(NULL, other_contents.GetContents()); - } - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_FALSE(contents.GetContents() == NULL); - } -} - -TEST_F(PrefServiceHashStoreContentsTest, GetAndSetSuperMac) { - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_TRUE(contents.GetSuperMac().empty()); - (*contents.GetMutableContents())->Set("foo", new base::StringValue("bar")); - ASSERT_TRUE(contents.GetSuperMac().empty()); - contents.SetSuperMac("0123456789"); - ASSERT_EQ("0123456789", contents.GetSuperMac()); - } - { - PrefServiceHashStoreContents contents("store_id", &local_state_); - ASSERT_EQ("0123456789", contents.GetSuperMac()); - PrefServiceHashStoreContents other_contents("other_store_id", - &local_state_); - ASSERT_TRUE(other_contents.GetSuperMac().empty()); - } -} - -TEST_F(PrefServiceHashStoreContentsTest, ResetAllPrefHashStores) { - { - PrefServiceHashStoreContents contents_1("store_id_1", &local_state_); - PrefServiceHashStoreContents contents_2("store_id_2", &local_state_); - (*contents_1.GetMutableContents()) - ->Set("foo", new base::StringValue("bar")); - (*contents_2.GetMutableContents()) - ->Set("foo", new base::StringValue("bar")); - } - { - PrefServiceHashStoreContents contents_1("store_id_1", &local_state_); - PrefServiceHashStoreContents contents_2("store_id_2", &local_state_); - ASSERT_TRUE(contents_1.IsInitialized()); - ASSERT_TRUE(contents_2.IsInitialized()); - } - - PrefServiceHashStoreContents::ResetAllPrefHashStores(&local_state_); - - { - PrefServiceHashStoreContents contents_1("store_id_1", &local_state_); - PrefServiceHashStoreContents contents_2("store_id_2", &local_state_); - ASSERT_FALSE(contents_1.IsInitialized()); - ASSERT_FALSE(contents_2.IsInitialized()); - } -} diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc new file mode 100644 index 00000000000..03d789839c5 --- /dev/null +++ b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.cc @@ -0,0 +1,182 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/user_prefs/tracked/registry_hash_store_contents_win.h" + +#include <windows.h> + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "base/win/registry.h" +#include "components/user_prefs/tracked/tracked_preference_histogram_names.h" + +using base::win::RegistryValueIterator; + +namespace { + +constexpr size_t kMacSize = 64; + +base::string16 GetSplitPrefKeyName(const base::string16& reg_key_name, + const std::string& split_key_name) { + return reg_key_name + L"\\" + base::UTF8ToUTF16(split_key_name); +} + +bool ReadMacFromRegistry(const base::win::RegKey& key, + const std::string& value_name, + std::string* out_mac) { + base::string16 string_value; + if (key.ReadValue(base::UTF8ToUTF16(value_name).c_str(), &string_value) == + ERROR_SUCCESS && + string_value.size() == kMacSize) { + out_mac->assign(base::UTF16ToUTF8(string_value)); + return true; + } + return false; +} + +// Removes |value_name| under |reg_key_name|. Returns true if found and +// successfully removed. +bool ClearAtomicMac(const base::string16& reg_key_name, + const std::string& value_name) { + base::win::RegKey key; + if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(), + KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + return key.DeleteValue(base::UTF8ToUTF16(value_name).c_str()) == + ERROR_SUCCESS; + } + return false; +} + +// Deletes |split_key_name| under |reg_key_name|. Returns true if found and +// successfully removed. +bool ClearSplitMac(const base::string16& reg_key_name, + const std::string& split_key_name) { + base::win::RegKey key; + if (key.Open(HKEY_CURRENT_USER, + GetSplitPrefKeyName(reg_key_name, split_key_name).c_str(), + KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + return key.DeleteKey(L"") == ERROR_SUCCESS; + } + return false; +} + +} // namespace + +RegistryHashStoreContentsWin::RegistryHashStoreContentsWin( + const base::string16& registry_path, + const base::string16& store_key) + : preference_key_name_(registry_path + L"\\PreferenceMACs\\" + store_key) {} + +RegistryHashStoreContentsWin::RegistryHashStoreContentsWin( + const RegistryHashStoreContentsWin& other) = default; + +bool RegistryHashStoreContentsWin::IsCopyable() const { + return true; +} + +std::unique_ptr<HashStoreContents> RegistryHashStoreContentsWin::MakeCopy() + const { + return base::WrapUnique(new RegistryHashStoreContentsWin(*this)); +} + +base::StringPiece RegistryHashStoreContentsWin::GetUMASuffix() const { + return user_prefs::tracked::kTrackedPrefRegistryValidationSuffix; +} + +void RegistryHashStoreContentsWin::Reset() { + base::win::RegKey key; + if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(), + KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + LONG result = key.DeleteKey(L""); + DCHECK(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND) << result; + } +} + +bool RegistryHashStoreContentsWin::GetMac(const std::string& path, + std::string* out_value) { + base::win::RegKey key; + if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(), + KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + return ReadMacFromRegistry(key, path, out_value); + } + + return false; +} + +bool RegistryHashStoreContentsWin::GetSplitMacs( + const std::string& path, + std::map<std::string, std::string>* split_macs) { + DCHECK(split_macs); + DCHECK(split_macs->empty()); + + RegistryValueIterator iter_key( + HKEY_CURRENT_USER, + GetSplitPrefKeyName(preference_key_name_, path).c_str()); + + for (; iter_key.Valid(); ++iter_key) { + split_macs->insert(make_pair(base::UTF16ToUTF8(iter_key.Name()), + base::UTF16ToUTF8(iter_key.Value()))); + } + + return !split_macs->empty(); +} + +void RegistryHashStoreContentsWin::SetMac(const std::string& path, + const std::string& value) { + base::win::RegKey key; + DCHECK_EQ(kMacSize, value.size()); + + if (key.Create(HKEY_CURRENT_USER, preference_key_name_.c_str(), + KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + key.WriteValue(base::UTF8ToUTF16(path).c_str(), + base::UTF8ToUTF16(value).c_str()); + } +} + +void RegistryHashStoreContentsWin::SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) { + base::win::RegKey key; + DCHECK_EQ(kMacSize, value.size()); + + if (key.Create(HKEY_CURRENT_USER, + GetSplitPrefKeyName(preference_key_name_, path).c_str(), + KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { + key.WriteValue(base::UTF8ToUTF16(split_path).c_str(), + base::UTF8ToUTF16(value).c_str()); + } +} + +bool RegistryHashStoreContentsWin::RemoveEntry(const std::string& path) { + return ClearAtomicMac(preference_key_name_, path) || + ClearSplitMac(preference_key_name_, path); +} + +void RegistryHashStoreContentsWin::ImportEntry(const std::string& path, + const base::Value* in_value) { + NOTREACHED() + << "RegistryHashStoreContents does not support the ImportEntry operation"; +} + +const base::DictionaryValue* RegistryHashStoreContentsWin::GetContents() const { + NOTREACHED() + << "RegistryHashStoreContents does not support the GetContents operation"; + return NULL; +} + +std::string RegistryHashStoreContentsWin::GetSuperMac() const { + NOTREACHED() + << "RegistryHashStoreContents does not support the GetSuperMac operation"; + return NULL; +} + +void RegistryHashStoreContentsWin::SetSuperMac(const std::string& super_mac) { + NOTREACHED() + << "RegistryHashStoreContents does not support the SetSuperMac operation"; +} diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h new file mode 100644 index 00000000000..b44898ef698 --- /dev/null +++ b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win.h @@ -0,0 +1,49 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_WIN_H_ +#define COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_WIN_H_ + +#include "base/macros.h" +#include "base/strings/string16.h" +#include "components/user_prefs/tracked/hash_store_contents.h" + +// Implements HashStoreContents by storing MACs in the Windows registry. +class RegistryHashStoreContentsWin : public HashStoreContents { + public: + // Constructs a RegistryHashStoreContents which acts on a registry entry + // defined by |registry_path| and |store_key|. + explicit RegistryHashStoreContentsWin(const base::string16& registry_path, + const base::string16& store_key); + + // HashStoreContents overrides: + bool IsCopyable() const override; + std::unique_ptr<HashStoreContents> MakeCopy() const override; + base::StringPiece GetUMASuffix() const override; + void Reset() override; + bool GetMac(const std::string& path, std::string* out_value) override; + bool GetSplitMacs(const std::string& path, + std::map<std::string, std::string>* split_macs) override; + void SetMac(const std::string& path, const std::string& value) override; + void SetSplitMac(const std::string& path, + const std::string& split_path, + const std::string& value) override; + bool RemoveEntry(const std::string& path) override; + + // Unsupported HashStoreContents overrides: + void ImportEntry(const std::string& path, + const base::Value* in_value) override; + const base::DictionaryValue* GetContents() const override; + std::string GetSuperMac() const override; + void SetSuperMac(const std::string& super_mac) override; + + private: + // Helper constructor for |MakeCopy|. + explicit RegistryHashStoreContentsWin( + const RegistryHashStoreContentsWin& other); + + const base::string16 preference_key_name_; +}; + +#endif // COMPONENTS_USER_PREFS_TRACKED_PREF_REGISTRY_HASH_STORE_CONTENTS_H_ diff --git a/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc new file mode 100644 index 00000000000..a34d7ade788 --- /dev/null +++ b/chromium/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc @@ -0,0 +1,119 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/user_prefs/tracked/registry_hash_store_contents_win.h" + +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/test_reg_util_win.h" +#include "base/values.h" +#include "base/win/registry.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +constexpr base::char16 kRegistryPath[] = L"Foo\\TestStore"; +constexpr base::char16 kStoreKey[] = L"test_store_key"; + +// Hex-encoded MACs are 64 characters long. +constexpr char kTestStringA[] = + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; +constexpr char kTestStringB[] = + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; + +constexpr char kAtomicPrefPath[] = "path1"; +constexpr char kSplitPrefPath[] = "extension"; + +class RegistryHashStoreContentsWinTest : public testing::Test { + protected: + RegistryHashStoreContentsWinTest() {} + + void SetUp() override { + registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER); + + contents.reset(new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey)); + } + + std::unique_ptr<HashStoreContents> contents; + + private: + registry_util::RegistryOverrideManager registry_override_manager_; + + DISALLOW_COPY_AND_ASSIGN(RegistryHashStoreContentsWinTest); +}; + +} // namespace + +TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetMac) { + std::string stored_mac; + EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac)); + + contents->SetMac(kAtomicPrefPath, kTestStringA); + + EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac)); + EXPECT_EQ(kTestStringA, stored_mac); +} + +TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetSplitMacs) { + std::map<std::string, std::string> split_macs; + EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs)); + + contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA); + contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB); + + EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs)); + EXPECT_EQ(2U, split_macs.size()); + EXPECT_EQ(kTestStringA, split_macs.at("a")); + EXPECT_EQ(kTestStringB, split_macs.at("b")); +} + +TEST_F(RegistryHashStoreContentsWinTest, TestRemoveAtomicMac) { + contents->SetMac(kAtomicPrefPath, kTestStringA); + + std::string stored_mac; + EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac)); + EXPECT_EQ(kTestStringA, stored_mac); + + contents->RemoveEntry(kAtomicPrefPath); + + EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac)); +} + +TEST_F(RegistryHashStoreContentsWinTest, TestRemoveSplitMacs) { + contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA); + contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB); + + std::map<std::string, std::string> split_macs; + EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs)); + EXPECT_EQ(2U, split_macs.size()); + + contents->RemoveEntry(kSplitPrefPath); + + split_macs.clear(); + EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs)); + EXPECT_EQ(0U, split_macs.size()); +} + +TEST_F(RegistryHashStoreContentsWinTest, TestReset) { + contents->SetMac(kAtomicPrefPath, kTestStringA); + contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA); + + std::string stored_mac; + EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac)); + EXPECT_EQ(kTestStringA, stored_mac); + + std::map<std::string, std::string> split_macs; + EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs)); + EXPECT_EQ(1U, split_macs.size()); + + contents->Reset(); + + stored_mac.clear(); + EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac)); + EXPECT_TRUE(stored_mac.empty()); + + split_macs.clear(); + EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs)); + EXPECT_EQ(0U, split_macs.size()); +} diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store.cc b/chromium/components/user_prefs/tracked/segregated_pref_store.cc index c5a6e25c2f3..af8dfe34be7 100644 --- a/chromium/components/user_prefs/tracked/segregated_pref_store.cc +++ b/chromium/components/user_prefs/tracked/segregated_pref_store.cc @@ -166,14 +166,16 @@ SegregatedPrefStore::~SegregatedPrefStore() { } PersistentPrefStore* SegregatedPrefStore::StoreForKey(const std::string& key) { - return (ContainsKey(selected_preference_names_, key) + return (base::ContainsKey(selected_preference_names_, key) ? selected_pref_store_ - : default_pref_store_).get(); + : default_pref_store_) + .get(); } const PersistentPrefStore* SegregatedPrefStore::StoreForKey( const std::string& key) const { - return (ContainsKey(selected_preference_names_, key) + return (base::ContainsKey(selected_preference_names_, key) ? selected_pref_store_ - : default_pref_store_).get(); + : default_pref_store_) + .get(); } diff --git a/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc b/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc index f3efce22f72..5d32d027d5e 100644 --- a/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc +++ b/chromium/components/user_prefs/tracked/segregated_pref_store_unittest.cc @@ -104,10 +104,10 @@ TEST_F(SegregatedPrefStoreTest, StoreValues) { // Properly stores new values. segregated_store_->SetValue(kSelectedPref, - base::WrapUnique(new base::StringValue(kValue1)), + base::MakeUnique<base::StringValue>(kValue1), WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); segregated_store_->SetValue(kUnselectedPref, - base::WrapUnique(new base::StringValue(kValue2)), + base::MakeUnique<base::StringValue>(kValue2), WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL)); @@ -129,10 +129,10 @@ TEST_F(SegregatedPrefStoreTest, StoreValues) { TEST_F(SegregatedPrefStoreTest, ReadValues) { selected_store_->SetValue(kSelectedPref, - base::WrapUnique(new base::StringValue(kValue1)), + base::MakeUnique<base::StringValue>(kValue1), WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); default_store_->SetValue(kUnselectedPref, - base::WrapUnique(new base::StringValue(kValue2)), + base::MakeUnique<base::StringValue>(kValue2), WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); // Works properly with values that are already there. @@ -157,11 +157,11 @@ TEST_F(SegregatedPrefStoreTest, Observer) { EXPECT_TRUE(observer_.initialization_success); EXPECT_TRUE(observer_.changed_keys.empty()); segregated_store_->SetValue(kSelectedPref, - base::WrapUnique(new base::StringValue(kValue1)), + base::MakeUnique<base::StringValue>(kValue1), WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); observer_.VerifyAndResetChangedKey(kSelectedPref); segregated_store_->SetValue(kUnselectedPref, - base::WrapUnique(new base::StringValue(kValue2)), + base::MakeUnique<base::StringValue>(kValue2), WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); observer_.VerifyAndResetChangedKey(kUnselectedPref); } diff --git a/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc b/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc index 4eb4b6129d2..e2b76784b81 100644 --- a/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc +++ b/chromium/components/user_prefs/tracked/tracked_atomic_preference.cc @@ -24,6 +24,10 @@ TrackedAtomicPreference::TrackedAtomicPreference( delegate_(delegate) { } +TrackedPreferenceType TrackedAtomicPreference::GetType() const { + return TrackedPreferenceType::ATOMIC; +} + void TrackedAtomicPreference::OnNewValue( const base::Value* value, PrefHashStoreTransaction* transaction) const { @@ -32,20 +36,31 @@ void TrackedAtomicPreference::OnNewValue( bool TrackedAtomicPreference::EnforceAndReport( base::DictionaryValue* pref_store_contents, - PrefHashStoreTransaction* transaction) const { + PrefHashStoreTransaction* transaction, + PrefHashStoreTransaction* external_validation_transaction) const { const base::Value* value = NULL; pref_store_contents->Get(pref_path_, &value); PrefHashStoreTransaction::ValueState value_state = transaction->CheckValue(pref_path_, value); + helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix()); - helper_.ReportValidationResult(value_state); + PrefHashStoreTransaction::ValueState external_validation_value_state = + PrefHashStoreTransaction::UNSUPPORTED; + if (external_validation_transaction) { + external_validation_value_state = + external_validation_transaction->CheckValue(pref_path_, value); + helper_.ReportValidationResult( + external_validation_value_state, + external_validation_transaction->GetStoreUMASuffix()); + } - TrackedPreferenceHelper::ResetAction reset_action = - helper_.GetAction(value_state); if (delegate_) { delegate_->OnAtomicPreferenceValidation(pref_path_, value, value_state, + external_validation_value_state, helper_.IsPersonal()); } + TrackedPreferenceHelper::ResetAction reset_action = + helper_.GetAction(value_state); helper_.ReportAction(reset_action); bool was_reset = false; @@ -61,5 +76,16 @@ bool TrackedAtomicPreference::EnforceAndReport( transaction->StoreHash(pref_path_, new_value); } + // Update MACs in the external store if there is one and there either was a + // reset or external validation failed. + if (external_validation_transaction && + (was_reset || + external_validation_value_state != + PrefHashStoreTransaction::UNCHANGED)) { + const base::Value* new_value = nullptr; + pref_store_contents->Get(pref_path_, &new_value); + external_validation_transaction->StoreHash(pref_path_, new_value); + } + return was_reset; } diff --git a/chromium/components/user_prefs/tracked/tracked_atomic_preference.h b/chromium/components/user_prefs/tracked/tracked_atomic_preference.h index 04bd0eaae85..e279af85947 100644 --- a/chromium/components/user_prefs/tracked/tracked_atomic_preference.h +++ b/chromium/components/user_prefs/tracked/tracked_atomic_preference.h @@ -30,10 +30,13 @@ class TrackedAtomicPreference : public TrackedPreference { TrackedPreferenceValidationDelegate* delegate); // TrackedPreference implementation. + TrackedPreferenceType GetType() const override; void OnNewValue(const base::Value* value, PrefHashStoreTransaction* transaction) const override; - bool EnforceAndReport(base::DictionaryValue* pref_store_contents, - PrefHashStoreTransaction* transaction) const override; + bool EnforceAndReport( + base::DictionaryValue* pref_store_contents, + PrefHashStoreTransaction* transaction, + PrefHashStoreTransaction* external_validation_transaction) const override; private: const std::string pref_path_; diff --git a/chromium/components/user_prefs/tracked/tracked_preference.h b/chromium/components/user_prefs/tracked/tracked_preference.h index 4773ac1cd3c..97666a0fcf8 100644 --- a/chromium/components/user_prefs/tracked/tracked_preference.h +++ b/chromium/components/user_prefs/tracked/tracked_preference.h @@ -12,12 +12,16 @@ class DictionaryValue; class Value; } +enum class TrackedPreferenceType { ATOMIC, SPLIT }; + // A TrackedPreference tracks changes to an individual preference, reporting and // reacting to them according to preference-specific and browser-wide policies. class TrackedPreference { public: virtual ~TrackedPreference() {} + virtual TrackedPreferenceType GetType() const = 0; + // Notifies the underlying TrackedPreference about its new |value| which // can update hashes in the corresponding hash store via |transaction|. virtual void OnNewValue(const base::Value* value, @@ -27,10 +31,14 @@ class TrackedPreference { // is valid. Responds to verification failures according to // preference-specific and browser-wide policy and reports results to via UMA. // May use |transaction| to check/modify hashes in the corresponding hash - // store. + // store. Performs validation and reports results without enforcing for + // |external_validation_transaction|. This call assumes exclusive access to + // |external_validation_transaction| and its associated state and as such + // should only be called before any other subsystem is made aware of it. virtual bool EnforceAndReport( base::DictionaryValue* pref_store_contents, - PrefHashStoreTransaction* transaction) const = 0; + PrefHashStoreTransaction* transaction, + PrefHashStoreTransaction* external_validation_transaction) const = 0; }; #endif // COMPONENTS_USER_PREFS_TRACKED_TRACKED_PREFERENCE_H_ diff --git a/chromium/components/user_prefs/tracked/tracked_preference_helper.cc b/chromium/components/user_prefs/tracked/tracked_preference_helper.cc index f2e6883cf8a..fb36a2a1518 100644 --- a/chromium/components/user_prefs/tracked/tracked_preference_helper.cc +++ b/chromium/components/user_prefs/tracked/tracked_preference_helper.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/metrics/histogram_macros.h" #include "components/user_prefs/tracked/tracked_preference_histogram_names.h" TrackedPreferenceHelper::TrackedPreferenceHelper( @@ -37,6 +38,10 @@ TrackedPreferenceHelper::ResetAction TrackedPreferenceHelper::GetAction( case PrefHashStoreTransaction::SECURE_LEGACY: // Accept secure legacy device ID based hashes. return DONT_RESET; + case PrefHashStoreTransaction::UNSUPPORTED: + NOTREACHED() + << "GetAction should not be called with an UNSUPPORTED value state"; + return DONT_RESET; case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE: // Falls through. case PrefHashStoreTransaction::CHANGED: return enforce_ ? DO_RESET : WANTED_RESET; @@ -51,46 +56,53 @@ bool TrackedPreferenceHelper::IsPersonal() const { } void TrackedPreferenceHelper::ReportValidationResult( - PrefHashStoreTransaction::ValueState value_state) const { + PrefHashStoreTransaction::ValueState value_state, + base::StringPiece validation_type_suffix) const { + const char* histogram_name = nullptr; switch (value_state) { case PrefHashStoreTransaction::UNCHANGED: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramUnchanged, reporting_id_, - reporting_ids_count_); - return; + histogram_name = user_prefs::tracked::kTrackedPrefHistogramUnchanged; + break; case PrefHashStoreTransaction::CLEARED: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramCleared, reporting_id_, - reporting_ids_count_); - return; + histogram_name = user_prefs::tracked::kTrackedPrefHistogramCleared; + break; case PrefHashStoreTransaction::SECURE_LEGACY: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, - reporting_id_, reporting_ids_count_); - return; + histogram_name = + user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId; + break; case PrefHashStoreTransaction::CHANGED: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramChanged, reporting_id_, - reporting_ids_count_); - return; + histogram_name = user_prefs::tracked::kTrackedPrefHistogramChanged; + break; case PrefHashStoreTransaction::UNTRUSTED_UNKNOWN_VALUE: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramInitialized, reporting_id_, - reporting_ids_count_); - return; + histogram_name = user_prefs::tracked::kTrackedPrefHistogramInitialized; + break; case PrefHashStoreTransaction::TRUSTED_UNKNOWN_VALUE: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized, - reporting_id_, reporting_ids_count_); - return; + histogram_name = + user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized; + break; case PrefHashStoreTransaction::TRUSTED_NULL_VALUE: - UMA_HISTOGRAM_ENUMERATION( - user_prefs::tracked::kTrackedPrefHistogramNullInitialized, - reporting_id_, reporting_ids_count_); + histogram_name = + user_prefs::tracked::kTrackedPrefHistogramNullInitialized; + break; + case PrefHashStoreTransaction::UNSUPPORTED: + NOTREACHED() << "ReportValidationResult should not be called with an " + "UNSUPPORTED value state"; return; } - NOTREACHED() << "Unexpected PrefHashStoreTransaction::ValueState: " - << value_state; + DCHECK(histogram_name); + + std::string full_histogram_name(histogram_name); + if (!validation_type_suffix.empty()) { + full_histogram_name.push_back('.'); + validation_type_suffix.AppendToString(&full_histogram_name); + } + + // Using FactoryGet to allow dynamic histogram names. This is equivalent to + // UMA_HISTOGRAM_ENUMERATION(name, reporting_id_, reporting_ids_count_); + base::HistogramBase* histogram = base::LinearHistogram::FactoryGet( + full_histogram_name, 1, reporting_ids_count_, reporting_ids_count_ + 1, + base::HistogramBase::kUmaTargetedHistogramFlag); + histogram->Add(reporting_id_); } void TrackedPreferenceHelper::ReportAction(ResetAction reset_action) const { diff --git a/chromium/components/user_prefs/tracked/tracked_preference_helper.h b/chromium/components/user_prefs/tracked/tracked_preference_helper.h index 883e3e8f789..57b35fb32a3 100644 --- a/chromium/components/user_prefs/tracked/tracked_preference_helper.h +++ b/chromium/components/user_prefs/tracked/tracked_preference_helper.h @@ -42,8 +42,9 @@ class TrackedPreferenceHelper { bool IsPersonal() const; // Reports |value_state| via UMA under |reporting_id_|. - void ReportValidationResult( - PrefHashStoreTransaction::ValueState value_state) const; + // |validation_type_suffix| is appended to the reported histogram's name. + void ReportValidationResult(PrefHashStoreTransaction::ValueState value_state, + base::StringPiece validation_type_suffix) const; // Reports |reset_action| via UMA under |reporting_id_|. void ReportAction(ResetAction reset_action) const; diff --git a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc index deb4236dd1a..431bb9a31cf 100644 --- a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc +++ b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.cc @@ -25,6 +25,7 @@ const char kTrackedPrefHistogramWantedReset[] = const char kTrackedPrefHistogramReset[] = "Settings.TrackedPreferenceReset"; const char kTrackedSplitPrefHistogramChanged[] = "Settings.TrackedSplitPreferenceChanged."; +const char kTrackedPrefRegistryValidationSuffix[] = "FromRegistry"; } // namespace tracked } // namespace user_prefs diff --git a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h index c5a82a557b5..31b9ce30448 100644 --- a/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h +++ b/chromium/components/user_prefs/tracked/tracked_preference_histogram_names.h @@ -18,6 +18,7 @@ extern const char kTrackedPrefHistogramNullInitialized[]; extern const char kTrackedPrefHistogramWantedReset[]; extern const char kTrackedPrefHistogramReset[]; extern const char kTrackedSplitPrefHistogramChanged[]; +extern const char kTrackedPrefRegistryValidationSuffix[]; } // namespace tracked } // namespace user_prefs diff --git a/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h b/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h index 8ea9c80a0a5..d010df5aee3 100644 --- a/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h +++ b/chromium/components/user_prefs/tracked/tracked_preference_validation_delegate.h @@ -28,6 +28,7 @@ class TrackedPreferenceValidationDelegate { const std::string& pref_path, const base::Value* value, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal) = 0; // Notifies observes of the result (|value_state|) of checking the split @@ -37,7 +38,9 @@ class TrackedPreferenceValidationDelegate { const std::string& pref_path, const base::DictionaryValue* dict_value, const std::vector<std::string>& invalid_keys, + const std::vector<std::string>& external_validation_invalid_keys, PrefHashStoreTransaction::ValueState value_state, + PrefHashStoreTransaction::ValueState external_validation_value_state, bool is_personal) = 0; }; diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc b/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc index 0835a1450a0..50299141ed5 100644 --- a/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc +++ b/chromium/components/user_prefs/tracked/tracked_preferences_migration.cc @@ -36,7 +36,6 @@ class TrackedPreferencesMigrator register_on_successful_protected_store_write_callback, std::unique_ptr<PrefHashStore> unprotected_pref_hash_store, std::unique_ptr<PrefHashStore> protected_pref_hash_store, - std::unique_ptr<HashStoreContents> legacy_pref_hash_store, InterceptablePrefFilter* unprotected_pref_filter, InterceptablePrefFilter* protected_pref_filter); @@ -79,7 +78,6 @@ class TrackedPreferencesMigrator std::unique_ptr<PrefHashStore> unprotected_pref_hash_store_; std::unique_ptr<PrefHashStore> protected_pref_hash_store_; - std::unique_ptr<HashStoreContents> legacy_pref_hash_store_; std::unique_ptr<base::DictionaryValue> unprotected_prefs_; std::unique_ptr<base::DictionaryValue> protected_prefs_; @@ -122,10 +120,9 @@ void ScheduleSourcePrefStoreCleanup( void CleanupMigratedHashes(const std::set<std::string>& migrated_pref_names, PrefHashStore* origin_pref_hash_store, base::DictionaryValue* origin_pref_store) { + DictionaryHashStoreContents dictionary_contents(origin_pref_store); std::unique_ptr<PrefHashStoreTransaction> transaction( - origin_pref_hash_store->BeginTransaction( - std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(origin_pref_store)))); + origin_pref_hash_store->BeginTransaction(&dictionary_contents)); for (std::set<std::string>::const_iterator it = migrated_pref_names.begin(); it != migrated_pref_names.end(); ++it) { @@ -141,17 +138,13 @@ void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names, base::DictionaryValue* old_store, base::DictionaryValue* new_store, PrefHashStore* new_hash_store, - HashStoreContents* legacy_hash_store, bool* old_store_needs_cleanup, - bool* new_store_altered, - bool* used_legacy_pref_hashes) { + bool* new_store_altered) { const base::DictionaryValue* old_hash_store_contents = DictionaryHashStoreContents(old_store).GetContents(); - const base::DictionaryValue* legacy_hash_store_contents = - legacy_hash_store->GetContents(); + DictionaryHashStoreContents dictionary_contents(new_store); std::unique_ptr<PrefHashStoreTransaction> new_hash_store_transaction( - new_hash_store->BeginTransaction(std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(new_store)))); + new_hash_store->BeginTransaction(&dictionary_contents)); for (std::set<std::string>::const_iterator it = pref_names.begin(); it != pref_names.end(); @@ -186,11 +179,6 @@ void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names, const base::Value* old_hash = NULL; if (old_hash_store_contents) old_hash_store_contents->Get(pref_name, &old_hash); - if (!old_hash && legacy_hash_store_contents) { - legacy_hash_store_contents->Get(pref_name, &old_hash); - if (old_hash) - *used_legacy_pref_hashes = true; - } if (old_hash) { new_hash_store_transaction->ImportHash(pref_name, old_hash); *new_store_altered = true; @@ -219,7 +207,6 @@ TrackedPreferencesMigrator::TrackedPreferencesMigrator( register_on_successful_protected_store_write_callback, std::unique_ptr<PrefHashStore> unprotected_pref_hash_store, std::unique_ptr<PrefHashStore> protected_pref_hash_store, - std::unique_ptr<HashStoreContents> legacy_pref_hash_store, InterceptablePrefFilter* unprotected_pref_filter, InterceptablePrefFilter* protected_pref_filter) : unprotected_pref_names_(unprotected_pref_names), @@ -231,8 +218,7 @@ TrackedPreferencesMigrator::TrackedPreferencesMigrator( register_on_successful_protected_store_write_callback_( register_on_successful_protected_store_write_callback), unprotected_pref_hash_store_(std::move(unprotected_pref_hash_store)), - protected_pref_hash_store_(std::move(protected_pref_hash_store)), - legacy_pref_hash_store_(std::move(legacy_pref_hash_store)) { + protected_pref_hash_store_(std::move(protected_pref_hash_store)) { // The callbacks bound below will own this TrackedPreferencesMigrator by // reference. unprotected_pref_filter->InterceptNextFilterOnLoad( @@ -271,29 +257,18 @@ void TrackedPreferencesMigrator::MigrateIfReady() { if (!protected_prefs_ || !unprotected_prefs_) return; - bool used_legacy_pref_hashes = false; bool protected_prefs_need_cleanup = false; bool unprotected_prefs_altered = false; - MigratePrefsFromOldToNewStore(unprotected_pref_names_, - protected_prefs_.get(), - unprotected_prefs_.get(), - unprotected_pref_hash_store_.get(), - legacy_pref_hash_store_.get(), - &protected_prefs_need_cleanup, - &unprotected_prefs_altered, - &used_legacy_pref_hashes); + MigratePrefsFromOldToNewStore( + unprotected_pref_names_, protected_prefs_.get(), unprotected_prefs_.get(), + unprotected_pref_hash_store_.get(), &protected_prefs_need_cleanup, + &unprotected_prefs_altered); bool unprotected_prefs_need_cleanup = false; bool protected_prefs_altered = false; - MigratePrefsFromOldToNewStore(protected_pref_names_, - unprotected_prefs_.get(), - protected_prefs_.get(), - protected_pref_hash_store_.get(), - legacy_pref_hash_store_.get(), - &unprotected_prefs_need_cleanup, - &protected_prefs_altered, - &used_legacy_pref_hashes); - UMA_HISTOGRAM_BOOLEAN("Settings.MigratedHashesFromLocalState", - used_legacy_pref_hashes); + MigratePrefsFromOldToNewStore( + protected_pref_names_, unprotected_prefs_.get(), protected_prefs_.get(), + protected_pref_hash_store_.get(), &unprotected_prefs_need_cleanup, + &protected_prefs_altered); if (!unprotected_prefs_altered && !protected_prefs_altered) { // Clean up any MACs that might have been previously migrated from the @@ -308,7 +283,6 @@ void TrackedPreferencesMigrator::MigrateIfReady() { CleanupMigratedHashes(protected_pref_names_, unprotected_pref_hash_store_.get(), unprotected_prefs_.get()); - legacy_pref_hash_store_->Reset(); } // Hand the processed prefs back to their respective filters. @@ -354,7 +328,6 @@ void SetupTrackedPreferencesMigration( register_on_successful_protected_store_write_callback, std::unique_ptr<PrefHashStore> unprotected_pref_hash_store, std::unique_ptr<PrefHashStore> protected_pref_hash_store, - std::unique_ptr<HashStoreContents> legacy_pref_hash_store, InterceptablePrefFilter* unprotected_pref_filter, InterceptablePrefFilter* protected_pref_filter) { scoped_refptr<TrackedPreferencesMigrator> prefs_migrator( @@ -364,7 +337,6 @@ void SetupTrackedPreferencesMigration( register_on_successful_unprotected_store_write_callback, register_on_successful_protected_store_write_callback, std::move(unprotected_pref_hash_store), - std::move(protected_pref_hash_store), - std::move(legacy_pref_hash_store), unprotected_pref_filter, + std::move(protected_pref_hash_store), unprotected_pref_filter, protected_pref_filter)); } diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration.h b/chromium/components/user_prefs/tracked/tracked_preferences_migration.h index 3b5939228bb..3c96668a88d 100644 --- a/chromium/components/user_prefs/tracked/tracked_preferences_migration.h +++ b/chromium/components/user_prefs/tracked/tracked_preferences_migration.h @@ -23,12 +23,11 @@ class PrefHashStore; // (un)protected_store_cleaner| and // |register_on_successful_(un)protected_store_write_callback| are used to do // post-migration cleanup tasks. Those should be bound to weak pointers to avoid -// blocking shutdown. |(un)protected_pref_hash_store| and -// |legacy_pref_hash_store| are used to migrate MACs along with their protected -// preferences and/or from the legacy location in Local State. Migrated MACs -// will only be cleared from their old location in a subsequent run. The -// migration framework is resilient to a failed cleanup (it will simply try -// again in the next Chrome run). +// blocking shutdown. |(un)protected_pref_hash_store| is used to migrate MACs +// along with their protected preferences. Migrated MACs will only be cleared +// from their old location in a subsequent run. The migration framework is +// resilient to a failed cleanup (it will simply try again in the next Chrome +// run). void SetupTrackedPreferencesMigration( const std::set<std::string>& unprotected_pref_names, const std::set<std::string>& protected_pref_names, @@ -41,7 +40,6 @@ void SetupTrackedPreferencesMigration( register_on_successful_protected_store_write_callback, std::unique_ptr<PrefHashStore> unprotected_pref_hash_store, std::unique_ptr<PrefHashStore> protected_pref_hash_store, - std::unique_ptr<HashStoreContents> legacy_pref_hash_store, InterceptablePrefFilter* unprotected_pref_filter, InterceptablePrefFilter* protected_pref_filter); diff --git a/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc b/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc index 534ee21cd47..b1137543d3c 100644 --- a/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc +++ b/chromium/components/user_prefs/tracked/tracked_preferences_migration_unittest.cc @@ -22,7 +22,6 @@ #include "components/user_prefs/tracked/pref_hash_store.h" #include "components/user_prefs/tracked/pref_hash_store_impl.h" #include "components/user_prefs/tracked/pref_hash_store_transaction.h" -#include "components/user_prefs/tracked/pref_service_hash_store_contents.h" #include "components/user_prefs/tracked/tracked_preferences_migration.h" #include "testing/gtest/include/gtest/gtest.h" @@ -48,9 +47,11 @@ class SimpleInterceptablePrefFilter : public InterceptablePrefFilter { public: // PrefFilter remaining implementation. void FilterUpdate(const std::string& path) override { ADD_FAILURE(); } - void FilterSerializeData( + OnWriteCallbackPair FilterSerializeData( base::DictionaryValue* pref_store_contents) override { ADD_FAILURE(); + return std::make_pair(base::Closure(), + base::Callback<void(bool success)>()); } private: @@ -87,7 +88,6 @@ class TrackedPreferencesMigrationTest : public testing::Test { protected_store_migration_complete_(false) {} void SetUp() override { - PrefServiceHashStoreContents::RegisterPrefs(local_state_.registry()); Reset(); } @@ -123,9 +123,6 @@ class TrackedPreferencesMigrationTest : public testing::Test { new PrefHashStoreImpl(kSeed, kDeviceId, false)), std::unique_ptr<PrefHashStore>( new PrefHashStoreImpl(kSeed, kDeviceId, true)), - std::unique_ptr<HashStoreContents>( - new PrefServiceHashStoreContents(kHashStoreId, &local_state_)), - &mock_unprotected_pref_filter_, &mock_protected_pref_filter_); // Verify initial expectations are met. @@ -147,16 +144,6 @@ class TrackedPreferencesMigrationTest : public testing::Test { PresetStoreValueHash(store_id, key, value); } - // Sets |key| to |value| in the test store identified by |store_id| before - // migration begins. Stores the value hash in Local State as in M36 and - // earlier. - void PresetLegacyStoreValue(MockPrefStoreID store_id, - const std::string& key, - const std::string value) { - PresetStoreValueOnly(store_id, key, value); - PresetLegacyValueHash(key, value); - } - // Stores a hash for |key| and |value| in the hash store identified by // |store_id| before migration begins. void PresetStoreValueHash(MockPrefStoreID store_id, @@ -177,24 +164,8 @@ class TrackedPreferencesMigrationTest : public testing::Test { DCHECK(store); base::StringValue string_value(value); - pref_hash_store - ->BeginTransaction(std::unique_ptr<HashStoreContents>( - new DictionaryHashStoreContents(store))) - ->StoreHash(key, &string_value); - } - - // Stores a hash for |key| and |value| in the legacy hash store in - // local_state. - void PresetLegacyValueHash(const std::string& key, - const std::string value) { - std::unique_ptr<PrefHashStore> pref_hash_store( - new PrefHashStoreImpl(kSeed, kDeviceId, true)); - - base::StringValue string_value(value); - PrefHashStoreImpl(kSeed, kDeviceId, true) - .BeginTransaction(std::unique_ptr<HashStoreContents>( - new PrefServiceHashStoreContents(kHashStoreId, &local_state_))) - ->StoreHash(key, &string_value); + DictionaryHashStoreContents contents(store); + pref_hash_store->BeginTransaction(&contents)->StoreHash(key, &string_value); } // Returns true if the store opposite to |store_id| is observed for its next @@ -255,16 +226,6 @@ class TrackedPreferencesMigrationTest : public testing::Test { static_cast<std::string*>(NULL)); } - // Determines whether |expected_pref_in_hash_store| has a hash in the Local - // State hash store. - bool ContainsLegacyHash(const std::string& expected_pref_in_hash_store) { - const base::DictionaryValue* hash_store_contents = - PrefServiceHashStoreContents(kHashStoreId, &local_state_).GetContents(); - return hash_store_contents && - hash_store_contents->GetString(expected_pref_in_hash_store, - static_cast<std::string*>(NULL)); - } - // Both stores need to hand their prefs over in order for migration to kick // in. void HandPrefsToMigrator(MockPrefStoreID store_id) { @@ -396,7 +357,6 @@ class TrackedPreferencesMigrationTest : public testing::Test { store->SetString(key, value); } - static const char kHashStoreId[]; static const char kSeed[]; static const char kDeviceId[]; @@ -421,9 +381,6 @@ class TrackedPreferencesMigrationTest : public testing::Test { }; // static -const char TrackedPreferencesMigrationTest::kHashStoreId[] = "hash-store-id"; - -// static const char TrackedPreferencesMigrationTest::kSeed[] = "seed"; // static @@ -482,208 +439,6 @@ TEST_F(TrackedPreferencesMigrationTest, NoMigrationRequired) { EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); } -TEST_F(TrackedPreferencesMigrationTest, LegacyHashMigrationOnly) { - PresetLegacyStoreValue( - MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue); - PresetLegacyStoreValue( - MOCK_PROTECTED_PREF_STORE, kProtectedPref, kProtectedPrefValue); - - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref)); - - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); - - EXPECT_TRUE(ContainsLegacyHash(kProtectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref)); - - // Hand unprotected prefs to the migrator which should wait for the protected - // prefs. - HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE); - EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE)); - EXPECT_FALSE(MigrationCompleted()); - - // Hand protected prefs to the migrator which should proceed with the - // migration synchronously. - HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE); - EXPECT_TRUE(MigrationCompleted()); - - // Prefs should have been handed back over. - EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE)); - - // There is no pending cleanup task for the modern hash stores. - EXPECT_FALSE( - WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_FALSE( - WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE)); - - // Both stores were modified as hashes were moved from Local State. - EXPECT_TRUE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_TRUE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE)); - - base::StringPairs expected_unprotected_values; - expected_unprotected_values.push_back( - std::make_pair(kUnprotectedPref, kUnprotectedPrefValue)); - VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values); - - base::StringPairs expected_protected_values; - expected_protected_values.push_back( - std::make_pair(kProtectedPref, kProtectedPrefValue)); - VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values); - - EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref)); - - EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); - - // The Local State hash store will not be reset until the next run. - EXPECT_TRUE(ContainsLegacyHash(kProtectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref)); - - Reset(); - - HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE); - HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE); - EXPECT_TRUE(MigrationCompleted()); - - // Neither store was modified. - EXPECT_FALSE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_FALSE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE)); - - EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref)); - - EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); - - EXPECT_FALSE(ContainsLegacyHash(kProtectedPref)); - EXPECT_FALSE(ContainsLegacyHash(kUnprotectedPref)); -} - -TEST_F(TrackedPreferencesMigrationTest, FullMigrationWithLegacyHashStore) { - // Store some values with matching MACs in Local State. - PresetLegacyStoreValue( - MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue); - PresetLegacyStoreValue(MOCK_UNPROTECTED_PREF_STORE, - kPreviouslyUnprotectedPref, - kPreviouslyUnprotectedPrefValue); - PresetLegacyStoreValue( - MOCK_PROTECTED_PREF_STORE, kProtectedPref, kProtectedPrefValue); - PresetLegacyStoreValue(MOCK_PROTECTED_PREF_STORE, - kPreviouslyProtectedPref, - kPreviouslyProtectedPrefValue); - - // Verify that there are no MACs in Preferences or Secure Preferences. - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref)); - - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref)); - - // Verify that there are MACs in Local State. - EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kPreviouslyUnprotectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kProtectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kPreviouslyProtectedPref)); - - // Perform a first-pass migration. - HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE); - HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE); - EXPECT_TRUE(MigrationCompleted()); - - // All values should have been moved to their preferred locations, including - // MACs. - base::StringPairs expected_unprotected_values; - expected_unprotected_values.push_back( - std::make_pair(kUnprotectedPref, kUnprotectedPrefValue)); - expected_unprotected_values.push_back( - std::make_pair(kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue)); - base::StringPairs expected_protected_values; - expected_protected_values.push_back( - std::make_pair(kProtectedPref, kProtectedPrefValue)); - expected_protected_values.push_back(std::make_pair( - kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue)); - - VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values); - VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values); - - EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_TRUE( - ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref)); - EXPECT_TRUE( - ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref)); - EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref)); - - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); - - EXPECT_FALSE( - ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref)); - - // Removing the values from their previous locations is deferred until the new - // locations are persisted. - EXPECT_TRUE(ContainsLegacyHash(kUnprotectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kPreviouslyUnprotectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kProtectedPref)); - EXPECT_TRUE(ContainsLegacyHash(kPreviouslyProtectedPref)); - - EXPECT_TRUE( - WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_TRUE( - WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE)); - - SimulateSuccessfulWrite(MOCK_UNPROTECTED_PREF_STORE); - SimulateSuccessfulWrite(MOCK_PROTECTED_PREF_STORE); - - Reset(); - - HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE); - HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE); - EXPECT_TRUE(MigrationCompleted()); - - // In this run the MACs should have been removed from their previous - // locations. There is no more pending action. - EXPECT_FALSE( - WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE)); - EXPECT_FALSE( - WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE)); - - EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref)); - EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_TRUE( - ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref)); - - EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref)); - EXPECT_TRUE( - ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref)); - EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref)); - EXPECT_FALSE( - ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref)); - - EXPECT_FALSE(ContainsLegacyHash(kUnprotectedPref)); - EXPECT_FALSE(ContainsLegacyHash(kPreviouslyUnprotectedPref)); - EXPECT_FALSE(ContainsLegacyHash(kProtectedPref)); - EXPECT_FALSE(ContainsLegacyHash(kPreviouslyProtectedPref)); - - VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values); - VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values); -} - TEST_F(TrackedPreferencesMigrationTest, FullMigration) { PresetStoreValue( MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref, kUnprotectedPrefValue); diff --git a/chromium/components/user_prefs/tracked/tracked_split_preference.cc b/chromium/components/user_prefs/tracked/tracked_split_preference.cc index 37bac10b760..2094d97b71e 100644 --- a/chromium/components/user_prefs/tracked/tracked_split_preference.cc +++ b/chromium/components/user_prefs/tracked/tracked_split_preference.cc @@ -27,6 +27,10 @@ TrackedSplitPreference::TrackedSplitPreference( delegate_(delegate) { } +TrackedPreferenceType TrackedSplitPreference::GetType() const { + return TrackedPreferenceType::SPLIT; +} + void TrackedSplitPreference::OnNewValue( const base::Value* value, PrefHashStoreTransaction* transaction) const { @@ -40,7 +44,8 @@ void TrackedSplitPreference::OnNewValue( bool TrackedSplitPreference::EnforceAndReport( base::DictionaryValue* pref_store_contents, - PrefHashStoreTransaction* transaction) const { + PrefHashStoreTransaction* transaction, + PrefHashStoreTransaction* external_validation_transaction) const { base::DictionaryValue* dict_value = NULL; if (!pref_store_contents->GetDictionary(pref_path_, &dict_value) && pref_store_contents->Get(pref_path_, NULL)) { @@ -56,14 +61,27 @@ bool TrackedSplitPreference::EnforceAndReport( if (value_state == PrefHashStoreTransaction::CHANGED) helper_.ReportSplitPreferenceChangedCount(invalid_keys.size()); - helper_.ReportValidationResult(value_state); + helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix()); + + PrefHashStoreTransaction::ValueState external_validation_value_state = + PrefHashStoreTransaction::UNSUPPORTED; + std::vector<std::string> external_validation_invalid_keys; + if (external_validation_transaction) { + external_validation_value_state = + external_validation_transaction->CheckSplitValue( + pref_path_, dict_value, &external_validation_invalid_keys); + helper_.ReportValidationResult( + external_validation_value_state, + external_validation_transaction->GetStoreUMASuffix()); + } - TrackedPreferenceHelper::ResetAction reset_action = - helper_.GetAction(value_state); if (delegate_) { - delegate_->OnSplitPreferenceValidation(pref_path_, dict_value, invalid_keys, - value_state, helper_.IsPersonal()); + delegate_->OnSplitPreferenceValidation( + pref_path_, dict_value, invalid_keys, external_validation_invalid_keys, + value_state, external_validation_value_state, helper_.IsPersonal()); } + TrackedPreferenceHelper::ResetAction reset_action = + helper_.GetAction(value_state); helper_.ReportAction(reset_action); bool was_reset = false; @@ -88,5 +106,16 @@ bool TrackedSplitPreference::EnforceAndReport( transaction->StoreSplitHash(pref_path_, new_dict_value); } + // Update MACs in the external store if there is one and there either was a + // reset or external validation failed. + if (external_validation_transaction && + (was_reset || + external_validation_value_state != + PrefHashStoreTransaction::UNCHANGED)) { + const base::DictionaryValue* new_dict_value = nullptr; + pref_store_contents->GetDictionary(pref_path_, &new_dict_value); + external_validation_transaction->StoreSplitHash(pref_path_, new_dict_value); + } + return was_reset; } diff --git a/chromium/components/user_prefs/tracked/tracked_split_preference.h b/chromium/components/user_prefs/tracked/tracked_split_preference.h index f2700a4ddab..359c8e1f570 100644 --- a/chromium/components/user_prefs/tracked/tracked_split_preference.h +++ b/chromium/components/user_prefs/tracked/tracked_split_preference.h @@ -33,10 +33,13 @@ class TrackedSplitPreference : public TrackedPreference { TrackedPreferenceValidationDelegate* delegate); // TrackedPreference implementation. + TrackedPreferenceType GetType() const override; void OnNewValue(const base::Value* value, PrefHashStoreTransaction* transaction) const override; - bool EnforceAndReport(base::DictionaryValue* pref_store_contents, - PrefHashStoreTransaction* transaction) const override; + bool EnforceAndReport( + base::DictionaryValue* pref_store_contents, + PrefHashStoreTransaction* transaction, + PrefHashStoreTransaction* external_validation_transaction) const override; private: const std::string pref_path_; |