OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/common/pref_service.h" | 5 #include "chrome/common/pref_service.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | |
8 #include "base/file_util.h" | |
9 #include "base/logging.h" | 7 #include "base/logging.h" |
10 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
11 #include "base/string_util.h" | 9 #include "base/string_util.h" |
12 #include "base/task.h" | |
13 #include "base/thread.h" | 10 #include "base/thread.h" |
14 #include "chrome/common/json_value_serializer.h" | 11 #include "chrome/common/json_value_serializer.h" |
15 #include "chrome/common/l10n_util.h" | 12 #include "chrome/common/l10n_util.h" |
16 #include "chrome/common/notification_service.h" | 13 #include "chrome/common/notification_service.h" |
17 #include "chrome/common/stl_util-inl.h" | 14 #include "chrome/common/stl_util-inl.h" |
18 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" |
19 | 16 |
20 namespace { | 17 namespace { |
21 | 18 |
22 // The number of milliseconds we'll wait to do a write of chrome prefs to disk. | |
23 // This lets us batch together write operations. | |
24 static const int kCommitIntervalMs = 10000; | |
25 | |
26 // Replaces the given file's content with the given data. This allows the | |
27 // preferences to be written to disk on a background thread. | |
28 class SaveLaterTask : public Task { | |
29 public: | |
30 SaveLaterTask(const FilePath& file_name, | |
31 const std::string& data) | |
32 : file_name_(file_name), | |
33 data_(data) { | |
34 } | |
35 | |
36 void Run() { | |
37 // Write the data to a temp file then rename to avoid data loss if we crash | |
38 // while writing the file. | |
39 FilePath tmp_file_name(file_name_.value() + FILE_PATH_LITERAL(".tmp")); | |
40 int bytes_written = file_util::WriteFile(tmp_file_name, data_.c_str(), | |
41 static_cast<int>(data_.length())); | |
42 if (bytes_written != -1) { | |
43 if (!file_util::Move(tmp_file_name, file_name_)) { | |
44 // Rename failed. Try again on the off chance someone has locked either | |
45 // file and hope we're successful the second time through. | |
46 bool move_result = file_util::Move(tmp_file_name, file_name_); | |
47 DCHECK(move_result); | |
48 } | |
49 } | |
50 } | |
51 | |
52 private: | |
53 FilePath file_name_; | |
54 std::string data_; | |
55 | |
56 DISALLOW_COPY_AND_ASSIGN(SaveLaterTask); | |
57 }; | |
58 | |
59 // A helper function for RegisterLocalized*Pref that creates a Value* based on | 19 // A helper function for RegisterLocalized*Pref that creates a Value* based on |
60 // the string value in the locale dll. Because we control the values in a | 20 // the string value in the locale dll. Because we control the values in a |
61 // locale dll, this should always return a Value of the appropriate type. | 21 // locale dll, this should always return a Value of the appropriate type. |
62 Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) { | 22 Value* CreateLocaleDefaultValue(Value::ValueType type, int message_id) { |
63 std::wstring resource_string = l10n_util::GetString(message_id); | 23 std::wstring resource_string = l10n_util::GetString(message_id); |
64 DCHECK(!resource_string.empty()); | 24 DCHECK(!resource_string.empty()); |
65 switch (type) { | 25 switch (type) { |
66 case Value::TYPE_BOOLEAN: { | 26 case Value::TYPE_BOOLEAN: { |
67 if (L"true" == resource_string) | 27 if (L"true" == resource_string) |
68 return Value::CreateBooleanValue(true); | 28 return Value::CreateBooleanValue(true); |
(...skipping 23 matching lines...) Expand all Loading... |
92 NOTREACHED() << | 52 NOTREACHED() << |
93 "list and dictionary types can not have default locale values"; | 53 "list and dictionary types can not have default locale values"; |
94 } | 54 } |
95 } | 55 } |
96 NOTREACHED(); | 56 NOTREACHED(); |
97 return Value::CreateNullValue(); | 57 return Value::CreateNullValue(); |
98 } | 58 } |
99 | 59 |
100 } // namespace | 60 } // namespace |
101 | 61 |
102 PrefService::PrefService() | 62 PrefService::PrefService(const FilePath& pref_filename, |
| 63 const base::Thread* backend_thread) |
103 : persistent_(new DictionaryValue), | 64 : persistent_(new DictionaryValue), |
104 transient_(new DictionaryValue), | 65 transient_(new DictionaryValue), |
105 save_preferences_factory_(NULL) { | 66 writer_(pref_filename, backend_thread) { |
106 } | 67 ReloadPersistentPrefs(); |
107 | |
108 PrefService::PrefService(const FilePath& pref_filename) | |
109 : persistent_(new DictionaryValue), | |
110 transient_(new DictionaryValue), | |
111 pref_filename_(pref_filename), | |
112 ALLOW_THIS_IN_INITIALIZER_LIST(save_preferences_factory_(this)) { | |
113 LoadPersistentPrefs(pref_filename_); | |
114 } | 68 } |
115 | 69 |
116 PrefService::~PrefService() { | 70 PrefService::~PrefService() { |
117 DCHECK(CalledOnValidThread()); | 71 DCHECK(CalledOnValidThread()); |
118 | 72 |
119 // Verify that there are no pref observers when we shut down. | 73 // Verify that there are no pref observers when we shut down. |
120 for (PrefObserverMap::iterator it = pref_observers_.begin(); | 74 for (PrefObserverMap::iterator it = pref_observers_.begin(); |
121 it != pref_observers_.end(); ++it) { | 75 it != pref_observers_.end(); ++it) { |
122 NotificationObserverList::Iterator obs_iterator(*(it->second)); | 76 NotificationObserverList::Iterator obs_iterator(*(it->second)); |
123 if (obs_iterator.GetNext()) { | 77 if (obs_iterator.GetNext()) { |
124 LOG(WARNING) << "pref observer found at shutdown " << it->first; | 78 LOG(WARNING) << "pref observer found at shutdown " << it->first; |
125 } | 79 } |
126 } | 80 } |
127 | 81 |
128 STLDeleteContainerPointers(prefs_.begin(), prefs_.end()); | 82 STLDeleteContainerPointers(prefs_.begin(), prefs_.end()); |
129 prefs_.clear(); | 83 prefs_.clear(); |
130 STLDeleteContainerPairSecondPointers(pref_observers_.begin(), | 84 STLDeleteContainerPairSecondPointers(pref_observers_.begin(), |
131 pref_observers_.end()); | 85 pref_observers_.end()); |
132 pref_observers_.clear(); | 86 pref_observers_.clear(); |
133 } | 87 } |
134 | 88 |
135 bool PrefService::LoadPersistentPrefs(const FilePath& file_path) { | 89 bool PrefService::ReloadPersistentPrefs() { |
136 DCHECK(!file_path.empty()); | |
137 DCHECK(CalledOnValidThread()); | 90 DCHECK(CalledOnValidThread()); |
138 | 91 |
139 JSONFileValueSerializer serializer(file_path); | 92 JSONFileValueSerializer serializer(writer_.path()); |
140 scoped_ptr<Value> root(serializer.Deserialize(NULL)); | 93 scoped_ptr<Value> root(serializer.Deserialize(NULL)); |
141 if (!root.get()) | 94 if (!root.get()) |
142 return false; | 95 return false; |
143 | 96 |
144 // Preferences should always have a dictionary root. | 97 // Preferences should always have a dictionary root. |
145 if (!root->IsType(Value::TYPE_DICTIONARY)) | 98 if (!root->IsType(Value::TYPE_DICTIONARY)) |
146 return false; | 99 return false; |
147 | 100 |
148 persistent_.reset(static_cast<DictionaryValue*>(root.release())); | 101 persistent_.reset(static_cast<DictionaryValue*>(root.release())); |
149 return true; | |
150 } | |
151 | |
152 void PrefService::ReloadPersistentPrefs() { | |
153 DCHECK(CalledOnValidThread()); | |
154 | |
155 JSONFileValueSerializer serializer(pref_filename_); | |
156 scoped_ptr<Value> root(serializer.Deserialize(NULL)); | |
157 if (!root.get()) | |
158 return; | |
159 | |
160 // Preferences should always have a dictionary root. | |
161 if (!root->IsType(Value::TYPE_DICTIONARY)) | |
162 return; | |
163 | |
164 persistent_.reset(static_cast<DictionaryValue*>(root.release())); | |
165 for (PreferenceSet::iterator it = prefs_.begin(); | 102 for (PreferenceSet::iterator it = prefs_.begin(); |
166 it != prefs_.end(); ++it) { | 103 it != prefs_.end(); ++it) { |
167 (*it)->root_pref_ = persistent_.get(); | 104 (*it)->root_pref_ = persistent_.get(); |
168 } | 105 } |
169 } | |
170 | 106 |
171 bool PrefService::SavePersistentPrefs(base::Thread* thread) const { | |
172 DCHECK(!pref_filename_.empty()); | |
173 DCHECK(CalledOnValidThread()); | |
174 | |
175 // TODO(tc): Do we want to prune webkit preferences that match the default | |
176 // value? | |
177 std::string data; | |
178 JSONStringValueSerializer serializer(&data); | |
179 serializer.set_pretty_print(true); | |
180 if (!serializer.Serialize(*(persistent_.get()))) | |
181 return false; | |
182 | |
183 SaveLaterTask* task = new SaveLaterTask(pref_filename_, data); | |
184 if (thread != NULL) { | |
185 // We can use the background thread, it will take ownership of the task. | |
186 thread->message_loop()->PostTask(FROM_HERE, task); | |
187 } else { | |
188 // In unit test mode, we have no background thread, just execute. | |
189 task->Run(); | |
190 delete task; | |
191 } | |
192 return true; | 107 return true; |
193 } | 108 } |
194 | 109 |
195 void PrefService::ScheduleSavePersistentPrefs(base::Thread* thread) { | 110 bool PrefService::SavePersistentPrefs() { |
196 if (!save_preferences_factory_.empty()) | 111 DCHECK(CalledOnValidThread()); |
197 return; | |
198 | 112 |
199 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 113 std::string data; |
200 save_preferences_factory_.NewRunnableMethod( | 114 if (!SerializePrefData(&data)) |
201 &PrefService::SavePersistentPrefs, thread), | 115 return false; |
202 kCommitIntervalMs); | 116 |
| 117 writer_.WriteNow(data); |
| 118 return true; |
| 119 } |
| 120 |
| 121 bool PrefService::ScheduleSavePersistentPrefs() { |
| 122 DCHECK(CalledOnValidThread()); |
| 123 |
| 124 std::string data; |
| 125 if (!SerializePrefData(&data)) |
| 126 return false; |
| 127 |
| 128 writer_.ScheduleWrite(data); |
| 129 return true; |
203 } | 130 } |
204 | 131 |
205 void PrefService::RegisterBooleanPref(const wchar_t* path, | 132 void PrefService::RegisterBooleanPref(const wchar_t* path, |
206 bool default_value) { | 133 bool default_value) { |
207 Preference* pref = new Preference(persistent_.get(), path, | 134 Preference* pref = new Preference(persistent_.get(), path, |
208 Value::CreateBooleanValue(default_value)); | 135 Value::CreateBooleanValue(default_value)); |
209 RegisterPreference(pref); | 136 RegisterPreference(pref); |
210 } | 137 } |
211 | 138 |
212 void PrefService::RegisterIntegerPref(const wchar_t* path, | 139 void PrefService::RegisterIntegerPref(const wchar_t* path, |
(...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 | 637 |
711 NotificationObserverList::Iterator it(*(observer_iterator->second)); | 638 NotificationObserverList::Iterator it(*(observer_iterator->second)); |
712 NotificationObserver* observer; | 639 NotificationObserver* observer; |
713 while ((observer = it.GetNext()) != NULL) { | 640 while ((observer = it.GetNext()) != NULL) { |
714 observer->Observe(NotificationType::PREF_CHANGED, | 641 observer->Observe(NotificationType::PREF_CHANGED, |
715 Source<PrefService>(this), | 642 Source<PrefService>(this), |
716 Details<std::wstring>(&path_str)); | 643 Details<std::wstring>(&path_str)); |
717 } | 644 } |
718 } | 645 } |
719 | 646 |
| 647 bool PrefService::SerializePrefData(std::string* output) const { |
| 648 // TODO(tc): Do we want to prune webkit preferences that match the default |
| 649 // value? |
| 650 JSONStringValueSerializer serializer(output); |
| 651 serializer.set_pretty_print(true); |
| 652 return serializer.Serialize(*(persistent_.get())); |
| 653 } |
| 654 |
720 /////////////////////////////////////////////////////////////////////////////// | 655 /////////////////////////////////////////////////////////////////////////////// |
721 // PrefService::Preference | 656 // PrefService::Preference |
722 | 657 |
723 PrefService::Preference::Preference(DictionaryValue* root_pref, | 658 PrefService::Preference::Preference(DictionaryValue* root_pref, |
724 const wchar_t* name, | 659 const wchar_t* name, |
725 Value* default_value) | 660 Value* default_value) |
726 : type_(Value::TYPE_NULL), | 661 : type_(Value::TYPE_NULL), |
727 name_(name), | 662 name_(name), |
728 default_value_(default_value), | 663 default_value_(default_value), |
729 root_pref_(root_pref) { | 664 root_pref_(root_pref) { |
(...skipping 22 matching lines...) Expand all Loading... |
752 } | 687 } |
753 | 688 |
754 // Pref not found, just return the app default. | 689 // Pref not found, just return the app default. |
755 return default_value_.get(); | 690 return default_value_.get(); |
756 } | 691 } |
757 | 692 |
758 bool PrefService::Preference::IsDefaultValue() const { | 693 bool PrefService::Preference::IsDefaultValue() const { |
759 DCHECK(default_value_.get()); | 694 DCHECK(default_value_.get()); |
760 return default_value_->Equals(GetValue()); | 695 return default_value_->Equals(GetValue()); |
761 } | 696 } |
OLD | NEW |