OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/common/json_pref_store.h" | 5 #include "chrome/common/json_pref_store.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
13 #include "base/message_loop_proxy.h" | |
13 #include "base/values.h" | 14 #include "base/values.h" |
14 #include "content/browser/browser_thread.h" | |
15 #include "content/common/json_value_serializer.h" | 15 #include "content/common/json_value_serializer.h" |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 // Some extensions we'll tack on to copies of the Preferences files. | 19 // Some extensions we'll tack on to copies of the Preferences files. |
20 const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); | 20 const FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); |
21 | 21 |
22 // Differentiates file loading between UI and FILE threads. | 22 // Differentiates file loading between current (aka ui) thread and passed |
23 // (aka file) thread. | |
23 class FileThreadDeserializer | 24 class FileThreadDeserializer |
24 : public base::RefCountedThreadSafe<FileThreadDeserializer> { | 25 : public base::RefCountedThreadSafe<FileThreadDeserializer> { |
25 public: | 26 public: |
26 explicit FileThreadDeserializer(JsonPrefStore* delegate) | 27 explicit FileThreadDeserializer(JsonPrefStore* delegate, |
27 : delegate_(delegate) { | 28 base::MessageLoopProxy* file_loop_proxy) |
29 : delegate_(delegate), | |
30 file_loop_proxy_(file_loop_proxy), | |
31 ui_loop_proxy_(base::MessageLoopProxy::CreateForCurrentThread()) { | |
28 } | 32 } |
29 | 33 |
30 void Start(const FilePath& path) { | 34 void Start(const FilePath& path) { |
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 35 DCHECK(ui_loop_proxy_->BelongsToCurrentThread()); |
32 BrowserThread::PostTask( | 36 file_loop_proxy_->PostTask( |
33 BrowserThread::FILE, | |
34 FROM_HERE, | 37 FROM_HERE, |
35 NewRunnableMethod(this, | 38 NewRunnableMethod(this, |
36 &FileThreadDeserializer::ReadFileAndReport, | 39 &FileThreadDeserializer::ReadFileAndReport, |
37 path)); | 40 path)); |
38 } | 41 } |
39 | 42 |
40 // Deserializes JSON on the FILE thread. | 43 // Deserializes JSON on the file thread. |
41 void ReadFileAndReport(const FilePath& path) { | 44 void ReadFileAndReport(const FilePath& path) { |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 45 DCHECK(file_loop_proxy_->BelongsToCurrentThread()); |
43 | 46 |
44 int error_code; | 47 value_.reset(DoReading(path, &error_, &no_dir_)); |
45 std::string error_msg; | |
46 JSONFileValueSerializer serializer(path); | |
47 value_.reset(serializer.Deserialize(&error_code, &error_msg)); | |
48 | 48 |
49 HandleErrors(value_.get(), path, error_code, error_msg, &error_); | 49 ui_loop_proxy_->PostTask( |
50 | |
51 no_dir_ = !file_util::PathExists(path.DirName()); | |
52 | |
53 BrowserThread::PostTask( | |
54 BrowserThread::UI, | |
55 FROM_HERE, | 50 FROM_HERE, |
56 NewRunnableMethod(this, &FileThreadDeserializer::ReportOnUIThread)); | 51 NewRunnableMethod(this, &FileThreadDeserializer::ReportOnUIThread)); |
57 } | 52 } |
58 | 53 |
59 // Reports deserialization result on the UI thread. | 54 // Reports deserialization result on the ui thread. |
60 void ReportOnUIThread() { | 55 void ReportOnUIThread() { |
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 56 DCHECK(ui_loop_proxy_->BelongsToCurrentThread()); |
62 delegate_->OnFileRead(value_.release(), error_, no_dir_); | 57 delegate_->OnFileRead(value_.release(), error_, no_dir_); |
63 } | 58 } |
64 | 59 |
60 static Value* DoReading(const FilePath& path, | |
61 PersistentPrefStore::PrefReadError* error, | |
62 bool* no_dir) { | |
63 int error_code; | |
64 std::string error_msg; | |
65 JSONFileValueSerializer serializer(path); | |
66 Value* value = serializer.Deserialize(&error_code, &error_msg); | |
67 HandleErrors(value, path, error_code, error_msg, error); | |
68 *no_dir = !file_util::PathExists(path.DirName()); | |
69 return value; | |
70 } | |
71 | |
65 static void HandleErrors(const Value* value, | 72 static void HandleErrors(const Value* value, |
66 const FilePath& path, | 73 const FilePath& path, |
67 int error_code, | 74 int error_code, |
68 const std::string& error_msg, | 75 const std::string& error_msg, |
69 PersistentPrefStore::PrefReadError* error); | 76 PersistentPrefStore::PrefReadError* error); |
70 | 77 |
71 private: | 78 private: |
72 friend class base::RefCountedThreadSafe<FileThreadDeserializer>; | 79 friend class base::RefCountedThreadSafe<FileThreadDeserializer>; |
73 | 80 |
74 bool no_dir_; | 81 bool no_dir_; |
75 PersistentPrefStore::PrefReadError error_; | 82 PersistentPrefStore::PrefReadError error_; |
76 scoped_ptr<Value> value_; | 83 scoped_ptr<Value> value_; |
77 scoped_refptr<JsonPrefStore> delegate_; | 84 scoped_refptr<JsonPrefStore> delegate_; |
85 scoped_refptr<base::MessageLoopProxy> file_loop_proxy_; | |
86 scoped_refptr<base::MessageLoopProxy> ui_loop_proxy_; | |
Mattias Nissler (ping if slow)
2011/04/27 12:16:30
ui_loop_proxy is a misnomer IMHO, the service proc
altimofeev
2011/05/04 13:46:14
Done.
| |
78 }; | 87 }; |
79 | 88 |
80 // static | 89 // static |
81 void FileThreadDeserializer::HandleErrors( | 90 void FileThreadDeserializer::HandleErrors( |
82 const Value* value, | 91 const Value* value, |
83 const FilePath& path, | 92 const FilePath& path, |
84 int error_code, | 93 int error_code, |
85 const std::string& error_msg, | 94 const std::string& error_msg, |
86 PersistentPrefStore::PrefReadError* error) { | 95 PersistentPrefStore::PrefReadError* error) { |
87 *error = PersistentPrefStore::PREF_READ_ERROR_NONE; | 96 *error = PersistentPrefStore::PREF_READ_ERROR_NONE; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
121 } else if (!value->IsType(Value::TYPE_DICTIONARY)) { | 130 } else if (!value->IsType(Value::TYPE_DICTIONARY)) { |
122 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; | 131 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; |
123 } | 132 } |
124 } | 133 } |
125 | 134 |
126 } // namespace | 135 } // namespace |
127 | 136 |
128 JsonPrefStore::JsonPrefStore(const FilePath& filename, | 137 JsonPrefStore::JsonPrefStore(const FilePath& filename, |
129 base::MessageLoopProxy* file_message_loop_proxy) | 138 base::MessageLoopProxy* file_message_loop_proxy) |
130 : path_(filename), | 139 : path_(filename), |
140 file_message_loop_proxy_(file_message_loop_proxy), | |
131 prefs_(new DictionaryValue()), | 141 prefs_(new DictionaryValue()), |
132 read_only_(false), | 142 read_only_(false), |
133 writer_(filename, file_message_loop_proxy) { | 143 writer_(filename, file_message_loop_proxy), |
144 error_(PREF_READ_ERROR_NONE), | |
145 is_fatal_(false) { | |
134 } | 146 } |
135 | 147 |
136 JsonPrefStore::~JsonPrefStore() { | 148 JsonPrefStore::~JsonPrefStore() { |
137 CommitPendingWrite(); | 149 CommitPendingWrite(); |
138 } | 150 } |
139 | 151 |
140 PrefStore::ReadResult JsonPrefStore::GetValue(const std::string& key, | 152 PrefStore::ReadResult JsonPrefStore::GetValue(const std::string& key, |
141 const Value** result) const { | 153 const Value** result) const { |
142 Value* tmp = NULL; | 154 Value* tmp = NULL; |
143 if (prefs_->Get(key, &tmp)) { | 155 if (prefs_->Get(key, &tmp)) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
186 } | 198 } |
187 } | 199 } |
188 | 200 |
189 bool JsonPrefStore::ReadOnly() const { | 201 bool JsonPrefStore::ReadOnly() const { |
190 return read_only_; | 202 return read_only_; |
191 } | 203 } |
192 | 204 |
193 void JsonPrefStore::OnFileRead(Value* value_owned, | 205 void JsonPrefStore::OnFileRead(Value* value_owned, |
194 PersistentPrefStore::PrefReadError error, | 206 PersistentPrefStore::PrefReadError error, |
195 bool no_dir) { | 207 bool no_dir) { |
208 error_ = error; | |
209 is_fatal_ = no_dir; | |
210 | |
196 scoped_ptr<Value> value(value_owned); | 211 scoped_ptr<Value> value(value_owned); |
197 switch (error) { | 212 switch (error) { |
198 case PREF_READ_ERROR_ACCESS_DENIED: | 213 case PREF_READ_ERROR_ACCESS_DENIED: |
199 case PREF_READ_ERROR_FILE_OTHER: | 214 case PREF_READ_ERROR_FILE_OTHER: |
200 case PREF_READ_ERROR_FILE_LOCKED: | 215 case PREF_READ_ERROR_FILE_LOCKED: |
201 case PREF_READ_ERROR_JSON_TYPE: | 216 case PREF_READ_ERROR_JSON_TYPE: |
217 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: | |
202 read_only_ = true; | 218 read_only_ = true; |
203 break; | 219 break; |
204 case PREF_READ_ERROR_NONE: | 220 case PREF_READ_ERROR_NONE: |
205 DCHECK(value.get()); | 221 DCHECK(value.get()); |
206 prefs_.reset(static_cast<DictionaryValue*>(value.release())); | 222 prefs_.reset(static_cast<DictionaryValue*>(value.release())); |
207 break; | 223 break; |
208 case PREF_READ_ERROR_NO_FILE: | 224 case PREF_READ_ERROR_NO_FILE: |
209 // If the file just doesn't exist, maybe this is first run. In any case | 225 // If the file just doesn't exist, maybe this is first run. In any case |
210 // there's no harm in writing out default prefs in this case. | 226 // there's no harm in writing out default prefs in this case. |
211 break; | 227 break; |
212 case PREF_READ_ERROR_JSON_PARSE: | 228 case PREF_READ_ERROR_JSON_PARSE: |
213 case PREF_READ_ERROR_JSON_REPEAT: | 229 case PREF_READ_ERROR_JSON_REPEAT: |
214 break; | 230 break; |
215 default: | 231 default: |
216 NOTREACHED() << "Unknown error: " << error; | 232 NOTREACHED() << "Unknown error: " << error; |
217 } | 233 } |
218 | 234 |
219 if (delegate_) | 235 FOR_EACH_OBSERVER(PrefStore::Observer, |
220 delegate_->OnPrefsRead(error, no_dir); | 236 observers_, |
237 OnInitializationCompleted()); | |
221 } | 238 } |
222 | 239 |
223 void JsonPrefStore::ReadPrefs(Delegate* delegate) { | 240 void JsonPrefStore::ReadPrefsAsync() { |
224 DCHECK(delegate); | |
225 delegate_ = delegate; | |
226 | |
227 if (path_.empty()) { | 241 if (path_.empty()) { |
228 read_only_ = true; | 242 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
229 delegate_->OnPrefsRead(PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | |
230 return; | 243 return; |
231 } | 244 } |
232 | 245 |
233 // This guarantees that class will not be deleted while JSON is readed. | |
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
235 | |
236 // Start async reading of the preferences file. It will delete itself | 246 // Start async reading of the preferences file. It will delete itself |
237 // in the end. | 247 // in the end. |
238 scoped_refptr<FileThreadDeserializer> deserializer( | 248 scoped_refptr<FileThreadDeserializer> deserializer( |
239 new FileThreadDeserializer(this)); | 249 new FileThreadDeserializer(this, file_message_loop_proxy_.get())); |
240 deserializer->Start(path_); | 250 deserializer->Start(path_); |
241 } | 251 } |
242 | 252 |
243 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { | 253 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { |
244 delegate_ = NULL; | |
245 | |
246 if (path_.empty()) { | 254 if (path_.empty()) { |
247 read_only_ = true; | 255 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
248 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; | 256 return error_; |
249 } | 257 } |
250 | 258 |
251 int error_code = 0; | 259 Value* value = FileThreadDeserializer::DoReading(path_, |
252 std::string error_msg; | 260 &error_, |
261 &is_fatal_); | |
262 OnFileRead(value, error_, is_fatal_); | |
263 return error_; | |
264 } | |
253 | 265 |
254 JSONFileValueSerializer serializer(path_); | 266 void JsonPrefStore::GetErrors(PrefReadError* error, bool* is_fatal) { |
255 scoped_ptr<Value> value(serializer.Deserialize(&error_code, &error_msg)); | 267 *error = error_; |
256 | 268 *is_fatal = is_fatal_; |
257 PersistentPrefStore::PrefReadError error; | |
258 FileThreadDeserializer::HandleErrors(value.get(), | |
259 path_, | |
260 error_code, | |
261 error_msg, | |
262 &error); | |
263 | |
264 OnFileRead(value.release(), error, false); | |
265 | |
266 return error; | |
267 } | 269 } |
268 | 270 |
269 bool JsonPrefStore::WritePrefs() { | 271 bool JsonPrefStore::WritePrefs() { |
270 std::string data; | 272 std::string data; |
271 if (!SerializeData(&data)) | 273 if (!SerializeData(&data)) |
272 return false; | 274 return false; |
273 | 275 |
274 // Lie about our ability to save. | 276 // Lie about our ability to save. |
275 if (read_only_) | 277 if (read_only_) |
276 return true; | 278 return true; |
(...skipping 19 matching lines...) Expand all Loading... | |
296 } | 298 } |
297 | 299 |
298 bool JsonPrefStore::SerializeData(std::string* output) { | 300 bool JsonPrefStore::SerializeData(std::string* output) { |
299 // TODO(tc): Do we want to prune webkit preferences that match the default | 301 // TODO(tc): Do we want to prune webkit preferences that match the default |
300 // value? | 302 // value? |
301 JSONStringValueSerializer serializer(output); | 303 JSONStringValueSerializer serializer(output); |
302 serializer.set_pretty_print(true); | 304 serializer.set_pretty_print(true); |
303 scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren()); | 305 scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren()); |
304 return serializer.Serialize(*(copy.get())); | 306 return serializer.Serialize(*(copy.get())); |
305 } | 307 } |
OLD | NEW |