tracked_preferences_migration.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/preferences/tracked/tracked_preferences_migration.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/memory/ref_counted.h"
  9. #include "base/metrics/histogram.h"
  10. #include "base/values.h"
  11. #include "services/preferences/tracked/dictionary_hash_store_contents.h"
  12. #include "services/preferences/tracked/hash_store_contents.h"
  13. #include "services/preferences/tracked/interceptable_pref_filter.h"
  14. #include "services/preferences/tracked/pref_hash_store.h"
  15. #include "services/preferences/tracked/pref_hash_store_transaction.h"
  16. namespace {
  17. class TrackedPreferencesMigrator
  18. : public base::RefCounted<TrackedPreferencesMigrator> {
  19. public:
  20. enum PrefFilterID { UNPROTECTED_PREF_FILTER, PROTECTED_PREF_FILTER };
  21. TrackedPreferencesMigrator(
  22. const std::set<std::string>& unprotected_pref_names,
  23. const std::set<std::string>& protected_pref_names,
  24. const base::RepeatingCallback<void(const std::string& key)>&
  25. unprotected_store_cleaner,
  26. const base::RepeatingCallback<void(const std::string& key)>&
  27. protected_store_cleaner,
  28. const base::RepeatingCallback<void(base::OnceClosure)>&
  29. register_on_successful_unprotected_store_write_callback,
  30. const base::RepeatingCallback<void(base::OnceClosure)>&
  31. register_on_successful_protected_store_write_callback,
  32. std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
  33. std::unique_ptr<PrefHashStore> protected_pref_hash_store,
  34. InterceptablePrefFilter* unprotected_pref_filter,
  35. InterceptablePrefFilter* protected_pref_filter);
  36. TrackedPreferencesMigrator(const TrackedPreferencesMigrator&) = delete;
  37. TrackedPreferencesMigrator& operator=(const TrackedPreferencesMigrator&) =
  38. delete;
  39. // Stores the data coming in from the filter identified by |id| into this
  40. // class and then calls MigrateIfReady();
  41. void InterceptFilterOnLoad(
  42. PrefFilterID id,
  43. InterceptablePrefFilter::FinalizeFilterOnLoadCallback
  44. finalize_filter_on_load,
  45. std::unique_ptr<base::DictionaryValue> prefs);
  46. private:
  47. friend class base::RefCounted<TrackedPreferencesMigrator>;
  48. ~TrackedPreferencesMigrator();
  49. // Proceeds with migration if both |unprotected_prefs_| and |protected_prefs_|
  50. // have been set.
  51. void MigrateIfReady();
  52. const std::set<std::string> unprotected_pref_names_;
  53. const std::set<std::string> protected_pref_names_;
  54. const base::RepeatingCallback<void(const std::string& key)>
  55. unprotected_store_cleaner_;
  56. const base::RepeatingCallback<void(const std::string& key)>
  57. protected_store_cleaner_;
  58. const base::RepeatingCallback<void(base::OnceClosure)>
  59. register_on_successful_unprotected_store_write_callback_;
  60. const base::RepeatingCallback<void(base::OnceClosure)>
  61. register_on_successful_protected_store_write_callback_;
  62. InterceptablePrefFilter::FinalizeFilterOnLoadCallback
  63. finalize_unprotected_filter_on_load_;
  64. InterceptablePrefFilter::FinalizeFilterOnLoadCallback
  65. finalize_protected_filter_on_load_;
  66. std::unique_ptr<PrefHashStore> unprotected_pref_hash_store_;
  67. std::unique_ptr<PrefHashStore> protected_pref_hash_store_;
  68. std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
  69. std::unique_ptr<base::DictionaryValue> protected_prefs_;
  70. };
  71. // Invokes |store_cleaner| for every |keys_to_clean|.
  72. void CleanupPrefStore(
  73. const base::RepeatingCallback<void(const std::string& key)>& store_cleaner,
  74. const std::set<std::string>& keys_to_clean) {
  75. for (std::set<std::string>::const_iterator it = keys_to_clean.begin();
  76. it != keys_to_clean.end(); ++it) {
  77. store_cleaner.Run(*it);
  78. }
  79. }
  80. // If |wait_for_commit_to_destination_store|: schedules (via
  81. // |register_on_successful_destination_store_write_callback|) a cleanup of the
  82. // |keys_to_clean| from the source pref store (through |source_store_cleaner|)
  83. // once the destination pref store they were migrated to was successfully
  84. // written to disk. Otherwise, executes the cleanup right away.
  85. void ScheduleSourcePrefStoreCleanup(
  86. const base::RepeatingCallback<void(base::OnceClosure)>&
  87. register_on_successful_destination_store_write_callback,
  88. const base::RepeatingCallback<void(const std::string& key)>&
  89. source_store_cleaner,
  90. const std::set<std::string>& keys_to_clean,
  91. bool wait_for_commit_to_destination_store) {
  92. DCHECK(!keys_to_clean.empty());
  93. if (wait_for_commit_to_destination_store) {
  94. register_on_successful_destination_store_write_callback.Run(
  95. base::BindOnce(&CleanupPrefStore, source_store_cleaner, keys_to_clean));
  96. } else {
  97. CleanupPrefStore(source_store_cleaner, keys_to_clean);
  98. }
  99. }
  100. // Removes hashes for |migrated_pref_names| from |origin_pref_store| using
  101. // the configuration/implementation in |origin_pref_hash_store|.
  102. void CleanupMigratedHashes(const std::set<std::string>& migrated_pref_names,
  103. PrefHashStore* origin_pref_hash_store,
  104. base::DictionaryValue* origin_pref_store) {
  105. DictionaryHashStoreContents dictionary_contents(origin_pref_store);
  106. std::unique_ptr<PrefHashStoreTransaction> transaction(
  107. origin_pref_hash_store->BeginTransaction(&dictionary_contents));
  108. for (std::set<std::string>::const_iterator it = migrated_pref_names.begin();
  109. it != migrated_pref_names.end(); ++it) {
  110. transaction->ClearHash(*it);
  111. }
  112. }
  113. // Copies the value of each pref in |pref_names| which is set in |old_store|,
  114. // but not in |new_store| into |new_store|. Sets |old_store_needs_cleanup| to
  115. // true if any old duplicates remain in |old_store| and sets |new_store_altered|
  116. // to true if any value was copied to |new_store|.
  117. void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
  118. base::DictionaryValue* old_store,
  119. base::DictionaryValue* new_store,
  120. PrefHashStore* new_hash_store,
  121. bool* old_store_needs_cleanup,
  122. bool* new_store_altered) {
  123. const base::DictionaryValue* old_hash_store_contents =
  124. DictionaryHashStoreContents(old_store).GetContents();
  125. DictionaryHashStoreContents dictionary_contents(new_store);
  126. std::unique_ptr<PrefHashStoreTransaction> new_hash_store_transaction(
  127. new_hash_store->BeginTransaction(&dictionary_contents));
  128. for (std::set<std::string>::const_iterator it = pref_names.begin();
  129. it != pref_names.end(); ++it) {
  130. const std::string& pref_name = *it;
  131. // If the destination does not have a hash for this pref we will
  132. // unconditionally attempt to move it.
  133. bool destination_hash_missing =
  134. !new_hash_store_transaction->HasHash(pref_name);
  135. // If we migrate the value we will also attempt to migrate the hash.
  136. bool migrated_value = false;
  137. if (const base::Value* value_in_old_store =
  138. old_store->FindPath(pref_name)) {
  139. // Whether this value ends up being copied below or was left behind by a
  140. // previous incomplete migration, it should be cleaned up.
  141. *old_store_needs_cleanup = true;
  142. if (!new_store->FindPath(pref_name)) {
  143. // Copy the value from |old_store| to |new_store| rather than moving it
  144. // to avoid data loss should |old_store| be flushed to disk without
  145. // |new_store| having equivalently been successfully flushed to disk
  146. // (e.g., on crash or in cases where |new_store| is read-only following
  147. // a read error on startup).
  148. new_store->SetPath(pref_name, value_in_old_store->Clone());
  149. migrated_value = true;
  150. *new_store_altered = true;
  151. }
  152. }
  153. if (destination_hash_missing || migrated_value) {
  154. const base::Value* old_hash = nullptr;
  155. if (old_hash_store_contents)
  156. old_hash = old_hash_store_contents->FindPath(pref_name);
  157. if (old_hash) {
  158. new_hash_store_transaction->ImportHash(pref_name, old_hash);
  159. *new_store_altered = true;
  160. } else if (!destination_hash_missing) {
  161. // Do not allow values to be migrated without MACs if the destination
  162. // already has a MAC (http://crbug.com/414554). Remove the migrated
  163. // value in order to provide the same no-op behaviour as if the pref was
  164. // added to the wrong file when there was already a value for
  165. // |pref_name| in |new_store|.
  166. new_store->RemovePath(pref_name);
  167. *new_store_altered = true;
  168. }
  169. }
  170. }
  171. }
  172. TrackedPreferencesMigrator::TrackedPreferencesMigrator(
  173. const std::set<std::string>& unprotected_pref_names,
  174. const std::set<std::string>& protected_pref_names,
  175. const base::RepeatingCallback<void(const std::string& key)>&
  176. unprotected_store_cleaner,
  177. const base::RepeatingCallback<void(const std::string& key)>&
  178. protected_store_cleaner,
  179. const base::RepeatingCallback<void(base::OnceClosure)>&
  180. register_on_successful_unprotected_store_write_callback,
  181. const base::RepeatingCallback<void(base::OnceClosure)>&
  182. register_on_successful_protected_store_write_callback,
  183. std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
  184. std::unique_ptr<PrefHashStore> protected_pref_hash_store,
  185. InterceptablePrefFilter* unprotected_pref_filter,
  186. InterceptablePrefFilter* protected_pref_filter)
  187. : unprotected_pref_names_(unprotected_pref_names),
  188. protected_pref_names_(protected_pref_names),
  189. unprotected_store_cleaner_(unprotected_store_cleaner),
  190. protected_store_cleaner_(protected_store_cleaner),
  191. register_on_successful_unprotected_store_write_callback_(
  192. register_on_successful_unprotected_store_write_callback),
  193. register_on_successful_protected_store_write_callback_(
  194. register_on_successful_protected_store_write_callback),
  195. unprotected_pref_hash_store_(std::move(unprotected_pref_hash_store)),
  196. protected_pref_hash_store_(std::move(protected_pref_hash_store)) {}
  197. TrackedPreferencesMigrator::~TrackedPreferencesMigrator() {}
  198. void TrackedPreferencesMigrator::InterceptFilterOnLoad(
  199. PrefFilterID id,
  200. InterceptablePrefFilter::FinalizeFilterOnLoadCallback
  201. finalize_filter_on_load,
  202. std::unique_ptr<base::DictionaryValue> prefs) {
  203. switch (id) {
  204. case UNPROTECTED_PREF_FILTER:
  205. finalize_unprotected_filter_on_load_ = std::move(finalize_filter_on_load);
  206. unprotected_prefs_ = std::move(prefs);
  207. break;
  208. case PROTECTED_PREF_FILTER:
  209. finalize_protected_filter_on_load_ = std::move(finalize_filter_on_load);
  210. protected_prefs_ = std::move(prefs);
  211. break;
  212. }
  213. MigrateIfReady();
  214. }
  215. void TrackedPreferencesMigrator::MigrateIfReady() {
  216. // Wait for both stores to have been read before proceeding.
  217. if (!protected_prefs_ || !unprotected_prefs_)
  218. return;
  219. bool protected_prefs_need_cleanup = false;
  220. bool unprotected_prefs_altered = false;
  221. MigratePrefsFromOldToNewStore(
  222. unprotected_pref_names_, protected_prefs_.get(), unprotected_prefs_.get(),
  223. unprotected_pref_hash_store_.get(), &protected_prefs_need_cleanup,
  224. &unprotected_prefs_altered);
  225. bool unprotected_prefs_need_cleanup = false;
  226. bool protected_prefs_altered = false;
  227. MigratePrefsFromOldToNewStore(
  228. protected_pref_names_, unprotected_prefs_.get(), protected_prefs_.get(),
  229. protected_pref_hash_store_.get(), &unprotected_prefs_need_cleanup,
  230. &protected_prefs_altered);
  231. if (!unprotected_prefs_altered && !protected_prefs_altered) {
  232. // Clean up any MACs that might have been previously migrated from the
  233. // various stores. It's safe to leave them behind for a little while as they
  234. // will be ignored unless the corresponding value is _also_ present. The
  235. // cleanup must be deferred until the MACs have been written to their target
  236. // stores, and doing so in a subsequent launch is easier than within the
  237. // same process.
  238. CleanupMigratedHashes(unprotected_pref_names_,
  239. protected_pref_hash_store_.get(),
  240. protected_prefs_.get());
  241. CleanupMigratedHashes(protected_pref_names_,
  242. unprotected_pref_hash_store_.get(),
  243. unprotected_prefs_.get());
  244. }
  245. // Hand the processed prefs back to their respective filters.
  246. std::move(finalize_unprotected_filter_on_load_)
  247. .Run(std::move(unprotected_prefs_), unprotected_prefs_altered);
  248. std::move(finalize_protected_filter_on_load_)
  249. .Run(std::move(protected_prefs_), protected_prefs_altered);
  250. if (unprotected_prefs_need_cleanup) {
  251. // Schedule a cleanup of the |protected_pref_names_| from the unprotected
  252. // prefs once the protected prefs were successfully written to disk (or
  253. // do it immediately if |!protected_prefs_altered|).
  254. ScheduleSourcePrefStoreCleanup(
  255. register_on_successful_protected_store_write_callback_,
  256. unprotected_store_cleaner_, protected_pref_names_,
  257. protected_prefs_altered);
  258. }
  259. if (protected_prefs_need_cleanup) {
  260. // Schedule a cleanup of the |unprotected_pref_names_| from the protected
  261. // prefs once the unprotected prefs were successfully written to disk (or
  262. // do it immediately if |!unprotected_prefs_altered|).
  263. ScheduleSourcePrefStoreCleanup(
  264. register_on_successful_unprotected_store_write_callback_,
  265. protected_store_cleaner_, unprotected_pref_names_,
  266. unprotected_prefs_altered);
  267. }
  268. }
  269. } // namespace
  270. void SetupTrackedPreferencesMigration(
  271. const std::set<std::string>& unprotected_pref_names,
  272. const std::set<std::string>& protected_pref_names,
  273. const base::RepeatingCallback<void(const std::string& key)>&
  274. unprotected_store_cleaner,
  275. const base::RepeatingCallback<void(const std::string& key)>&
  276. protected_store_cleaner,
  277. const base::RepeatingCallback<void(base::OnceClosure)>&
  278. register_on_successful_unprotected_store_write_callback,
  279. const base::RepeatingCallback<void(base::OnceClosure)>&
  280. register_on_successful_protected_store_write_callback,
  281. std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
  282. std::unique_ptr<PrefHashStore> protected_pref_hash_store,
  283. InterceptablePrefFilter* unprotected_pref_filter,
  284. InterceptablePrefFilter* protected_pref_filter) {
  285. auto prefs_migrator = base::MakeRefCounted<TrackedPreferencesMigrator>(
  286. unprotected_pref_names, protected_pref_names, unprotected_store_cleaner,
  287. protected_store_cleaner,
  288. register_on_successful_unprotected_store_write_callback,
  289. register_on_successful_protected_store_write_callback,
  290. std::move(unprotected_pref_hash_store),
  291. std::move(protected_pref_hash_store), unprotected_pref_filter,
  292. protected_pref_filter);
  293. // The callbacks bound below will own this TrackedPreferencesMigrator by
  294. // reference.
  295. unprotected_pref_filter->InterceptNextFilterOnLoad(base::BindOnce(
  296. &TrackedPreferencesMigrator::InterceptFilterOnLoad, prefs_migrator,
  297. TrackedPreferencesMigrator::UNPROTECTED_PREF_FILTER));
  298. protected_pref_filter->InterceptNextFilterOnLoad(base::BindOnce(
  299. &TrackedPreferencesMigrator::InterceptFilterOnLoad, prefs_migrator,
  300. TrackedPreferencesMigrator::PROTECTED_PREF_FILTER));
  301. }