[email protected] | 42c037e | 2012-06-26 22:23:32 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
brettw | f00b9b4 | 2016-02-01 22:11:38 | [diff] [blame] | 5 | #include "components/prefs/pref_notifier_impl.h" |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 6 | |
Dominic Battre | af8b8e4 | 2019-08-09 18:17:56 | [diff] [blame] | 7 | #include "base/debug/alias.h" |
Dominic Battre | 343d7512 | 2019-03-29 21:47:49 | [diff] [blame] | 8 | #include "base/debug/dump_without_crashing.h" |
[email protected] | 42c037e | 2012-06-26 22:23:32 | [diff] [blame] | 9 | #include "base/logging.h" |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 10 | #include "base/memory/ptr_util.h" |
Dominic Battre | af8b8e4 | 2019-08-09 18:17:56 | [diff] [blame] | 11 | #include "base/strings/strcat.h" |
brettw | f00b9b4 | 2016-02-01 22:11:38 | [diff] [blame] | 12 | #include "components/prefs/pref_service.h" |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 13 | |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 14 | PrefNotifierImpl::PrefNotifierImpl() : pref_service_(nullptr) {} |
[email protected] | 361d37f6 | 2011-11-22 10:37:02 | [diff] [blame] | 15 | |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 16 | PrefNotifierImpl::PrefNotifierImpl(PrefService* service) |
| 17 | : pref_service_(service) { |
| 18 | } |
| 19 | |
| 20 | PrefNotifierImpl::~PrefNotifierImpl() { |
[email protected] | 5b7238f | 2013-04-22 15:56:40 | [diff] [blame] | 21 | DCHECK(thread_checker_.CalledOnValidThread()); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 22 | |
| 23 | // Verify that there are no pref observers when we shut down. |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 24 | for (const auto& observer_list : pref_observers_) { |
Dominic Battre | 343d7512 | 2019-03-29 21:47:49 | [diff] [blame] | 25 | if (observer_list.second->begin() != observer_list.second->end()) { |
| 26 | // Generally, there should not be any subscribers left when the profile |
| 27 | // is destroyed because a) those may indicate that the subscriber class |
| 28 | // maintains an active pointer to the profile that might be used for |
| 29 | // accessing a destroyed profile and b) those subscribers will try to |
| 30 | // unsubscribe from a PrefService that has been destroyed with the |
| 31 | // profile. |
| 32 | // There is one exception that is safe: Static objects that are leaked |
| 33 | // on process termination, if these objects just subscribe to preferences |
| 34 | // and never access the profile after destruction. As these objects are |
| 35 | // leaked on termination, it is guaranteed that they don't attempt to |
| 36 | // unsubscribe. |
| 37 | const auto& pref_name = observer_list.first; |
Dominic Battre | af8b8e4 | 2019-08-09 18:17:56 | [diff] [blame] | 38 | std::string message = base::StrCat( |
| 39 | {"Pref observer for ", pref_name, " found at shutdown."}); |
| 40 | LOG(WARNING) << message; |
| 41 | DEBUG_ALIAS_FOR_CSTR(aliased_message, message.c_str(), 128); |
Dominic Battre | 343d7512 | 2019-03-29 21:47:49 | [diff] [blame] | 42 | |
| 43 | // TODO(crbug.com/942491, 946668, 945772) The following code collects |
| 44 | // stacktraces that show how the profile is destroyed that owns |
| 45 | // preferences which are known to have subscriptions outliving the |
| 46 | // profile. |
| 47 | if ( |
| 48 | // For GlobalMenuBarX11, crbug.com/946668 |
| 49 | pref_name == "bookmark_bar.show_on_all_tabs" || |
| 50 | // For BrowserWindowPropertyManager, crbug.com/942491 |
| 51 | pref_name == "profile.icon_version" || |
| 52 | // For BrowserWindowDefaultTouchBar, crbug.com/945772 |
| 53 | pref_name == "default_search_provider_data.template_url_data") { |
Dominic Battre | 343d7512 | 2019-03-29 21:47:49 | [diff] [blame] | 54 | base::debug::DumpWithoutCrashing(); |
| 55 | } |
| 56 | } |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 57 | } |
| 58 | |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 59 | // Same for initialization observers. |
| 60 | if (!init_observers_.empty()) |
| 61 | LOG(WARNING) << "Init observer found at shutdown."; |
| 62 | |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 63 | pref_observers_.clear(); |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 64 | init_observers_.clear(); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 65 | } |
| 66 | |
georgesak | 7da6e9d | 2014-12-03 01:10:29 | [diff] [blame] | 67 | void PrefNotifierImpl::AddPrefObserver(const std::string& path, |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 68 | PrefObserver* obs) { |
Dominic Battre | 3ee56661 | 2019-11-29 18:00:51 | [diff] [blame] | 69 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 70 | |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 71 | // Get the pref observer list associated with the path. |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 72 | PrefObserverList* observer_list = nullptr; |
| 73 | auto observer_iterator = pref_observers_.find(path); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 74 | if (observer_iterator == pref_observers_.end()) { |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 75 | observer_list = new PrefObserverList; |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 76 | pref_observers_[path] = base::WrapUnique(observer_list); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 77 | } else { |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 78 | observer_list = observer_iterator->second.get(); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 79 | } |
| 80 | |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 81 | // Add the pref observer. ObserverList will DCHECK if it already is |
| 82 | // in the list. |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 83 | observer_list->AddObserver(obs); |
| 84 | } |
| 85 | |
georgesak | 7da6e9d | 2014-12-03 01:10:29 | [diff] [blame] | 86 | void PrefNotifierImpl::RemovePrefObserver(const std::string& path, |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 87 | PrefObserver* obs) { |
[email protected] | 5b7238f | 2013-04-22 15:56:40 | [diff] [blame] | 88 | DCHECK(thread_checker_.CalledOnValidThread()); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 89 | |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 90 | auto observer_iterator = pref_observers_.find(path); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 91 | if (observer_iterator == pref_observers_.end()) { |
| 92 | return; |
| 93 | } |
| 94 | |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 95 | PrefObserverList* observer_list = observer_iterator->second.get(); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 96 | observer_list->RemoveObserver(obs); |
| 97 | } |
| 98 | |
Brett Wilson | 21cf626a | 2017-09-07 00:30:20 | [diff] [blame] | 99 | void PrefNotifierImpl::AddPrefObserverAllPrefs(PrefObserver* observer) { |
| 100 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 101 | all_prefs_pref_observers_.AddObserver(observer); |
| 102 | } |
| 103 | |
| 104 | void PrefNotifierImpl::RemovePrefObserverAllPrefs(PrefObserver* observer) { |
| 105 | DCHECK(thread_checker_.CalledOnValidThread()); |
| 106 | all_prefs_pref_observers_.RemoveObserver(observer); |
| 107 | } |
| 108 | |
Kenichi Ishibashi | f958ad6 | 2017-12-19 02:43:14 | [diff] [blame] | 109 | void PrefNotifierImpl::AddInitObserver(base::OnceCallback<void(bool)> obs) { |
| 110 | init_observers_.push_back(std::move(obs)); |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 111 | } |
| 112 | |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 113 | void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) { |
| 114 | FireObservers(path); |
| 115 | } |
| 116 | |
[email protected] | 845b43a8 | 2011-05-11 10:14:43 | [diff] [blame] | 117 | void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) { |
[email protected] | 5b7238f | 2013-04-22 15:56:40 | [diff] [blame] | 118 | DCHECK(thread_checker_.CalledOnValidThread()); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 119 | |
Kenichi Ishibashi | f958ad6 | 2017-12-19 02:43:14 | [diff] [blame] | 120 | // We must move init_observers_ to a local variable before we run |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 121 | // observers, or we can end up in this method re-entrantly before |
| 122 | // clearing the observers list. |
Kenichi Ishibashi | f958ad6 | 2017-12-19 02:43:14 | [diff] [blame] | 123 | PrefInitObserverList observers; |
| 124 | std::swap(observers, init_observers_); |
[email protected] | a6a7ced | 2012-11-01 17:24:18 | [diff] [blame] | 125 | |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 126 | for (auto& observer : observers) |
Kenichi Ishibashi | f958ad6 | 2017-12-19 02:43:14 | [diff] [blame] | 127 | std::move(observer).Run(succeeded); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | void PrefNotifierImpl::FireObservers(const std::string& path) { |
[email protected] | 5b7238f | 2013-04-22 15:56:40 | [diff] [blame] | 131 | DCHECK(thread_checker_.CalledOnValidThread()); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 132 | |
| 133 | // Only send notifications for registered preferences. |
georgesak | 7da6e9d | 2014-12-03 01:10:29 | [diff] [blame] | 134 | if (!pref_service_->FindPreference(path)) |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 135 | return; |
| 136 | |
Brett Wilson | 21cf626a | 2017-09-07 00:30:20 | [diff] [blame] | 137 | // Fire observers for any preference change. |
| 138 | for (auto& observer : all_prefs_pref_observers_) |
| 139 | observer.OnPreferenceChanged(pref_service_, path); |
| 140 | |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 141 | auto observer_iterator = pref_observers_.find(path); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 142 | if (observer_iterator == pref_observers_.end()) |
| 143 | return; |
| 144 | |
ericwilligers | 42b92c1 | 2016-10-24 20:21:13 | [diff] [blame] | 145 | for (PrefObserver& observer : *(observer_iterator->second)) |
| 146 | observer.OnPreferenceChanged(pref_service_, path); |
[email protected] | acd78969c | 2010-12-08 09:49:11 | [diff] [blame] | 147 | } |
[email protected] | 361d37f6 | 2011-11-22 10:37:02 | [diff] [blame] | 148 | |
| 149 | void PrefNotifierImpl::SetPrefService(PrefService* pref_service) { |
avi | a92d13b | 2016-09-21 07:48:40 | [diff] [blame] | 150 | DCHECK(pref_service_ == nullptr); |
[email protected] | 361d37f6 | 2011-11-22 10:37:02 | [diff] [blame] | 151 | pref_service_ = pref_service; |
| 152 | } |