1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/prefs/overlay_user_pref_store.h"
6
7 #include <memory>
8 #include <ostream>
9 #include <string>
10 #include <utility>
11
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/observer_list.h"
15 #include "base/strings/string_piece.h"
16 #include "base/values.h"
17 #include "components/prefs/in_memory_pref_store.h"
18
19 // Allows us to monitor two pref stores and tell updates from them apart. It
20 // essentially mimics a Callback for the Observer interface (e.g. it allows
21 // binding additional arguments).
22 class OverlayUserPrefStore::ObserverAdapter : public PrefStore::Observer {
23 public:
ObserverAdapter(bool ephemeral,OverlayUserPrefStore * parent)24 ObserverAdapter(bool ephemeral, OverlayUserPrefStore* parent)
25 : ephemeral_user_pref_store_(ephemeral), parent_(parent) {}
26
27 // Methods of PrefStore::Observer.
OnPrefValueChanged(const std::string & key)28 void OnPrefValueChanged(const std::string& key) override {
29 parent_->OnPrefValueChanged(ephemeral_user_pref_store_, key);
30 }
OnInitializationCompleted(bool succeeded)31 void OnInitializationCompleted(bool succeeded) override {
32 parent_->OnInitializationCompleted(ephemeral_user_pref_store_, succeeded);
33 }
34
35 private:
36 // Is the update for the ephemeral?
37 const bool ephemeral_user_pref_store_;
38 const raw_ptr<OverlayUserPrefStore> parent_;
39 };
40
OverlayUserPrefStore(PersistentPrefStore * persistent)41 OverlayUserPrefStore::OverlayUserPrefStore(PersistentPrefStore* persistent)
42 : OverlayUserPrefStore(new InMemoryPrefStore(), persistent) {}
43
OverlayUserPrefStore(PersistentPrefStore * ephemeral,PersistentPrefStore * persistent)44 OverlayUserPrefStore::OverlayUserPrefStore(PersistentPrefStore* ephemeral,
45 PersistentPrefStore* persistent)
46 : ephemeral_pref_store_observer_(
47 std::make_unique<OverlayUserPrefStore::ObserverAdapter>(true, this)),
48 persistent_pref_store_observer_(
49 std::make_unique<OverlayUserPrefStore::ObserverAdapter>(false, this)),
50 ephemeral_user_pref_store_(ephemeral),
51 persistent_user_pref_store_(persistent) {
52 DCHECK(ephemeral->IsInitializationComplete());
53 ephemeral_user_pref_store_->AddObserver(ephemeral_pref_store_observer_.get());
54 persistent_user_pref_store_->AddObserver(
55 persistent_pref_store_observer_.get());
56 }
57
IsSetInOverlay(const std::string & key) const58 bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
59 return ephemeral_user_pref_store_->GetValue(key, nullptr);
60 }
61
AddObserver(PrefStore::Observer * observer)62 void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
63 observers_.AddObserver(observer);
64 }
65
RemoveObserver(PrefStore::Observer * observer)66 void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) {
67 observers_.RemoveObserver(observer);
68 }
69
HasObservers() const70 bool OverlayUserPrefStore::HasObservers() const {
71 return !observers_.empty();
72 }
73
IsInitializationComplete() const74 bool OverlayUserPrefStore::IsInitializationComplete() const {
75 return persistent_user_pref_store_->IsInitializationComplete() &&
76 ephemeral_user_pref_store_->IsInitializationComplete();
77 }
78
GetValue(base::StringPiece key,const base::Value ** result) const79 bool OverlayUserPrefStore::GetValue(base::StringPiece key,
80 const base::Value** result) const {
81 // If the |key| shall NOT be stored in the ephemeral store, there must not
82 // be an entry.
83 DCHECK(!ShallBeStoredInPersistent(key) ||
84 !ephemeral_user_pref_store_->GetValue(key, nullptr));
85
86 if (ephemeral_user_pref_store_->GetValue(key, result))
87 return true;
88 return persistent_user_pref_store_->GetValue(key, result);
89 }
90
GetValues() const91 base::Value::Dict OverlayUserPrefStore::GetValues() const {
92 auto values = ephemeral_user_pref_store_->GetValues();
93 auto persistent_values = persistent_user_pref_store_->GetValues();
94
95 // Output |values| are read from |ephemeral_user_pref_store_| (in-memory
96 // store). Then the values of preferences in |persistent_names_set_| are
97 // overwritten by the content of |persistent_user_pref_store_| (the persistent
98 // store).
99 for (const auto& key : persistent_names_set_) {
100 std::optional<base::Value> out_value =
101 persistent_values.ExtractByDottedPath(key);
102 if (out_value.has_value()) {
103 values.SetByDottedPath(key, std::move(*out_value));
104 }
105 }
106 return values;
107 }
108
GetMutableValue(const std::string & key,base::Value ** result)109 bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
110 base::Value** result) {
111 if (ShallBeStoredInPersistent(key))
112 return persistent_user_pref_store_->GetMutableValue(key, result);
113
114 if (ephemeral_user_pref_store_->GetMutableValue(key, result))
115 return true;
116
117 // Try to create copy of persistent if the ephemeral does not contain a value.
118 base::Value* persistent_value = nullptr;
119 if (!persistent_user_pref_store_->GetMutableValue(key, &persistent_value))
120 return false;
121
122 ephemeral_user_pref_store_->SetValue(
123 key, persistent_value->Clone(),
124 WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
125 ephemeral_user_pref_store_->GetMutableValue(key, result);
126 return true;
127 }
128
SetValue(const std::string & key,base::Value value,uint32_t flags)129 void OverlayUserPrefStore::SetValue(const std::string& key,
130 base::Value value,
131 uint32_t flags) {
132 if (ShallBeStoredInPersistent(key)) {
133 persistent_user_pref_store_->SetValue(key, std::move(value), flags);
134 return;
135 }
136
137 // TODO(crbug.com/40584094): If we always store in in-memory storage
138 // and conditionally also stored in persistent one, we wouldn't have to do a
139 // complex merge in GetValues().
140 ephemeral_user_pref_store_->SetValue(key, std::move(value), flags);
141 }
142
SetValueSilently(const std::string & key,base::Value value,uint32_t flags)143 void OverlayUserPrefStore::SetValueSilently(const std::string& key,
144 base::Value value,
145 uint32_t flags) {
146 if (ShallBeStoredInPersistent(key)) {
147 persistent_user_pref_store_->SetValueSilently(key, std::move(value), flags);
148 return;
149 }
150
151 ephemeral_user_pref_store_->SetValueSilently(key, std::move(value), flags);
152 }
153
RemoveValue(const std::string & key,uint32_t flags)154 void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
155 if (ShallBeStoredInPersistent(key)) {
156 persistent_user_pref_store_->RemoveValue(key, flags);
157 return;
158 }
159
160 ephemeral_user_pref_store_->RemoveValue(key, flags);
161 }
162
RemoveValuesByPrefixSilently(const std::string & prefix)163 void OverlayUserPrefStore::RemoveValuesByPrefixSilently(
164 const std::string& prefix) {
165 NOTIMPLEMENTED();
166 }
167
ReadOnly() const168 bool OverlayUserPrefStore::ReadOnly() const {
169 return false;
170 }
171
GetReadError() const172 PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const {
173 return PersistentPrefStore::PREF_READ_ERROR_NONE;
174 }
175
ReadPrefs()176 PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
177 // We do not read intentionally.
178 OnInitializationCompleted(/* ephemeral */ false, true);
179 return PersistentPrefStore::PREF_READ_ERROR_NONE;
180 }
181
ReadPrefsAsync(ReadErrorDelegate * error_delegate_raw)182 void OverlayUserPrefStore::ReadPrefsAsync(
183 ReadErrorDelegate* error_delegate_raw) {
184 std::unique_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
185 // We do not read intentionally.
186 OnInitializationCompleted(/* ephemeral */ false, true);
187 }
188
CommitPendingWrite(base::OnceClosure reply_callback,base::OnceClosure synchronous_done_callback)189 void OverlayUserPrefStore::CommitPendingWrite(
190 base::OnceClosure reply_callback,
191 base::OnceClosure synchronous_done_callback) {
192 persistent_user_pref_store_->CommitPendingWrite(
193 std::move(reply_callback), std::move(synchronous_done_callback));
194 // We do not write our content intentionally.
195 }
196
SchedulePendingLossyWrites()197 void OverlayUserPrefStore::SchedulePendingLossyWrites() {
198 persistent_user_pref_store_->SchedulePendingLossyWrites();
199 }
200
ReportValueChanged(const std::string & key,uint32_t flags)201 void OverlayUserPrefStore::ReportValueChanged(const std::string& key,
202 uint32_t flags) {
203 for (PrefStore::Observer& observer : observers_)
204 observer.OnPrefValueChanged(key);
205 }
206
RegisterPersistentPref(const std::string & key)207 void OverlayUserPrefStore::RegisterPersistentPref(const std::string& key) {
208 DCHECK(!key.empty()) << "Key is empty";
209 DCHECK(persistent_names_set_.find(key) == persistent_names_set_.end())
210 << "Key already registered: " << key;
211 persistent_names_set_.insert(key);
212 }
213
OnStoreDeletionFromDisk()214 void OverlayUserPrefStore::OnStoreDeletionFromDisk() {
215 persistent_user_pref_store_->OnStoreDeletionFromDisk();
216 }
217
~OverlayUserPrefStore()218 OverlayUserPrefStore::~OverlayUserPrefStore() {
219 ephemeral_user_pref_store_->RemoveObserver(
220 ephemeral_pref_store_observer_.get());
221 persistent_user_pref_store_->RemoveObserver(
222 persistent_pref_store_observer_.get());
223 }
224
OnPrefValueChanged(bool ephemeral,const std::string & key)225 void OverlayUserPrefStore::OnPrefValueChanged(bool ephemeral,
226 const std::string& key) {
227 if (ephemeral) {
228 ReportValueChanged(key, DEFAULT_PREF_WRITE_FLAGS);
229 } else {
230 if (!ephemeral_user_pref_store_->GetValue(key, nullptr))
231 ReportValueChanged(key, DEFAULT_PREF_WRITE_FLAGS);
232 }
233 }
234
OnInitializationCompleted(bool ephemeral,bool succeeded)235 void OverlayUserPrefStore::OnInitializationCompleted(bool ephemeral,
236 bool succeeded) {
237 if (!IsInitializationComplete())
238 return;
239 for (PrefStore::Observer& observer : observers_)
240 observer.OnInitializationCompleted(succeeded);
241 }
242
ShallBeStoredInPersistent(base::StringPiece key) const243 bool OverlayUserPrefStore::ShallBeStoredInPersistent(
244 base::StringPiece key) const {
245 return persistent_names_set_.find(key) != persistent_names_set_.end();
246 }
247