Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / base / prefs / json_pref_store.cc
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.
4
5 #include "base/prefs/json_pref_store.h"
6
7 #include <algorithm>
8
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"
23
24 // Result returned from internal read tasks.
25 struct JsonPrefStore::ReadResult {
26  public:
27   ReadResult();
28   ~ReadResult();
29
30   scoped_ptr<base::Value> value;
31   PrefReadError error;
32   bool no_dir;
33
34  private:
35   DISALLOW_COPY_AND_ASSIGN(ReadResult);
36 };
37
38 JsonPrefStore::ReadResult::ReadResult()
39     : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) {
40 }
41
42 JsonPrefStore::ReadResult::~ReadResult() {
43 }
44
45 namespace {
46
47 // Some extensions we'll tack on to copies of the Preferences files.
48 const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad");
49
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);
79
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;
87     }
88   } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
89     return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
90   }
91   return PersistentPrefStore::PREF_READ_ERROR_NONE;
92 }
93
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);
100   }
101
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();
112 }
113
114 }  // namespace
115
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);
125 }
126
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) {
140 }
141
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) {
157 }
158
159 bool JsonPrefStore::GetValue(const std::string& key,
160                              const base::Value** result) const {
161   DCHECK(CalledOnValidThread());
162
163   base::Value* tmp = NULL;
164   if (!prefs_->Get(key, &tmp))
165     return false;
166
167   if (result)
168     *result = tmp;
169   return true;
170 }
171
172 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
173   DCHECK(CalledOnValidThread());
174
175   observers_.AddObserver(observer);
176 }
177
178 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
179   DCHECK(CalledOnValidThread());
180
181   observers_.RemoveObserver(observer);
182 }
183
184 bool JsonPrefStore::HasObservers() const {
185   DCHECK(CalledOnValidThread());
186
187   return observers_.might_have_observers();
188 }
189
190 bool JsonPrefStore::IsInitializationComplete() const {
191   DCHECK(CalledOnValidThread());
192
193   return initialized_;
194 }
195
196 bool JsonPrefStore::GetMutableValue(const std::string& key,
197                                     base::Value** result) {
198   DCHECK(CalledOnValidThread());
199
200   return prefs_->Get(key, result);
201 }
202
203 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) {
204   DCHECK(CalledOnValidThread());
205
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);
213   }
214 }
215
216 void JsonPrefStore::SetValueSilently(const std::string& key,
217                                      base::Value* value) {
218   DCHECK(CalledOnValidThread());
219
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);
228   }
229 }
230
231 void JsonPrefStore::RemoveValue(const std::string& key) {
232   DCHECK(CalledOnValidThread());
233
234   if (prefs_->RemovePath(key, NULL))
235     ReportValueChanged(key);
236 }
237
238 void JsonPrefStore::RemoveValueSilently(const std::string& key) {
239   DCHECK(CalledOnValidThread());
240
241   prefs_->RemovePath(key, NULL);
242   if (!read_only_)
243     writer_.ScheduleWrite(this);
244 }
245
246 bool JsonPrefStore::ReadOnly() const {
247   DCHECK(CalledOnValidThread());
248
249   return read_only_;
250 }
251
252 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
253   DCHECK(CalledOnValidThread());
254
255   return read_error_;
256 }
257
258 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
259   DCHECK(CalledOnValidThread());
260
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;
266   }
267
268   OnFileRead(ReadPrefsFromDisk(path_, alternate_path_));
269   return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
270                                 : read_error_;
271 }
272
273 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
274   DCHECK(CalledOnValidThread());
275
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;
283   }
284
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()));
291 }
292
293 void JsonPrefStore::CommitPendingWrite() {
294   DCHECK(CalledOnValidThread());
295
296   if (writer_.HasPendingWrite() && !read_only_)
297     writer_.DoScheduledWrite();
298 }
299
300 void JsonPrefStore::ReportValueChanged(const std::string& key) {
301   DCHECK(CalledOnValidThread());
302
303   if (pref_filter_)
304     pref_filter_->FilterUpdate(key);
305
306   FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
307
308   if (!read_only_)
309     writer_.ScheduleWrite(this);
310 }
311
312 void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
313     const base::Closure& on_next_successful_write) {
314   DCHECK(CalledOnValidThread());
315
316   writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write);
317 }
318
319 void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
320   DCHECK(CalledOnValidThread());
321
322   DCHECK(read_result);
323
324   scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue);
325
326   read_error_ = read_result->error;
327
328   bool initialization_successful = !read_result->no_dir;
329
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;
365     }
366   }
367
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);
378   }
379 }
380
381 JsonPrefStore::~JsonPrefStore() {
382   CommitPendingWrite();
383 }
384
385 bool JsonPrefStore::SerializeData(std::string* output) {
386   DCHECK(CalledOnValidThread());
387
388   if (pref_filter_)
389     pref_filter_->FilterSerializeData(prefs_.get());
390
391   JSONStringValueSerializer serializer(output);
392   serializer.set_pretty_print(true);
393   bool result = serializer.Serialize(*prefs_);
394
395   if (result) {
396     std::string spaceless_basename;
397     base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
398                        &spaceless_basename);
399
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,
406             1,
407             10000,
408             50,
409             base::HistogramBase::kUmaTargetedHistogramFlag);
410     histogram->Add(static_cast<int>(output->size()) / 1024);
411   }
412
413   return result;
414 }
415
416 void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
417                                      scoped_ptr<base::DictionaryValue> prefs,
418                                      bool schedule_write) {
419   DCHECK(CalledOnValidThread());
420
421   filtering_in_progress_ = false;
422
423   if (!initialization_successful) {
424     FOR_EACH_OBSERVER(PrefStore::Observer,
425                       observers_,
426                       OnInitializationCompleted(false));
427     return;
428   }
429
430   prefs_ = prefs.Pass();
431
432   initialized_ = true;
433
434   if (schedule_write && !read_only_)
435     writer_.ScheduleWrite(this);
436
437   if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
438     error_delegate_->OnError(read_error_);
439
440   FOR_EACH_OBSERVER(PrefStore::Observer,
441                     observers_,
442                     OnInitializationCompleted(true));
443
444   return;
445 }