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