| 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 <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "chrome/browser/browser_process.h" | 11 #include "chrome/browser/browser_process.h" |
| 12 #include "chrome/browser/extensions/extensions_service.h" | 12 #include "chrome/browser/extensions/extensions_service.h" |
| 13 #include "chrome/browser/extensions/extension_prefs.h" | 13 #include "chrome/browser/extensions/extension_prefs.h" |
| 14 #include "chrome/browser/prefs/pref_service.h" | 14 #include "chrome/browser/prefs/pref_service.h" |
| 15 #include "chrome/browser/profile.h" | 15 #include "chrome/browser/profile.h" |
| 16 #include "chrome/common/extensions/extension.h" | 16 #include "chrome/common/extensions/extension.h" |
| 17 #include "chrome/common/notification_service.h" | 17 #include "chrome/common/notification_details.h" |
| 18 #include "chrome/common/notification_source.h" |
| 19 #include "chrome/common/notification_type.h" |
| 18 | 20 |
| 19 ExtensionPrefStore::ExtensionPrefStore(Profile* profile, | 21 ExtensionPrefStore::ExtensionPrefStore(Profile* profile, |
| 20 PrefNotifier::PrefStoreType type) | 22 PrefNotifier::PrefStoreType type) |
| 21 : prefs_(new DictionaryValue()), | 23 : prefs_(new DictionaryValue()), |
| 22 profile_(profile), | 24 profile_(profile), |
| 23 type_(type) { | 25 type_(type) { |
| 24 RegisterObservers(); | 26 RegisterObservers(); |
| 25 } | 27 } |
| 26 | 28 |
| 27 ExtensionPrefStore::~ExtensionPrefStore() { | 29 ExtensionPrefStore::~ExtensionPrefStore() { |
| 28 STLDeleteElements(&extension_stack_); | 30 STLDeleteElements(&extension_stack_); |
| 29 notification_registrar_.RemoveAll(); | 31 notification_registrar_.RemoveAll(); |
| 30 } | 32 } |
| 31 | 33 |
| 32 void ExtensionPrefStore::InstallExtensionPref(const Extension* extension, | 34 void ExtensionPrefStore::InstallExtensionPref(const Extension* extension, |
| 33 const char* new_pref_path, | 35 const char* new_pref_path, |
| 34 Value* new_pref_value) { | 36 Value* new_pref_value) { |
| 35 if (extension_stack_.empty()) | 37 if (extension_stack_.empty()) |
| 36 LazyInit(); | 38 LazyInit(); |
| 37 | 39 |
| 38 ExtensionStack::iterator i; | 40 ExtensionStack::iterator i; |
| 39 for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) { | 41 for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) { |
| 40 if ((*i)->extension_id == extension->id()) | 42 if ((*i)->extension_id == extension->id()) |
| 41 break; | 43 break; |
| 42 } | 44 } |
| 43 | 45 |
| 44 // If this extension is not already in the stack, add it. Otherwise, update | 46 // If this extension is not already in the stack, add it. Otherwise, update |
| 45 // or add the value of this preference, but don't change the extension's | 47 // or add the value of this preference, but don't change the extension's |
| 46 // position in the stack. We store the extension even if this preference | 48 // position in the stack. |
| 47 // isn't registered with our PrefService, so that the ordering of extensions | |
| 48 // is consistent among all local-state and user ExtensionPrefStores. | |
| 49 PrefService* pref_service = GetPrefService(); | |
| 50 // The pref_service may be NULL in unit testing. | |
| 51 bool is_registered_pref = (pref_service == NULL || | |
| 52 pref_service->FindPreference(new_pref_path) != NULL); | |
| 53 PrefValueMap* pref_values; | |
| 54 if (i == extension_stack_.end()) { | 49 if (i == extension_stack_.end()) { |
| 55 pref_values = new PrefValueMap(); | 50 PrefValueMap* pref_values = new PrefValueMap(); |
| 56 if (is_registered_pref) | 51 (*pref_values)[new_pref_path] = new_pref_value; |
| 57 (*pref_values)[new_pref_path] = new_pref_value; | |
| 58 | 52 |
| 59 ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension->id(), | 53 ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension->id(), |
| 60 pref_values); | 54 pref_values); |
| 61 extension_stack_.push_front(extension_prefs); | 55 extension_stack_.push_front(extension_prefs); |
| 62 AddPrecedence(extension->id()); | 56 AddPrecedence(extension->id()); |
| 63 | 57 |
| 64 } else if (is_registered_pref) { | 58 } else { |
| 65 pref_values = (*i)->pref_values; | 59 PrefValueMap* pref_values = (*i)->pref_values; |
| 66 delete (*pref_values)[new_pref_path]; | 60 delete (*pref_values)[new_pref_path]; |
| 67 (*pref_values)[new_pref_path] = new_pref_value; | 61 (*pref_values)[new_pref_path] = new_pref_value; |
| 68 } | 62 } |
| 69 | 63 |
| 70 // Apply the preference to our local |prefs_| store. | 64 // Apply the preference to our local |prefs_| store. |
| 71 UpdateOnePref(new_pref_path); | 65 UpdateOnePref(new_pref_path); |
| 72 } | 66 } |
| 73 | 67 |
| 74 void ExtensionPrefStore::UninstallExtension(const Extension* extension) { | 68 void ExtensionPrefStore::UninstallExtension(const Extension* extension) { |
| 75 // Remove this extension from the stack. | 69 // Remove this extension from the stack. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 90 i != extension_stack_.end(); ++i) { | 84 i != extension_stack_.end(); ++i) { |
| 91 (*result).push_back((*i)->extension_id); | 85 (*result).push_back((*i)->extension_id); |
| 92 } | 86 } |
| 93 } | 87 } |
| 94 | 88 |
| 95 // This could be sped up by keeping track of which extension currently controls | 89 // This could be sped up by keeping track of which extension currently controls |
| 96 // a given preference, among other optimizations. But probably fewer than 10 | 90 // a given preference, among other optimizations. But probably fewer than 10 |
| 97 // installed extensions will be trying to control any preferences, so stick | 91 // installed extensions will be trying to control any preferences, so stick |
| 98 // with this simpler algorithm until it causes a problem. | 92 // with this simpler algorithm until it causes a problem. |
| 99 void ExtensionPrefStore::UpdateOnePref(const char* path) { | 93 void ExtensionPrefStore::UpdateOnePref(const char* path) { |
| 100 PrefService* pref_service = GetPrefService(); | |
| 101 | |
| 102 // There are at least two PrefServices, one for local state and one for | |
| 103 // user prefs. (See browser_main.cc.) Different preferences are registered | |
| 104 // in each; if this one doesn't have the desired pref registered, we ignore | |
| 105 // it and let the other one handle it. | |
| 106 // The pref_service may be NULL in unit testing. | |
| 107 if (pref_service && !pref_service->FindPreference(path)) | |
| 108 return; | |
| 109 | |
| 110 // Save the old value before removing it from the local cache. | 94 // Save the old value before removing it from the local cache. |
| 111 Value* my_old_value_ptr = NULL; | 95 Value* my_old_value_ptr = NULL; |
| 112 prefs_->Get(path, &my_old_value_ptr); | 96 prefs_->Get(path, &my_old_value_ptr); |
| 113 scoped_ptr<Value> my_old_value; | 97 scoped_ptr<Value> my_old_value; |
| 114 if (my_old_value_ptr) | 98 if (my_old_value_ptr) |
| 115 my_old_value.reset(my_old_value_ptr->DeepCopy()); | 99 my_old_value.reset(my_old_value_ptr->DeepCopy()); |
| 116 | 100 |
| 117 // DictionaryValue::Set complains if a key is overwritten with the same | 101 // DictionaryValue::Set complains if a key is overwritten with the same |
| 118 // value, so remove it first. | 102 // value, so remove it first. |
| 119 prefs_->Remove(path, NULL); | 103 prefs_->Remove(path, NULL); |
| 120 | 104 |
| 121 // Find the first extension that wants to set this pref and use its value. | 105 // Find the first extension that wants to set this pref and use its value. |
| 122 Value* my_new_value = NULL; | 106 Value* my_new_value = NULL; |
| 123 for (ExtensionStack::iterator ext_iter = extension_stack_.begin(); | 107 for (ExtensionStack::iterator ext_iter = extension_stack_.begin(); |
| 124 ext_iter != extension_stack_.end(); ++ext_iter) { | 108 ext_iter != extension_stack_.end(); ++ext_iter) { |
| 125 PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path); | 109 PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path); |
| 126 if (value_iter != (*ext_iter)->pref_values->end()) { | 110 if (value_iter != (*ext_iter)->pref_values->end()) { |
| 127 prefs_->Set(path, (*value_iter).second->DeepCopy()); | 111 prefs_->Set(path, (*value_iter).second->DeepCopy()); |
| 128 my_new_value = (*value_iter).second; | 112 my_new_value = (*value_iter).second; |
| 129 break; | 113 break; |
| 130 } | 114 } |
| 131 } | 115 } |
| 132 | 116 |
| 117 // May be null in unit tests. |
| 118 PrefService* pref_service = GetPrefService(); |
| 133 if (pref_service) { | 119 if (pref_service) { |
| 134 bool value_changed = true; | 120 bool value_changed = true; |
| 135 if (!my_old_value.get() && !my_new_value) { | 121 if (!my_old_value.get() && !my_new_value) { |
| 136 value_changed = false; | 122 value_changed = false; |
| 137 } else if (my_old_value.get() && | 123 } else if (my_old_value.get() && |
| 138 my_new_value && | 124 my_new_value && |
| 139 my_old_value->Equals(my_new_value)) { | 125 my_old_value->Equals(my_new_value)) { |
| 140 value_changed = false; | 126 value_changed = false; |
| 141 } | 127 } |
| 142 | 128 |
| 143 if (value_changed) | 129 if (value_changed) |
| 144 pref_service->pref_notifier()->OnPreferenceSet(path, type_); | 130 pref_service->pref_notifier()->OnPreferenceSet(path, type_); |
| 145 } | 131 } |
| 146 } | 132 } |
| 147 | 133 |
| 148 void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) { | 134 void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) { |
| 149 if (!pref_values) | 135 if (!pref_values) |
| 150 return; | 136 return; |
| 151 | 137 |
| 152 for (PrefValueMap::const_iterator i = pref_values->begin(); | 138 for (PrefValueMap::const_iterator i = pref_values->begin(); |
| 153 i != pref_values->end(); ++i) { | 139 i != pref_values->end(); ++i) { |
| 154 UpdateOnePref(i->first); | 140 UpdateOnePref(i->first); |
| 155 } | 141 } |
| 156 } | 142 } |
| 157 | 143 |
| 158 PrefService* ExtensionPrefStore::GetPrefService() { | 144 PrefService* ExtensionPrefStore::GetPrefService() { |
| 159 if (profile_) | 145 // May be null in unit tests. |
| 160 return profile_->GetPrefs(); | 146 if (!profile_) |
| 161 return g_browser_process->local_state(); | 147 return NULL; |
| 148 return profile_->GetPrefs(); |
| 162 } | 149 } |
| 163 | 150 |
| 164 void ExtensionPrefStore::RegisterObservers() { | 151 void ExtensionPrefStore::RegisterObservers() { |
| 152 // If profile_==NULL, this ExtensionPrefStore is for local-state. |
| 153 if (!profile_) |
| 154 return; |
| 155 |
| 165 notification_registrar_.Add(this, | 156 notification_registrar_.Add(this, |
| 166 NotificationType::EXTENSION_PREF_CHANGED, | 157 NotificationType::EXTENSION_PREF_CHANGED, |
| 167 NotificationService::AllSources()); | 158 Source<Profile>(profile_)); |
| 168 | 159 |
| 169 notification_registrar_.Add(this, | 160 notification_registrar_.Add(this, |
| 170 NotificationType::EXTENSION_UNLOADED, | 161 NotificationType::EXTENSION_UNLOADED, |
| 171 NotificationService::AllSources()); | 162 Source<Profile>(profile_)); |
| 172 } | 163 } |
| 173 | 164 |
| 174 void ExtensionPrefStore::Observe(NotificationType type, | 165 void ExtensionPrefStore::Observe(NotificationType type, |
| 175 const NotificationSource& source, | 166 const NotificationSource& source, |
| 176 const NotificationDetails& details) { | 167 const NotificationDetails& details) { |
| 177 switch (type.value) { | 168 switch (type.value) { |
| 178 case NotificationType::EXTENSION_PREF_CHANGED: { | 169 case NotificationType::EXTENSION_PREF_CHANGED: { |
| 179 Profile* extension_profile = Source<Profile>(source).ptr(); | 170 ExtensionPrefStore::ExtensionPrefDetails* data = |
| 180 // The ExtensionPrefStore for the local state watches all profiles. | 171 Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr(); |
| 181 if (!profile_ || profile_ == extension_profile) { | 172 InstallExtensionPref(data->first, data->second.first, |
| 182 ExtensionPrefStore::ExtensionPrefDetails* data = | 173 data->second.second); |
| 183 Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr(); | |
| 184 InstallExtensionPref(data->first, data->second.first, | |
| 185 data->second.second); | |
| 186 } | |
| 187 break; | 174 break; |
| 188 } | 175 } |
| 189 case NotificationType::EXTENSION_UNLOADED: { | 176 case NotificationType::EXTENSION_UNLOADED: { |
| 190 Profile* extension_profile = Source<Profile>(source).ptr(); | |
| 191 const Extension* extension = Details<const Extension>(details).ptr(); | 177 const Extension* extension = Details<const Extension>(details).ptr(); |
| 192 // The ExtensionPrefStore for the local state watches all profiles. | 178 UninstallExtension(extension); |
| 193 if (profile_ == NULL || profile_ == extension_profile) | |
| 194 UninstallExtension(extension); | |
| 195 break; | 179 break; |
| 196 } | 180 } |
| 197 default: { | 181 default: { |
| 198 NOTREACHED(); | 182 NOTREACHED(); |
| 199 } | 183 } |
| 200 } | 184 } |
| 201 } | 185 } |
| 202 | 186 |
| 203 void ExtensionPrefStore::AddPrecedence(const std::string& extension_id) { | 187 void ExtensionPrefStore::AddPrecedence(const std::string& extension_id) { |
| 204 std::vector<std::string> precedence; | 188 std::vector<std::string> precedence; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 } | 243 } |
| 260 | 244 |
| 261 ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs( | 245 ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs( |
| 262 const std::string& extension_id, PrefValueMap* values) | 246 const std::string& extension_id, PrefValueMap* values) |
| 263 : extension_id(extension_id), pref_values(values) {} | 247 : extension_id(extension_id), pref_values(values) {} |
| 264 | 248 |
| 265 ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() { | 249 ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() { |
| 266 STLDeleteValues(pref_values); | 250 STLDeleteValues(pref_values); |
| 267 delete pref_values; | 251 delete pref_values; |
| 268 } | 252 } |
| OLD | NEW |