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

Unified Diff: chrome/browser/extensions/extension_pref_store.cc

Issue 4852002: Fix for Bug 50726 "Save extension list and "winning" prefs from extensions" (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Renamed key under which preferences are stored in the user prefs Created 10 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_pref_store.cc
diff --git a/chrome/browser/extensions/extension_pref_store.cc b/chrome/browser/extensions/extension_pref_store.cc
index 27719ed3a69345009a2b73be9c7c7156c619e99e..4d1f81e7550d8e7136aaadc74b0071ae537fe9d4 100644
--- a/chrome/browser/extensions/extension_pref_store.cc
+++ b/chrome/browser/extensions/extension_pref_store.cc
@@ -7,79 +7,183 @@
#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/extensions/extension.h"
-#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+
+const char ExtensionPrefStore::kExtensionPreferencesKey[] =
+ "extensions.prefvalues";
+
+// ExtensionPrefs implementation:
+
+const char ExtensionPrefStore::ExtensionPrefs::kIdKey[] = "id";
+const char ExtensionPrefStore::ExtensionPrefs::kPreferencesKey[] =
+ "preferences";
+
+ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(DictionaryValue* dict)
+ : dict_(dict) {
+ DCHECK(dict_->HasKey("id"));
+ DCHECK(dict_->HasKey("preferences"));
+ DCHECK_EQ(2u, dict_->size());
+}
+
+ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {}
+
+DictionaryValue* ExtensionPrefStore::ExtensionPrefs::Create(
+ const std::string& extension_id) {
+ scoped_ptr<DictionaryValue> dict(new DictionaryValue());
+ dict->Set(kIdKey, Value::CreateStringValue(extension_id));
+ dict->Set(kPreferencesKey, new DictionaryValue());
+ return dict.release();
+}
+
+std::string ExtensionPrefStore::ExtensionPrefs::extension_id() const {
+ std::string string_value;
+ DCHECK(dict_->GetString(kIdKey, &string_value));
+ return string_value;
+}
+
+DictionaryValue* ExtensionPrefStore::ExtensionPrefs::pref_values() {
+ DictionaryValue* value = NULL;
+ CHECK(dict_->GetDictionary(kPreferencesKey, &value));
+ return value;
+}
+
+void ExtensionPrefStore::ExtensionPrefs::Set(const std::string& key,
+ Value *value) {
+ if (value == NULL)
+ pref_values()->RemoveWithoutPathExpansion(key, NULL);
+ else
+ pref_values()->SetWithoutPathExpansion(key, value);
+}
+
+Value* ExtensionPrefStore::ExtensionPrefs::Get(const std::string& key) {
+ Value* value = NULL;
+ pref_values()->GetWithoutPathExpansion(key, &value);
+ return value;
+}
+
+
+// ExtensionStack implementation:
+
+ExtensionPrefStore::ExtensionStack::ExtensionStack()
+: list_(NULL) {}
+
+ExtensionPrefStore::ExtensionStack::~ExtensionStack() {}
+
+void ExtensionPrefStore::ExtensionStack::Init(ListValue* list) {
+ list_ = list;
+}
+
+bool ExtensionPrefStore::ExtensionStack::IsInitialized() const {
+ return list_ != NULL;
+}
+
+size_t ExtensionPrefStore::ExtensionStack::Size() const {
+ DCHECK(IsInitialized());
+ return list_->GetSize();
+}
+
+ExtensionPrefStore::ExtensionPrefs
+ ExtensionPrefStore::ExtensionStack::Get(int index) {
+ DCHECK(IsInitialized());
+ DictionaryValue* dict;
+ CHECK(list_->GetDictionary(index, &dict));
+ return ExtensionPrefs(dict);
+}
+
+void ExtensionPrefStore::ExtensionStack::Remove(int index) {
+ DCHECK(IsInitialized());
+ CHECK(list_->Remove(index, NULL));
+}
+
+ExtensionPrefStore::ExtensionPrefs
+ ExtensionPrefStore::ExtensionStack::CreateEntry(
+ const std::string& extension_id) {
+ DCHECK(IsInitialized());
+ list_->Insert(0, ExtensionPrefs::Create(extension_id));
+ return Get(0);
+}
+
+
+// ExtensionPrefStore implementation:
ExtensionPrefStore::ExtensionPrefStore(Profile* profile,
PrefNotifier::PrefStoreType type)
: prefs_(new DictionaryValue()),
profile_(profile),
+ dummy_prefs(profile ? NULL : new ListValue),
type_(type) {
RegisterObservers();
}
ExtensionPrefStore::~ExtensionPrefStore() {
- STLDeleteElements(&extension_stack_);
notification_registrar_.RemoveAll();
}
void ExtensionPrefStore::InstallExtensionPref(const Extension* extension,
const char* new_pref_path,
Value* new_pref_value) {
- ExtensionStack::iterator i;
- for (i = extension_stack_.begin(); i != extension_stack_.end(); ++i) {
- if ((*i)->extension == extension)
+ if (!extension_stack_.IsInitialized())
+ LazyInit();
+
+ int nr_extensions = extension_stack_.Size();
+ int i;
+ for (i = 0; i < nr_extensions; ++i) {
+ if (extension_stack_.Get(i).extension_id() == extension->id())
break;
}
// If this extension is not already in the stack, add it. Otherwise, update
// or add the value of this preference, but don't change the extension's
- // position in the stack. We store the extension even if this preference
- // isn't registered with our PrefService, so that the ordering of extensions
- // is consistent among all local-state and user ExtensionPrefStores.
- PrefService* pref_service = GetPrefService();
- // The pref_service may be NULL in unit testing.
- bool is_registered_pref = (pref_service == NULL ||
- pref_service->FindPreference(new_pref_path) != NULL);
- PrefValueMap* pref_values;
- if (i == extension_stack_.end()) {
- pref_values = new PrefValueMap();
- if (is_registered_pref)
- (*pref_values)[new_pref_path] = new_pref_value;
-
- ExtensionPrefs* extension_prefs = new ExtensionPrefs(extension,
- pref_values);
- extension_stack_.push_front(extension_prefs);
- } else if (is_registered_pref) {
- pref_values = (*i)->pref_values;
- delete (*pref_values)[new_pref_path];
- (*pref_values)[new_pref_path] = new_pref_value;
+ // position in the stack.
+ if (i == nr_extensions) {
+ ExtensionPrefs extension_prefs =
+ extension_stack_.CreateEntry(extension->id());
+ extension_prefs.Set(new_pref_path, new_pref_value);
+ } else {
+ ExtensionPrefs extension_prefs = extension_stack_.Get(i);
+ extension_prefs.Set(new_pref_path, new_pref_value);
}
// Apply the preference to our local |prefs_| store.
UpdateOnePref(new_pref_path);
+ SchedulePersist();
}
void ExtensionPrefStore::UninstallExtension(const Extension* extension) {
+ if (!extension_stack_.IsInitialized())
+ LazyInit();
+
// Remove this extension from the stack.
- for (ExtensionStack::iterator i = extension_stack_.begin();
- i != extension_stack_.end(); ++i) {
- if ((*i)->extension == extension) {
- scoped_ptr<ExtensionPrefs> to_be_deleted(*i);
- extension_stack_.erase(i);
- UpdatePrefs(to_be_deleted->pref_values);
+ for (int i = 0, n = extension_stack_.Size(); i < n; ++i) {
+ ExtensionPrefs extension_prefs = extension_stack_.Get(i);
+ if (extension_prefs.extension_id() == extension->id()) {
+ scoped_ptr<DictionaryValue> dict_values(
+ extension_prefs.pref_values()->DeepCopyWithoutEmptyChildren());
+ extension_stack_.Remove(i);
+ UpdatePrefs(dict_values.get());
+ SchedulePersist();
return;
}
}
}
+DictionaryValue* ExtensionPrefStore::prefs() const {
+ if (!extension_stack_.IsInitialized())
+ LazyInit();
+ return prefs_.get();
+}
+
void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) {
- for (ExtensionStack::iterator i = extension_stack_.begin();
- i != extension_stack_.end(); ++i) {
- (*result).push_back((*i)->extension->id());
- }
+ if (!extension_stack_.IsInitialized())
+ LazyInit();
+ for (int i = 0, n = extension_stack_.Size(); i < n; ++i)
+ result->push_back(extension_stack_.Get(i).extension_id());
}
// This could be sped up by keeping track of which extension currently controls
@@ -87,16 +191,6 @@ void ExtensionPrefStore::GetExtensionIDs(std::vector<std::string>* result) {
// installed extensions will be trying to control any preferences, so stick
// with this simpler algorithm until it causes a problem.
void ExtensionPrefStore::UpdateOnePref(const char* path) {
- PrefService* pref_service = GetPrefService();
-
- // There are at least two PrefServices, one for local state and one for
- // user prefs. (See browser_main.cc.) Different preferences are registered
- // in each; if this one doesn't have the desired pref registered, we ignore
- // it and let the other one handle it.
- // The pref_service may be NULL in unit testing.
- if (pref_service && !pref_service->FindPreference(path))
- return;
-
// Save the old value before removing it from the local cache.
Value* my_old_value_ptr = NULL;
prefs_->Get(path, &my_old_value_ptr);
@@ -110,16 +204,19 @@ void ExtensionPrefStore::UpdateOnePref(const char* path) {
// Find the first extension that wants to set this pref and use its value.
Value* my_new_value = NULL;
- for (ExtensionStack::iterator ext_iter = extension_stack_.begin();
- ext_iter != extension_stack_.end(); ++ext_iter) {
- PrefValueMap::iterator value_iter = (*ext_iter)->pref_values->find(path);
- if (value_iter != (*ext_iter)->pref_values->end()) {
- prefs_->Set(path, (*value_iter).second->DeepCopy());
- my_new_value = (*value_iter).second;
+ for (int i = 0, n = extension_stack_.Size(); i < n; ++i) {
+ DictionaryValue* pref_values = extension_stack_.Get(i).pref_values();
+ bool has_pref = pref_values->GetWithoutPathExpansion(path, &my_new_value);
+ if (has_pref) {
+ prefs_->Set(path, my_new_value->DeepCopy());
break;
}
}
+ // If any extension contained a value for |path| it is stored in my_new_value
+ // now.
+ // May be null in unit tests.
+ PrefService* pref_service = GetPrefService();
if (pref_service) {
bool value_changed = true;
if (!my_old_value.get() && !my_new_value) {
@@ -135,30 +232,41 @@ void ExtensionPrefStore::UpdateOnePref(const char* path) {
}
}
-void ExtensionPrefStore::UpdatePrefs(const PrefValueMap* pref_values) {
+void ExtensionPrefStore::UpdatePrefs(const DictionaryValue* pref_values) {
if (!pref_values)
return;
- for (PrefValueMap::const_iterator i = pref_values->begin();
- i != pref_values->end(); ++i) {
- UpdateOnePref(i->first);
+ for (DictionaryValue::key_iterator i = pref_values->begin_keys();
+ i != pref_values->end_keys(); ++i) {
+ UpdateOnePref((*i).c_str());
}
}
-PrefService* ExtensionPrefStore::GetPrefService() {
- if (profile_)
- return profile_->GetPrefs();
- return g_browser_process->local_state();
+PrefService* ExtensionPrefStore::GetPrefService() const {
+ // In case of local state, there is no profile nor pref service.
+ if (!profile_)
+ return NULL;
+ return profile_->GetPrefs();
+}
+
+void ExtensionPrefStore::SchedulePersist() {
+ PrefService* prefService = GetPrefService();
+ if (prefService)
+ prefService->ScheduleSavePersistentPrefs();
}
void ExtensionPrefStore::RegisterObservers() {
+ // If profile_ is NULL, this ExtensionPrefStore is for local-state.
+ if (!profile_)
+ return;
+
notification_registrar_.Add(this,
NotificationType::EXTENSION_PREF_CHANGED,
- NotificationService::AllSources());
+ Source<Profile>(profile_));
notification_registrar_.Add(this,
NotificationType::EXTENSION_UNLOADED,
- NotificationService::AllSources());
+ Source<Profile>(profile_));
}
void ExtensionPrefStore::Observe(NotificationType type,
@@ -166,22 +274,15 @@ void ExtensionPrefStore::Observe(NotificationType type,
const NotificationDetails& details) {
switch (type.value) {
case NotificationType::EXTENSION_PREF_CHANGED: {
- Profile* extension_profile = Source<Profile>(source).ptr();
- // The ExtensionPrefStore for the local state watches all profiles.
- if (!profile_ || profile_ == extension_profile) {
- ExtensionPrefStore::ExtensionPrefDetails* data =
- Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr();
- InstallExtensionPref(data->first, data->second.first,
- data->second.second);
- }
+ ExtensionPrefStore::ExtensionPrefDetails* data =
+ Details<ExtensionPrefStore::ExtensionPrefDetails>(details).ptr();
+ InstallExtensionPref(data->first, data->second.first,
+ data->second.second);
break;
}
case NotificationType::EXTENSION_UNLOADED: {
- Profile* extension_profile = Source<Profile>(source).ptr();
const Extension* extension = Details<const Extension>(details).ptr();
- // The ExtensionPrefStore for the local state watches all profiles.
- if (profile_ == NULL || profile_ == extension_profile)
- UninstallExtension(extension);
+ UninstallExtension(extension);
break;
}
default: {
@@ -190,10 +291,33 @@ void ExtensionPrefStore::Observe(NotificationType type,
}
}
-ExtensionPrefStore::ExtensionPrefs::ExtensionPrefs(const Extension* extension,
- PrefValueMap* values) : extension(extension), pref_values(values) {}
+void ExtensionPrefStore::LazyInit() const {
+ // If profile_==NULL, this ExtensionPrefStore is for local-state.
+ DCHECK(!extension_stack_.IsInitialized())
+ << "LazyInit called even though extension_stack_ is already initialized";
+
+ PrefService* pref_service = GetPrefService();
+ if (!pref_service) {
+ extension_stack_.Init(dummy_prefs.get());
+ return;
+ }
+ pref_service->RegisterListPref(kExtensionPreferencesKey);
+
+ scoped_ptr<ListValue> dict(
+ pref_service->GetMutableList(kExtensionPreferencesKey));
+
+ extension_stack_.Init(dict.release());
-ExtensionPrefStore::ExtensionPrefs::~ExtensionPrefs() {
- STLDeleteValues(pref_values);
- delete pref_values;
+ for (int i = 0, n = extension_stack_.Size(); i < n; ++i) {
+ DictionaryValue* pref_values = extension_stack_.Get(i).pref_values();
+ for (DictionaryValue::key_iterator iter = pref_values->begin_keys();
+ iter != pref_values->end_keys(); ++iter) {
+ const std::string& key = *iter;
+ if (!prefs_->HasKey(key)) {
+ Value *value;
+ if (pref_values->GetWithoutPathExpansion(key, &value))
+ prefs_->Set(key, value->DeepCopy());
+ }
+ }
+ }
}
« no previous file with comments | « chrome/browser/extensions/extension_pref_store.h ('k') | chrome/browser/extensions/extension_pref_store_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698