123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- // 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 "services/preferences/tracked/tracked_preferences_migration.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/memory/ref_counted.h"
- #include "base/metrics/histogram.h"
- #include "base/values.h"
- #include "services/preferences/tracked/dictionary_hash_store_contents.h"
- #include "services/preferences/tracked/hash_store_contents.h"
- #include "services/preferences/tracked/interceptable_pref_filter.h"
- #include "services/preferences/tracked/pref_hash_store.h"
- #include "services/preferences/tracked/pref_hash_store_transaction.h"
- namespace {
- class TrackedPreferencesMigrator
- : public base::RefCounted<TrackedPreferencesMigrator> {
- public:
- enum PrefFilterID { UNPROTECTED_PREF_FILTER, PROTECTED_PREF_FILTER };
- TrackedPreferencesMigrator(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::RepeatingCallback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::RepeatingCallback<void(const std::string& key)>&
- protected_store_cleaner,
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_unprotected_store_write_callback,
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter);
- TrackedPreferencesMigrator(const TrackedPreferencesMigrator&) = delete;
- TrackedPreferencesMigrator& operator=(const TrackedPreferencesMigrator&) =
- delete;
- // Stores the data coming in from the filter identified by |id| into this
- // class and then calls MigrateIfReady();
- void InterceptFilterOnLoad(
- PrefFilterID id,
- InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- finalize_filter_on_load,
- std::unique_ptr<base::DictionaryValue> prefs);
- private:
- friend class base::RefCounted<TrackedPreferencesMigrator>;
- ~TrackedPreferencesMigrator();
- // Proceeds with migration if both |unprotected_prefs_| and |protected_prefs_|
- // have been set.
- void MigrateIfReady();
- const std::set<std::string> unprotected_pref_names_;
- const std::set<std::string> protected_pref_names_;
- const base::RepeatingCallback<void(const std::string& key)>
- unprotected_store_cleaner_;
- const base::RepeatingCallback<void(const std::string& key)>
- protected_store_cleaner_;
- const base::RepeatingCallback<void(base::OnceClosure)>
- register_on_successful_unprotected_store_write_callback_;
- const base::RepeatingCallback<void(base::OnceClosure)>
- register_on_successful_protected_store_write_callback_;
- InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- finalize_unprotected_filter_on_load_;
- InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- finalize_protected_filter_on_load_;
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store_;
- std::unique_ptr<PrefHashStore> protected_pref_hash_store_;
- std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
- std::unique_ptr<base::DictionaryValue> protected_prefs_;
- };
- // Invokes |store_cleaner| for every |keys_to_clean|.
- void CleanupPrefStore(
- const base::RepeatingCallback<void(const std::string& key)>& store_cleaner,
- const std::set<std::string>& keys_to_clean) {
- for (std::set<std::string>::const_iterator it = keys_to_clean.begin();
- it != keys_to_clean.end(); ++it) {
- store_cleaner.Run(*it);
- }
- }
- // If |wait_for_commit_to_destination_store|: schedules (via
- // |register_on_successful_destination_store_write_callback|) a cleanup of the
- // |keys_to_clean| from the source pref store (through |source_store_cleaner|)
- // once the destination pref store they were migrated to was successfully
- // written to disk. Otherwise, executes the cleanup right away.
- void ScheduleSourcePrefStoreCleanup(
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_destination_store_write_callback,
- const base::RepeatingCallback<void(const std::string& key)>&
- source_store_cleaner,
- const std::set<std::string>& keys_to_clean,
- bool wait_for_commit_to_destination_store) {
- DCHECK(!keys_to_clean.empty());
- if (wait_for_commit_to_destination_store) {
- register_on_successful_destination_store_write_callback.Run(
- base::BindOnce(&CleanupPrefStore, source_store_cleaner, keys_to_clean));
- } else {
- CleanupPrefStore(source_store_cleaner, keys_to_clean);
- }
- }
- // Removes hashes for |migrated_pref_names| from |origin_pref_store| using
- // the configuration/implementation in |origin_pref_hash_store|.
- 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(&dictionary_contents));
- for (std::set<std::string>::const_iterator it = migrated_pref_names.begin();
- it != migrated_pref_names.end(); ++it) {
- transaction->ClearHash(*it);
- }
- }
- // Copies the value of each pref in |pref_names| which is set in |old_store|,
- // but not in |new_store| into |new_store|. Sets |old_store_needs_cleanup| to
- // true if any old duplicates remain in |old_store| and sets |new_store_altered|
- // to true if any value was copied to |new_store|.
- void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
- base::DictionaryValue* old_store,
- base::DictionaryValue* new_store,
- PrefHashStore* new_hash_store,
- bool* old_store_needs_cleanup,
- bool* new_store_altered) {
- const base::DictionaryValue* old_hash_store_contents =
- DictionaryHashStoreContents(old_store).GetContents();
- DictionaryHashStoreContents dictionary_contents(new_store);
- std::unique_ptr<PrefHashStoreTransaction> new_hash_store_transaction(
- new_hash_store->BeginTransaction(&dictionary_contents));
- for (std::set<std::string>::const_iterator it = pref_names.begin();
- it != pref_names.end(); ++it) {
- const std::string& pref_name = *it;
- // If the destination does not have a hash for this pref we will
- // unconditionally attempt to move it.
- bool destination_hash_missing =
- !new_hash_store_transaction->HasHash(pref_name);
- // If we migrate the value we will also attempt to migrate the hash.
- bool migrated_value = false;
- if (const base::Value* value_in_old_store =
- old_store->FindPath(pref_name)) {
- // Whether this value ends up being copied below or was left behind by a
- // previous incomplete migration, it should be cleaned up.
- *old_store_needs_cleanup = true;
- if (!new_store->FindPath(pref_name)) {
- // Copy the value from |old_store| to |new_store| rather than moving it
- // to avoid data loss should |old_store| be flushed to disk without
- // |new_store| having equivalently been successfully flushed to disk
- // (e.g., on crash or in cases where |new_store| is read-only following
- // a read error on startup).
- new_store->SetPath(pref_name, value_in_old_store->Clone());
- migrated_value = true;
- *new_store_altered = true;
- }
- }
- if (destination_hash_missing || migrated_value) {
- const base::Value* old_hash = nullptr;
- if (old_hash_store_contents)
- old_hash = old_hash_store_contents->FindPath(pref_name);
- if (old_hash) {
- new_hash_store_transaction->ImportHash(pref_name, old_hash);
- *new_store_altered = true;
- } else if (!destination_hash_missing) {
- // Do not allow values to be migrated without MACs if the destination
- // already has a MAC (http://crbug.com/414554). Remove the migrated
- // value in order to provide the same no-op behaviour as if the pref was
- // added to the wrong file when there was already a value for
- // |pref_name| in |new_store|.
- new_store->RemovePath(pref_name);
- *new_store_altered = true;
- }
- }
- }
- }
- TrackedPreferencesMigrator::TrackedPreferencesMigrator(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::RepeatingCallback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::RepeatingCallback<void(const std::string& key)>&
- protected_store_cleaner,
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_unprotected_store_write_callback,
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter)
- : unprotected_pref_names_(unprotected_pref_names),
- protected_pref_names_(protected_pref_names),
- unprotected_store_cleaner_(unprotected_store_cleaner),
- protected_store_cleaner_(protected_store_cleaner),
- register_on_successful_unprotected_store_write_callback_(
- register_on_successful_unprotected_store_write_callback),
- 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)) {}
- TrackedPreferencesMigrator::~TrackedPreferencesMigrator() {}
- void TrackedPreferencesMigrator::InterceptFilterOnLoad(
- PrefFilterID id,
- InterceptablePrefFilter::FinalizeFilterOnLoadCallback
- finalize_filter_on_load,
- std::unique_ptr<base::DictionaryValue> prefs) {
- switch (id) {
- case UNPROTECTED_PREF_FILTER:
- finalize_unprotected_filter_on_load_ = std::move(finalize_filter_on_load);
- unprotected_prefs_ = std::move(prefs);
- break;
- case PROTECTED_PREF_FILTER:
- finalize_protected_filter_on_load_ = std::move(finalize_filter_on_load);
- protected_prefs_ = std::move(prefs);
- break;
- }
- MigrateIfReady();
- }
- void TrackedPreferencesMigrator::MigrateIfReady() {
- // Wait for both stores to have been read before proceeding.
- if (!protected_prefs_ || !unprotected_prefs_)
- return;
- 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(), &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(), &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
- // various stores. It's safe to leave them behind for a little while as they
- // will be ignored unless the corresponding value is _also_ present. The
- // cleanup must be deferred until the MACs have been written to their target
- // stores, and doing so in a subsequent launch is easier than within the
- // same process.
- CleanupMigratedHashes(unprotected_pref_names_,
- protected_pref_hash_store_.get(),
- protected_prefs_.get());
- CleanupMigratedHashes(protected_pref_names_,
- unprotected_pref_hash_store_.get(),
- unprotected_prefs_.get());
- }
- // Hand the processed prefs back to their respective filters.
- std::move(finalize_unprotected_filter_on_load_)
- .Run(std::move(unprotected_prefs_), unprotected_prefs_altered);
- std::move(finalize_protected_filter_on_load_)
- .Run(std::move(protected_prefs_), protected_prefs_altered);
- if (unprotected_prefs_need_cleanup) {
- // Schedule a cleanup of the |protected_pref_names_| from the unprotected
- // prefs once the protected prefs were successfully written to disk (or
- // do it immediately if |!protected_prefs_altered|).
- ScheduleSourcePrefStoreCleanup(
- register_on_successful_protected_store_write_callback_,
- unprotected_store_cleaner_, protected_pref_names_,
- protected_prefs_altered);
- }
- if (protected_prefs_need_cleanup) {
- // Schedule a cleanup of the |unprotected_pref_names_| from the protected
- // prefs once the unprotected prefs were successfully written to disk (or
- // do it immediately if |!unprotected_prefs_altered|).
- ScheduleSourcePrefStoreCleanup(
- register_on_successful_unprotected_store_write_callback_,
- protected_store_cleaner_, unprotected_pref_names_,
- unprotected_prefs_altered);
- }
- }
- } // namespace
- void SetupTrackedPreferencesMigration(
- const std::set<std::string>& unprotected_pref_names,
- const std::set<std::string>& protected_pref_names,
- const base::RepeatingCallback<void(const std::string& key)>&
- unprotected_store_cleaner,
- const base::RepeatingCallback<void(const std::string& key)>&
- protected_store_cleaner,
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_unprotected_store_write_callback,
- const base::RepeatingCallback<void(base::OnceClosure)>&
- register_on_successful_protected_store_write_callback,
- std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
- std::unique_ptr<PrefHashStore> protected_pref_hash_store,
- InterceptablePrefFilter* unprotected_pref_filter,
- InterceptablePrefFilter* protected_pref_filter) {
- auto prefs_migrator = base::MakeRefCounted<TrackedPreferencesMigrator>(
- unprotected_pref_names, protected_pref_names, unprotected_store_cleaner,
- protected_store_cleaner,
- 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), unprotected_pref_filter,
- protected_pref_filter);
- // The callbacks bound below will own this TrackedPreferencesMigrator by
- // reference.
- unprotected_pref_filter->InterceptNextFilterOnLoad(base::BindOnce(
- &TrackedPreferencesMigrator::InterceptFilterOnLoad, prefs_migrator,
- TrackedPreferencesMigrator::UNPROTECTED_PREF_FILTER));
- protected_pref_filter->InterceptNextFilterOnLoad(base::BindOnce(
- &TrackedPreferencesMigrator::InterceptFilterOnLoad, prefs_migrator,
- TrackedPreferencesMigrator::PROTECTED_PREF_FILTER));
- }
|