| Index: chrome/browser/extensions/extension_prefs.cc
|
| diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
|
| index 07195e42e189765006377726e936e68b8426f145..2a31019edb90d81f4f232005a4a96d3b3d1ed9b3 100644
|
| --- a/chrome/browser/extensions/extension_prefs.cc
|
| +++ b/chrome/browser/extensions/extension_prefs.cc
|
| @@ -92,6 +92,12 @@ 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 contains any extension-controlled preferences.
|
| +const char kPrefPreferences[] = "preferences";
|
| +
|
| } // namespace
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -139,9 +145,11 @@ ExtensionPrefs::ExtensionPrefs(PrefService* prefs, const FilePath& root_dir)
|
| install_directory_(root_dir) {
|
| // TODO(asargent) - Remove this in a couple of months. (See comment above
|
| // CleanupBadExtensionKeys).
|
| - CleanupBadExtensionKeys(prefs);
|
| + CleanupBadExtensionKeys(prefs_);
|
|
|
| MakePathsRelative();
|
| +
|
| + InitPrefStore();
|
| }
|
|
|
| ExtensionPrefs::~ExtensionPrefs() {}
|
| @@ -643,7 +651,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) {
|
| @@ -670,12 +678,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));
|
| @@ -693,6 +707,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
|
| @@ -704,10 +721,12 @@ void ExtensionPrefs::OnExtensionUninstalled(const std::string& extension_id,
|
| } else {
|
| DeleteExtensionPrefs(extension_id);
|
| }
|
| +
|
| + UpdatePrefStore(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.
|
| @@ -728,6 +747,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);
|
| + UpdatePrefStore(pref_keys);
|
| +
|
| SavePrefsAndNotify();
|
| }
|
|
|
| @@ -831,6 +855,18 @@ DictionaryValue* ExtensionPrefs::GetExtensionPref(
|
| return extension;
|
| }
|
|
|
| +DictionaryValue* ExtensionPrefs::GetExtensionControlledPrefs(
|
| + const std::string& extension_id) const {
|
| + DictionaryValue* extension = GetExtensionPref(extension_id);
|
| + if (!extension) {
|
| + NOTREACHED();
|
| + return NULL;
|
| + }
|
| + DictionaryValue* preferences = NULL;
|
| + extension->GetDictionary(kPrefPreferences, &preferences);
|
| + return preferences;
|
| +}
|
| +
|
| // Helper function for GetInstalledExtensionsInfo.
|
| static ExtensionInfo* GetInstalledExtensionInfoImpl(
|
| DictionaryValue* extension_data,
|
| @@ -1090,6 +1126,184 @@ 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 (!extension) {
|
| + NOTREACHED();
|
| + 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 {
|
| + CHECK(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);
|
| + CHECK(extension);
|
| +
|
| + 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::InitPrefStore() {
|
| + // 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);
|
| + }
|
| +
|
| + // Store winning preference for each extension controlled preference.
|
| + UpdatePrefStore(ext_controlled_prefs);
|
| +}
|
| +
|
| +const Value* ExtensionPrefs::GetWinningExtensionControlledPrefValue(
|
| + 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::UpdatePrefStore(
|
| + const ExtensionPrefs::PrefKeySet& pref_keys) {
|
| + for (PrefKeySet::const_iterator i = pref_keys.begin();
|
| + i != pref_keys.end(); ++i) {
|
| + UpdatePrefStore(*i);
|
| + }
|
| +}
|
| +
|
| +void ExtensionPrefs::UpdatePrefStore(const std::string& pref_key) {
|
| + PrefStore* extension_pref_store =
|
| + pref_service()->GetExtensionPrefStore();
|
| + if (extension_pref_store == NULL)
|
| + return; // Profile is being shut down, Pref Service is already gone.
|
| + const Value* winning_pref_value =
|
| + GetWinningExtensionControlledPrefValue(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(ERROR) << "Extension preference for " << extension_id << " undefined";
|
| + 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();
|
| +
|
| + UpdatePrefStore(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->insert(*i);
|
| + }
|
| + }
|
| +}
|
| +
|
| // static
|
| void ExtensionPrefs::RegisterUserPrefs(PrefService* prefs) {
|
| prefs->RegisterDictionaryPref(kExtensionsPref);
|
|
|