OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/extensions/extension_pref_store.h" | 5 #include "chrome/browser/extensions/extension_pref_store.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/values.h" | 8 #include "base/values.h" |
9 #include "chrome/browser/browser_process.h" | 9 #include "chrome/browser/browser_process.h" |
| 10 #include "chrome/browser/extensions/extensions_service.h" |
10 #include "chrome/browser/prefs/pref_service.h" | 11 #include "chrome/browser/prefs/pref_service.h" |
11 #include "chrome/browser/profile.h" | 12 #include "chrome/browser/profile.h" |
12 #include "chrome/common/extensions/extension.h" | 13 #include "chrome/common/extensions/extension.h" |
13 #include "chrome/common/notification_service.h" | 14 #include "chrome/common/notification_details.h" |
| 15 #include "chrome/common/notification_source.h" |
| 16 #include "chrome/common/notification_type.h" |
| 17 |
| 18 const char ExtensionPrefStore::kExtensionPreferencesKey[] = |
| 19 "extensions.prefvalues"; |
| 20 |
| 21 // ExtensionPrefs implementation: |
| 22 |
| 23 const char ExtensionPrefStore::ExtensionPrefs::kIdKey[] = "id"; |
| 24 const char ExtensionPrefStore::ExtensionPrefs::kPreferencesKey[] = |
| 25 "preferences"; |
| 26 |
| 27 ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(DictionaryValue* dict) |
| 28 : dict_(dict) { |
| 29 DCHECK(dict_->HasKey("id")); |
| 30 DCHECK(dict_->HasKey("preferences")); |
| 31 DCHECK_EQ(2u, dict_->size()); |
| 32 } |
| 33 |
| 34 ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {} |
| 35 |
| 36 DictionaryValue* ExtensionPrefStore::ExtensionPrefs::Create( |
| 37 const std::string& extension_id) { |
| 38 scoped_ptr<DictionaryValue> dict(new DictionaryValue()); |
| 39 dict->Set(kIdKey, Value::CreateStringValue(extension_id)); |
| 40 dict->Set(kPreferencesKey, new DictionaryValue()); |
| 41 return dict.release(); |
| 42 } |
| 43 |
| 44 std::string ExtensionPrefStore::ExtensionPrefs::extension_id() const { |
| 45 std::string string_value; |
| 46 DCHECK(dict_->GetString(kIdKey, &string_value)); |
| 47 return string_value; |
| 48 } |
| 49 |
| 50 DictionaryValue* ExtensionPrefStore::ExtensionPrefs::pref_values() { |
| 51 DictionaryValue* value = NULL; |
| 52 CHECK(dict_->GetDictionary(kPreferencesKey, &value)); |
| 53 return value; |
| 54 } |
| 55 |
| 56 void ExtensionPrefStore::ExtensionPrefs::Set(const std::string& key, |
| 57 Value *value) { |
| 58 if (value == NULL) |
| 59 pref_values()->RemoveWithoutPathExpansion(key, NULL); |
| 60 else |
| 61 pref_values()->SetWithoutPathExpansion(key, value); |
| 62 } |
| 63 |
| 64 Value* ExtensionPrefStore::ExtensionPrefs::Get(const std::string& key) { |
| 65 Value* value = NULL; |
| 66 pref_values()->GetWithoutPathExpansion(key, &value); |
| 67 return value; |
| 68 } |
| 69 |
| 70 |
| 71 // ExtensionStack implementation: |
| 72 |
| 73 ExtensionPrefStore::ExtensionStack::ExtensionStack() |
| 74 : list_(NULL) {} |
| 75 |
| 76 ExtensionPrefStore::ExtensionStack::~ExtensionStack() {} |
| 77 |
| 78 void ExtensionPrefStore::ExtensionStack::Init(ListValue* list) { |
| 79 list_ = list; |
| 80 } |
| 81 |
| 82 bool ExtensionPrefStore::ExtensionStack::IsInitialized() const { |
| 83 return list_ != NULL; |
| 84 } |
| 85 |
| 86 size_t ExtensionPrefStore::ExtensionStack::Size() const { |
| 87 DCHECK(IsInitialized()); |
| 88 return list_->GetSize(); |
| 89 } |
| 90 |
| 91 ExtensionPrefStore::ExtensionPrefs |
| 92 ExtensionPrefStore::ExtensionStack::Get(int index) { |
| 93 DCHECK(IsInitialized()); |
| 94 DictionaryValue* dict; |
| 95 CHECK(list_->GetDictionary(index, &dict)); |
| 96 return ExtensionPrefs(dict); |
| 97 } |
| 98 |
| 99 void ExtensionPrefStore::ExtensionStack::Remove(int index) { |
| 100 DCHECK(IsInitialized()); |
| 101 CHECK(list_->Remove(index, NULL)); |
| 102 } |
| 103 |
| 104 ExtensionPrefStore::ExtensionPrefs |
| 105 ExtensionPrefStore::ExtensionStack::CreateEntry( |
| 106 const std::string& extension_id) { |
| 107 DCHECK(IsInitialized()); |
| 108 list_->Insert(0, ExtensionPrefs::Create(extension_id)); |
| 109 return Get(0); |
| 110 } |
| 111 |
| 112 |
| 113 // ExtensionPrefStore implementation: |
14 | 114 |
15 ExtensionPrefStore::ExtensionPrefStore(Profile* profile, | 115 ExtensionPrefStore::ExtensionPrefStore(Profile* profile, |
16 PrefNotifier::PrefStoreType type) | 116 PrefNotifier::PrefStoreType type) |
17 : prefs_(new DictionaryValue()), | 117 : prefs_(new DictionaryValue()), |
18 profile_(profile), | 118 profile_(profile), |
| 119 dummy_prefs(profile ? NULL : new ListValue), |
19 type_(type) { | 120 type_(type) { |
20 RegisterObservers(); | 121 RegisterObservers(); |
21 } | 122 } |
22 | 123 |
23 ExtensionPrefStore::~ExtensionPrefStore() { | 124 ExtensionPrefStore::~ExtensionPrefStore() { |
24 STLDeleteElements(&extension_stack_); | |
25 notification_registrar_.RemoveAll(); | 125 notification_registrar_.RemoveAll(); |
26 } | 126 } |
27 | 127 |
28 void ExtensionPrefStore::InstallExtensionPref(const Extension* extension, | 128 void ExtensionPrefStore::InstallExtensionPref(const Extension* extension, |
29 const char* new_pref_path, | 129 const char* new_pref_path, |
30 Value* new_pref_value) { | 130 Value* new_pref_value) { |
31 ExtensionStack::iterator i; | 131 if (!extension_stack_.IsInitialized()) |
32 for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) { | 132 LazyInit(); |
33 if ((*i)->extension == extension) | 133 |
| 134 int nr_extensions = extension_stack_.Size(); |
| 135 int i; |
| 136 for (i = 0; i < nr_extensions; ++i) { |
| 137 if (extension_stack_.Get(i).extension_id() == extension->id()) |
34 break; | 138 break; |
35 } | 139 } |
36 | 140 |
37 // If this extension is not already in the stack, add it. Otherwise, update | 141 // If this extension is not already in the stack, add it. Otherwise, update |
38 // or add the value of this preference, but don't change the extension's | 142 // or add the value of this preference, but don't change the extension's |
39 // position in the stack. We store the extension even if this preference | 143 // position in the stack. |
40 // isn't registered with our PrefService, so that the ordering of extensions | 144 if (i == nr_extensions) { |
41 // is consistent among all local-state and user ExtensionPrefStores. | 145 ExtensionPrefs extension_prefs = |
42 PrefService* pref_service = GetPrefService(); | 146 extension_stack_.CreateEntry(extension->id()); |
43 // The pref_service may be NULL in unit testing. | 147 extension_prefs.Set(new_pref_path, new_pref_value); |
44 bool is_registered_pref = (pref_service == NULL || | 148 } else { |
45 pref_service->FindPreference(new_pref_path) != NULL); | 149 ExtensionPrefs extension_prefs = extension_stack_.Get(i); |
46 PrefValueMap* pref_values; | 150 extension_prefs.Set(new_pref_path, new_pref_value); |
47 if (i == extension_stack_.end()) { | |
48 pref_values = new PrefValueMap(); | |
49 if (is_registered_pref) | |
50 (*pref_values)[new_pref_path] = new_pref_value; | |
51 | |
52 ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension, | |
53 pref_values); | |
54 extension_stack_.push_front(extension_prefs); | |
55 } else if (is_registered_pref) { | |
56 pref_values = (*i)->pref_values; | |
57 delete (*pref_values)[new_pref_path]; | |
58 (*pref_values)[new_pref_path] = new_pref_value; | |
59 } | 151 } |
60 | 152 |
61 // Apply the preference to our local |prefs_| store. | 153 // Apply the preference to our local |prefs_| store. |
62 UpdateOnePref(new_pref_path); | 154 UpdateOnePref(new_pref_path); |
| 155 SchedulePersist(); |
63 } | 156 } |
64 | 157 |
65 void ExtensionPrefStore::UninstallExtension(const Extension* extension) { | 158 void ExtensionPrefStore::UninstallExtension(const Extension* extension) { |
| 159 if (!extension_stack_.IsInitialized()) |
| 160 LazyInit(); |
| 161 |
66 // Remove this extension from the stack. | 162 // Remove this extension from the stack. |
67 for (ExtensionStack::iterator i = extension_stack_.begin(); | 163 for (int i = 0, n = extension_stack_.Size(); i < n; ++i) { |
68 i != extension_stack_.end(); ++i) { | 164 ExtensionPrefs extension_prefs = extension_stack_.Get(i); |
69 if ((*i)->extension == extension) { | 165 if (extension_prefs.extension_id() == extension->id()) { |
70 scoped_ptr<ExtensionPrefs> to_be_deleted(*i); | 166 scoped_ptr<DictionaryValue> dict_values( |
71 extension_stack_.erase(i); | 167 extension_prefs.pref_values()->DeepCopyWithoutEmptyChildren()); |
72 UpdatePrefs(to_be_deleted->pref_values); | 168 extension_stack_.Remove(i); |
| 169 UpdatePrefs(dict_values.get()); |
| 170 SchedulePersist(); |
73 return; | 171 return; |
74 } | 172 } |
75 } | 173 } |
76 } | 174 } |
77 | 175 |
| 176 DictionaryValue* ExtensionPrefStore::prefs() const { |
| 177 if (!extension_stack_.IsInitialized()) |
| 178 LazyInit(); |
| 179 return prefs_.get(); |
| 180 } |
| 181 |
78 void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) { | 182 void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) { |
79 for (ExtensionStack::iterator i = extension_stack_.begin(); | 183 if (!extension_stack_.IsInitialized()) |
80 i != extension_stack_.end(); ++i) { | 184 LazyInit(); |
81 (*result).push_back((*i)->extension->id()); | 185 for (int i = 0, n = extension_stack_.Size(); i < n; ++i) |
82 } | 186 result->push_back(extension_stack_.Get(i).extension_id()); |
83 } | 187 } |
84 | 188 |
85 // This could be sped up by keeping track of which extension currently controls | 189 // This could be sped up by keeping track of which extension currently controls |
86 // a given preference, among other optimizations. But probably fewer than 10 | 190 // a given preference, among other optimizations. But probably fewer than 10 |
87 // installed extensions will be trying to control any preferences, so stick | 191 // installed extensions will be trying to control any preferences, so stick |
88 // with this simpler algorithm until it causes a problem. | 192 // with this simpler algorithm until it causes a problem. |
89 void ExtensionPrefStore::UpdateOnePref(const char* path) { | 193 void ExtensionPrefStore::UpdateOnePref(const char* path) { |
90 PrefService* pref_service = GetPrefService(); | |
91 | |
92 // There are at least two PrefServices, one for local state and one for | |
93 // user prefs. (See browser_main.cc.) Different preferences are registered | |
94 // in each; if this one doesn't have the desired pref registered, we ignore | |
95 // it and let the other one handle it. | |
96 // The pref_service may be NULL in unit testing. | |
97 if (pref_service && !pref_service->FindPreference(path)) | |
98 return; | |
99 | |
100 // Save the old value before removing it from the local cache. | 194 // Save the old value before removing it from the local cache. |
101 Value* my_old_value_ptr = NULL; | 195 Value* my_old_value_ptr = NULL; |
102 prefs_->Get(path, &my_old_value_ptr); | 196 prefs_->Get(path, &my_old_value_ptr); |
103 scoped_ptr<Value> my_old_value; | 197 scoped_ptr<Value> my_old_value; |
104 if (my_old_value_ptr) | 198 if (my_old_value_ptr) |
105 my_old_value.reset(my_old_value_ptr->DeepCopy()); | 199 my_old_value.reset(my_old_value_ptr->DeepCopy()); |
106 | 200 |
107 // DictionaryValue::Set complains if a key is overwritten with the same | 201 // DictionaryValue::Set complains if a key is overwritten with the same |
108 // value, so remove it first. | 202 // value, so remove it first. |
109 prefs_->Remove(path, NULL); | 203 prefs_->Remove(path, NULL); |
110 | 204 |
111 // Find the first extension that wants to set this pref and use its value. | 205 // Find the first extension that wants to set this pref and use its value. |
112 Value* my_new_value = NULL; | 206 Value* my_new_value = NULL; |
113 for (ExtensionStack::iterator ext_iter = extension_stack_.begin(); | 207 for (int i = 0, n = extension_stack_.Size(); i < n; ++i) { |
114 ext_iter != extension_stack_.end(); ++ext_iter) { | 208 DictionaryValue* pref_values = extension_stack_.Get(i).pref_values(); |
115 PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path); | 209 bool has_pref = pref_values->GetWithoutPathExpansion(path, &my_new_value); |
116 if (value_iter != (*ext_iter)->pref_values->end()) { | 210 if (has_pref) { |
117 prefs_->Set(path, (*value_iter).second->DeepCopy()); | 211 prefs_->Set(path, my_new_value->DeepCopy()); |
118 my_new_value = (*value_iter).second; | |
119 break; | 212 break; |
120 } | 213 } |
121 } | 214 } |
| 215 // If any extension contained a value for |path| it is stored in my_new_value |
| 216 // now. |
122 | 217 |
| 218 // May be null in unit tests. |
| 219 PrefService* pref_service = GetPrefService(); |
123 if (pref_service) { | 220 if (pref_service) { |
124 bool value_changed = true; | 221 bool value_changed = true; |
125 if (!my_old_value.get() && !my_new_value) { | 222 if (!my_old_value.get() && !my_new_value) { |
126 value_changed = false; | 223 value_changed = false; |
127 } else if (my_old_value.get() && | 224 } else if (my_old_value.get() && |
128 my_new_value && | 225 my_new_value && |
129 my_old_value->Equals(my_new_value)) { | 226 my_old_value->Equals(my_new_value)) { |
130 value_changed = false; | 227 value_changed = false; |
131 } | 228 } |
132 | 229 |
133 if (value_changed) | 230 if (value_changed) |
134 pref_service->pref_notifier()->OnPreferenceSet(path, type_); | 231 pref_service->pref_notifier()->OnPreferenceSet(path, type_); |
135 } | 232 } |
136 } | 233 } |
137 | 234 |
138 void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) { | 235 void ExtensionPrefStore::UpdatePrefs(const DictionaryValue* pref_values) { |
139 if (!pref_values) | 236 if (!pref_values) |
140 return; | 237 return; |
141 | 238 |
142 for (PrefValueMap::const_iterator i = pref_values->begin(); | 239 for (DictionaryValue::key_iterator i = pref_values->begin_keys(); |
143 i != pref_values->end(); ++i) { | 240 i != pref_values->end_keys(); ++i) { |
144 UpdateOnePref(i->first); | 241 UpdateOnePref((*i).c_str()); |
145 } | 242 } |
146 } | 243 } |
147 | 244 |
148 PrefService* ExtensionPrefStore::GetPrefService() { | 245 PrefService* ExtensionPrefStore::GetPrefService() const { |
149 if (profile_) | 246 // In case of local state, there is no profile nor pref service. |
150 return profile_->GetPrefs(); | 247 if (!profile_) |
151 return g_browser_process->local_state(); | 248 return NULL; |
| 249 return profile_->GetPrefs(); |
| 250 } |
| 251 |
| 252 void ExtensionPrefStore::SchedulePersist() { |
| 253 PrefService* prefService = GetPrefService(); |
| 254 if (prefService) |
| 255 prefService->ScheduleSavePersistentPrefs(); |
152 } | 256 } |
153 | 257 |
154 void ExtensionPrefStore::RegisterObservers() { | 258 void ExtensionPrefStore::RegisterObservers() { |
| 259 // If profile_ is NULL, this ExtensionPrefStore is for local-state. |
| 260 if (!profile_) |
| 261 return; |
| 262 |
155 notification_registrar_.Add(this, | 263 notification_registrar_.Add(this, |
156 NotificationType::EXTENSION_PREF_CHANGED, | 264 NotificationType::EXTENSION_PREF_CHANGED, |
157 NotificationService::AllSources()); | 265 Source<Profile>(profile_)); |
158 | 266 |
159 notification_registrar_.Add(this, | 267 notification_registrar_.Add(this, |
160 NotificationType::EXTENSION_UNLOADED, | 268 NotificationType::EXTENSION_UNLOADED, |
161 NotificationService::AllSources()); | 269 Source<Profile>(profile_)); |
162 } | 270 } |
163 | 271 |
164 void ExtensionPrefStore::Observe(NotificationType type, | 272 void ExtensionPrefStore::Observe(NotificationType type, |
165 const NotificationSource& source, | 273 const NotificationSource& source, |
166 const NotificationDetails& details) { | 274 const NotificationDetails& details) { |
167 switch (type.value) { | 275 switch (type.value) { |
168 case NotificationType::EXTENSION_PREF_CHANGED: { | 276 case NotificationType::EXTENSION_PREF_CHANGED: { |
169 Profile* extension_profile = Source<Profile>(source).ptr(); | 277 ExtensionPrefStore::ExtensionPrefDetails* data = |
170 // The ExtensionPrefStore for the local state watches all profiles. | 278 Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr(); |
171 if (!profile_ || profile_ == extension_profile) { | 279 InstallExtensionPref(data->first, data->second.first, |
172 ExtensionPrefStore::ExtensionPrefDetails* data = | 280 data->second.second); |
173 Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr(); | |
174 InstallExtensionPref(data->first, data->second.first, | |
175 data->second.second); | |
176 } | |
177 break; | 281 break; |
178 } | 282 } |
179 case NotificationType::EXTENSION_UNLOADED: { | 283 case NotificationType::EXTENSION_UNLOADED: { |
180 Profile* extension_profile = Source<Profile>(source).ptr(); | |
181 const Extension* extension = Details<const Extension>(details).ptr(); | 284 const Extension* extension = Details<const Extension>(details).ptr(); |
182 // The ExtensionPrefStore for the local state watches all profiles. | 285 UninstallExtension(extension); |
183 if (profile_ == NULL || profile_ == extension_profile) | |
184 UninstallExtension(extension); | |
185 break; | 286 break; |
186 } | 287 } |
187 default: { | 288 default: { |
188 NOTREACHED(); | 289 NOTREACHED(); |
189 } | 290 } |
190 } | 291 } |
191 } | 292 } |
192 | 293 |
193 ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension, | 294 void ExtensionPrefStore::LazyInit() const { |
194 PrefValueMap* values) : extension(extension), pref_values(values) {} | 295 // If profile_==NULL, this ExtensionPrefStore is for local-state. |
| 296 DCHECK(!extension_stack_.IsInitialized()) |
| 297 << "LazyInit called even though extension_stack_ is already initialized"; |
195 | 298 |
196 ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() { | 299 PrefService* pref_service = GetPrefService(); |
197 STLDeleteValues(pref_values); | 300 if (!pref_service) { |
198 delete pref_values; | 301 extension_stack_.Init(dummy_prefs.get()); |
| 302 return; |
| 303 } |
| 304 pref_service->RegisterListPref(kExtensionPreferencesKey); |
| 305 |
| 306 scoped_ptr<ListValue> dict( |
| 307 pref_service->GetMutableList(kExtensionPreferencesKey)); |
| 308 |
| 309 extension_stack_.Init(dict.release()); |
| 310 |
| 311 for (int i = 0, n = extension_stack_.Size(); i < n; ++i) { |
| 312 DictionaryValue* pref_values = extension_stack_.Get(i).pref_values(); |
| 313 for (DictionaryValue::key_iterator iter = pref_values->begin_keys(); |
| 314 iter != pref_values->end_keys(); ++iter) { |
| 315 const std::string& key = *iter; |
| 316 if (!prefs_->HasKey(key)) { |
| 317 Value *value; |
| 318 if (pref_values->GetWithoutPathExpansion(key, &value)) |
| 319 prefs_->Set(key, value->DeepCopy()); |
| 320 } |
| 321 } |
| 322 } |
199 } | 323 } |
OLD | NEW |