OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/browser/pref_service.h" | 5 #include "chrome/browser/pref_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
| 11 #include "base/histogram.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
13 #include "base/stl_util-inl.h" | 14 #include "base/stl_util-inl.h" |
14 #include "base/string_util.h" | 15 #include "base/string_util.h" |
15 #include "base/sys_string_conversions.h" | 16 #include "base/sys_string_conversions.h" |
16 #include "base/utf_string_conversions.h" | 17 #include "base/utf_string_conversions.h" |
17 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 19 #include "chrome/browser/chrome_thread.h" |
18 #include "chrome/common/json_value_serializer.h" | 20 #include "chrome/common/json_value_serializer.h" |
19 #include "chrome/common/notification_service.h" | 21 #include "chrome/common/notification_service.h" |
| 22 #include "grit/chromium_strings.h" |
20 #include "grit/generated_resources.h" | 23 #include "grit/generated_resources.h" |
21 | 24 |
22 namespace { | 25 namespace { |
23 | 26 |
24 // A helper function for RegisterLocalized*Pref that creates a Value* based on | 27 // A helper function for RegisterLocalized*Pref that creates a Value* based on |
25 // the string value in the locale dll. Because we control the values in a | 28 // the string value in the locale dll. Because we control the values in a |
26 // locale dll, this should always return a Value of the appropriate type. | 29 // locale dll, this should always return a Value of the appropriate type. |
27 Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) { | 30 Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) { |
28 std::wstring resource_string = l10n_util::GetString(message_id); | 31 std::wstring resource_string = l10n_util::GetString(message_id); |
29 DCHECK(!resource_string.empty()); | 32 DCHECK(!resource_string.empty()); |
(...skipping 25 matching lines...) Expand all Loading... |
55 | 58 |
56 default: { | 59 default: { |
57 NOTREACHED() << | 60 NOTREACHED() << |
58 "list and dictionary types can not have default locale values"; | 61 "list and dictionary types can not have default locale values"; |
59 } | 62 } |
60 } | 63 } |
61 NOTREACHED(); | 64 NOTREACHED(); |
62 return Value::CreateNullValue(); | 65 return Value::CreateNullValue(); |
63 } | 66 } |
64 | 67 |
| 68 // Forwards a notification after a PostMessage so that we can wait for the |
| 69 // MessageLoop to run. |
| 70 void NotifyReadError(PrefService* pref, int message_id) { |
| 71 Source<PrefService> source(pref); |
| 72 NotificationService::current()->Notify(NotificationType::PROFILE_ERROR, |
| 73 source, Details<int>(&message_id)); |
| 74 } |
| 75 |
65 } // namespace | 76 } // namespace |
66 | 77 |
67 PrefService::PrefService(const FilePath& pref_filename) | 78 PrefService::PrefService(const FilePath& pref_filename) |
68 : persistent_(new DictionaryValue), | 79 : persistent_(new DictionaryValue), |
69 writer_(pref_filename) { | 80 writer_(pref_filename), |
70 ReloadPersistentPrefs(); | 81 read_only_(false) { |
| 82 InitFromDisk(); |
71 } | 83 } |
72 | 84 |
73 PrefService::~PrefService() { | 85 PrefService::~PrefService() { |
74 DCHECK(CalledOnValidThread()); | 86 DCHECK(CalledOnValidThread()); |
75 | 87 |
76 // Verify that there are no pref observers when we shut down. | 88 // Verify that there are no pref observers when we shut down. |
77 for (PrefObserverMap::iterator it = pref_observers_.begin(); | 89 for (PrefObserverMap::iterator it = pref_observers_.begin(); |
78 it != pref_observers_.end(); ++it) { | 90 it != pref_observers_.end(); ++it) { |
79 NotificationObserverList::Iterator obs_iterator(*(it->second)); | 91 NotificationObserverList::Iterator obs_iterator(*(it->second)); |
80 if (obs_iterator.GetNext()) { | 92 if (obs_iterator.GetNext()) { |
81 LOG(WARNING) << "pref observer found at shutdown " << it->first; | 93 LOG(WARNING) << "pref observer found at shutdown " << it->first; |
82 } | 94 } |
83 } | 95 } |
84 | 96 |
85 STLDeleteContainerPointers(prefs_.begin(), prefs_.end()); | 97 STLDeleteContainerPointers(prefs_.begin(), prefs_.end()); |
86 prefs_.clear(); | 98 prefs_.clear(); |
87 STLDeleteContainerPairSecondPointers(pref_observers_.begin(), | 99 STLDeleteContainerPairSecondPointers(pref_observers_.begin(), |
88 pref_observers_.end()); | 100 pref_observers_.end()); |
89 pref_observers_.clear(); | 101 pref_observers_.clear(); |
90 | 102 |
91 if (writer_.HasPendingWrite()) | 103 if (writer_.HasPendingWrite() && !read_only_) |
92 writer_.DoScheduledWrite(); | 104 writer_.DoScheduledWrite(); |
93 } | 105 } |
94 | 106 |
| 107 void PrefService::InitFromDisk() { |
| 108 PrefReadError error = LoadPersistentPrefs(); |
| 109 if (error == PREF_READ_ERROR_NONE) |
| 110 return; |
| 111 |
| 112 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for |
| 113 // an example problem that this can cause. |
| 114 // Do some diagnosis and try to avoid losing data. |
| 115 int message_id = 0; |
| 116 if (error <= PREF_READ_ERROR_JSON_TYPE) { |
| 117 // JSON errors indicate file corruption of some sort. |
| 118 // It's possible the user hand-edited the file, so don't clobber it yet. |
| 119 // Give them a chance to recover the file. |
| 120 // TODO(erikkay) maybe we should just move it aside and continue. |
| 121 read_only_ = true; |
| 122 message_id = IDS_PREFERENCES_CORRUPT_ERROR; |
| 123 } if (error == PREF_READ_ERROR_NO_FILE) { |
| 124 // If the file just doesn't exist, maybe this is first run. In any case |
| 125 // there's no harm in writing out default prefs in this case. |
| 126 } else { |
| 127 // If the file exists but is simply unreadable, put the file into a state |
| 128 // where we don't try to save changes. Otherwise, we could clobber the |
| 129 // existing prefs. |
| 130 read_only_ = true; |
| 131 message_id = IDS_PREFERENCES_UNREADABLE_ERROR; |
| 132 } |
| 133 |
| 134 if (message_id) { |
| 135 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 136 NewRunnableFunction(&NotifyReadError, this, message_id)); |
| 137 } |
| 138 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error, 20); |
| 139 } |
| 140 |
95 bool PrefService::ReloadPersistentPrefs() { | 141 bool PrefService::ReloadPersistentPrefs() { |
| 142 return (LoadPersistentPrefs() == PREF_READ_ERROR_NONE); |
| 143 } |
| 144 |
| 145 PrefService::PrefReadError PrefService::LoadPersistentPrefs() { |
96 DCHECK(CalledOnValidThread()); | 146 DCHECK(CalledOnValidThread()); |
| 147 JSONFileValueSerializer serializer(writer_.path()); |
97 | 148 |
98 JSONFileValueSerializer serializer(writer_.path()); | 149 int error_code; |
99 scoped_ptr<Value> root(serializer.Deserialize(NULL)); | 150 std::string error_msg; |
100 if (!root.get()) | 151 scoped_ptr<Value> root(serializer.Deserialize(&error_code, &error_msg)); |
101 return false; | 152 if (!root.get()) { |
| 153 PLOG(ERROR) << "Error reading Preferences: " << error_msg << " " << |
| 154 writer_.path().value(); |
| 155 PrefReadError pref_error; |
| 156 switch (error_code) { |
| 157 case JSONFileValueSerializer::JSON_ACCESS_DENIED: |
| 158 pref_error = PREF_READ_ERROR_ACCESS_DENIED; |
| 159 break; |
| 160 case JSONFileValueSerializer::JSON_CANNOT_READ_FILE: |
| 161 pref_error = PREF_READ_ERROR_FILE_OTHER; |
| 162 break; |
| 163 case JSONFileValueSerializer::JSON_FILE_LOCKED: |
| 164 pref_error = PREF_READ_ERROR_FILE_LOCKED; |
| 165 break; |
| 166 case JSONFileValueSerializer::JSON_NO_SUCH_FILE: |
| 167 pref_error = PREF_READ_ERROR_NO_FILE; |
| 168 break; |
| 169 default: |
| 170 pref_error = PREF_READ_ERROR_JSON_PARSE; |
| 171 break; |
| 172 } |
| 173 return pref_error; |
| 174 } |
102 | 175 |
103 // Preferences should always have a dictionary root. | 176 // Preferences should always have a dictionary root. |
104 if (!root->IsType(Value::TYPE_DICTIONARY)) | 177 if (!root->IsType(Value::TYPE_DICTIONARY)) |
105 return false; | 178 return PREF_READ_ERROR_JSON_TYPE; |
106 | 179 |
107 persistent_.reset(static_cast<DictionaryValue*>(root.release())); | 180 persistent_.reset(static_cast<DictionaryValue*>(root.release())); |
108 for (PreferenceSet::iterator it = prefs_.begin(); | 181 for (PreferenceSet::iterator it = prefs_.begin(); |
109 it != prefs_.end(); ++it) { | 182 it != prefs_.end(); ++it) { |
110 (*it)->root_pref_ = persistent_.get(); | 183 (*it)->root_pref_ = persistent_.get(); |
111 } | 184 } |
112 | 185 |
113 return true; | 186 return PREF_READ_ERROR_NONE; |
114 } | 187 } |
115 | 188 |
116 bool PrefService::SavePersistentPrefs() { | 189 bool PrefService::SavePersistentPrefs() { |
117 DCHECK(CalledOnValidThread()); | 190 DCHECK(CalledOnValidThread()); |
118 | 191 |
119 std::string data; | 192 std::string data; |
120 if (!SerializeData(&data)) | 193 if (!SerializeData(&data)) |
121 return false; | 194 return false; |
122 | 195 |
| 196 // Lie about our ability to save. |
| 197 if (read_only_) |
| 198 return true; |
| 199 |
123 writer_.WriteNow(data); | 200 writer_.WriteNow(data); |
124 return true; | 201 return true; |
125 } | 202 } |
126 | 203 |
127 void PrefService::ScheduleSavePersistentPrefs() { | 204 void PrefService::ScheduleSavePersistentPrefs() { |
128 DCHECK(CalledOnValidThread()); | 205 DCHECK(CalledOnValidThread()); |
| 206 |
| 207 if (read_only_) |
| 208 return; |
| 209 |
129 writer_.ScheduleWrite(this); | 210 writer_.ScheduleWrite(this); |
130 } | 211 } |
131 | 212 |
132 void PrefService::RegisterBooleanPref(const wchar_t* path, | 213 void PrefService::RegisterBooleanPref(const wchar_t* path, |
133 bool default_value) { | 214 bool default_value) { |
134 Preference* pref = new Preference(persistent_.get(), path, | 215 Preference* pref = new Preference(persistent_.get(), path, |
135 Value::CreateBooleanValue(default_value)); | 216 Value::CreateBooleanValue(default_value)); |
136 RegisterPreference(pref); | 217 RegisterPreference(pref); |
137 } | 218 } |
138 | 219 |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 } | 773 } |
693 | 774 |
694 // Pref not found, just return the app default. | 775 // Pref not found, just return the app default. |
695 return default_value_.get(); | 776 return default_value_.get(); |
696 } | 777 } |
697 | 778 |
698 bool PrefService::Preference::IsDefaultValue() const { | 779 bool PrefService::Preference::IsDefaultValue() const { |
699 DCHECK(default_value_.get()); | 780 DCHECK(default_value_.get()); |
700 return default_value_->Equals(GetValue()); | 781 return default_value_->Equals(GetValue()); |
701 } | 782 } |
OLD | NEW |