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

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: Addressed Mattias' comments 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 96e497f2e1bc8e913d696b887332ed2f4ae45811..75dd5be70f8c1dd3f7e3239ce9c75fa6c3dc9f3b 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -7,6 +7,7 @@
#include "base/string_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/profile.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/notification_service.h"
@@ -91,6 +92,14 @@ const char kPrefGrantedPermissionsAPI[] = "granted_permissions.api";
const char kPrefGrantedPermissionsHost[] = "granted_permissions.host";
const char kPrefGrantedPermissionsAll[] = "granted_permissions.full";
+// 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. The value is a dictionary mapping (non-expanded) preference keys
+// to the values configured by the extension.
+const char kPrefPreferences[] = "preferences";
Aaron Boodman 2010/12/03 08:58:10 I think it is OK to assume the reader has read the
battre (please use the other) 2010/12/03 19:32:58 Done.
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -133,14 +142,19 @@ static void ExtentToStringSet(const ExtensionExtent& host_extent,
} // namespace
-ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir)
- : prefs_(prefs),
+ExtensionPrefs::ExtensionPrefs(Profile* profile,
+ const FilePath& root_dir)
+ : profile_(profile),
+ prefs_(NULL),
install_directory_(root_dir) {
+ prefs_ = profile_->GetPrefs();
// TODO(asargent) - Remove this in a couple of months. (See comment above
// CleanupBadExtensionKeys).
- CleanupBadExtensionKeys(prefs);
+ CleanupBadExtensionKeys(prefs_);
MakePathsRelative();
+
+ InstallPersistedExtensionControlledPrefs();
}
ExtensionPrefs::~ExtensionPrefs() {}
@@ -642,7 +656,7 @@ void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
}
std::vector<std::string> ExtensionPrefs::GetToolbarOrder() {
- std::vector<std::string> extension_ids;
+ ExtensionPrefs::ExtensionIdSet extension_ids;
const ListValue* toolbar_order = prefs_->GetList(kExtensionToolbar);
if (toolbar_order) {
for (size_t i = 0; i < toolbar_order->GetSize(); ++i) {
@@ -669,12 +683,18 @@ void ExtensionPrefs::OnExtensionInstalled(
const Extension* extension, Extension::State initial_state,
bool initial_incognito_enabled) {
const std::string& id = extension->id();
+ const base::Time install_time = 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(install_time.ToInternalValue())));
+ UpdateExtensionPref(id, kPrefPreferences, new DictionaryValue());
+
FilePath::StringType path = MakePathRelative(install_directory_,
extension->path(), NULL);
UpdateExtensionPref(id, kPrefPath, Value::CreateStringValue(path));
@@ -692,6 +712,9 @@ void ExtensionPrefs::OnExtensionInstalled(
void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
const Extension::Location& location,
bool external_uninstall) {
+ PrefKeySet pref_keys;
+ GetExtensionControlledPrefKeys(extension_id, &pref_keys);
+
// For external extensions, we save a preference reminding ourself not to try
// and install the extension anymore (except when |external_uninstall| is
// true, which signifies that the registry key was deleted or the pref file
@@ -703,10 +726,12 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
} else {
DeleteExtensionPrefs(extension_id);
}
+
+ UpdateWinningPrefs(pref_keys);
}
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.
@@ -727,6 +752,11 @@ void ExtensionPrefs::SetExtensionState(const Extension* extension,
Extension::State state) {
UpdateExtensionPref(extension->id(), kPrefState,
Value::CreateIntegerValue(state));
+
+ PrefKeySet pref_keys;
+ GetExtensionControlledPrefKeys(extension->id(), &pref_keys);
+ UpdateWinningPrefs(pref_keys);
+
SavePrefsAndNotify();
}
@@ -830,6 +860,18 @@ DictionaryValue* ExtensionPrefs::GetExtensionPref(
return extension;
}
+DictionaryValue* ExtensionPrefs::GetExtensionControlledPrefs(
+ const std::string& extension_id) const {
+ DictionaryValue* extension = GetExtensionPref(extension_id);
+
+ // If the extension doesn't have a pref, it's a --load-extension.
+ if (!extension)
+ return NULL;
+ DictionaryValue* preferences = NULL;
+ extension->GetDictionary(kPrefPreferences, &preferences);
+ return preferences;
+}
+
// Helper function for GetInstalledExtensionsInfo.
static ExtensionInfo* GetInstalledExtensionInfoImpl(
DictionaryValue* extension_data,
@@ -1089,6 +1131,191 @@ 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 std::string& extension_id) const {
+ const DictionaryValue* extension = GetExtensionPref(extension_id);
+
+ // If the extension doesn't have a pref, it's a --load-extension.
+ if (!extension)
+ return base::Time::Time();
+ 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::GetEnabledExtensions(ExtensionIdSet* out) const {
+ DCHECK(out);
+ const DictionaryValue* extensions =
+ pref_service()->GetDictionary(kExtensionsPref);
+
+ for (DictionaryValue::key_iterator ext_id = extensions->begin_keys();
+ ext_id != extensions->end_keys(); ++ext_id) {
+ if (GetExtensionState(*ext_id) != Extension::ENABLED)
+ continue;
+ out->push_back(*ext_id);
+ }
+}
+
+void ExtensionPrefs::FixMissingPrefs(const ExtensionIdSet& extension_ids) {
+ // Fix old entries that did not get an installation time entry when they
+ // were installed or don't have a preferences field.
+ bool persist_required = false;
+ for (ExtensionIdSet::const_iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ DictionaryValue* extension = GetExtensionPref(*ext_id);
+ // If the extension doesn't have a pref, it's a --load-extension.
+ if (extension == NULL)
+ continue;
+
+ if (GetInstallTime(*ext_id) == base::Time::Time()) {
+ const base::Time install_time = GetCurrentTime();
+ extension->Set(kPrefInstallTime,
+ Value::CreateStringValue(
+ base::Int64ToString(install_time.ToInternalValue())));
+ persist_required = true;
+ }
+ }
+ if (persist_required)
+ SavePrefsAndNotify();
+}
+
+void ExtensionPrefs::InstallPersistedExtensionControlledPrefs() {
+ // When this is called, the PrefService is initialized and provides access
+ // to the user preferences stored in a JSON file.
+ ExtensionIdSet extension_ids;
+ GetEnabledExtensions(&extension_ids);
+ FixMissingPrefs(extension_ids);
+
+ // Collect the unique extension controlled preference keys of all extensions.
+ PrefKeySet ext_controlled_prefs;
+ for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ GetExtensionControlledPrefKeys(*ext_id, &ext_controlled_prefs);
+ }
+ std::sort(ext_controlled_prefs.begin(), ext_controlled_prefs.end());
Aaron Boodman 2010/12/03 08:58:10 Did you consider having PrefKeySet actually be a s
battre (please use the other) 2010/12/03 19:32:58 Done.
+ PrefKeySet unique_ext_controlled_prefs;
+ std::unique_copy(ext_controlled_prefs.begin(),
+ ext_controlled_prefs.end(),
+ std::back_insert_iterator<PrefKeySet>(
+ unique_ext_controlled_prefs));
+
+ // Store winning preference for each extension controlled preference.
+ UpdateWinningPrefs(unique_ext_controlled_prefs);
+}
+
+const Value* ExtensionPrefs::WinningExtensionControlledPrefValue(
+ const std::string& key) const {
+ Value *winner = NULL;
+ base::Time winners_install_time = base::Time::Time();
+
+ ExtensionIdSet extension_ids;
+ GetEnabledExtensions(&extension_ids);
+ for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
+ base::Time extension_install_time = GetInstallTime(*ext_id);
+
+ // 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_id);
+ Value *value = NULL;
+ if (preferences && 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::UpdateWinningPrefs(
+ const ExtensionPrefs::PrefKeySet& pref_keys) {
+ for (PrefKeySet::const_iterator i = pref_keys.begin();
+ i != pref_keys.end(); ++i)
+ UpdateWinningPref(*i);
+}
+
+void ExtensionPrefs::UpdateWinningPref(const std::string& pref_key) {
+ PrefStore* extension_pref_store = profile_->GetExtensionPrefStore();
+ if (extension_pref_store == NULL)
+ return; // Profile is being shut down, Pref Service is already gone.
+ const Value* winning_pref_value =
+ WinningExtensionControlledPrefValue(pref_key);
+ Value* old_value = NULL;
+ extension_pref_store->prefs()->Get(pref_key, &old_value);
+ bool changed = !Value::Equals(winning_pref_value, old_value);
+
+ if (winning_pref_value) {
+ extension_pref_store->prefs()->Set(pref_key,
+ winning_pref_value->DeepCopy());
+ } else {
+ extension_pref_store->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) {
+ DCHECK(pref_service()->FindPreference(pref_key.c_str()))
+ << "Extension controlled preference key " << pref_key
+ << " not registered.";
+ DictionaryValue* extension_preferences =
+ GetExtensionControlledPrefs(extension_id);
+
+ if (extension_preferences == NULL) { // May be pruned when writing to disk.
+ DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (extension == NULL) {
+ LOG(WARNING) << "Not setting preference for " << pref_key
Aaron Boodman 2010/12/03 08:58:10 This warning doesn't seem quite right... We do sto
battre (please use the other) 2010/12/03 19:32:58 Done.
+ << " because extension is --load-extension initiated.";
+ return;
+ }
+ extension_preferences = new DictionaryValue;
+ extension->Set(kPrefPreferences, extension_preferences);
+ }
+
+ Value* oldValue = NULL;
+ extension_preferences->GetWithoutPathExpansion(pref_key, &oldValue);
+ bool modified = !Value::Equals(oldValue, value);
+ if (!modified)
+ return;
+
+ if (value == NULL)
+ extension_preferences->RemoveWithoutPathExpansion(pref_key, NULL);
+ else
+ extension_preferences->SetWithoutPathExpansion(pref_key, value);
+ pref_service()->ScheduleSavePersistentPrefs();
+
+ UpdateWinningPref(pref_key);
+}
+
+void ExtensionPrefs::GetExtensionControlledPrefKeys(
+ const std::string& extension_id, PrefKeySet *out) const {
+ DCHECK(out != NULL);
+ DictionaryValue* ext_prefs = GetExtensionControlledPrefs(extension_id);
+ if (ext_prefs) {
+ for (DictionaryValue::key_iterator i = ext_prefs->begin_keys();
+ i != ext_prefs->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