diff options
Diffstat (limited to 'chrome/browser/pref_service.cc')
-rw-r--r-- | chrome/browser/pref_service.cc | 131 |
1 files changed, 103 insertions, 28 deletions
diff --git a/chrome/browser/pref_service.cc b/chrome/browser/pref_service.cc index 62f8340..060e462 100644 --- a/chrome/browser/pref_service.cc +++ b/chrome/browser/pref_service.cc @@ -17,6 +17,7 @@ #include "base/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/chrome_thread.h" +#include "chrome/common/json_value_serializer.h" #include "chrome/common/notification_service.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" @@ -74,8 +75,11 @@ void NotifyReadError(PrefService* pref, int message_id) { } // namespace -PrefService::PrefService(PrefStore* storage) : store_(storage) { - InitFromStorage(); +PrefService::PrefService(const FilePath& pref_filename) + : persistent_(new DictionaryValue), + writer_(pref_filename), + read_only_(false) { + InitFromDisk(); } PrefService::~PrefService() { @@ -95,20 +99,35 @@ PrefService::~PrefService() { STLDeleteContainerPairSecondPointers(pref_observers_.begin(), pref_observers_.end()); pref_observers_.clear(); + + if (writer_.HasPendingWrite() && !read_only_) + writer_.DoScheduledWrite(); } -void PrefService::InitFromStorage() { - PrefStore::PrefReadError error = LoadPersistentPrefs(); - if (error == PrefStore::PREF_READ_ERROR_NONE) +void PrefService::InitFromDisk() { + PrefReadError error = LoadPersistentPrefs(); + if (error == PREF_READ_ERROR_NONE) return; // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for // an example problem that this can cause. // Do some diagnosis and try to avoid losing data. int message_id = 0; - if (error <= PrefStore::PREF_READ_ERROR_JSON_TYPE) { + if (error <= PREF_READ_ERROR_JSON_TYPE) { + // JSON errors indicate file corruption of some sort. + // It's possible the user hand-edited the file, so don't clobber it yet. + // Give them a chance to recover the file. + // TODO(erikkay) maybe we should just move it aside and continue. + read_only_ = true; message_id = IDS_PREFERENCES_CORRUPT_ERROR; - } else if (error != PrefStore::PREF_READ_ERROR_NO_FILE) { + } else if (error == 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. + } else { + // If the file exists but is simply unreadable, put the file into a state + // where we don't try to save changes. Otherwise, we could clobber the + // existing prefs. + read_only_ = true; message_id = IDS_PREFERENCES_UNREADABLE_ERROR; } @@ -120,107 +139,153 @@ void PrefService::InitFromStorage() { } bool PrefService::ReloadPersistentPrefs() { - return (LoadPersistentPrefs() == PrefStore::PREF_READ_ERROR_NONE); + return (LoadPersistentPrefs() == PREF_READ_ERROR_NONE); } -PrefStore::PrefReadError PrefService::LoadPersistentPrefs() { +PrefService::PrefReadError PrefService::LoadPersistentPrefs() { DCHECK(CalledOnValidThread()); + JSONFileValueSerializer serializer(writer_.path()); + + int error_code = 0; + std::string error_msg; + scoped_ptr<Value> root(serializer.Deserialize(&error_code, &error_msg)); + if (!root.get()) { +#if defined(GOOGLE_CHROME_BUILD) + // This log could be used for more detailed client-side error diagnosis, + // but since this triggers often with unit tests, we need to disable it + // in non-official builds. + PLOG(ERROR) << "Error reading Preferences: " << error_msg << " " << + writer_.path().value(); +#endif + PrefReadError pref_error; + switch (error_code) { + case JSONFileValueSerializer::JSON_ACCESS_DENIED: + pref_error = PREF_READ_ERROR_ACCESS_DENIED; + break; + case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: + pref_error = PREF_READ_ERROR_FILE_OTHER; + break; + case JSONFileValueSerializer::JSON_FILE_LOCKED: + pref_error = PREF_READ_ERROR_FILE_LOCKED; + break; + case JSONFileValueSerializer::JSON_NO_SUCH_FILE: + pref_error = PREF_READ_ERROR_NO_FILE; + break; + default: + pref_error = PREF_READ_ERROR_JSON_PARSE; + break; + } + return pref_error; + } - PrefStore::PrefReadError pref_error = store_->ReadPrefs(); - - persistent_ = store_->Prefs(); + // Preferences should always have a dictionary root. + if (!root->IsType(Value::TYPE_DICTIONARY)) + return PREF_READ_ERROR_JSON_TYPE; + persistent_.reset(static_cast<DictionaryValue*>(root.release())); for (PreferenceSet::iterator it = prefs_.begin(); it != prefs_.end(); ++it) { - (*it)->root_pref_ = persistent_; + (*it)->root_pref_ = persistent_.get(); } - return pref_error; + return PREF_READ_ERROR_NONE; } bool PrefService::SavePersistentPrefs() { DCHECK(CalledOnValidThread()); - return store_->WritePrefs(); + std::string data; + if (!SerializeData(&data)) + return false; + + // Lie about our ability to save. + if (read_only_) + return true; + + writer_.WriteNow(data); + return true; } void PrefService::ScheduleSavePersistentPrefs() { DCHECK(CalledOnValidThread()); - store_->ScheduleWritePrefs(); + if (read_only_) + return; + + writer_.ScheduleWrite(this); } void PrefService::RegisterBooleanPref(const wchar_t* path, bool default_value) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, Value::CreateBooleanValue(default_value)); RegisterPreference(pref); } void PrefService::RegisterIntegerPref(const wchar_t* path, int default_value) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, Value::CreateIntegerValue(default_value)); RegisterPreference(pref); } void PrefService::RegisterRealPref(const wchar_t* path, double default_value) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, Value::CreateRealValue(default_value)); RegisterPreference(pref); } void PrefService::RegisterStringPref(const wchar_t* path, const std::wstring& default_value) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, Value::CreateStringValue(default_value)); RegisterPreference(pref); } void PrefService::RegisterFilePathPref(const wchar_t* path, const FilePath& default_value) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, Value::CreateStringValue(default_value.value())); RegisterPreference(pref); } void PrefService::RegisterListPref(const wchar_t* path) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, new ListValue); RegisterPreference(pref); } void PrefService::RegisterDictionaryPref(const wchar_t* path) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, new DictionaryValue()); RegisterPreference(pref); } void PrefService::RegisterLocalizedBooleanPref(const wchar_t* path, int locale_default_message_id) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, CreateLocaleDefaultValue(Value::TYPE_BOOLEAN, locale_default_message_id)); RegisterPreference(pref); } void PrefService::RegisterLocalizedIntegerPref(const wchar_t* path, int locale_default_message_id) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, CreateLocaleDefaultValue(Value::TYPE_INTEGER, locale_default_message_id)); RegisterPreference(pref); } void PrefService::RegisterLocalizedRealPref(const wchar_t* path, int locale_default_message_id) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, CreateLocaleDefaultValue(Value::TYPE_REAL, locale_default_message_id)); RegisterPreference(pref); } void PrefService::RegisterLocalizedStringPref(const wchar_t* path, int locale_default_message_id) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, CreateLocaleDefaultValue(Value::TYPE_STRING, locale_default_message_id)); RegisterPreference(pref); } @@ -411,6 +476,7 @@ void PrefService::ClearPref(const wchar_t* path) { NOTREACHED() << "Trying to clear an unregistered pref: " << path; return; } + Value* value; bool has_old_value = persistent_->Get(path, &value); persistent_->Remove(path, NULL); @@ -586,7 +652,7 @@ int64 PrefService::GetInt64(const wchar_t* path) const { } void PrefService::RegisterInt64Pref(const wchar_t* path, int64 default_value) { - Preference* pref = new Preference(persistent_, path, + Preference* pref = new Preference(persistent_.get(), path, Value::CreateStringValue(Int64ToWString(default_value))); RegisterPreference(pref); } @@ -668,6 +734,15 @@ void PrefService::FireObservers(const wchar_t* path) { } } +bool PrefService::SerializeData(std::string* output) { + // TODO(tc): Do we want to prune webkit preferences that match the default + // value? + JSONStringValueSerializer serializer(output); + serializer.set_pretty_print(true); + scoped_ptr<DictionaryValue> copy(persistent_->DeepCopyWithoutEmptyChildren()); + return serializer.Serialize(*(copy.get())); +} + /////////////////////////////////////////////////////////////////////////////// // PrefService::Preference |