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 3 // found in the LICENSE file. 4 5 #include "base/prefs/json_pref_store.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/callback.h" 11 #include "base/file_util.h" 12 #include "base/json/json_file_value_serializer.h" 13 #include "base/json/json_string_value_serializer.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/message_loop/message_loop_proxy.h" 16 #include "base/sequenced_task_runner.h" 17 #include "base/threading/sequenced_worker_pool.h" 18 #include "base/values.h" 19 20 namespace { 21 22 // Some extensions we'll tack on to copies of the Preferences files. 23 const base::FilePath::CharType* kBadExtension = FILE_PATH_LITERAL("bad"); 24 25 // Differentiates file loading between origin thread and passed 26 // (aka file) thread. 27 class FileThreadDeserializer 28 : public base::RefCountedThreadSafe<FileThreadDeserializer> { 29 public: 30 FileThreadDeserializer(JsonPrefStore* delegate, 31 base::SequencedTaskRunner* sequenced_task_runner) 32 : no_dir_(false), 33 error_(PersistentPrefStore::PREF_READ_ERROR_NONE), 34 delegate_(delegate), 35 sequenced_task_runner_(sequenced_task_runner), 36 origin_loop_proxy_(base::MessageLoopProxy::current()) { 37 } 38 39 void Start(const base::FilePath& path) { 40 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); 41 sequenced_task_runner_->PostTask( 42 FROM_HERE, 43 base::Bind(&FileThreadDeserializer::ReadFileAndReport, 44 this, path)); 45 } 46 47 // Deserializes JSON on the sequenced task runner. 48 void ReadFileAndReport(const base::FilePath& path) { 49 DCHECK(sequenced_task_runner_->RunsTasksOnCurrentThread()); 50 51 value_.reset(DoReading(path, &error_, &no_dir_)); 52 53 origin_loop_proxy_->PostTask( 54 FROM_HERE, 55 base::Bind(&FileThreadDeserializer::ReportOnOriginThread, this)); 56 } 57 58 // Reports deserialization result on the origin thread. 59 void ReportOnOriginThread() { 60 DCHECK(origin_loop_proxy_->BelongsToCurrentThread()); 61 delegate_->OnFileRead(value_.release(), error_, no_dir_); 62 } 63 64 static base::Value* DoReading(const base::FilePath& path, 65 PersistentPrefStore::PrefReadError* error, 66 bool* no_dir) { 67 int error_code; 68 std::string error_msg; 69 JSONFileValueSerializer serializer(path); 70 base::Value* value = serializer.Deserialize(&error_code, &error_msg); 71 HandleErrors(value, path, error_code, error_msg, error); 72 *no_dir = !base::PathExists(path.DirName()); 73 return value; 74 } 75 76 static void HandleErrors(const base::Value* value, 77 const base::FilePath& path, 78 int error_code, 79 const std::string& error_msg, 80 PersistentPrefStore::PrefReadError* error); 81 82 private: 83 friend class base::RefCountedThreadSafe<FileThreadDeserializer>; 84 ~FileThreadDeserializer() {} 85 86 bool no_dir_; 87 PersistentPrefStore::PrefReadError error_; 88 scoped_ptr<base::Value> value_; 89 const scoped_refptr<JsonPrefStore> delegate_; 90 const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; 91 const scoped_refptr<base::MessageLoopProxy> origin_loop_proxy_; 92 }; 93 94 // static 95 void FileThreadDeserializer::HandleErrors( 96 const base::Value* value, 97 const base::FilePath& path, 98 int error_code, 99 const std::string& error_msg, 100 PersistentPrefStore::PrefReadError* error) { 101 *error = PersistentPrefStore::PREF_READ_ERROR_NONE; 102 if (!value) { 103 DVLOG(1) << "Error while loading JSON file: " << error_msg 104 << ", file: " << path.value(); 105 switch (error_code) { 106 case JSONFileValueSerializer::JSON_ACCESS_DENIED: 107 *error = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED; 108 break; 109 case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: 110 *error = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER; 111 break; 112 case JSONFileValueSerializer::JSON_FILE_LOCKED: 113 *error = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED; 114 break; 115 case JSONFileValueSerializer::JSON_NO_SUCH_FILE: 116 *error = PersistentPrefStore::PREF_READ_ERROR_NO_FILE; 117 break; 118 default: 119 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE; 120 // JSON errors indicate file corruption of some sort. 121 // Since the file is corrupt, move it to the side and continue with 122 // empty preferences. This will result in them losing their settings. 123 // We keep the old file for possible support and debugging assistance 124 // as well as to detect if they're seeing these errors repeatedly. 125 // TODO(erikkay) Instead, use the last known good file. 126 base::FilePath bad = path.ReplaceExtension(kBadExtension); 127 128 // If they've ever had a parse error before, put them in another bucket. 129 // TODO(erikkay) if we keep this error checking for very long, we may 130 // want to differentiate between recent and long ago errors. 131 if (base::PathExists(bad)) 132 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT; 133 base::Move(path, bad); 134 break; 135 } 136 } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) { 137 *error = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE; 138 } 139 } 140 141 } // namespace 142 143 scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile( 144 const base::FilePath& filename, 145 base::SequencedWorkerPool* worker_pool) { 146 std::string token("json_pref_store-"); 147 token.append(filename.AsUTF8Unsafe()); 148 return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior( 149 worker_pool->GetNamedSequenceToken(token), 150 base::SequencedWorkerPool::BLOCK_SHUTDOWN); 151 } 152 153 JsonPrefStore::JsonPrefStore(const base::FilePath& filename, 154 base::SequencedTaskRunner* sequenced_task_runner) 155 : path_(filename), 156 sequenced_task_runner_(sequenced_task_runner), 157 prefs_(new base::DictionaryValue()), 158 read_only_(false), 159 writer_(filename, sequenced_task_runner), 160 initialized_(false), 161 read_error_(PREF_READ_ERROR_OTHER) {} 162 163 bool JsonPrefStore::GetValue(const std::string& key, 164 const base::Value** result) const { 165 base::Value* tmp = NULL; 166 if (!prefs_->Get(key, &tmp)) 167 return false; 168 169 if (result) 170 *result = tmp; 171 return true; 172 } 173 174 void JsonPrefStore::AddObserver(PrefStore::Observer* observer) { 175 observers_.AddObserver(observer); 176 } 177 178 void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) { 179 observers_.RemoveObserver(observer); 180 } 181 182 bool JsonPrefStore::HasObservers() const { 183 return observers_.might_have_observers(); 184 } 185 186 bool JsonPrefStore::IsInitializationComplete() const { 187 return initialized_; 188 } 189 190 bool JsonPrefStore::GetMutableValue(const std::string& key, 191 base::Value** result) { 192 return prefs_->Get(key, result); 193 } 194 195 void JsonPrefStore::SetValue(const std::string& key, base::Value* value) { 196 DCHECK(value); 197 scoped_ptr<base::Value> new_value(value); 198 base::Value* old_value = NULL; 199 prefs_->Get(key, &old_value); 200 if (!old_value || !value->Equals(old_value)) { 201 prefs_->Set(key, new_value.release()); 202 ReportValueChanged(key); 203 } 204 } 205 206 void JsonPrefStore::SetValueSilently(const std::string& key, 207 base::Value* value) { 208 DCHECK(value); 209 scoped_ptr<base::Value> new_value(value); 210 base::Value* old_value = NULL; 211 prefs_->Get(key, &old_value); 212 if (!old_value || !value->Equals(old_value)) { 213 prefs_->Set(key, new_value.release()); 214 if (!read_only_) 215 writer_.ScheduleWrite(this); 216 } 217 } 218 219 void JsonPrefStore::RemoveValue(const std::string& key) { 220 if (prefs_->RemovePath(key, NULL)) 221 ReportValueChanged(key); 222 } 223 224 bool JsonPrefStore::ReadOnly() const { 225 return read_only_; 226 } 227 228 PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const { 229 return read_error_; 230 } 231 232 PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() { 233 if (path_.empty()) { 234 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); 235 return PREF_READ_ERROR_FILE_NOT_SPECIFIED; 236 } 237 238 PrefReadError error; 239 bool no_dir; 240 base::Value* value = 241 FileThreadDeserializer::DoReading(path_, &error, &no_dir); 242 OnFileRead(value, error, no_dir); 243 return error; 244 } 245 246 void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate *error_delegate) { 247 initialized_ = false; 248 error_delegate_.reset(error_delegate); 249 if (path_.empty()) { 250 OnFileRead(NULL, PREF_READ_ERROR_FILE_NOT_SPECIFIED, false); 251 return; 252 } 253 254 // Start async reading of the preferences file. It will delete itself 255 // in the end. 256 scoped_refptr<FileThreadDeserializer> deserializer( 257 new FileThreadDeserializer(this, sequenced_task_runner_.get())); 258 deserializer->Start(path_); 259 } 260 261 void JsonPrefStore::CommitPendingWrite() { 262 if (writer_.HasPendingWrite() && !read_only_) 263 writer_.DoScheduledWrite(); 264 } 265 266 void JsonPrefStore::ReportValueChanged(const std::string& key) { 267 FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); 268 if (!read_only_) 269 writer_.ScheduleWrite(this); 270 } 271 272 void JsonPrefStore::OnFileRead(base::Value* value_owned, 273 PersistentPrefStore::PrefReadError error, 274 bool no_dir) { 275 scoped_ptr<base::Value> value(value_owned); 276 read_error_ = error; 277 278 if (no_dir) { 279 FOR_EACH_OBSERVER(PrefStore::Observer, 280 observers_, 281 OnInitializationCompleted(false)); 282 return; 283 } 284 285 initialized_ = true; 286 287 switch (error) { 288 case PREF_READ_ERROR_ACCESS_DENIED: 289 case PREF_READ_ERROR_FILE_OTHER: 290 case PREF_READ_ERROR_FILE_LOCKED: 291 case PREF_READ_ERROR_JSON_TYPE: 292 case PREF_READ_ERROR_FILE_NOT_SPECIFIED: 293 read_only_ = true; 294 break; 295 case PREF_READ_ERROR_NONE: 296 DCHECK(value.get()); 297 prefs_.reset(static_cast<base::DictionaryValue*>(value.release())); 298 break; 299 case PREF_READ_ERROR_NO_FILE: 300 // If the file just doesn't exist, maybe this is first run. In any case 301 // there's no harm in writing out default prefs in this case. 302 break; 303 case PREF_READ_ERROR_JSON_PARSE: 304 case PREF_READ_ERROR_JSON_REPEAT: 305 break; 306 default: 307 NOTREACHED() << "Unknown error: " << error; 308 } 309 310 if (error_delegate_.get() && error != PREF_READ_ERROR_NONE) 311 error_delegate_->OnError(error); 312 313 FOR_EACH_OBSERVER(PrefStore::Observer, 314 observers_, 315 OnInitializationCompleted(true)); 316 } 317 318 JsonPrefStore::~JsonPrefStore() { 319 CommitPendingWrite(); 320 } 321 322 bool JsonPrefStore::SerializeData(std::string* output) { 323 JSONStringValueSerializer serializer(output); 324 serializer.set_pretty_print(true); 325 return serializer.Serialize(*prefs_); 326 } 327