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" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/json/json_file_value_serializer.h" | 13 #include "base/json/json_file_value_serializer.h" |
| 14 #include "base/json/json_string_value_serializer.h" | 14 #include "base/json/json_string_value_serializer.h" |
| 15 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
| 16 #include "base/message_loop/message_loop_proxy.h" | |
| 17 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
| 18 #include "base/prefs/pref_filter.h" | 17 #include "base/prefs/pref_filter.h" |
| 19 #include "base/sequenced_task_runner.h" | 18 #include "base/sequenced_task_runner.h" |
| 20 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
| 20 #include "base/task_runner_util.h" | |
| 21 #include "base/threading/sequenced_worker_pool.h" | 21 #include "base/threading/sequenced_worker_pool.h" |
| 22 #include "base/values.h" | 22 #include "base/values.h" |
| 23 | 23 |
| 24 // Result returned from internal read tasks. | |
| 25 struct JsonPrefStore::ReadResult { | |
| 26 public: | |
| 27 ReadResult(); | |
| 28 ~ReadResult(); | |
| 29 | |
| 30 scoped_ptr<base::Value> value; | |
| 31 PrefReadError error; | |
| 32 bool no_dir; | |
| 33 | |
| 34 private: | |
| 35 DISALLOW_COPY_AND_ASSIGN(ReadResult); | |
| 36 }; | |
| 37 | |
| 38 JsonPrefStore::ReadResult::ReadResult() | |
| 39 : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) { | |
| 40 } | |
| 41 | |
| 42 JsonPrefStore::ReadResult::~ReadResult() { | |
| 43 } | |
| 44 | |
| 24 namespace { | 45 namespace { |
| 25 | 46 |
| 26 // Some extensions we'll tack on to copies of the Preferences files. | 47 // Some extensions we'll tack on to copies of the Preferences files. |
| 27 const base::FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); | 48 const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad"); |
| 28 | 49 |
| 29 // Differentiates file loading between origin thread and passed | 50 PersistentPrefStore::PrefReadError HandleReadErrors( |
| 30 // (aka file) thread. | |
| 31 class FileThreadDeserializer | |
| 32 : public base::RefCountedThreadSafe<FileThreadDeserializer> { | |
| 33 public: | |
| 34 FileThreadDeserializer(JsonPrefStore* delegate, | |
| 35 base::SequencedTaskRunner* sequenced_task_runner) | |
| 36 : no_dir_(false), | |
| 37 error_(PersistentPrefStore::PREF_READ_ERROR_NONE), | |
| 38 delegate_(delegate), | |
| 39 sequenced_task_runner_(sequenced_task_runner), | |
| 40 origin_loop_proxy_(base::MessageLoopProxy::current()) { | |
| 41 } | |
| 42 | |
| 43 void Start(const base::FilePath& path, | |
| 44 const base::FilePath& alternate_path) { | |
| 45 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | |
| 46 // TODO(gab): This should use PostTaskAndReplyWithResult instead of using | |
| 47 // the |error_| member to pass data across tasks. | |
| 48 sequenced_task_runner_->PostTask( | |
| 49 FROM_HERE, | |
| 50 base::Bind(&FileThreadDeserializer::ReadFileAndReport, | |
| 51 this, path, alternate_path)); | |
| 52 } | |
| 53 | |
| 54 // Deserializes JSON on the sequenced task runner. | |
| 55 void ReadFileAndReport(const base::FilePath& path, | |
| 56 const base::FilePath& alternate_path) { | |
| 57 DCHECK(sequenced_task_runner_->RunsTasksOnCurrentThread()); | |
| 58 | |
| 59 value_.reset(DoReading(path, alternate_path, &error_, &no_dir_)); | |
| 60 | |
| 61 origin_loop_proxy_->PostTask( | |
| 62 FROM_HERE, | |
| 63 base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this)); | |
| 64 } | |
| 65 | |
| 66 // Reports deserialization result on the origin thread. | |
| 67 void ReportOnOriginThread() { | |
| 68 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); | |
| 69 delegate_->OnFileRead(value_.Pass(), error_, no_dir_); | |
| 70 } | |
| 71 | |
| 72 static base::Value* DoReading(const base::FilePath& path, | |
| 73 const base::FilePath& alternate_path, | |
| 74 PersistentPrefStore::PrefReadError* error, | |
| 75 bool* no_dir) { | |
| 76 if (!base::PathExists(path) && !alternate_path.empty() && | |
| 77 base::PathExists(alternate_path)) { | |
| 78 base::Move(alternate_path, path); | |
| 79 } | |
| 80 | |
| 81 int error_code; | |
| 82 std::string error_msg; | |
| 83 JSONFileValueSerializer serializer(path); | |
| 84 base::Value* value = serializer.Deserialize(&error_code, &error_msg); | |
| 85 HandleErrors(value, path, error_code, error_msg, error); | |
| 86 *no_dir = !base::PathExists(path.DirName()); | |
| 87 return value; | |
| 88 } | |
| 89 | |
| 90 static void HandleErrors(const base::Value* value, | |
| 91 const base::FilePath& path, | |
| 92 int error_code, | |
| 93 const std::string& error_msg, | |
| 94 PersistentPrefStore::PrefReadError* error); | |
| 95 | |
| 96 private: | |
| 97 friend class base::RefCountedThreadSafe<FileThreadDeserializer>; | |
| 98 ~FileThreadDeserializer() {} | |
| 99 | |
| 100 bool no_dir_; | |
| 101 PersistentPrefStore::PrefReadError error_; | |
| 102 scoped_ptr<base::Value> value_; | |
| 103 const scoped_refptr<JsonPrefStore> delegate_; | |
| 104 const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; | |
| 105 const scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_; | |
| 106 }; | |
| 107 | |
| 108 // static | |
| 109 void FileThreadDeserializer::HandleErrors( | |
| 110 const base::Value* value, | 51 const base::Value* value, |
| 111 const base::FilePath& path, | 52 const base::FilePath& path, |
| 112 int error_code, | 53 int error_code, |
| 113 const std::string& error_msg, | 54 const std::string& error_msg) { |
| 114 PersistentPrefStore::PrefReadError* error) { | |
| 115 *error = PersistentPrefStore::PREF_READ_ERROR_NONE; | |
| 116 if (!value) { | 55 if (!value) { |
| 117 DVLOG(1) << "Error while loading JSON file: " << error_msg | 56 DVLOG(1) << "Error while loading JSON file: " << error_msg |
| 118 << ", file: " << path.value(); | 57 << ", file: " << path.value(); |
| 119 switch (error_code) { | 58 switch (error_code) { |
| 120 case JSONFileValueSerializer::JSON_ACCESS_DENIED: | 59 case JSONFileValueSerializer::JSON_ACCESS_DENIED: |
| 121 *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED; | 60 return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED; |
| 122 break; | 61 break; |
| 123 case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: | 62 case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: |
| 124 *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER; | 63 return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER; |
| 125 break; | 64 break; |
| 126 case JSONFileValueSerializer::JSON_FILE_LOCKED: | 65 case JSONFileValueSerializer::JSON_FILE_LOCKED: |
| 127 *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED; | 66 return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED; |
| 128 break; | 67 break; |
| 129 case JSONFileValueSerializer::JSON_NO_SUCH_FILE: | 68 case JSONFileValueSerializer::JSON_NO_SUCH_FILE: |
| 130 *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE; | 69 return PersistentPrefStore::PREF_READ_ERROR_NO_FILE; |
| 131 break; | 70 break; |
| 132 default: | 71 default: |
| 133 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE; | |
| 134 // JSON errors indicate file corruption of some sort. | 72 // JSON errors indicate file corruption of some sort. |
| 135 // Since the file is corrupt, move it to the side and continue with | 73 // Since the file is corrupt, move it to the side and continue with |
| 136 // empty preferences. This will result in them losing their settings. | 74 // empty preferences. This will result in them losing their settings. |
| 137 // We keep the old file for possible support and debugging assistance | 75 // We keep the old file for possible support and debugging assistance |
| 138 // as well as to detect if they're seeing these errors repeatedly. | 76 // as well as to detect if they're seeing these errors repeatedly. |
| 139 // TODO(erikkay) Instead, use the last known good file. | 77 // TODO(erikkay) Instead, use the last known good file. |
| 140 base::FilePath bad = path.ReplaceExtension(kBadExtension); | 78 base::FilePath bad = path.ReplaceExtension(kBadExtension); |
| 141 | 79 |
| 142 // If they've ever had a parse error before, put them in another bucket. | 80 // If they've ever had a parse error before, put them in another bucket. |
| 143 // TODO(erikkay) if we keep this error checking for very long, we may | 81 // TODO(erikkay) if we keep this error checking for very long, we may |
| 144 // want to differentiate between recent and long ago errors. | 82 // want to differentiate between recent and long ago errors. |
| 145 if (base::PathExists(bad)) | 83 bool bad_existed = base::PathExists(bad); |
| 146 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT; | |
| 147 base::Move(path, bad); | 84 base::Move(path, bad); |
| 148 break; | 85 return bad_existed ? PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT |
| 86 : PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE; | |
| 149 } | 87 } |
| 150 } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) { | 88 } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) { |
| 151 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; | 89 return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; |
| 152 } | 90 } |
| 91 return PersistentPrefStore::PREF_READ_ERROR_NONE; | |
| 92 } | |
| 93 | |
| 94 scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk( | |
| 95 const base::FilePath& path, | |
| 96 const base::FilePath& alternate_path) { | |
| 97 if (!base::PathExists(path) && !alternate_path.empty() && | |
| 98 base::PathExists(alternate_path)) { | |
| 99 base::Move(alternate_path, path); | |
| 100 } | |
| 101 | |
| 102 int error_code; | |
| 103 std::string error_msg; | |
| 104 scoped_ptr<JsonPrefStore::ReadResult> read_result( | |
| 105 new JsonPrefStore::ReadResult); | |
| 106 JSONFileValueSerializer serializer(path); | |
| 107 read_result->value.reset(serializer.Deserialize(&error_code, &error_msg)); | |
| 108 read_result->error = | |
| 109 HandleReadErrors(read_result->value.get(), path, error_code, error_msg); | |
| 110 read_result->no_dir = !base::PathExists(path.DirName()); | |
| 111 return read_result.Pass(); | |
| 112 } | |
| 113 | |
| 114 // Posts a task to run ReadPrefsFromDisk() on |sequenced_task_runner| which will | |
| 115 // report back the ReadResult on the origin thread via |on_file_read|. | |
| 116 void PostAsyncReadTask( | |
|
Bernhard Bauer
2014/07/22 16:22:00
Could you inline this method?
gab
2014/07/22 16:47:43
Indeed :-)!
| |
| 117 base::SequencedTaskRunner* sequenced_task_runner, | |
| 118 const base::FilePath& path, | |
| 119 const base::FilePath& alternate_path, | |
| 120 const base::Callback<void(scoped_ptr<JsonPrefStore::ReadResult>)>& | |
| 121 on_file_read) { | |
| 122 base::PostTaskAndReplyWithResult( | |
| 123 sequenced_task_runner, | |
| 124 FROM_HERE, | |
| 125 base::Bind(&ReadPrefsFromDisk, path, alternate_path), | |
| 126 on_file_read); | |
| 153 } | 127 } |
| 154 | 128 |
| 155 } // namespace | 129 } // namespace |
| 156 | 130 |
| 131 // static | |
| 157 scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile( | 132 scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile( |
| 158 const base::FilePath& filename, | 133 const base::FilePath& filename, |
| 159 base::SequencedWorkerPool* worker_pool) { | 134 base::SequencedWorkerPool* worker_pool) { |
| 160 std::string token("json_pref_store-"); | 135 std::string token("json_pref_store-"); |
| 161 token.append(filename.AsUTF8Unsafe()); | 136 token.append(filename.AsUTF8Unsafe()); |
| 162 return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( | 137 return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( |
| 163 worker_pool->GetNamedSequenceToken(token), | 138 worker_pool->GetNamedSequenceToken(token), |
| 164 base::SequencedWorkerPool::BLOCK_SHUTDOWN); | 139 base::SequencedWorkerPool::BLOCK_SHUTDOWN); |
| 165 } | 140 } |
| 166 | 141 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 189 read_only_(false), | 164 read_only_(false), |
| 190 writer_(filename, sequenced_task_runner), | 165 writer_(filename, sequenced_task_runner), |
| 191 pref_filter_(pref_filter.Pass()), | 166 pref_filter_(pref_filter.Pass()), |
| 192 initialized_(false), | 167 initialized_(false), |
| 193 filtering_in_progress_(false), | 168 filtering_in_progress_(false), |
| 194 read_error_(PREF_READ_ERROR_NONE) { | 169 read_error_(PREF_READ_ERROR_NONE) { |
| 195 } | 170 } |
| 196 | 171 |
| 197 bool JsonPrefStore::GetValue(const std::string& key, | 172 bool JsonPrefStore::GetValue(const std::string& key, |
| 198 const base::Value** result) const { | 173 const base::Value** result) const { |
| 174 DCHECK(CalledOnValidThread()); | |
| 175 | |
| 199 base::Value* tmp = NULL; | 176 base::Value* tmp = NULL; |
| 200 if (!prefs_->Get(key, &tmp)) | 177 if (!prefs_->Get(key, &tmp)) |
| 201 return false; | 178 return false; |
| 202 | 179 |
| 203 if (result) | 180 if (result) |
| 204 *result = tmp; | 181 *result = tmp; |
| 205 return true; | 182 return true; |
| 206 } | 183 } |
| 207 | 184 |
| 208 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) { | 185 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) { |
| 186 DCHECK(CalledOnValidThread()); | |
| 187 | |
| 209 observers_.AddObserver(observer); | 188 observers_.AddObserver(observer); |
| 210 } | 189 } |
| 211 | 190 |
| 212 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { | 191 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { |
| 192 DCHECK(CalledOnValidThread()); | |
| 193 | |
| 213 observers_.RemoveObserver(observer); | 194 observers_.RemoveObserver(observer); |
| 214 } | 195 } |
| 215 | 196 |
| 216 bool JsonPrefStore::HasObservers() const { | 197 bool JsonPrefStore::HasObservers() const { |
| 198 DCHECK(CalledOnValidThread()); | |
| 199 | |
| 217 return observers_.might_have_observers(); | 200 return observers_.might_have_observers(); |
| 218 } | 201 } |
| 219 | 202 |
| 220 bool JsonPrefStore::IsInitializationComplete() const { | 203 bool JsonPrefStore::IsInitializationComplete() const { |
| 204 DCHECK(CalledOnValidThread()); | |
| 205 | |
| 221 return initialized_; | 206 return initialized_; |
| 222 } | 207 } |
| 223 | 208 |
| 224 bool JsonPrefStore::GetMutableValue(const std::string& key, | 209 bool JsonPrefStore::GetMutableValue(const std::string& key, |
| 225 base::Value** result) { | 210 base::Value** result) { |
| 211 DCHECK(CalledOnValidThread()); | |
| 212 | |
| 226 return prefs_->Get(key, result); | 213 return prefs_->Get(key, result); |
| 227 } | 214 } |
| 228 | 215 |
| 229 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) { | 216 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) { |
| 217 DCHECK(CalledOnValidThread()); | |
| 218 | |
| 230 DCHECK(value); | 219 DCHECK(value); |
| 231 scoped_ptr<base::Value> new_value(value); | 220 scoped_ptr<base::Value> new_value(value); |
| 232 base::Value* old_value = NULL; | 221 base::Value* old_value = NULL; |
| 233 prefs_->Get(key, &old_value); | 222 prefs_->Get(key, &old_value); |
| 234 if (!old_value || !value->Equals(old_value)) { | 223 if (!old_value || !value->Equals(old_value)) { |
| 235 prefs_->Set(key, new_value.release()); | 224 prefs_->Set(key, new_value.release()); |
| 236 ReportValueChanged(key); | 225 ReportValueChanged(key); |
| 237 } | 226 } |
| 238 } | 227 } |
| 239 | 228 |
| 240 void JsonPrefStore::SetValueSilently(const std::string& key, | 229 void JsonPrefStore::SetValueSilently(const std::string& key, |
| 241 base::Value* value) { | 230 base::Value* value) { |
| 231 DCHECK(CalledOnValidThread()); | |
| 232 | |
| 242 DCHECK(value); | 233 DCHECK(value); |
| 243 scoped_ptr<base::Value> new_value(value); | 234 scoped_ptr<base::Value> new_value(value); |
| 244 base::Value* old_value = NULL; | 235 base::Value* old_value = NULL; |
| 245 prefs_->Get(key, &old_value); | 236 prefs_->Get(key, &old_value); |
| 246 if (!old_value || !value->Equals(old_value)) { | 237 if (!old_value || !value->Equals(old_value)) { |
| 247 prefs_->Set(key, new_value.release()); | 238 prefs_->Set(key, new_value.release()); |
| 248 if (!read_only_) | 239 if (!read_only_) |
| 249 writer_.ScheduleWrite(this); | 240 writer_.ScheduleWrite(this); |
| 250 } | 241 } |
| 251 } | 242 } |
| 252 | 243 |
| 253 void JsonPrefStore::RemoveValue(const std::string& key) { | 244 void JsonPrefStore::RemoveValue(const std::string& key) { |
| 245 DCHECK(CalledOnValidThread()); | |
| 246 | |
| 254 if (prefs_->RemovePath(key, NULL)) | 247 if (prefs_->RemovePath(key, NULL)) |
| 255 ReportValueChanged(key); | 248 ReportValueChanged(key); |
| 256 } | 249 } |
| 257 | 250 |
| 258 void JsonPrefStore::RemoveValueSilently(const std::string& key) { | 251 void JsonPrefStore::RemoveValueSilently(const std::string& key) { |
| 252 DCHECK(CalledOnValidThread()); | |
| 253 | |
| 259 prefs_->RemovePath(key, NULL); | 254 prefs_->RemovePath(key, NULL); |
| 260 if (!read_only_) | 255 if (!read_only_) |
| 261 writer_.ScheduleWrite(this); | 256 writer_.ScheduleWrite(this); |
| 262 } | 257 } |
| 263 | 258 |
| 264 bool JsonPrefStore::ReadOnly() const { | 259 bool JsonPrefStore::ReadOnly() const { |
| 260 DCHECK(CalledOnValidThread()); | |
| 261 | |
| 265 return read_only_; | 262 return read_only_; |
| 266 } | 263 } |
| 267 | 264 |
| 268 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { | 265 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { |
| 266 DCHECK(CalledOnValidThread()); | |
| 267 | |
| 269 return read_error_; | 268 return read_error_; |
| 270 } | 269 } |
| 271 | 270 |
| 272 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { | 271 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { |
| 272 DCHECK(CalledOnValidThread()); | |
| 273 | |
| 273 if (path_.empty()) { | 274 if (path_.empty()) { |
| 274 OnFileRead( | 275 scoped_ptr<ReadResult> no_file_result; |
| 275 scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | 276 no_file_result->error = PREF_READ_ERROR_FILE_NOT_SPECIFIED; |
| 277 OnFileRead(no_file_result.Pass()); | |
| 276 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; | 278 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; |
| 277 } | 279 } |
| 278 | 280 |
| 279 PrefReadError error; | 281 OnFileRead(ReadPrefsFromDisk(path_, alternate_path_)); |
| 280 bool no_dir; | 282 return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE |
| 281 scoped_ptr<base::Value> value( | 283 : read_error_; |
| 282 FileThreadDeserializer::DoReading(path_, alternate_path_, &error, | |
| 283 &no_dir)); | |
| 284 OnFileRead(value.Pass(), error, no_dir); | |
| 285 return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE : | |
| 286 error; | |
| 287 } | 284 } |
| 288 | 285 |
| 289 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { | 286 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { |
| 287 DCHECK(CalledOnValidThread()); | |
| 288 | |
| 290 initialized_ = false; | 289 initialized_ = false; |
| 291 error_delegate_.reset(error_delegate); | 290 error_delegate_.reset(error_delegate); |
| 292 if (path_.empty()) { | 291 if (path_.empty()) { |
| 293 OnFileRead( | 292 scoped_ptr<ReadResult> no_file_result; |
| 294 scoped_ptr<base::Value>(), PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); | 293 no_file_result->error = PREF_READ_ERROR_FILE_NOT_SPECIFIED; |
| 294 OnFileRead(no_file_result.Pass()); | |
| 295 return; | 295 return; |
| 296 } | 296 } |
| 297 | 297 |
| 298 // Start async reading of the preferences file. It will delete itself | 298 PostAsyncReadTask(sequenced_task_runner_, |
| 299 // in the end. | 299 path_, |
| 300 scoped_refptr<FileThreadDeserializer> deserializer( | 300 alternate_path_, |
| 301 new FileThreadDeserializer(this, sequenced_task_runner_.get())); | 301 base::Bind(&JsonPrefStore::OnFileRead, this)); |
| 302 deserializer->Start(path_, alternate_path_); | |
| 303 } | 302 } |
| 304 | 303 |
| 305 void JsonPrefStore::CommitPendingWrite() { | 304 void JsonPrefStore::CommitPendingWrite() { |
| 305 DCHECK(CalledOnValidThread()); | |
| 306 | |
| 306 if (writer_.HasPendingWrite() && !read_only_) | 307 if (writer_.HasPendingWrite() && !read_only_) |
| 307 writer_.DoScheduledWrite(); | 308 writer_.DoScheduledWrite(); |
| 308 } | 309 } |
| 309 | 310 |
| 310 void JsonPrefStore::ReportValueChanged(const std::string& key) { | 311 void JsonPrefStore::ReportValueChanged(const std::string& key) { |
| 312 DCHECK(CalledOnValidThread()); | |
| 313 | |
| 311 if (pref_filter_) | 314 if (pref_filter_) |
| 312 pref_filter_->FilterUpdate(key); | 315 pref_filter_->FilterUpdate(key); |
| 313 | 316 |
| 314 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); | 317 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); |
| 315 | 318 |
| 316 if (!read_only_) | 319 if (!read_only_) |
| 317 writer_.ScheduleWrite(this); | 320 writer_.ScheduleWrite(this); |
| 318 } | 321 } |
| 319 | 322 |
| 320 void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback( | 323 void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback( |
| 321 const base::Closure& on_next_successful_write) { | 324 const base::Closure& on_next_successful_write) { |
| 325 DCHECK(CalledOnValidThread()); | |
| 326 | |
| 322 writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write); | 327 writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write); |
| 323 } | 328 } |
| 324 | 329 |
| 325 void JsonPrefStore::OnFileRead(scoped_ptr<base::Value> value, | 330 void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) { |
| 326 PersistentPrefStore::PrefReadError error, | 331 DCHECK(CalledOnValidThread()); |
| 327 bool no_dir) { | 332 |
| 333 DCHECK(read_result); | |
| 334 | |
| 328 scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue); | 335 scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue); |
| 329 | 336 |
| 330 read_error_ = error; | 337 read_error_ = read_result->error; |
| 331 | 338 |
| 332 bool initialization_successful = !no_dir; | 339 bool initialization_successful = !read_result->no_dir; |
| 333 | 340 |
| 334 if (initialization_successful) { | 341 if (initialization_successful) { |
| 335 switch (read_error_) { | 342 switch (read_error_) { |
| 336 case PREF_READ_ERROR_ACCESS_DENIED: | 343 case PREF_READ_ERROR_ACCESS_DENIED: |
| 337 case PREF_READ_ERROR_FILE_OTHER: | 344 case PREF_READ_ERROR_FILE_OTHER: |
| 338 case PREF_READ_ERROR_FILE_LOCKED: | 345 case PREF_READ_ERROR_FILE_LOCKED: |
| 339 case PREF_READ_ERROR_JSON_TYPE: | 346 case PREF_READ_ERROR_JSON_TYPE: |
| 340 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: | 347 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: |
| 341 read_only_ = true; | 348 read_only_ = true; |
| 342 break; | 349 break; |
| 343 case PREF_READ_ERROR_NONE: | 350 case PREF_READ_ERROR_NONE: |
| 344 DCHECK(value.get()); | 351 DCHECK(read_result->value.get()); |
| 345 unfiltered_prefs.reset( | 352 unfiltered_prefs.reset( |
| 346 static_cast<base::DictionaryValue*>(value.release())); | 353 static_cast<base::DictionaryValue*>(read_result->value.release())); |
| 347 break; | 354 break; |
| 348 case PREF_READ_ERROR_NO_FILE: | 355 case PREF_READ_ERROR_NO_FILE: |
| 349 // If the file just doesn't exist, maybe this is first run. In any case | 356 // If the file just doesn't exist, maybe this is first run. In any case |
| 350 // there's no harm in writing out default prefs in this case. | 357 // there's no harm in writing out default prefs in this case. |
| 351 break; | 358 break; |
| 352 case PREF_READ_ERROR_JSON_PARSE: | 359 case PREF_READ_ERROR_JSON_PARSE: |
| 353 case PREF_READ_ERROR_JSON_REPEAT: | 360 case PREF_READ_ERROR_JSON_REPEAT: |
| 354 break; | 361 break; |
| 355 case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE: | 362 case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE: |
| 356 // This is a special error code to be returned by ReadPrefs when it | 363 // This is a special error code to be returned by ReadPrefs when it |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 379 } else { | 386 } else { |
| 380 FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false); | 387 FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false); |
| 381 } | 388 } |
| 382 } | 389 } |
| 383 | 390 |
| 384 JsonPrefStore::~JsonPrefStore() { | 391 JsonPrefStore::~JsonPrefStore() { |
| 385 CommitPendingWrite(); | 392 CommitPendingWrite(); |
| 386 } | 393 } |
| 387 | 394 |
| 388 bool JsonPrefStore::SerializeData(std::string* output) { | 395 bool JsonPrefStore::SerializeData(std::string* output) { |
| 396 DCHECK(CalledOnValidThread()); | |
| 397 | |
| 389 if (pref_filter_) | 398 if (pref_filter_) |
| 390 pref_filter_->FilterSerializeData(prefs_.get()); | 399 pref_filter_->FilterSerializeData(prefs_.get()); |
| 391 | 400 |
| 392 JSONStringValueSerializer serializer(output); | 401 JSONStringValueSerializer serializer(output); |
| 393 serializer.set_pretty_print(true); | 402 serializer.set_pretty_print(true); |
| 394 bool result = serializer.Serialize(*prefs_); | 403 bool result = serializer.Serialize(*prefs_); |
| 395 | 404 |
| 396 if (result) { | 405 if (result) { |
| 397 std::string spaceless_basename; | 406 std::string spaceless_basename; |
| 398 base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_", | 407 base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_", |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 410 base::HistogramBase::kUmaTargetedHistogramFlag); | 419 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 411 histogram->Add(static_cast<int>(output->size()) / 1024); | 420 histogram->Add(static_cast<int>(output->size()) / 1024); |
| 412 } | 421 } |
| 413 | 422 |
| 414 return result; | 423 return result; |
| 415 } | 424 } |
| 416 | 425 |
| 417 void JsonPrefStore::FinalizeFileRead(bool initialization_successful, | 426 void JsonPrefStore::FinalizeFileRead(bool initialization_successful, |
| 418 scoped_ptr<base::DictionaryValue> prefs, | 427 scoped_ptr<base::DictionaryValue> prefs, |
| 419 bool schedule_write) { | 428 bool schedule_write) { |
| 429 DCHECK(CalledOnValidThread()); | |
| 430 | |
| 420 filtering_in_progress_ = false; | 431 filtering_in_progress_ = false; |
| 421 | 432 |
| 422 if (!initialization_successful) { | 433 if (!initialization_successful) { |
| 423 FOR_EACH_OBSERVER(PrefStore::Observer, | 434 FOR_EACH_OBSERVER(PrefStore::Observer, |
| 424 observers_, | 435 observers_, |
| 425 OnInitializationCompleted(false)); | 436 OnInitializationCompleted(false)); |
| 426 return; | 437 return; |
| 427 } | 438 } |
| 428 | 439 |
| 429 prefs_ = prefs.Pass(); | 440 prefs_ = prefs.Pass(); |
| 430 | 441 |
| 431 initialized_ = true; | 442 initialized_ = true; |
| 432 | 443 |
| 433 if (schedule_write && !read_only_) | 444 if (schedule_write && !read_only_) |
| 434 writer_.ScheduleWrite(this); | 445 writer_.ScheduleWrite(this); |
| 435 | 446 |
| 436 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) | 447 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) |
| 437 error_delegate_->OnError(read_error_); | 448 error_delegate_->OnError(read_error_); |
| 438 | 449 |
| 439 FOR_EACH_OBSERVER(PrefStore::Observer, | 450 FOR_EACH_OBSERVER(PrefStore::Observer, |
| 440 observers_, | 451 observers_, |
| 441 OnInitializationCompleted(true)); | 452 OnInitializationCompleted(true)); |
| 442 | 453 |
| 443 return; | 454 return; |
| 444 } | 455 } |
| OLD | NEW |