Add APIs to thumbnail_store to decompress thumbnails into SkBitmap
[chromium-blink-merge.git] / base / prefs / json_pref_store.cc
blobd4714037c0137ad0df0a3c7a081fde00edcfaa1f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/prefs/json_pref_store.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/json/json_file_value_serializer.h"
14 #include "base/json/json_string_value_serializer.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/metrics/histogram.h"
17 #include "base/prefs/pref_filter.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/strings/string_util.h"
20 #include "base/task_runner_util.h"
21 #include "base/threading/sequenced_worker_pool.h"
22 #include "base/values.h"
24 // Result returned from internal read tasks.
25 struct JsonPrefStore::ReadResult {
26 public:
27 ReadResult();
28 ~ReadResult();
30 scoped_ptr<base::Value> value;
31 PrefReadError error;
32 bool no_dir;
34 private:
35 DISALLOW_COPY_AND_ASSIGN(ReadResult);
38 JsonPrefStore::ReadResult::ReadResult()
39 : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) {
42 JsonPrefStore::ReadResult::~ReadResult() {
45 namespace {
47 // Some extensions we'll tack on to copies of the Preferences files.
48 const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad");
50 PersistentPrefStore::PrefReadError HandleReadErrors(
51 const base::Value* value,
52 const base::FilePath& path,
53 int error_code,
54 const std::string& error_msg) {
55 if (!value) {
56 DVLOG(1) << "Error while loading JSON file: " << error_msg
57 << ", file: " << path.value();
58 switch (error_code) {
59 case JSONFileValueSerializer::JSON_ACCESS_DENIED:
60 return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
61 break;
62 case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
63 return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
64 break;
65 case JSONFileValueSerializer::JSON_FILE_LOCKED:
66 return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
67 break;
68 case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
69 return PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
70 break;
71 default:
72 // JSON errors indicate file corruption of some sort.
73 // Since the file is corrupt, move it to the side and continue with
74 // empty preferences. This will result in them losing their settings.
75 // We keep the old file for possible support and debugging assistance
76 // as well as to detect if they're seeing these errors repeatedly.
77 // TODO(erikkay) Instead, use the last known good file.
78 base::FilePath bad = path.ReplaceExtension(kBadExtension);
80 // If they've ever had a parse error before, put them in another bucket.
81 // TODO(erikkay) if we keep this error checking for very long, we may
82 // want to differentiate between recent and long ago errors.
83 bool bad_existed = base::PathExists(bad);
84 base::Move(path, bad);
85 return bad_existed ? PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT
86 : PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
88 } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
89 return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
91 return PersistentPrefStore::PREF_READ_ERROR_NONE;
94 scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
95 const base::FilePath& path,
96 const base::FilePath& alternate_path) {
97 if (!base::PathExists(path) && !alternate_path.empty() &&
98 base::PathExists(alternate_path)) {
99 base::Move(alternate_path, path);
102 int error_code;
103 std::string error_msg;
104 scoped_ptr<JsonPrefStore::ReadResult> read_result(
105 new JsonPrefStore::ReadResult);
106 JSONFileValueSerializer serializer(path);
107 read_result->value.reset(serializer.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 return read_result.Pass();
114 } // namespace
116 // static
117 scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile(
118 const base::FilePath& filename,
119 base::SequencedWorkerPool* worker_pool) {
120 std::string token("json_pref_store-");
121 token.append(filename.AsUTF8Unsafe());
122 return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
123 worker_pool->GetNamedSequenceToken(token),
124 base::SequencedWorkerPool::BLOCK_SHUTDOWN);
127 JsonPrefStore::JsonPrefStore(
128 const base::FilePath& filename,
129 const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
130 scoped_ptr<PrefFilter> pref_filter)
131 : path_(filename),
132 sequenced_task_runner_(sequenced_task_runner),
133 prefs_(new base::DictionaryValue()),
134 read_only_(false),
135 writer_(filename, sequenced_task_runner),
136 pref_filter_(pref_filter.Pass()),
137 initialized_(false),
138 filtering_in_progress_(false),
139 read_error_(PREF_READ_ERROR_NONE) {
142 JsonPrefStore::JsonPrefStore(
143 const base::FilePath& filename,
144 const base::FilePath& alternate_filename,
145 const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
146 scoped_ptr<PrefFilter> pref_filter)
147 : path_(filename),
148 alternate_path_(alternate_filename),
149 sequenced_task_runner_(sequenced_task_runner),
150 prefs_(new base::DictionaryValue()),
151 read_only_(false),
152 writer_(filename, sequenced_task_runner),
153 pref_filter_(pref_filter.Pass()),
154 initialized_(false),
155 filtering_in_progress_(false),
156 read_error_(PREF_READ_ERROR_NONE) {
159 bool JsonPrefStore::GetValue(const std::string& key,
160 const base::Value** result) const {
161 DCHECK(CalledOnValidThread());
163 base::Value* tmp = NULL;
164 if (!prefs_->Get(key, &tmp))
165 return false;
167 if (result)
168 *result = tmp;
169 return true;
172 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
173 DCHECK(CalledOnValidThread());
175 observers_.AddObserver(observer);
178 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
179 DCHECK(CalledOnValidThread());
181 observers_.RemoveObserver(observer);
184 bool JsonPrefStore::HasObservers() const {
185 DCHECK(CalledOnValidThread());
187 return observers_.might_have_observers();
190 bool JsonPrefStore::IsInitializationComplete() const {
191 DCHECK(CalledOnValidThread());
193 return initialized_;
196 bool JsonPrefStore::GetMutableValue(const std::string& key,
197 base::Value** result) {
198 DCHECK(CalledOnValidThread());
200 return prefs_->Get(key, result);
203 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) {
204 DCHECK(CalledOnValidThread());
206 DCHECK(value);
207 scoped_ptr<base::Value> new_value(value);
208 base::Value* old_value = NULL;
209 prefs_->Get(key, &old_value);
210 if (!old_value || !value->Equals(old_value)) {
211 prefs_->Set(key, new_value.release());
212 ReportValueChanged(key);
216 void JsonPrefStore::SetValueSilently(const std::string& key,
217 base::Value* value) {
218 DCHECK(CalledOnValidThread());
220 DCHECK(value);
221 scoped_ptr<base::Value> new_value(value);
222 base::Value* old_value = NULL;
223 prefs_->Get(key, &old_value);
224 if (!old_value || !value->Equals(old_value)) {
225 prefs_->Set(key, new_value.release());
226 if (!read_only_)
227 writer_.ScheduleWrite(this);
231 void JsonPrefStore::RemoveValue(const std::string& key) {
232 DCHECK(CalledOnValidThread());
234 if (prefs_->RemovePath(key, NULL))
235 ReportValueChanged(key);
238 void JsonPrefStore::RemoveValueSilently(const std::string& key) {
239 DCHECK(CalledOnValidThread());
241 prefs_->RemovePath(key, NULL);
242 if (!read_only_)
243 writer_.ScheduleWrite(this);
246 bool JsonPrefStore::ReadOnly() const {
247 DCHECK(CalledOnValidThread());
249 return read_only_;
252 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
253 DCHECK(CalledOnValidThread());
255 return read_error_;
258 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
259 DCHECK(CalledOnValidThread());
261 if (path_.empty()) {
262 scoped_ptr<ReadResult> no_file_result;
263 no_file_result->error = PREF_READ_ERROR_FILE_NOT_SPECIFIED;
264 OnFileRead(no_file_result.Pass());
265 return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
268 OnFileRead(ReadPrefsFromDisk(path_, alternate_path_));
269 return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
270 : read_error_;
273 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
274 DCHECK(CalledOnValidThread());
276 initialized_ = false;
277 error_delegate_.reset(error_delegate);
278 if (path_.empty()) {
279 scoped_ptr<ReadResult> no_file_result;
280 no_file_result->error = PREF_READ_ERROR_FILE_NOT_SPECIFIED;
281 OnFileRead(no_file_result.Pass());
282 return;
285 // Weakly binds the read task so that it doesn't kick in during shutdown.
286 base::PostTaskAndReplyWithResult(
287 sequenced_task_runner_.get(),
288 FROM_HERE,
289 base::Bind(&ReadPrefsFromDisk, path_, alternate_path_),
290 base::Bind(&JsonPrefStore::OnFileRead, AsWeakPtr()));
293 void JsonPrefStore::CommitPendingWrite() {
294 DCHECK(CalledOnValidThread());
296 if (writer_.HasPendingWrite() && !read_only_)
297 writer_.DoScheduledWrite();
300 void JsonPrefStore::ReportValueChanged(const std::string& key) {
301 DCHECK(CalledOnValidThread());
303 if (pref_filter_)
304 pref_filter_->FilterUpdate(key);
306 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
308 if (!read_only_)
309 writer_.ScheduleWrite(this);
312 void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
313 const base::Closure& on_next_successful_write) {
314 DCHECK(CalledOnValidThread());
316 writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write);
319 void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
320 DCHECK(CalledOnValidThread());
322 DCHECK(read_result);
324 scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue);
326 read_error_ = read_result->error;
328 bool initialization_successful = !read_result->no_dir;
330 if (initialization_successful) {
331 switch (read_error_) {
332 case PREF_READ_ERROR_ACCESS_DENIED:
333 case PREF_READ_ERROR_FILE_OTHER:
334 case PREF_READ_ERROR_FILE_LOCKED:
335 case PREF_READ_ERROR_JSON_TYPE:
336 case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
337 read_only_ = true;
338 break;
339 case PREF_READ_ERROR_NONE:
340 DCHECK(read_result->value.get());
341 unfiltered_prefs.reset(
342 static_cast<base::DictionaryValue*>(read_result->value.release()));
343 break;
344 case PREF_READ_ERROR_NO_FILE:
345 // If the file just doesn't exist, maybe this is first run. In any case
346 // there's no harm in writing out default prefs in this case.
347 break;
348 case PREF_READ_ERROR_JSON_PARSE:
349 case PREF_READ_ERROR_JSON_REPEAT:
350 break;
351 case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
352 // This is a special error code to be returned by ReadPrefs when it
353 // can't complete synchronously, it should never be returned by the read
354 // operation itself.
355 NOTREACHED();
356 break;
357 case PREF_READ_ERROR_LEVELDB_IO:
358 case PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY:
359 case PREF_READ_ERROR_LEVELDB_CORRUPTION:
360 // These are specific to LevelDBPrefStore.
361 NOTREACHED();
362 case PREF_READ_ERROR_MAX_ENUM:
363 NOTREACHED();
364 break;
368 if (pref_filter_) {
369 filtering_in_progress_ = true;
370 const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback(
371 base::Bind(
372 &JsonPrefStore::FinalizeFileRead, AsWeakPtr(),
373 initialization_successful));
374 pref_filter_->FilterOnLoad(post_filter_on_load_callback,
375 unfiltered_prefs.Pass());
376 } else {
377 FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false);
381 JsonPrefStore::~JsonPrefStore() {
382 CommitPendingWrite();
385 bool JsonPrefStore::SerializeData(std::string* output) {
386 DCHECK(CalledOnValidThread());
388 if (pref_filter_)
389 pref_filter_->FilterSerializeData(prefs_.get());
391 JSONStringValueSerializer serializer(output);
392 serializer.set_pretty_print(true);
393 bool result = serializer.Serialize(*prefs_);
395 if (result) {
396 std::string spaceless_basename;
397 base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
398 &spaceless_basename);
400 // The histogram below is an expansion of the UMA_HISTOGRAM_COUNTS_10000
401 // macro adapted to allow for a dynamically suffixed histogram name.
402 // Note: The factory creates and owns the histogram.
403 base::HistogramBase* histogram =
404 base::LinearHistogram::FactoryGet(
405 "Settings.JsonDataSizeKilobytes." + spaceless_basename,
407 10000,
409 base::HistogramBase::kUmaTargetedHistogramFlag);
410 histogram->Add(static_cast<int>(output->size()) / 1024);
413 return result;
416 void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
417 scoped_ptr<base::DictionaryValue> prefs,
418 bool schedule_write) {
419 DCHECK(CalledOnValidThread());
421 filtering_in_progress_ = false;
423 if (!initialization_successful) {
424 FOR_EACH_OBSERVER(PrefStore::Observer,
425 observers_,
426 OnInitializationCompleted(false));
427 return;
430 prefs_ = prefs.Pass();
432 initialized_ = true;
434 if (schedule_write && !read_only_)
435 writer_.ScheduleWrite(this);
437 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
438 error_delegate_->OnError(read_error_);
440 FOR_EACH_OBSERVER(PrefStore::Observer,
441 observers_,
442 OnInitializationCompleted(true));
444 return;