Fix emulator build error
[platform/framework/web/chromium-efl.git] / components / prefs / json_pref_store.cc
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/json_pref_store.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <string>
11 #include <utility>
12
13 #include "base/feature_list.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/functional/bind.h"
17 #include "base/functional/callback.h"
18 #include "base/functional/callback_helpers.h"
19 #include "base/json/json_file_value_serializer.h"
20 #include "base/json/json_writer.h"
21 #include "base/logging.h"
22 #include "base/memory/ref_counted.h"
23 #include "base/metrics/histogram.h"
24 #include "base/notreached.h"
25 #include "base/observer_list.h"
26 #include "base/ranges/algorithm.h"
27 #include "base/strings/string_number_conversions.h"
28 #include "base/strings/string_piece.h"
29 #include "base/strings/string_util.h"
30 #include "base/task/sequenced_task_runner.h"
31 #include "base/time/default_clock.h"
32 #include "base/values.h"
33 #include "components/prefs/pref_filter.h"
34
35 // Result returned from internal read tasks.
36 struct JsonPrefStore::ReadResult {
37  public:
38   ReadResult();
39   ~ReadResult();
40   ReadResult(const ReadResult&) = delete;
41   ReadResult& operator=(const ReadResult&) = delete;
42
43   std::unique_ptr<base::Value> value;
44   PrefReadError error = PersistentPrefStore::PREF_READ_ERROR_NONE;
45   bool no_dir = false;
46   size_t num_bytes_read = 0u;
47 };
48
49 JsonPrefStore::ReadResult::ReadResult() = default;
50 JsonPrefStore::ReadResult::~ReadResult() = default;
51
52 namespace {
53
54 // Some extensions we'll tack on to copies of the Preferences files.
55 const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad");
56
57 bool BackupPrefsFile(const base::FilePath& path) {
58   const base::FilePath bad = path.ReplaceExtension(kBadExtension);
59   const bool bad_existed = base::PathExists(bad);
60   base::Move(path, bad);
61   return bad_existed;
62 }
63
64 PersistentPrefStore::PrefReadError HandleReadErrors(
65     const base::Value* value,
66     const base::FilePath& path,
67     int error_code,
68     const std::string& error_msg) {
69   if (!value) {
70     DVLOG(1) << "Error while loading JSON file: " << error_msg
71              << ", file: " << path.value();
72     switch (error_code) {
73       case JSONFileValueDeserializer::JSON_ACCESS_DENIED:
74         return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
75       case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE:
76         return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
77       case JSONFileValueDeserializer::JSON_FILE_LOCKED:
78         return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
79       case JSONFileValueDeserializer::JSON_NO_SUCH_FILE:
80         return PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
81       default:
82         // JSON errors indicate file corruption of some sort.
83         // Since the file is corrupt, move it to the side and continue with
84         // empty preferences.  This will result in them losing their settings.
85         // We keep the old file for possible support and debugging assistance
86         // as well as to detect if they're seeing these errors repeatedly.
87         // TODO(erikkay) Instead, use the last known good file.
88         // If they've ever had a parse error before, put them in another bucket.
89         // TODO(erikkay) if we keep this error checking for very long, we may
90         // want to differentiate between recent and long ago errors.
91         const bool bad_existed = BackupPrefsFile(path);
92         return bad_existed ? PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT
93                            : PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
94     }
95   }
96   if (!value->is_dict())
97     return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
98   return PersistentPrefStore::PREF_READ_ERROR_NONE;
99 }
100
101 std::unique_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
102     const base::FilePath& path) {
103   int error_code;
104   std::string error_msg;
105   auto read_result = std::make_unique<JsonPrefStore::ReadResult>();
106   JSONFileValueDeserializer deserializer(path);
107   read_result->value = deserializer.Deserialize(&error_code, &error_msg);
108   read_result->error =
109       HandleReadErrors(read_result->value.get(), path, error_code, error_msg);
110   read_result->no_dir = !base::PathExists(path.DirName());
111   read_result->num_bytes_read = deserializer.get_last_read_size();
112
113   return read_result;
114 }
115
116 // Returns the a histogram suffix for a few allowlisted JsonPref files.
117 const char* GetHistogramSuffix(const base::FilePath& path) {
118   std::string spaceless_basename;
119   base::ReplaceChars(path.BaseName().MaybeAsASCII(), " ", "_",
120                      &spaceless_basename);
121   static constexpr std::array<const char*, 3> kAllowList{
122       "Secure_Preferences", "Preferences", "Local_State"};
123   const char* const* it = base::ranges::find(kAllowList, spaceless_basename);
124   return it != kAllowList.end() ? *it : "";
125 }
126
127 absl::optional<std::string> DoSerialize(base::ValueView value,
128                                         const base::FilePath& path) {
129   std::string output;
130   if (!base::JSONWriter::Write(value, &output)) {
131     // Failed to serialize prefs file. Backup the existing prefs file and
132     // crash.
133     BackupPrefsFile(path);
134     NOTREACHED_NORETURN() << "Failed to serialize preferences : " << path
135                           << "\nBacked up under "
136                           << path.ReplaceExtension(kBadExtension);
137   }
138   return output;
139 }
140
141 }  // namespace
142
143 JsonPrefStore::JsonPrefStore(
144     const base::FilePath& pref_filename,
145     std::unique_ptr<PrefFilter> pref_filter,
146     scoped_refptr<base::SequencedTaskRunner> file_task_runner,
147     bool read_only)
148     : path_(pref_filename),
149       file_task_runner_(std::move(file_task_runner)),
150       read_only_(read_only),
151       writer_(pref_filename,
152               file_task_runner_,
153               GetHistogramSuffix(pref_filename)),
154       pref_filter_(std::move(pref_filter)),
155       initialized_(false),
156       filtering_in_progress_(false),
157       pending_lossy_write_(false),
158       read_error_(PREF_READ_ERROR_NONE),
159       has_pending_write_reply_(false) {
160   DCHECK(!path_.empty());
161 }
162
163 bool JsonPrefStore::GetValue(base::StringPiece key,
164                              const base::Value** result) const {
165   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
166
167   const base::Value* tmp = prefs_.FindByDottedPath(key);
168   if (!tmp)
169     return false;
170
171   if (result)
172     *result = tmp;
173   return true;
174 }
175
176 base::Value::Dict JsonPrefStore::GetValues() const {
177   return prefs_.Clone();
178 }
179
180 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
181   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
182
183   observers_.AddObserver(observer);
184 }
185
186 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
187   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
188
189   observers_.RemoveObserver(observer);
190 }
191
192 bool JsonPrefStore::HasObservers() const {
193   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
194   return !observers_.empty();
195 }
196
197 bool JsonPrefStore::IsInitializationComplete() const {
198   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
199
200   return initialized_;
201 }
202
203 bool JsonPrefStore::GetMutableValue(const std::string& key,
204                                     base::Value** result) {
205   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
206
207   base::Value* tmp = prefs_.FindByDottedPath(key);
208   if (!tmp)
209     return false;
210
211   if (result)
212     *result = tmp;
213   return true;
214 }
215
216 void JsonPrefStore::SetValue(const std::string& key,
217                              base::Value value,
218                              uint32_t flags) {
219   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
220
221   base::Value* old_value = prefs_.FindByDottedPath(key);
222   if (!old_value || value != *old_value) {
223     prefs_.SetByDottedPath(key, std::move(value));
224     ReportValueChanged(key, flags);
225   }
226 }
227
228 void JsonPrefStore::SetValueSilently(const std::string& key,
229                                      base::Value value,
230                                      uint32_t flags) {
231   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
232
233   base::Value* old_value = prefs_.FindByDottedPath(key);
234   if (!old_value || value != *old_value) {
235     prefs_.SetByDottedPath(key, std::move(value));
236     ScheduleWrite(flags);
237   }
238 }
239
240 void JsonPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
241   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
242
243   if (prefs_.RemoveByDottedPath(key)) {
244     ReportValueChanged(key, flags);
245   }
246 }
247
248 void JsonPrefStore::RemoveValueSilently(const std::string& key,
249                                         uint32_t flags) {
250   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
251
252   prefs_.RemoveByDottedPath(key);
253   ScheduleWrite(flags);
254 }
255
256 void JsonPrefStore::RemoveValuesByPrefixSilently(const std::string& prefix) {
257   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
258   RemoveValueSilently(prefix, /*flags*/ 0);
259 }
260
261 bool JsonPrefStore::ReadOnly() const {
262   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
263
264   return read_only_;
265 }
266
267 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
268   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
269
270   return read_error_;
271 }
272
273 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
274   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
275
276   OnFileRead(ReadPrefsFromDisk(path_));
277   return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
278                                 : read_error_;
279 }
280
281 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
282   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
283
284   initialized_ = false;
285   error_delegate_.reset(error_delegate);
286
287   // Weakly binds the read task so that it doesn't kick in during shutdown.
288   file_task_runner_->PostTaskAndReplyWithResult(
289       FROM_HERE, base::BindOnce(&ReadPrefsFromDisk, path_),
290       base::BindOnce(&JsonPrefStore::OnFileRead, AsWeakPtr()));
291 }
292
293 void JsonPrefStore::CommitPendingWrite(
294     base::OnceClosure reply_callback,
295     base::OnceClosure synchronous_done_callback) {
296   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
297
298   // Schedule a write for any lossy writes that are outstanding to ensure that
299   // they get flushed when this function is called.
300   SchedulePendingLossyWrites();
301
302   if (writer_.HasPendingWrite() && !read_only_)
303     writer_.DoScheduledWrite();
304
305   // Since disk operations occur on |file_task_runner_|, the reply of a task
306   // posted to |file_task_runner_| will run after currently pending disk
307   // operations. Also, by definition of PostTaskAndReply(), the reply (in the
308   // |reply_callback| case will run on the current sequence.
309
310   if (synchronous_done_callback) {
311     file_task_runner_->PostTask(FROM_HERE,
312                                 std::move(synchronous_done_callback));
313   }
314
315   if (reply_callback) {
316     file_task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
317                                         std::move(reply_callback));
318   }
319 }
320
321 void JsonPrefStore::SchedulePendingLossyWrites() {
322   if (pending_lossy_write_)
323     writer_.ScheduleWrite(this);
324 }
325
326 void JsonPrefStore::ReportValueChanged(const std::string& key, uint32_t flags) {
327   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
328
329   if (pref_filter_)
330     pref_filter_->FilterUpdate(key);
331
332   for (PrefStore::Observer& observer : observers_)
333     observer.OnPrefValueChanged(key);
334
335   ScheduleWrite(flags);
336 }
337
338 void JsonPrefStore::PerformPreserializationTasks() {
339   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
340   pending_lossy_write_ = false;
341   if (pref_filter_) {
342     OnWriteCallbackPair callbacks = pref_filter_->FilterSerializeData(prefs_);
343     if (!callbacks.first.is_null() || !callbacks.second.is_null())
344       RegisterOnNextWriteSynchronousCallbacks(std::move(callbacks));
345   }
346 }
347
348 void JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback(
349     bool write_success) {
350   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
351
352   has_pending_write_reply_ = false;
353   if (!on_next_successful_write_reply_.is_null()) {
354     base::OnceClosure on_successful_write =
355         std::move(on_next_successful_write_reply_);
356     if (write_success) {
357       std::move(on_successful_write).Run();
358     } else {
359       RegisterOnNextSuccessfulWriteReply(std::move(on_successful_write));
360     }
361   }
362 }
363
364 // static
365 void JsonPrefStore::PostWriteCallback(
366     base::OnceCallback<void(bool success)> on_next_write_callback,
367     base::OnceCallback<void(bool success)> on_next_write_reply,
368     scoped_refptr<base::SequencedTaskRunner> reply_task_runner,
369     bool write_success) {
370   if (!on_next_write_callback.is_null())
371     std::move(on_next_write_callback).Run(write_success);
372
373   // We can't run |on_next_write_reply| on the current thread. Bounce back to
374   // the |reply_task_runner| which is the correct sequenced thread.
375   reply_task_runner->PostTask(
376       FROM_HERE, base::BindOnce(std::move(on_next_write_reply), write_success));
377 }
378
379 void JsonPrefStore::RegisterOnNextSuccessfulWriteReply(
380     base::OnceClosure on_next_successful_write_reply) {
381   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
382   DCHECK(on_next_successful_write_reply_.is_null());
383
384   on_next_successful_write_reply_ = std::move(on_next_successful_write_reply);
385
386   // If there are pending callbacks, avoid erasing them; the reply will be used
387   // as we set |on_next_successful_write_reply_|. Otherwise, setup a reply with
388   // an empty callback.
389   if (!has_pending_write_reply_) {
390     has_pending_write_reply_ = true;
391     writer_.RegisterOnNextWriteCallbacks(
392         base::OnceClosure(),
393         base::BindOnce(
394             &PostWriteCallback, base::OnceCallback<void(bool success)>(),
395             base::BindOnce(
396                 &JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
397                 AsWeakPtr()),
398             base::SequencedTaskRunner::GetCurrentDefault()));
399   }
400 }
401
402 void JsonPrefStore::RegisterOnNextWriteSynchronousCallbacks(
403     OnWriteCallbackPair callbacks) {
404   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
405
406   has_pending_write_reply_ = true;
407
408   writer_.RegisterOnNextWriteCallbacks(
409       std::move(callbacks.first),
410       base::BindOnce(
411           &PostWriteCallback, std::move(callbacks.second),
412           base::BindOnce(
413               &JsonPrefStore::RunOrScheduleNextSuccessfulWriteCallback,
414               AsWeakPtr()),
415           base::SequencedTaskRunner::GetCurrentDefault()));
416 }
417
418 void JsonPrefStore::OnStoreDeletionFromDisk() {
419   if (pref_filter_)
420     pref_filter_->OnStoreDeletionFromDisk();
421 }
422
423 void JsonPrefStore::OnFileRead(std::unique_ptr<ReadResult> read_result) {
424   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
425
426   DCHECK(read_result);
427
428   base::Value::Dict unfiltered_prefs;
429
430   read_error_ = read_result->error;
431
432   bool initialization_successful = !read_result->no_dir;
433
434   if (initialization_successful) {
435     switch (read_error_) {
436       case PREF_READ_ERROR_ACCESS_DENIED:
437       case PREF_READ_ERROR_FILE_OTHER:
438       case PREF_READ_ERROR_FILE_LOCKED:
439       case PREF_READ_ERROR_JSON_TYPE:
440       case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
441         read_only_ = true;
442         break;
443       case PREF_READ_ERROR_NONE:
444         DCHECK(read_result->value);
445         DCHECK(read_result->value->is_dict());
446         writer_.set_previous_data_size(read_result->num_bytes_read);
447         unfiltered_prefs = std::move(*read_result->value).TakeDict();
448         break;
449       case PREF_READ_ERROR_NO_FILE:
450         // If the file just doesn't exist, maybe this is first run.  In any case
451         // there's no harm in writing out default prefs in this case.
452       case PREF_READ_ERROR_JSON_PARSE:
453       case PREF_READ_ERROR_JSON_REPEAT:
454         break;
455       case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
456         // This is a special error code to be returned by ReadPrefs when it
457         // can't complete synchronously, it should never be returned by the read
458         // operation itself.
459       case PREF_READ_ERROR_MAX_ENUM:
460         NOTREACHED();
461         break;
462     }
463   }
464
465   if (pref_filter_) {
466     filtering_in_progress_ = true;
467     PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback(
468         base::BindOnce(&JsonPrefStore::FinalizeFileRead, AsWeakPtr(),
469                        initialization_successful));
470     pref_filter_->FilterOnLoad(std::move(post_filter_on_load_callback),
471                                std::move(unfiltered_prefs));
472   } else {
473     FinalizeFileRead(initialization_successful, std::move(unfiltered_prefs),
474                      false);
475   }
476 }
477
478 JsonPrefStore::~JsonPrefStore() {
479   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
480   CommitPendingWrite();
481 }
482
483 absl::optional<std::string> JsonPrefStore::SerializeData() {
484   PerformPreserializationTasks();
485   return DoSerialize(prefs_, path_);
486 }
487
488 base::ImportantFileWriter::BackgroundDataProducerCallback
489 JsonPrefStore::GetSerializedDataProducerForBackgroundSequence() {
490   PerformPreserializationTasks();
491   return base::BindOnce(&DoSerialize, prefs_.Clone(), path_);
492 }
493
494 void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
495                                      base::Value::Dict prefs,
496                                      bool schedule_write) {
497   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
498
499   filtering_in_progress_ = false;
500
501   if (!initialization_successful) {
502     for (PrefStore::Observer& observer : observers_)
503       observer.OnInitializationCompleted(false);
504     return;
505   }
506
507   prefs_ = std::move(prefs);
508
509   initialized_ = true;
510
511   if (schedule_write)
512     ScheduleWrite(DEFAULT_PREF_WRITE_FLAGS);
513
514   if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
515     error_delegate_->OnError(read_error_);
516
517   for (PrefStore::Observer& observer : observers_)
518     observer.OnInitializationCompleted(true);
519
520   return;
521 }
522
523 void JsonPrefStore::ScheduleWrite(uint32_t flags) {
524   if (read_only_)
525     return;
526
527   if (flags & LOSSY_PREF_WRITE_FLAG) {
528     pending_lossy_write_ = true;
529   } else {
530     writer_.ScheduleWriteWithBackgroundDataSerializer(this);
531   }
532 }