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