Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "base/prefs/json_pref_store.h" | 5 #include "base/prefs/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" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 value_.reset(DoReading(path, &error_, &no_dir_)); | 52 value_.reset(DoReading(path, &error_, &no_dir_)); |
| 53 | 53 |
| 54 origin_loop_proxy_->PostTask( | 54 origin_loop_proxy_->PostTask( |
| 55 FROM_HERE, | 55 FROM_HERE, |
| 56 base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this)); | 56 base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this)); |
| 57 } | 57 } |
| 58 | 58 |
| 59 // Reports deserialization result on the origin thread. | 59 // Reports deserialization result on the origin thread. |
| 60 void ReportOnOriginThread() { | 60 void ReportOnOriginThread() { |
| 61 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | 61 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); |
| 62 delegate_->OnFileRead(value_.release(), error_, no_dir_); | 62 // TODO(gab): There is a race condition in error reporting here as |error_| |
| 63 // is initialized on the origin thread, set on the task runner's thread in | |
| 64 // HandleErrors(), and then read here on the origin thread again with no | |
| 65 // synchronization barriers (which means we potentially report | |
| 66 // PREF_READ_ERROR_NONE when there actually was an error). | |
|
Bernhard Bauer
2014/05/01 12:37:09
Huh, why is that? Doing PostTask should guarantee
gab
2014/05/01 15:34:54
Right, not a race condition in the sense that they
Bernhard Bauer
2014/05/01 20:16:00
I think it's already correct as it currently is, o
gab
2014/05/02 04:15:01
Oh I see, this is very well hidden side-effect of
| |
| 67 delegate_->OnFileRead(value_.Pass(), error_, no_dir_); | |
| 63 } | 68 } |
| 64 | 69 |
| 65 static base::Value* DoReading(const base::FilePath& path, | 70 static base::Value* DoReading(const base::FilePath& path, |
| 66 PersistentPrefStore::PrefReadError* error, | 71 PersistentPrefStore::PrefReadError* error, |
| 67 bool* no_dir) { | 72 bool* no_dir) { |
| 68 int error_code; | 73 int error_code; |
| 69 std::string error_msg; | 74 std::string error_msg; |
| 70 JSONFileValueSerializer serializer(path); | 75 JSONFileValueSerializer serializer(path); |
| 71 base::Value* value = serializer.Deserialize(&error_code, &error_msg); | 76 base::Value* value = serializer.Deserialize(&error_code, &error_msg); |
| 72 HandleErrors(value, path, error_code, error_msg, error); | 77 HandleErrors(value, path, error_code, error_msg, error); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 JsonPrefStore::JsonPrefStore(const base::FilePath& filename, | 159 JsonPrefStore::JsonPrefStore(const base::FilePath& filename, |
| 155 base::SequencedTaskRunner* sequenced_task_runner, | 160 base::SequencedTaskRunner* sequenced_task_runner, |
| 156 scoped_ptr<PrefFilter> pref_filter) | 161 scoped_ptr<PrefFilter> pref_filter) |
| 157 : path_(filename), | 162 : path_(filename), |
| 158 sequenced_task_runner_(sequenced_task_runner), | 163 sequenced_task_runner_(sequenced_task_runner), |
| 159 prefs_(new base::DictionaryValue()), | 164 prefs_(new base::DictionaryValue()), |
| 160 read_only_(false), | 165 read_only_(false), |
| 161 writer_(filename, sequenced_task_runner), | 166 writer_(filename, sequenced_task_runner), |
| 162 pref_filter_(pref_filter.Pass()), | 167 pref_filter_(pref_filter.Pass()), |
| 163 initialized_(false), | 168 initialized_(false), |
| 164 read_error_(PREF_READ_ERROR_OTHER) {} | 169 read_error_(PREF_READ_ERROR_NONE), |
| 170 weak_factory_(this) {} | |
| 165 | 171 |
| 166 bool JsonPrefStore::GetValue(const std::string& key, | 172 bool JsonPrefStore::GetValue(const std::string& key, |
| 167 const base::Value** result) const { | 173 const base::Value** result) const { |
| 168 base::Value* tmp = NULL; | 174 base::Value* tmp = NULL; |
| 169 if (!prefs_->Get(key, &tmp)) | 175 if (!prefs_->Get(key, &tmp)) |
| 170 return false; | 176 return false; |
| 171 | 177 |
| 172 if (result) | 178 if (result) |
| 173 *result = tmp; | 179 *result = tmp; |
| 174 return true; | 180 return true; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 217 if (!read_only_) | 223 if (!read_only_) |
| 218 writer_.ScheduleWrite(this); | 224 writer_.ScheduleWrite(this); |
| 219 } | 225 } |
| 220 } | 226 } |
| 221 | 227 |
| 222 void JsonPrefStore::RemoveValue(const std::string& key) { | 228 void JsonPrefStore::RemoveValue(const std::string& key) { |
| 223 if (prefs_->RemovePath(key, NULL)) | 229 if (prefs_->RemovePath(key, NULL)) |
| 224 ReportValueChanged(key); | 230 ReportValueChanged(key); |
| 225 } | 231 } |
| 226 | 232 |
| 233 void JsonPrefStore::RemoveValueSilently(const std::string& key) { | |
| 234 prefs_->RemovePath(key, NULL); | |
| 235 if (!read_only_) | |
| 236 writer_.ScheduleWrite(this); | |
| 237 } | |
| 238 | |
| 227 bool JsonPrefStore::ReadOnly() const { | 239 bool JsonPrefStore::ReadOnly() const { |
| 228 return read_only_; | 240 return read_only_; |
| 229 } | 241 } |
| 230 | 242 |
| 231 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { | 243 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { |
| 232 return read_error_; | 244 return read_error_; |
| 233 } | 245 } |
| 234 | 246 |
| 235 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { | 247 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { |
| 236 if (path_.empty()) { | 248 if (path_.empty()) { |
| 237 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | 249 OnFileRead( |
| 250 scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | |
| 238 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; | 251 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; |
| 239 } | 252 } |
| 240 | 253 |
| 241 PrefReadError error; | 254 PrefReadError error; |
| 242 bool no_dir; | 255 bool no_dir; |
| 243 base::Value* value = | 256 scoped_ptr<base::Value> value( |
| 244 FileThreadDeserializer::DoReading(path_, &error, &no_dir); | 257 FileThreadDeserializer::DoReading(path_, &error, &no_dir)); |
| 245 OnFileRead(value, error, no_dir); | 258 OnFileRead(value.Pass(), error, no_dir); |
| 246 return error; | 259 return error; |
| 247 } | 260 } |
| 248 | 261 |
| 249 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) { | 262 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { |
| 250 initialized_ = false; | 263 initialized_ = false; |
| 251 error_delegate_.reset(error_delegate); | 264 error_delegate_.reset(error_delegate); |
| 252 if (path_.empty()) { | 265 if (path_.empty()) { |
| 253 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | 266 OnFileRead( |
| 267 scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | |
| 254 return; | 268 return; |
| 255 } | 269 } |
| 256 | 270 |
| 257 // Start async reading of the preferences file. It will delete itself | 271 // Start async reading of the preferences file. It will delete itself |
| 258 // in the end. | 272 // in the end. |
| 259 scoped_refptr<FileThreadDeserializer> deserializer( | 273 scoped_refptr<FileThreadDeserializer> deserializer( |
| 260 new FileThreadDeserializer(this, sequenced_task_runner_.get())); | 274 new FileThreadDeserializer(this, sequenced_task_runner_.get())); |
| 261 deserializer->Start(path_); | 275 deserializer->Start(path_); |
| 262 } | 276 } |
| 263 | 277 |
| 264 void JsonPrefStore::CommitPendingWrite() { | 278 void JsonPrefStore::CommitPendingWrite() { |
| 265 if (writer_.HasPendingWrite() && !read_only_) | 279 if (writer_.HasPendingWrite() && !read_only_) |
| 266 writer_.DoScheduledWrite(); | 280 writer_.DoScheduledWrite(); |
| 267 } | 281 } |
| 268 | 282 |
| 269 void JsonPrefStore::ReportValueChanged(const std::string& key) { | 283 void JsonPrefStore::ReportValueChanged(const std::string& key) { |
| 270 if (pref_filter_) | 284 if (pref_filter_) |
| 271 pref_filter_->FilterUpdate(key); | 285 pref_filter_->FilterUpdate(key); |
| 272 | 286 |
| 273 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); | 287 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); |
| 274 | 288 |
| 275 if (!read_only_) | 289 if (!read_only_) |
| 276 writer_.ScheduleWrite(this); | 290 writer_.ScheduleWrite(this); |
| 277 } | 291 } |
| 278 | 292 |
| 279 void JsonPrefStore::OnFileRead(base::Value* value_owned, | 293 void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback( |
| 294 const base::Closure& on_next_successful_write) { | |
| 295 writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write); | |
| 296 } | |
| 297 | |
| 298 void JsonPrefStore::InterceptNextFileRead( | |
| 299 const OnFileReadInterceptor& on_file_read_interceptor) { | |
| 300 DCHECK(on_file_read_interceptor_.is_null()); | |
| 301 on_file_read_interceptor_ = on_file_read_interceptor; | |
| 302 } | |
| 303 | |
| 304 void JsonPrefStore::OnFileRead(scoped_ptr<base::Value> value, | |
| 280 PersistentPrefStore::PrefReadError error, | 305 PersistentPrefStore::PrefReadError error, |
| 281 bool no_dir) { | 306 bool no_dir) { |
| 282 scoped_ptr<base::Value> value(value_owned); | 307 scoped_ptr<base::DictionaryValue> unprocessed_prefs( |
| 308 new base::DictionaryValue); | |
| 309 | |
| 283 read_error_ = error; | 310 read_error_ = error; |
| 284 | 311 |
| 285 if (no_dir) { | 312 bool initialization_successful = !no_dir; |
| 286 FOR_EACH_OBSERVER(PrefStore::Observer, | 313 |
| 287 observers_, | 314 if (initialization_successful) { |
| 288 OnInitializationCompleted(false)); | 315 switch (error) { |
| 289 return; | 316 case PREF_READ_ERROR_ACCESS_DENIED: |
| 317 case PREF_READ_ERROR_FILE_OTHER: | |
| 318 case PREF_READ_ERROR_FILE_LOCKED: | |
| 319 case PREF_READ_ERROR_JSON_TYPE: | |
| 320 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: | |
| 321 read_only_ = true; | |
| 322 break; | |
| 323 case PREF_READ_ERROR_NONE: | |
| 324 DCHECK(value.get()); | |
| 325 unprocessed_prefs.reset( | |
| 326 static_cast<base::DictionaryValue*>(value.release())); | |
| 327 break; | |
| 328 case PREF_READ_ERROR_NO_FILE: | |
| 329 // If the file just doesn't exist, maybe this is first run. In any case | |
| 330 // there's no harm in writing out default prefs in this case. | |
| 331 break; | |
| 332 case PREF_READ_ERROR_JSON_PARSE: | |
| 333 case PREF_READ_ERROR_JSON_REPEAT: | |
| 334 break; | |
| 335 case PREF_READ_ERROR_MAX_ENUM: | |
| 336 NOTREACHED(); | |
| 337 break; | |
| 338 } | |
| 290 } | 339 } |
| 291 | 340 |
| 292 initialized_ = true; | 341 if (on_file_read_interceptor_.is_null()) { |
| 293 | 342 FinalizeFileRead(initialization_successful, unprocessed_prefs.Pass(), |
| 294 switch (error) { | 343 false); |
| 295 case PREF_READ_ERROR_ACCESS_DENIED: | 344 } else { |
| 296 case PREF_READ_ERROR_FILE_OTHER: | 345 const FinalizePrefsReadCallback finalize_file_read( |
| 297 case PREF_READ_ERROR_FILE_LOCKED: | 346 base::Bind(&JsonPrefStore::FinalizeFileRead, this, |
| 298 case PREF_READ_ERROR_JSON_TYPE: | 347 initialization_successful)); |
| 299 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: | 348 on_file_read_interceptor_.Run(unprocessed_prefs.Pass(), |
| 300 read_only_ = true; | 349 finalize_file_read); |
| 301 break; | 350 on_file_read_interceptor_.Reset(); |
| 302 case PREF_READ_ERROR_NONE: | |
| 303 DCHECK(value.get()); | |
| 304 prefs_.reset(static_cast<base::DictionaryValue*>(value.release())); | |
| 305 break; | |
| 306 case PREF_READ_ERROR_NO_FILE: | |
| 307 // If the file just doesn't exist, maybe this is first run. In any case | |
| 308 // there's no harm in writing out default prefs in this case. | |
| 309 break; | |
| 310 case PREF_READ_ERROR_JSON_PARSE: | |
| 311 case PREF_READ_ERROR_JSON_REPEAT: | |
| 312 break; | |
| 313 default: | |
| 314 NOTREACHED() << "Unknown error: " << error; | |
| 315 } | 351 } |
| 316 | |
| 317 if (pref_filter_ && pref_filter_->FilterOnLoad(prefs_.get())) | |
| 318 writer_.ScheduleWrite(this); | |
| 319 | |
| 320 if (error_delegate_.get() && error != PREF_READ_ERROR_NONE) | |
| 321 error_delegate_->OnError(error); | |
| 322 | |
| 323 FOR_EACH_OBSERVER(PrefStore::Observer, | |
| 324 observers_, | |
| 325 OnInitializationCompleted(true)); | |
| 326 } | 352 } |
| 327 | 353 |
| 328 JsonPrefStore::~JsonPrefStore() { | 354 JsonPrefStore::~JsonPrefStore() { |
| 329 CommitPendingWrite(); | 355 CommitPendingWrite(); |
| 330 } | 356 } |
| 331 | 357 |
| 332 bool JsonPrefStore::SerializeData(std::string* output) { | 358 bool JsonPrefStore::SerializeData(std::string* output) { |
| 333 if (pref_filter_) | 359 if (pref_filter_) |
| 334 pref_filter_->FilterSerializeData(prefs_.get()); | 360 pref_filter_->FilterSerializeData(prefs_.get()); |
| 335 | 361 |
| 336 JSONStringValueSerializer serializer(output); | 362 JSONStringValueSerializer serializer(output); |
| 337 serializer.set_pretty_print(true); | 363 serializer.set_pretty_print(true); |
| 338 return serializer.Serialize(*prefs_); | 364 return serializer.Serialize(*prefs_); |
| 339 } | 365 } |
| 366 | |
| 367 base::WeakPtr<JsonPrefStore> JsonPrefStore::FinalizeFileRead( | |
| 368 bool initialization_successful, | |
| 369 scoped_ptr<base::DictionaryValue> prefs, | |
| 370 bool schedule_write) { | |
| 371 if (!initialization_successful) { | |
| 372 FOR_EACH_OBSERVER(PrefStore::Observer, | |
| 373 observers_, | |
| 374 OnInitializationCompleted(false)); | |
| 375 return weak_factory_.GetWeakPtr(); | |
| 376 } | |
| 377 | |
| 378 prefs_ = prefs.Pass(); | |
| 379 | |
| 380 initialized_ = true; | |
| 381 | |
| 382 bool had_filter_modification = | |
| 383 pref_filter_ && pref_filter_->FilterOnLoad(prefs_.get()); | |
| 384 | |
| 385 if ((schedule_write || had_filter_modification) && !read_only_) | |
| 386 writer_.ScheduleWrite(this); | |
| 387 | |
| 388 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) | |
| 389 error_delegate_->OnError(read_error_); | |
| 390 | |
| 391 FOR_EACH_OBSERVER(PrefStore::Observer, | |
| 392 observers_, | |
| 393 OnInitializationCompleted(true)); | |
| 394 | |
| 395 return weak_factory_.GetWeakPtr(); | |
| 396 } | |
| OLD | NEW |