Chromium Code Reviews| 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 |