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

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

Issue 5213002: 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: Fixed Mac compile issue 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_prefs.cc
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 3c789b094fa88fcce2fcb8526a45694e5e428fb3..8a0b45b9e6899e96e26b8f9553ea418db86c55cd 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -8,6 +8,7 @@
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/in_memory_pref_store.h"
#include "chrome/common/pref_names.h"
using base::Time;
@@ -78,6 +79,13 @@ const char kPrefAppLaunchIndex[] = "app_launcher_index";
// "A preference for storing extra data sent in update checks for an extension.
const char kUpdateUrlData[] = "update_url_data";
+// A preference that indicates when an extension was installed.
+const char kPrefInstallTime[] = "install_time";
+
+// A preference that indicates the last effective preference values of an
+// extension.
Mattias Nissler (ping if slow) 2010/11/18 16:30:33 Maybe add "The value is a dictionary mapping prefe
battre (please use the other) 2010/11/18 16:47:33 Done.
+const char kPrefPreferences[] = "preferences";
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -119,6 +127,8 @@ ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir)
CleanupBadExtensionKeys(prefs);
MakePathsRelative();
+
+ InstallPersistedExtensionControlledPrefs();
}
ExtensionPrefs::~ExtensionPrefs() {}
@@ -524,12 +534,18 @@ void ExtensionPrefs::OnExtensionInstalled(
const Extension* extension, Extension::State initial_state,
bool initial_incognito_enabled) {
const std::string& id = extension->id();
+ const base::Time installTime = GetCurrentTime();
UpdateExtensionPref(id, kPrefState,
Value::CreateIntegerValue(initial_state));
UpdateExtensionPref(id, kPrefIncognitoEnabled,
Value::CreateBooleanValue(initial_incognito_enabled));
UpdateExtensionPref(id, kPrefLocation,
Value::CreateIntegerValue(extension->location()));
+ UpdateExtensionPref(id, kPrefInstallTime,
+ Value::CreateStringValue(
+ base::Int64ToString(installTime.ToInternalValue())));
+ UpdateExtensionPref(id, kPrefPreferences, new DictionaryValue());
+
FilePath::StringType path = MakePathRelative(install_directory_,
extension->path(), NULL);
UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path));
@@ -551,6 +567,10 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
// and install the extension anymore (except when |external_uninstall| is
// true, which signifies that the registry key was deleted or the pref file
// no longer lists the extension).
+
+ std::vector<std::string> prefKeys;
+ GetExtensionControlledPrefKeys(extension_id, &prefKeys);
+
if (!external_uninstall && Extension::IsExternalLocation(location)) {
UpdateExtensionPref(extension_id, kPrefState,
Value::CreateIntegerValue(Extension::KILLBIT));
@@ -558,10 +578,15 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
} else {
DeleteExtensionPrefs(extension_id);
}
+
+ for (std::vector<std::string>::iterator i = prefKeys.begin();
+ i != prefKeys.end(); ++i) {
+ UpdateWinningPref(*i);
+ }
}
Extension::State ExtensionPrefs::GetExtensionState(
- const std::string& extension_id) {
+ const std::string& extension_id) const {
DictionaryValue* extension = GetExtensionPref(extension_id);
// If the extension doesn't have a pref, it's a --load-extension.
@@ -582,6 +607,14 @@ void ExtensionPrefs::SetExtensionState(const Extension* extension,
Extension::State state) {
UpdateExtensionPref(extension->id(), kPrefState,
Value::CreateIntegerValue(state));
+
+ std::vector<std::string> prefKeys;
+ GetExtensionControlledPrefKeys(extension->id(), &prefKeys);
+ for (std::vector<std::string>::iterator i = prefKeys.begin();
+ i != prefKeys.end(); ++i) {
+ UpdateWinningPref(*i);
+ }
+
SavePrefsAndNotify();
}
@@ -661,6 +694,16 @@ DictionaryValue* ExtensionPrefs::GetExtensionPref(
return extension;
}
+DictionaryValue* ExtensionPrefs::GetExtensionControlledPrefs(
+ const std::string& extension_id) const {
+ DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return NULL;
+ DictionaryValue* preferences = NULL;
+ extension->GetDictionary(kPrefPreferences, &preferences);
+ return preferences;
+}
+
// Helper function for GetInstalledExtensionsInfo.
static ExtensionInfo* GetInstalledExtensionInfoImpl(
DictionaryValue* extension_data,
@@ -920,6 +963,189 @@ std::string ExtensionPrefs::GetUpdateUrlData(const std::string& extension_id) {
return data;
}
+base::Time ExtensionPrefs::GetCurrentTime() const {
+ return base::Time::Now();
+}
+
+base::Time ExtensionPrefs::GetInstallTime(const DictionaryValue* extension)
+ const {
+ DCHECK(extension);
+ std::string install_time_str("0");
+ extension->GetString(kPrefInstallTime, &install_time_str);
+ int64 install_time_i64 = 0;
+ base::StringToInt64(install_time_str, &install_time_i64);
+ LOG_IF(ERROR, install_time_i64 == 0)
+ << "Error parsing installation time of an extension";
+ return base::Time::FromInternalValue(install_time_i64);
+}
+
+void ExtensionPrefs::InstallPersistedExtensionControlledPrefs() {
+ // When this is called, the PrefService is initialized and provides access
+ // to the user preferences stored in a JSON file. We take the persisted
+ // preferences of all extensions, calculate the effective preferences
+ // (considering that one extension overrides preferences of other extensions)
+ // and store the effective preferences in the PrefService.
+
+ const DictionaryValue* extensions =
+ pref_service()->GetDictionary(kExtensionsPref);
+
+ // Collect extensions, sorted by time (latest installed appears last).
+ std::vector<DictionaryValue*> sorted_extensions;
+ for (DictionaryValue::key_iterator ext_id = extensions->begin_keys();
+ ext_id != extensions->end_keys(); ++ext_id) {
+ if (GetExtensionState(*ext_id) != Extension::ENABLED)
+ continue;
+
+ DictionaryValue* extension = GetExtensionPref(*ext_id);
+ CHECK(extension != NULL);
+
+ if (GetInstallTime(extension) == base::Time::FromInternalValue(0)) {
+ // Fix old entry that did not get an installation time entry when
+ // it was installed.
+ const base::Time installTime = GetCurrentTime();
+ extension->Set(kPrefInstallTime,
+ Value::CreateStringValue(
+ base::Int64ToString(installTime.ToInternalValue())));
+ SavePrefsAndNotify();
+ }
+ DictionaryValue* dummy_prefs;
+ if (!extension->GetDictionary(kPrefPreferences, &dummy_prefs)) {
+ extension->Set(kPrefPreferences, new DictionaryValue());
+ }
+
+ // Currently we sort only by time, no tie-breaker.
+ std::vector<DictionaryValue*>::iterator insert_pos =
+ sorted_extensions.begin();
+ while (insert_pos != sorted_extensions.end() &&
+ GetInstallTime(extension) > GetInstallTime(*insert_pos)) {
+ ++insert_pos;
+ }
+ sorted_extensions.insert(insert_pos, extension);
+ }
+
+ // Collect all effective preferences (later ones override newer ones).
+ scoped_ptr<DictionaryValue> merged_non_expanded(new DictionaryValue);
+ for (std::vector<DictionaryValue*>::iterator i = sorted_extensions.begin();
+ i != sorted_extensions.end(); ++i) {
+ DictionaryValue* preferences;
+ if ((*i)->GetDictionary(kPrefPreferences, &preferences))
+ merged_non_expanded->MergeDictionary(preferences);
+ }
+
+ // Expand all keys.
+ scoped_ptr<InMemoryPrefStore> extension_prefs(new InMemoryPrefStore);
+ for (DictionaryValue::key_iterator prefkey =
+ merged_non_expanded->begin_keys();
+ prefkey != merged_non_expanded->end_keys();
+ ++prefkey) {
+ Value* value;
+ CHECK(merged_non_expanded->GetWithoutPathExpansion(*prefkey, &value));
+ extension_prefs->prefs()->Set(*prefkey, value->DeepCopy());
+ }
+
+ // Store result in pref service.
+ pref_service()->pref_value_store()->ReplaceExtensionPrefStore(
+ extension_prefs.release());
+}
+
+namespace subtle {
+static bool equalValues(const Value* a, const Value* b) {
+ if ((a == NULL) && (b == NULL)) return true;
+ if ((a == NULL) ^ (b == NULL)) return false;
+ return a->Equals(b);
+}
+}
+
+const Value* ExtensionPrefs::WinningExtensionControlledPrefValue(
+ const std::string& key) const {
+ Value *winner = NULL;
+ int64 winners_install_time = 0;
+
+ const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+ for (DictionaryValue::key_iterator ext_iter = extensions->begin_keys();
+ ext_iter != extensions->end_keys(); ++ext_iter) {
+ if (GetExtensionState(*ext_iter) != Extension::ENABLED)
+ continue;
+
+ DictionaryValue* extension = GetExtensionPref(*ext_iter);
+ CHECK(extension);
+
+ std::string extension_install_time_s = "0";
+ extension->GetString(kPrefInstallTime, &extension_install_time_s);
+ int64 extension_install_time = 0;
+ base::StringToInt64(extension_install_time_s, &extension_install_time);
+
+ // We do not need to consider extensions that were installed before the
+ // most recent extension found that provides the requested preference.
+ if (extension_install_time < winners_install_time) {
+ continue;
+ }
+
+ DictionaryValue* preferences = GetExtensionControlledPrefs(*ext_iter);
+ CHECK(preferences);
+
+ Value *value = NULL;
+ if (preferences->GetWithoutPathExpansion(key, &value)) {
+ // This extension is more recent than the last one providing this pref.
+ winner = value;
+ winners_install_time = extension_install_time;
+ }
+ }
+ return winner;
+}
+
+void ExtensionPrefs::UpdateWinningPref(const std::string& pref_key) {
+ PrefStore* extensionPrefStore =
+ pref_service()->pref_value_store()->GetExtensionPrefStore();
+ const Value* winningPrefValue = WinningExtensionControlledPrefValue(pref_key);
+ Value* oldValue = NULL;
+ extensionPrefStore->prefs()->Get(pref_key, &oldValue);
+ bool changed = !subtle::equalValues(winningPrefValue, oldValue);
+
+ if (winningPrefValue) {
+ extensionPrefStore->prefs()->Set(pref_key, winningPrefValue->DeepCopy());
+ } else {
+ extensionPrefStore->prefs()->Remove(pref_key, NULL);
+ }
+
+ if (changed)
+ pref_service()->pref_notifier()->OnPreferenceSet(
+ pref_key.c_str(), PrefNotifier::EXTENSION_STORE);
+}
+
+void ExtensionPrefs::SetExtensionControlledPref(const std::string& extension_id,
+ const std::string& pref_key,
+ Value* value) {
+ DictionaryValue* extensionPreferences =
+ GetExtensionControlledPrefs(extension_id);
+
+ Value* oldValue = NULL;
+ extensionPreferences->GetWithoutPathExpansion(pref_key, &oldValue);
+ bool modified = subtle::equalValues(oldValue, value);
+
+ if (value == NULL)
+ extensionPreferences->RemoveWithoutPathExpansion(pref_key, NULL);
+ else
+ extensionPreferences->SetWithoutPathExpansion(pref_key, value);
+
+ if (modified)
+ pref_service()->ScheduleSavePersistentPrefs();
+
+ UpdateWinningPref(pref_key);
+}
+
+void ExtensionPrefs::GetExtensionControlledPrefKeys(
+ const std::string& extension_id, std::vector<std::string> *out) const {
+ DCHECK(out != NULL);
+ DictionaryValue* extPrefs = GetExtensionControlledPrefs(extension_id);
+ if (extPrefs) {
+ for (DictionaryValue::key_iterator i = extPrefs->begin_keys();
+ i != extPrefs->end_keys(); ++i) {
+ out->push_back(*i);
+ }
+ }
+}
+
// static
void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterDictionaryPref(kExtensionsPref);

Powered by Google App Engine
This is Rietveld 408576698