pref_notifier_impl.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // Copyright (c) 2012 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 "components/prefs/pref_notifier_impl.h"
  5. #include "base/debug/alias.h"
  6. #include "base/debug/dump_without_crashing.h"
  7. #include "base/logging.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/observer_list.h"
  10. #include "base/strings/strcat.h"
  11. #include "components/prefs/pref_service.h"
  12. PrefNotifierImpl::PrefNotifierImpl() : pref_service_(nullptr) {}
  13. PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
  14. : pref_service_(service) {
  15. }
  16. PrefNotifierImpl::~PrefNotifierImpl() {
  17. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  18. // Verify that there are no pref observers when we shut down.
  19. for (const auto& observer_list : pref_observers_) {
  20. if (observer_list.second->begin() != observer_list.second->end()) {
  21. // Generally, there should not be any subscribers left when the profile
  22. // is destroyed because a) those may indicate that the subscriber class
  23. // maintains an active pointer to the profile that might be used for
  24. // accessing a destroyed profile and b) those subscribers will try to
  25. // unsubscribe from a PrefService that has been destroyed with the
  26. // profile.
  27. // There is one exception that is safe: Static objects that are leaked
  28. // on process termination, if these objects just subscribe to preferences
  29. // and never access the profile after destruction. As these objects are
  30. // leaked on termination, it is guaranteed that they don't attempt to
  31. // unsubscribe.
  32. const auto& pref_name = observer_list.first;
  33. std::string message = base::StrCat(
  34. {"Pref observer for ", pref_name, " found at shutdown."});
  35. LOG(WARNING) << message;
  36. DEBUG_ALIAS_FOR_CSTR(aliased_message, message.c_str(), 128);
  37. // TODO(crbug.com/942491, 946668, 945772) The following code collects
  38. // stacktraces that show how the profile is destroyed that owns
  39. // preferences which are known to have subscriptions outliving the
  40. // profile.
  41. if (
  42. // For DbusAppmenu, crbug.com/946668
  43. pref_name == "bookmark_bar.show_on_all_tabs" ||
  44. // For BrowserWindowPropertyManager, crbug.com/942491
  45. pref_name == "profile.icon_version") {
  46. base::debug::DumpWithoutCrashing();
  47. }
  48. }
  49. }
  50. // Same for initialization observers.
  51. if (!init_observers_.empty())
  52. LOG(WARNING) << "Init observer found at shutdown.";
  53. pref_observers_.clear();
  54. init_observers_.clear();
  55. }
  56. void PrefNotifierImpl::AddPrefObserver(const std::string& path,
  57. PrefObserver* obs) {
  58. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  59. // Get the pref observer list associated with the path.
  60. PrefObserverList* observer_list = nullptr;
  61. auto observer_iterator = pref_observers_.find(path);
  62. if (observer_iterator == pref_observers_.end()) {
  63. observer_list = new PrefObserverList;
  64. pref_observers_[path] = base::WrapUnique(observer_list);
  65. } else {
  66. observer_list = observer_iterator->second.get();
  67. }
  68. // Add the pref observer. ObserverList will DCHECK if it already is
  69. // in the list.
  70. observer_list->AddObserver(obs);
  71. }
  72. void PrefNotifierImpl::RemovePrefObserver(const std::string& path,
  73. PrefObserver* obs) {
  74. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  75. auto observer_iterator = pref_observers_.find(path);
  76. if (observer_iterator == pref_observers_.end()) {
  77. return;
  78. }
  79. PrefObserverList* observer_list = observer_iterator->second.get();
  80. observer_list->RemoveObserver(obs);
  81. }
  82. void PrefNotifierImpl::AddPrefObserverAllPrefs(PrefObserver* observer) {
  83. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  84. all_prefs_pref_observers_.AddObserver(observer);
  85. }
  86. void PrefNotifierImpl::RemovePrefObserverAllPrefs(PrefObserver* observer) {
  87. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  88. all_prefs_pref_observers_.RemoveObserver(observer);
  89. }
  90. void PrefNotifierImpl::AddInitObserver(base::OnceCallback<void(bool)> obs) {
  91. init_observers_.push_back(std::move(obs));
  92. }
  93. void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) {
  94. FireObservers(path);
  95. }
  96. void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) {
  97. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  98. // We must move init_observers_ to a local variable before we run
  99. // observers, or we can end up in this method re-entrantly before
  100. // clearing the observers list.
  101. PrefInitObserverList observers;
  102. std::swap(observers, init_observers_);
  103. for (auto& observer : observers)
  104. std::move(observer).Run(succeeded);
  105. }
  106. void PrefNotifierImpl::FireObservers(const std::string& path) {
  107. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  108. // Only send notifications for registered preferences.
  109. if (!pref_service_->FindPreference(path))
  110. return;
  111. // Fire observers for any preference change.
  112. for (auto& observer : all_prefs_pref_observers_)
  113. observer.OnPreferenceChanged(pref_service_, path);
  114. auto observer_iterator = pref_observers_.find(path);
  115. if (observer_iterator == pref_observers_.end())
  116. return;
  117. for (PrefObserver& observer : *(observer_iterator->second))
  118. observer.OnPreferenceChanged(pref_service_, path);
  119. }
  120. void PrefNotifierImpl::SetPrefService(PrefService* pref_service) {
  121. DCHECK(pref_service_ == nullptr);
  122. pref_service_ = pref_service;
  123. }