Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Side by Side Diff: chrome/browser/pref_service.cc

Issue 1120006: detect preferences errors (Closed)
Patch Set: changes from review Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/pref_service.h ('k') | chrome/browser/pref_service_uitest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/pref_service.h ('k') | chrome/browser/pref_service_uitest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698