Upstream version 7.36.149.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/file_util.h"
12 #include "base/json/json_file_value_serializer.h"
13 #include "base/json/json_string_value_serializer.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/prefs/pref_filter.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/values.h"
20
21 namespace {
22
23 // Some extensions we'll tack on to copies of the Preferences files.
24 const base::FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad");
25
26 // Differentiates file loading between origin thread and passed
27 // (aka file) thread.
28 class FileThreadDeserializer
29     : public base::RefCountedThreadSafe<FileThreadDeserializer> {
30  public:
31   FileThreadDeserializer(JsonPrefStore* delegate,
32                          base::SequencedTaskRunner* sequenced_task_runner)
33       : no_dir_(false),
34         error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
35         delegate_(delegate),
36         sequenced_task_runner_(sequenced_task_runner),
37         origin_loop_proxy_(base::MessageLoopProxy::current()) {
38   }
39
40   void Start(const base::FilePath& path) {
41     DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
42     // TODO(gab): This should use PostTaskAndReplyWithResult instead of using
43     // the |error_| member to pass data across tasks.
44     sequenced_task_runner_->PostTask(
45         FROM_HERE,
46         base::Bind(&FileThreadDeserializer::ReadFileAndReport,
47                    this, path));
48   }
49
50   // Deserializes JSON on the sequenced task runner.
51   void ReadFileAndReport(const base::FilePath& path) {
52     DCHECK(sequenced_task_runner_->RunsTasksOnCurrentThread());
53
54     value_.reset(DoReading(path, &error_, &no_dir_));
55
56     origin_loop_proxy_->PostTask(
57         FROM_HERE,
58         base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this));
59   }
60
61   // Reports deserialization result on the origin thread.
62   void ReportOnOriginThread() {
63     DCHECK(origin_loop_proxy_->BelongsToCurrentThread());
64     delegate_->OnFileRead(value_.Pass(), error_, no_dir_);
65   }
66
67   static base::Value* DoReading(const base::FilePath& path,
68                                 PersistentPrefStore::PrefReadError* error,
69                                 bool* no_dir) {
70     int error_code;
71     std::string error_msg;
72     JSONFileValueSerializer serializer(path);
73     base::Value* value = serializer.Deserialize(&error_code, &error_msg);
74     HandleErrors(value, path, error_code, error_msg, error);
75     *no_dir = !base::PathExists(path.DirName());
76     return value;
77   }
78
79   static void HandleErrors(const base::Value* value,
80                            const base::FilePath& path,
81                            int error_code,
82                            const std::string& error_msg,
83                            PersistentPrefStore::PrefReadError* error);
84
85  private:
86   friend class base::RefCountedThreadSafe<FileThreadDeserializer>;
87   ~FileThreadDeserializer() {}
88
89   bool no_dir_;
90   PersistentPrefStore::PrefReadError error_;
91   scoped_ptr<base::Value> value_;
92   const scoped_refptr<JsonPrefStore> delegate_;
93   const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
94   const scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_;
95 };
96
97 // static
98 void FileThreadDeserializer::HandleErrors(
99     const base::Value* value,
100     const base::FilePath& path,
101     int error_code,
102     const std::string& error_msg,
103     PersistentPrefStore::PrefReadError* error) {
104   *error = PersistentPrefStore::PREF_READ_ERROR_NONE;
105   if (!value) {
106     DVLOG(1) << "Error while loading JSON file: " << error_msg
107              << ", file: " << path.value();
108     switch (error_code) {
109       case JSONFileValueSerializer::JSON_ACCESS_DENIED:
110         *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
111         break;
112       case JSONFileValueSerializer::JSON_CANNOT_READ_FILE:
113         *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
114         break;
115       case JSONFileValueSerializer::JSON_FILE_LOCKED:
116         *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
117         break;
118       case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
119         *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
120         break;
121       default:
122         *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
123         // JSON errors indicate file corruption of some sort.
124         // Since the file is corrupt, move it to the side and continue with
125         // empty preferences.  This will result in them losing their settings.
126         // We keep the old file for possible support and debugging assistance
127         // as well as to detect if they're seeing these errors repeatedly.
128         // TODO(erikkay) Instead, use the last known good file.
129         base::FilePath bad = path.ReplaceExtension(kBadExtension);
130
131         // If they've ever had a parse error before, put them in another bucket.
132         // TODO(erikkay) if we keep this error checking for very long, we may
133         // want to differentiate between recent and long ago errors.
134         if (base::PathExists(bad))
135           *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
136         base::Move(path, bad);
137         break;
138     }
139   } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
140     *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
141   }
142 }
143
144 }  // namespace
145
146 scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile(
147     const base::FilePath& filename,
148     base::SequencedWorkerPool* worker_pool) {
149   std::string token("json_pref_store-");
150   token.append(filename.AsUTF8Unsafe());
151   return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
152       worker_pool->GetNamedSequenceToken(token),
153       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
154 }
155
156 JsonPrefStore::JsonPrefStore(const base::FilePath& filename,
157                              base::SequencedTaskRunner* sequenced_task_runner,
158                              scoped_ptr<PrefFilter> pref_filter)
159     : path_(filename),
160       sequenced_task_runner_(sequenced_task_runner),
161       prefs_(new base::DictionaryValue()),
162       read_only_(false),
163       writer_(filename, sequenced_task_runner),
164       pref_filter_(pref_filter.Pass()),
165       initialized_(false),
166       filtering_in_progress_(false),
167       read_error_(PREF_READ_ERROR_NONE) {
168 }
169
170 bool JsonPrefStore::GetValue(const std::string& key,
171                              const base::Value** result) const {
172   base::Value* tmp = NULL;
173   if (!prefs_->Get(key, &tmp))
174     return false;
175
176   if (result)
177     *result = tmp;
178   return true;
179 }
180
181 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
182   observers_.AddObserver(observer);
183 }
184
185 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
186   observers_.RemoveObserver(observer);
187 }
188
189 bool JsonPrefStore::HasObservers() const {
190   return observers_.might_have_observers();
191 }
192
193 bool JsonPrefStore::IsInitializationComplete() const {
194   return initialized_;
195 }
196
197 bool JsonPrefStore::GetMutableValue(const std::string& key,
198                                     base::Value** result) {
199   return prefs_->Get(key, result);
200 }
201
202 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) {
203   DCHECK(value);
204   scoped_ptr<base::Value> new_value(value);
205   base::Value* old_value = NULL;
206   prefs_->Get(key, &old_value);
207   if (!old_value || !value->Equals(old_value)) {
208     prefs_->Set(key, new_value.release());
209     ReportValueChanged(key);
210   }
211 }
212
213 void JsonPrefStore::SetValueSilently(const std::string& key,
214                                      base::Value* value) {
215   DCHECK(value);
216   scoped_ptr<base::Value> new_value(value);
217   base::Value* old_value = NULL;
218   prefs_->Get(key, &old_value);
219   if (!old_value || !value->Equals(old_value)) {
220     prefs_->Set(key, new_value.release());
221     if (!read_only_)
222       writer_.ScheduleWrite(this);
223   }
224 }
225
226 void JsonPrefStore::RemoveValue(const std::string& key) {
227   if (prefs_->RemovePath(key, NULL))
228     ReportValueChanged(key);
229 }
230
231 void JsonPrefStore::RemoveValueSilently(const std::string& key) {
232   prefs_->RemovePath(key, NULL);
233   if (!read_only_)
234     writer_.ScheduleWrite(this);
235 }
236
237 bool JsonPrefStore::ReadOnly() const {
238   return read_only_;
239 }
240
241 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
242   return read_error_;
243 }
244
245 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
246   if (path_.empty()) {
247     OnFileRead(
248         scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
249     return PREF_READ_ERROR_FILE_NOT_SPECIFIED;
250   }
251
252   PrefReadError error;
253   bool no_dir;
254   scoped_ptr<base::Value> value(
255       FileThreadDeserializer::DoReading(path_, &error, &no_dir));
256   OnFileRead(value.Pass(), error, no_dir);
257   return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE :
258                                   error;
259 }
260
261 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
262   initialized_ = false;
263   error_delegate_.reset(error_delegate);
264   if (path_.empty()) {
265     OnFileRead(
266         scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false);
267     return;
268   }
269
270   // Start async reading of the preferences file. It will delete itself
271   // in the end.
272   scoped_refptr<FileThreadDeserializer> deserializer(
273       new FileThreadDeserializer(this, sequenced_task_runner_.get()));
274   deserializer->Start(path_);
275 }
276
277 void JsonPrefStore::CommitPendingWrite() {
278   if (writer_.HasPendingWrite() && !read_only_)
279     writer_.DoScheduledWrite();
280 }
281
282 void JsonPrefStore::ReportValueChanged(const std::string& key) {
283   if (pref_filter_)
284     pref_filter_->FilterUpdate(key);
285
286   FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
287
288   if (!read_only_)
289     writer_.ScheduleWrite(this);
290 }
291
292 void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
293     const base::Closure& on_next_successful_write) {
294   writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write);
295 }
296
297 void JsonPrefStore::OnFileRead(scoped_ptr<base::Value> value,
298                                PersistentPrefStore::PrefReadError error,
299                                bool no_dir) {
300   scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue);
301
302   read_error_ = error;
303
304   bool initialization_successful = !no_dir;
305
306   if (initialization_successful) {
307     switch (read_error_) {
308       case PREF_READ_ERROR_ACCESS_DENIED:
309       case PREF_READ_ERROR_FILE_OTHER:
310       case PREF_READ_ERROR_FILE_LOCKED:
311       case PREF_READ_ERROR_JSON_TYPE:
312       case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
313         read_only_ = true;
314         break;
315       case PREF_READ_ERROR_NONE:
316         DCHECK(value.get());
317         unfiltered_prefs.reset(
318             static_cast<base::DictionaryValue*>(value.release()));
319         break;
320       case PREF_READ_ERROR_NO_FILE:
321         // If the file just doesn't exist, maybe this is first run.  In any case
322         // there's no harm in writing out default prefs in this case.
323         break;
324       case PREF_READ_ERROR_JSON_PARSE:
325       case PREF_READ_ERROR_JSON_REPEAT:
326         break;
327       case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
328         // This is a special error code to be returned by ReadPrefs when it
329         // can't complete synchronously, it should never be returned by the read
330         // operation itself.
331         NOTREACHED();
332         break;
333       case PREF_READ_ERROR_MAX_ENUM:
334         NOTREACHED();
335         break;
336     }
337   }
338
339   if (pref_filter_) {
340     filtering_in_progress_ = true;
341     const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback(
342         base::Bind(
343             &JsonPrefStore::FinalizeFileRead, this, initialization_successful));
344     pref_filter_->FilterOnLoad(post_filter_on_load_callback,
345                                unfiltered_prefs.Pass());
346   } else {
347     FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false);
348   }
349 }
350
351 JsonPrefStore::~JsonPrefStore() {
352   CommitPendingWrite();
353 }
354
355 bool JsonPrefStore::SerializeData(std::string* output) {
356   if (pref_filter_)
357     pref_filter_->FilterSerializeData(prefs_.get());
358
359   JSONStringValueSerializer serializer(output);
360   serializer.set_pretty_print(true);
361   return serializer.Serialize(*prefs_);
362 }
363
364 void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
365                                      scoped_ptr<base::DictionaryValue> prefs,
366                                      bool schedule_write) {
367   filtering_in_progress_ = false;
368
369   if (!initialization_successful) {
370     FOR_EACH_OBSERVER(PrefStore::Observer,
371                       observers_,
372                       OnInitializationCompleted(false));
373     return;
374   }
375
376   prefs_ = prefs.Pass();
377
378   initialized_ = true;
379
380   if (schedule_write && !read_only_)
381     writer_.ScheduleWrite(this);
382
383   if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
384     error_delegate_->OnError(read_error_);
385
386   FOR_EACH_OBSERVER(PrefStore::Observer,
387                     observers_,
388                     OnInitializationCompleted(true));
389
390   return;
391 }