Index: base/prefs/json_pref_store.cc |
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc |
index b0a16cc11431e01fd8661949388c11cdc972f156..60823c3b38aeed3b67dde150d8afae1df2a485e1 100644 |
--- a/base/prefs/json_pref_store.cc |
+++ b/base/prefs/json_pref_store.cc |
@@ -59,7 +59,12 @@ class FileThreadDeserializer |
// Reports deserialization result on the origin thread. |
void ReportOnOriginThread() { |
DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); |
- delegate_->OnFileRead(value_.release(), error_, no_dir_); |
+ // TODO(gab): There is a race condition in error reporting here as |error_| |
+ // is initialized on the origin thread, set on the task runner's thread in |
+ // HandleErrors(), and then read here on the origin thread again with no |
+ // synchronization barriers (which means we potentially report |
+ // 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
|
+ delegate_->OnFileRead(value_.Pass(), error_, no_dir_); |
} |
static base::Value* DoReading(const base::FilePath& path, |
@@ -161,7 +166,8 @@ JsonPrefStore::JsonPrefStore(const base::FilePath& filename, |
writer_(filename, sequenced_task_runner), |
pref_filter_(pref_filter.Pass()), |
initialized_(false), |
- read_error_(PREF_READ_ERROR_OTHER) {} |
+ read_error_(PREF_READ_ERROR_NONE), |
+ weak_factory_(this) {} |
bool JsonPrefStore::GetValue(const std::string& key, |
const base::Value** result) const { |
@@ -224,6 +230,12 @@ void JsonPrefStore::RemoveValue(const std::string& key) { |
ReportValueChanged(key); |
} |
+void JsonPrefStore::RemoveValueSilently(const std::string& key) { |
+ prefs_->RemovePath(key, NULL); |
+ if (!read_only_) |
+ writer_.ScheduleWrite(this); |
+} |
+ |
bool JsonPrefStore::ReadOnly() const { |
return read_only_; |
} |
@@ -234,23 +246,25 @@ PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { |
PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { |
if (path_.empty()) { |
- OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
+ OnFileRead( |
+ scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
return PREF_READ_ERROR_FILE_NOT_SPECIFIED; |
} |
PrefReadError error; |
bool no_dir; |
- base::Value* value = |
- FileThreadDeserializer::DoReading(path_, &error, &no_dir); |
- OnFileRead(value, error, no_dir); |
+ scoped_ptr<base::Value> value( |
+ FileThreadDeserializer::DoReading(path_, &error, &no_dir)); |
+ OnFileRead(value.Pass(), error, no_dir); |
return error; |
} |
-void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) { |
+void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { |
initialized_ = false; |
error_delegate_.reset(error_delegate); |
if (path_.empty()) { |
- OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
+ OnFileRead( |
+ scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); |
return; |
} |
@@ -276,53 +290,65 @@ void JsonPrefStore::ReportValueChanged(const std::string& key) { |
writer_.ScheduleWrite(this); |
} |
-void JsonPrefStore::OnFileRead(base::Value* value_owned, |
+void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback( |
+ const base::Closure& on_next_successful_write) { |
+ writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write); |
+} |
+ |
+void JsonPrefStore::InterceptNextFileRead( |
+ const OnFileReadInterceptor& on_file_read_interceptor) { |
+ DCHECK(on_file_read_interceptor_.is_null()); |
+ on_file_read_interceptor_ = on_file_read_interceptor; |
+} |
+ |
+void JsonPrefStore::OnFileRead(scoped_ptr<base::Value> value, |
PersistentPrefStore::PrefReadError error, |
bool no_dir) { |
- scoped_ptr<base::Value> value(value_owned); |
- read_error_ = error; |
+ scoped_ptr<base::DictionaryValue> unprocessed_prefs( |
+ new base::DictionaryValue); |
- if (no_dir) { |
- FOR_EACH_OBSERVER(PrefStore::Observer, |
- observers_, |
- OnInitializationCompleted(false)); |
- return; |
- } |
+ read_error_ = error; |
- initialized_ = true; |
+ bool initialization_successful = !no_dir; |
- switch (error) { |
- case PREF_READ_ERROR_ACCESS_DENIED: |
- case PREF_READ_ERROR_FILE_OTHER: |
- case PREF_READ_ERROR_FILE_LOCKED: |
- case PREF_READ_ERROR_JSON_TYPE: |
- case PREF_READ_ERROR_FILE_NOT_SPECIFIED: |
- read_only_ = true; |
- break; |
- case PREF_READ_ERROR_NONE: |
- DCHECK(value.get()); |
- prefs_.reset(static_cast<base::DictionaryValue*>(value.release())); |
- break; |
- case PREF_READ_ERROR_NO_FILE: |
- // If the file just doesn't exist, maybe this is first run. In any case |
- // there's no harm in writing out default prefs in this case. |
- break; |
- case PREF_READ_ERROR_JSON_PARSE: |
- case PREF_READ_ERROR_JSON_REPEAT: |
- break; |
- default: |
- NOTREACHED() << "Unknown error: " << error; |
+ if (initialization_successful) { |
+ switch (error) { |
+ case PREF_READ_ERROR_ACCESS_DENIED: |
+ case PREF_READ_ERROR_FILE_OTHER: |
+ case PREF_READ_ERROR_FILE_LOCKED: |
+ case PREF_READ_ERROR_JSON_TYPE: |
+ case PREF_READ_ERROR_FILE_NOT_SPECIFIED: |
+ read_only_ = true; |
+ break; |
+ case PREF_READ_ERROR_NONE: |
+ DCHECK(value.get()); |
+ unprocessed_prefs.reset( |
+ static_cast<base::DictionaryValue*>(value.release())); |
+ break; |
+ case PREF_READ_ERROR_NO_FILE: |
+ // If the file just doesn't exist, maybe this is first run. In any case |
+ // there's no harm in writing out default prefs in this case. |
+ break; |
+ case PREF_READ_ERROR_JSON_PARSE: |
+ case PREF_READ_ERROR_JSON_REPEAT: |
+ break; |
+ case PREF_READ_ERROR_MAX_ENUM: |
+ NOTREACHED(); |
+ break; |
+ } |
} |
- if (pref_filter_ && pref_filter_->FilterOnLoad(prefs_.get())) |
- writer_.ScheduleWrite(this); |
- |
- if (error_delegate_.get() && error != PREF_READ_ERROR_NONE) |
- error_delegate_->OnError(error); |
- |
- FOR_EACH_OBSERVER(PrefStore::Observer, |
- observers_, |
- OnInitializationCompleted(true)); |
+ if (on_file_read_interceptor_.is_null()) { |
+ FinalizeFileRead(initialization_successful, unprocessed_prefs.Pass(), |
+ false); |
+ } else { |
+ const FinalizePrefsReadCallback finalize_file_read( |
+ base::Bind(&JsonPrefStore::FinalizeFileRead, this, |
+ initialization_successful)); |
+ on_file_read_interceptor_.Run(unprocessed_prefs.Pass(), |
+ finalize_file_read); |
+ on_file_read_interceptor_.Reset(); |
+ } |
} |
JsonPrefStore::~JsonPrefStore() { |
@@ -337,3 +363,34 @@ bool JsonPrefStore::SerializeData(std::string* output) { |
serializer.set_pretty_print(true); |
return serializer.Serialize(*prefs_); |
} |
+ |
+base::WeakPtr<JsonPrefStore> JsonPrefStore::FinalizeFileRead( |
+ bool initialization_successful, |
+ scoped_ptr<base::DictionaryValue> prefs, |
+ bool schedule_write) { |
+ if (!initialization_successful) { |
+ FOR_EACH_OBSERVER(PrefStore::Observer, |
+ observers_, |
+ OnInitializationCompleted(false)); |
+ return weak_factory_.GetWeakPtr(); |
+ } |
+ |
+ prefs_ = prefs.Pass(); |
+ |
+ initialized_ = true; |
+ |
+ bool had_filter_modification = |
+ pref_filter_ && pref_filter_->FilterOnLoad(prefs_.get()); |
+ |
+ if ((schedule_write || had_filter_modification) && !read_only_) |
+ writer_.ScheduleWrite(this); |
+ |
+ if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) |
+ error_delegate_->OnError(read_error_); |
+ |
+ FOR_EACH_OBSERVER(PrefStore::Observer, |
+ observers_, |
+ OnInitializationCompleted(true)); |
+ |
+ return weak_factory_.GetWeakPtr(); |
+} |