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 origin 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 origin_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(origin_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 |
| 47 value_.reset(DoReading(path, &error_, &no_dir_)); |
| 48 |
| 49 origin_loop_proxy_->PostTask( |
| 50 FROM_HERE, |
| 51 NewRunnableMethod(this, &FileThreadDeserializer::ReportOnOriginThread)); |
| 52 } |
| 53 |
| 54 // Reports deserialization result on the origin thread. |
| 55 void ReportOnOriginThread() { |
| 56 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); |
| 57 delegate_->OnFileRead(value_.release(), error_, no_dir_); |
| 58 } |
| 59 |
| 60 static Value* DoReading(const FilePath& path, |
| 61 PersistentPrefStore::PrefReadError* error, |
| 62 bool* no_dir) { |
44 int error_code; | 63 int error_code; |
45 std::string error_msg; | 64 std::string error_msg; |
46 JSONFileValueSerializer serializer(path); | 65 JSONFileValueSerializer serializer(path); |
47 value_.reset(serializer.Deserialize(&error_code, &error_msg)); | 66 Value* value = serializer.Deserialize(&error_code, &error_msg); |
48 | 67 HandleErrors(value, path, error_code, error_msg, error); |
49 HandleErrors(value_.get(), path, error_code, error_msg, &error_); | 68 *no_dir = !file_util::PathExists(path.DirName()); |
50 | 69 return value; |
51 no_dir_ = !file_util::PathExists(path.DirName()); | |
52 | |
53 BrowserThread::PostTask( | |
54 BrowserThread::UI, | |
55 FROM_HERE, | |
56 NewRunnableMethod(this, &FileThreadDeserializer::ReportOnUIThread)); | |
57 } | |
58 | |
59 // Reports deserialization result on the UI thread. | |
60 void ReportOnUIThread() { | |
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
62 delegate_->OnFileRead(value_.release(), error_, no_dir_); | |
63 } | 70 } |
64 | 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> origin_loop_proxy_; |
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_delegate_(NULL), |
| 145 initialized_(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)) { |
144 *result = tmp; | 156 *result = tmp; |
145 return READ_OK; | 157 return READ_OK; |
146 } | 158 } |
147 return READ_NO_VALUE; | 159 return READ_NO_VALUE; |
148 } | 160 } |
149 | 161 |
150 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) { | 162 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) { |
151 observers_.AddObserver(observer); | 163 observers_.AddObserver(observer); |
152 } | 164 } |
153 | 165 |
154 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { | 166 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { |
155 observers_.RemoveObserver(observer); | 167 observers_.RemoveObserver(observer); |
156 } | 168 } |
157 | 169 |
| 170 bool JsonPrefStore::IsInitializationComplete() const { |
| 171 return initialized_; |
| 172 } |
| 173 |
158 PrefStore::ReadResult JsonPrefStore::GetMutableValue(const std::string& key, | 174 PrefStore::ReadResult JsonPrefStore::GetMutableValue(const std::string& key, |
159 Value** result) { | 175 Value** result) { |
160 return prefs_->Get(key, result) ? READ_OK : READ_NO_VALUE; | 176 return prefs_->Get(key, result) ? READ_OK : READ_NO_VALUE; |
161 } | 177 } |
162 | 178 |
163 void JsonPrefStore::SetValue(const std::string& key, Value* value) { | 179 void JsonPrefStore::SetValue(const std::string& key, Value* value) { |
164 DCHECK(value); | 180 DCHECK(value); |
165 scoped_ptr<Value> new_value(value); | 181 scoped_ptr<Value> new_value(value); |
166 Value* old_value = NULL; | 182 Value* old_value = NULL; |
167 prefs_->Get(key, &old_value); | 183 prefs_->Get(key, &old_value); |
(...skipping 19 matching lines...) Expand all Loading... |
187 } | 203 } |
188 | 204 |
189 bool JsonPrefStore::ReadOnly() const { | 205 bool JsonPrefStore::ReadOnly() const { |
190 return read_only_; | 206 return read_only_; |
191 } | 207 } |
192 | 208 |
193 void JsonPrefStore::OnFileRead(Value* value_owned, | 209 void JsonPrefStore::OnFileRead(Value* value_owned, |
194 PersistentPrefStore::PrefReadError error, | 210 PersistentPrefStore::PrefReadError error, |
195 bool no_dir) { | 211 bool no_dir) { |
196 scoped_ptr<Value> value(value_owned); | 212 scoped_ptr<Value> value(value_owned); |
| 213 |
| 214 if (no_dir) { |
| 215 FOR_EACH_OBSERVER(PrefStore::Observer, |
| 216 observers_, |
| 217 OnInitializationCompleted(false)); |
| 218 return; |
| 219 } |
| 220 |
| 221 initialized_ = true; |
| 222 |
197 switch (error) { | 223 switch (error) { |
198 case PREF_READ_ERROR_ACCESS_DENIED: | 224 case PREF_READ_ERROR_ACCESS_DENIED: |
199 case PREF_READ_ERROR_FILE_OTHER: | 225 case PREF_READ_ERROR_FILE_OTHER: |
200 case PREF_READ_ERROR_FILE_LOCKED: | 226 case PREF_READ_ERROR_FILE_LOCKED: |
201 case PREF_READ_ERROR_JSON_TYPE: | 227 case PREF_READ_ERROR_JSON_TYPE: |
| 228 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: |
202 read_only_ = true; | 229 read_only_ = true; |
203 break; | 230 break; |
204 case PREF_READ_ERROR_NONE: | 231 case PREF_READ_ERROR_NONE: |
205 DCHECK(value.get()); | 232 DCHECK(value.get()); |
206 prefs_.reset(static_cast<DictionaryValue*>(value.release())); | 233 prefs_.reset(static_cast<DictionaryValue*>(value.release())); |
207 break; | 234 break; |
208 case PREF_READ_ERROR_NO_FILE: | 235 case PREF_READ_ERROR_NO_FILE: |
209 // If the file just doesn't exist, maybe this is first run. In any case | 236 // 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. | 237 // there's no harm in writing out default prefs in this case. |
211 break; | 238 break; |
212 case PREF_READ_ERROR_JSON_PARSE: | 239 case PREF_READ_ERROR_JSON_PARSE: |
213 case PREF_READ_ERROR_JSON_REPEAT: | 240 case PREF_READ_ERROR_JSON_REPEAT: |
214 break; | 241 break; |
215 default: | 242 default: |
216 NOTREACHED() << "Unknown error: " << error; | 243 NOTREACHED() << "Unknown error: " << error; |
217 } | 244 } |
218 | 245 |
219 if (delegate_) | 246 if (error_delegate_.get() && error != PREF_READ_ERROR_NONE) |
220 delegate_->OnPrefsRead(error, no_dir); | 247 error_delegate_->OnError(error); |
| 248 |
| 249 FOR_EACH_OBSERVER(PrefStore::Observer, |
| 250 observers_, |
| 251 OnInitializationCompleted(true)); |
221 } | 252 } |
222 | 253 |
223 void JsonPrefStore::ReadPrefs(Delegate* delegate) { | 254 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) { |
224 DCHECK(delegate); | 255 initialized_ = false; |
225 delegate_ = delegate; | 256 error_delegate_.reset(error_delegate); |
226 | |
227 if (path_.empty()) { | 257 if (path_.empty()) { |
228 read_only_ = true; | 258 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
229 delegate_->OnPrefsRead(PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | |
230 return; | 259 return; |
231 } | 260 } |
232 | 261 |
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 | 262 // Start async reading of the preferences file. It will delete itself |
237 // in the end. | 263 // in the end. |
238 scoped_refptr<FileThreadDeserializer> deserializer( | 264 scoped_refptr<FileThreadDeserializer> deserializer( |
239 new FileThreadDeserializer(this)); | 265 new FileThreadDeserializer(this, file_message_loop_proxy_.get())); |
240 deserializer->Start(path_); | 266 deserializer->Start(path_); |
241 } | 267 } |
242 | 268 |
243 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { | 269 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { |
244 delegate_ = NULL; | |
245 | |
246 if (path_.empty()) { | 270 if (path_.empty()) { |
247 read_only_ = true; | 271 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
248 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; | 272 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; |
249 } | 273 } |
250 | 274 |
251 int error_code = 0; | 275 PrefReadError error; |
252 std::string error_msg; | 276 bool no_dir; |
253 | 277 Value* value = FileThreadDeserializer::DoReading(path_, &error, &no_dir); |
254 JSONFileValueSerializer serializer(path_); | 278 OnFileRead(value, error, no_dir); |
255 scoped_ptr<Value> value(serializer.Deserialize(&error_code, &error_msg)); | |
256 | |
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; | 279 return error; |
267 } | 280 } |
268 | 281 |
269 bool JsonPrefStore::WritePrefs() { | 282 bool JsonPrefStore::WritePrefs() { |
270 std::string data; | 283 std::string data; |
271 if (!SerializeData(&data)) | 284 if (!SerializeData(&data)) |
272 return false; | 285 return false; |
273 | 286 |
274 // Lie about our ability to save. | 287 // Lie about our ability to save. |
275 if (read_only_) | 288 if (read_only_) |
(...skipping 20 matching lines...) Expand all Loading... |
296 } | 309 } |
297 | 310 |
298 bool JsonPrefStore::SerializeData(std::string* output) { | 311 bool JsonPrefStore::SerializeData(std::string* output) { |
299 // TODO(tc): Do we want to prune webkit preferences that match the default | 312 // TODO(tc): Do we want to prune webkit preferences that match the default |
300 // value? | 313 // value? |
301 JSONStringValueSerializer serializer(output); | 314 JSONStringValueSerializer serializer(output); |
302 serializer.set_pretty_print(true); | 315 serializer.set_pretty_print(true); |
303 scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren()); | 316 scoped_ptr<DictionaryValue> copy(prefs_->DeepCopyWithoutEmptyChildren()); |
304 return serializer.Serialize(*(copy.get())); | 317 return serializer.Serialize(*(copy.get())); |
305 } | 318 } |
OLD | NEW |