summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 03:10:34 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 03:10:34 +0000
commit7387509129d02968481c9cd912ab60c79bd6deea (patch)
tree1cb2e357aea3217dc79f83d98528b65280d2bf21 /chrome/browser/extensions
parent653a73f611d9c3c69be17fdafcce6e41328df18a (diff)
downloadchromium_src-7387509129d02968481c9cd912ab60c79bd6deea.zip
chromium_src-7387509129d02968481c9cd912ab60c79bd6deea.tar.gz
chromium_src-7387509129d02968481c9cd912ab60c79bd6deea.tar.bz2
Revert r18661.
Broke purify and mac valgrind. "Pull Extension-related prefs into its own class. Also add a notification for when the extensions service has finished its initial load of extensions, separate from EXTENSIONS_LOADED.TEST=noneBUG=none" Review URL: http://codereview.chromium.org/132008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18682 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/extension_prefs.cc184
-rw-r--r--chrome/browser/extensions/extension_prefs.h85
-rw-r--r--chrome/browser/extensions/extensions_service.cc273
-rw-r--r--chrome/browser/extensions/extensions_service.h45
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc6
-rw-r--r--chrome/browser/extensions/user_script_master.cc10
-rw-r--r--chrome/browser/extensions/user_script_master.h4
7 files changed, 244 insertions, 363 deletions
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
deleted file mode 100644
index d4de0d5..0000000
--- a/chrome/browser/extensions/extension_prefs.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/extension_prefs.h"
-
-#include "base/string_util.h"
-#include "chrome/common/extensions/extension.h"
-
-namespace {
-
-// Preferences keys
-
-// A preference that keeps track of per-extension settings. This is a dictionary
-// object read from the Preferences file, keyed off of extension id's.
-const wchar_t kExtensionsPref[] = L"extensions.settings";
-
-// Where an extension was installed from. (see Extension::Location)
-const wchar_t kPrefLocation[] = L"location";
-
-// Enabled, disabled, killed, etc. (see Extension::State)
-const wchar_t kPrefState[] = L"state";
-
-// The path to the current version's manifest file.
-const wchar_t kPrefPath[] = L"path";
-
-// A preference that tracks extension shelf configuration. This is a list
-// object read from the Preferences file, containing a list of toolstrip URLs.
-const wchar_t kExtensionShelf[] = L"extensions.shelf";
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-InstalledExtensions::InstalledExtensions(ExtensionPrefs* prefs) {
- extension_data_ = prefs->CopyCurrentExtensions();
-}
-
-void InstalledExtensions::VisitInstalledExtensions(
- InstalledExtensions::Callback *callback) {
- DictionaryValue::key_iterator extension_id = extension_data_->begin_keys();
- for (; extension_id != extension_data_->end_keys(); ++extension_id) {
- DictionaryValue* ext;
- if (!extension_data_->GetDictionary(*extension_id, &ext)) {
- LOG(WARNING) << "Invalid pref for extension " << *extension_id;
- NOTREACHED();
- continue;
- }
- FilePath::StringType path;
- if (!ext->GetString(kPrefPath, &path)) {
- LOG(WARNING) << "Missing path pref for extension " << *extension_id;
- NOTREACHED();
- continue;
- }
- int location_value;
- if (!ext->GetInteger(kPrefLocation, &location_value)) {
- LOG(WARNING) << "Missing location pref for extension " << *extension_id;
- NOTREACHED();
- continue;
- }
- Extension::Location location =
- static_cast<Extension::Location>(location_value);
- callback->Run(WideToASCII(*extension_id), FilePath(path), location);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-ExtensionPrefs::ExtensionPrefs(PrefService* prefs) : prefs_(prefs) {
- if (!prefs_->FindPreference(kExtensionsPref))
- prefs_->RegisterDictionaryPref(kExtensionsPref);
- if (!prefs->FindPreference(kExtensionShelf))
- prefs->RegisterListPref(kExtensionShelf);
-}
-
-DictionaryValue* ExtensionPrefs::CopyCurrentExtensions() {
- const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
- if (extensions) {
- DictionaryValue* copy =
- static_cast<DictionaryValue*>(extensions->DeepCopy());
- return copy;
- }
- return new DictionaryValue;
-}
-
-void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) {
- const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
- if (!dict || dict->GetSize() == 0)
- return;
-
- for (DictionaryValue::key_iterator i = dict->begin_keys();
- i != dict->end_keys(); ++i) {
- std::wstring key_name = *i;
- if (!Extension::IdIsValid(WideToASCII(key_name))) {
- LOG(WARNING) << "Invalid external extension ID encountered: "
- << WideToASCII(key_name);
- continue;
- }
-
- DictionaryValue* extension = NULL;
- if (!dict->GetDictionary(key_name, &extension)) {
- NOTREACHED();
- continue;
- }
-
- // Check to see if the extension has been killed.
- int state;
- if (extension->GetInteger(kPrefState, &state) &&
- state == static_cast<int>(Extension::KILLBIT)) {
- StringToLowerASCII(&key_name);
- killed_ids->insert(WideToASCII(key_name));
- }
- }
-}
-
-ExtensionPrefs::URLList ExtensionPrefs::GetShelfToolstripOrder() {
- URLList urls;
- const ListValue* toolstrip_urls = prefs_->GetList(kExtensionShelf);
- if (toolstrip_urls) {
- for (size_t i = 0; i < toolstrip_urls->GetSize(); ++i) {
- std::string url;
- if (toolstrip_urls->GetString(i, &url))
- urls.push_back(GURL(url));
- }
- }
- return urls;
-}
-
-void ExtensionPrefs::OnExtensionInstalled(Extension* extension) {
- std::string id = extension->id();
- UpdateExtensionPref(id, kPrefState,
- Value::CreateIntegerValue(Extension::ENABLED));
- UpdateExtensionPref(id, kPrefLocation,
- Value::CreateIntegerValue(extension->location()));
- UpdateExtensionPref(id, kPrefPath,
- Value::CreateStringValue(extension->path().value()));
- prefs_->ScheduleSavePersistentPrefs();
-}
-
-void ExtensionPrefs::OnExtensionUninstalled(const Extension* extension) {
- // For external extensions, we save a preference reminding ourself not to try
- // and install the extension anymore.
- if (Extension::IsExternalLocation(extension->location())) {
- UpdateExtensionPref(extension->id(), kPrefState,
- Value::CreateIntegerValue(Extension::KILLBIT));
- prefs_->ScheduleSavePersistentPrefs();
- } else {
- DeleteExtensionPrefs(extension->id());
- }
-}
-
-bool ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
- const std::wstring& key,
- Value* data_value) {
- DictionaryValue* extension = GetOrCreateExtensionPref(extension_id);
- if (!extension->Set(key, data_value)) {
- NOTREACHED() << L"Cannot modify key: '" << key.c_str()
- << "' for extension: '" << extension_id.c_str() << "'";
- return false;
- }
- return true;
-}
-
-void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
- std::wstring id = ASCIIToWide(extension_id);
- DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
- if (dict->HasKey(id)) {
- dict->Remove(id, NULL);
- prefs_->ScheduleSavePersistentPrefs();
- }
-}
-
-DictionaryValue* ExtensionPrefs::GetOrCreateExtensionPref(
- const std::string& extension_id) {
- DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
- DictionaryValue* extension = NULL;
- std::wstring id = ASCIIToWide(extension_id);
- if (!dict->GetDictionary(id, &extension)) {
- // Extension pref does not exist, create it.
- extension = new DictionaryValue();
- dict->Set(id, extension);
- }
- return extension;
-}
-
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
deleted file mode 100644
index db5847b..0000000
--- a/chrome/browser/extensions/extension_prefs.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_H
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_H
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/task.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/pref_service.h"
-#include "googleurl/src/gurl.h"
-
-// Class for managing global and per-extension preferences.
-// This class is instantiated by ExtensionsService, so it should be accessed
-// from there.
-class ExtensionPrefs {
- public:
- explicit ExtensionPrefs(PrefService* prefs);
-
- // Returns a copy of the Extensions prefs.
- // TODO(erikkay) Remove this so that external consumers don't need to be
- // aware of the internal structure of the preferences.
- DictionaryValue* CopyCurrentExtensions();
-
- // Populate |killed_ids| with extension ids that have been killed.
- void GetKilledExtensionIds(std::set<std::string>* killed_ids);
-
- // Get the order that toolstrip URLs appear in the shelf.
- typedef std::vector<GURL> URLList;
- URLList GetShelfToolstripOrder();
-
- // Called when an extension is installed, so that prefs get created.
- void OnExtensionInstalled(Extension* extension);
-
- // Called when an extension is uninstalled, so that prefs get cleaned up.
- void OnExtensionUninstalled(const Extension* extension);
-
- private:
- // Sets the pref |key| for extension |id| to |value|.
- bool UpdateExtensionPref(const std::string& id,
- const std::wstring& key,
- Value* value);
-
- // Deletes the pref dictionary for extension |id|.
- void DeleteExtensionPrefs(const std::string& id);
-
- // Ensures and returns a mutable dictionary for extension |id|'s prefs.
- DictionaryValue* GetOrCreateExtensionPref(const std::string& id);
-
- // The pref service specific to this set of extension prefs.
- PrefService* prefs_;
-
- // The URLs of all of the toolstrips.
- URLList shelf_order_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionPrefs);
-};
-
-// A helper class that has a list of the currently installed extensions
-// and can iterate over them to a provided callback.
-class InstalledExtensions {
- public:
- explicit InstalledExtensions(ExtensionPrefs* prefs);
-
- typedef Callback3<const std::string&,
- const FilePath&,
- Extension::Location>::Type Callback;
-
- // Runs |callback| for each installed extension with the path to the
- // version directory and the location.
- void VisitInstalledExtensions(Callback *callback);
-
- private:
- // A copy of the extensions pref dictionary so that this can be passed
- // around without a dependency on prefs.
- DictionaryValue* extension_data_;
-
- DISALLOW_COPY_AND_ASSIGN(InstalledExtensions);
-};
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PREFS_H
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index 2e655d10..a39a4cd 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -60,6 +60,24 @@ const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL";
namespace {
+////////////////////
+// Preferences keys
+
+// A preference that keeps track of per-extension settings. This is a dictionary
+// object read from the Preferences file, keyed off of extension id's.
+const wchar_t kExtensionsPref[] = L"extensions.settings";
+
+// Where an extension was installed from (Extension::Location)
+const wchar_t kPrefLocation[] = L"location";
+
+// Enabled, disabled, killed, etc. (Extension::State)
+const wchar_t kPrefState[] = L"state";
+
+// The path to the current version's manifest file.
+const wchar_t kPrefPath[] = L"path";
+
+////////////////////
+
// A temporary subdirectory where we unpack extensions.
const char* kUnpackExtensionDir = "TEMP_UNPACK";
@@ -213,18 +231,22 @@ class ExtensionsServiceBackend::UnpackerClient
ExtensionsService::ExtensionsService(Profile* profile,
MessageLoop* frontend_loop,
MessageLoop* backend_loop)
- : extension_prefs_(new ExtensionPrefs(profile->GetPrefs())),
+ : prefs_(profile->GetPrefs()),
backend_loop_(backend_loop),
install_directory_(profile->GetPath().AppendASCII(kInstallDirectoryName)),
extensions_enabled_(
CommandLine::ForCurrentProcess()->
HasSwitch(switches::kEnableExtensions)),
show_extensions_prompts_(true) {
+ if (!prefs_->FindPreference(kExtensionsPref))
+ prefs_->RegisterDictionaryPref(kExtensionsPref);
+
// We pass ownership of this object to the Backend.
- DictionaryValue* extensions = extension_prefs_->CopyCurrentExtensions();
+ DictionaryValue* external_extensions = new DictionaryValue;
+ GetExternalExtensions(external_extensions, NULL);
backend_ = new ExtensionsServiceBackend(
install_directory_, g_browser_process->resource_dispatcher_host(),
- frontend_loop, extensions);
+ frontend_loop, external_extensions);
}
ExtensionsService::~ExtensionsService() {
@@ -258,12 +280,22 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id) {
Extension* extension = GetExtensionById(extension_id);
// Callers should not send us nonexistant extensions.
- DCHECK(extension);
+ CHECK(extension);
- extension_prefs_->OnExtensionUninstalled(extension);
+ Extension::Location location = extension->location();
+
+ // For external extensions, we save a preference reminding ourself not to try
+ // and install the extension anymore.
+ if (Extension::IsExternalLocation(location)) {
+ UpdateExtensionPref(ASCIIToWide(extension_id), kPrefState,
+ Value::CreateIntegerValue(Extension::KILLBIT), true);
+ } else {
+ DeleteExtensionPrefs(ASCIIToWide(extension_id));
+ }
// Tell the backend to start deleting installed extensions on the file thread.
- if (Extension::LOAD != extension->location()) {
+ if (location == Extension::INTERNAL ||
+ Extension::IsExternalLocation(location)) {
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
&ExtensionsServiceBackend::UninstallExtension, extension_id));
}
@@ -278,17 +310,22 @@ void ExtensionsService::LoadExtension(const FilePath& extension_path) {
}
void ExtensionsService::LoadAllExtensions() {
- // Load the previously installed extensions.
- backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
- &ExtensionsServiceBackend::LoadInstalledExtensions,
- scoped_refptr<ExtensionsService>(this),
- new InstalledExtensions(extension_prefs_.get())));
+ // Load the extensions we know about from previous runs.
+ const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+ if (extensions) {
+ DictionaryValue* copy =
+ static_cast<DictionaryValue*>(extensions->DeepCopy());
+ backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
+ &ExtensionsServiceBackend::LoadExtensionsFromPrefs,
+ scoped_refptr<ExtensionsService>(this),
+ copy));
+ }
}
void ExtensionsService::CheckForUpdates() {
// This installs or updates externally provided extensions.
std::set<std::string> killed_extensions;
- extension_prefs_->GetKilledExtensionIds(&killed_extensions);
+ GetExternalExtensions(NULL, &killed_extensions);
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
&ExtensionsServiceBackend::CheckForExternalUpdates,
killed_extensions,
@@ -342,13 +379,6 @@ void ExtensionsService::GarbageCollectExtensions() {
scoped_refptr<ExtensionsService>(this)));
}
-void ExtensionsService::OnLoadedInstalledExtensions() {
- NotificationService::current()->Notify(
- NotificationType::EXTENSIONS_READY,
- Source<ExtensionsService>(this),
- NotificationService::NoDetails());
-}
-
void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
scoped_ptr<ExtensionList> cleanup(new_extensions);
@@ -382,17 +412,28 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
}
}
- if (enabled_extensions.size()) {
- NotificationService::current()->Notify(
- NotificationType::EXTENSIONS_LOADED,
- NotificationService::AllSources(),
- Details<ExtensionList>(&enabled_extensions));
- }
+ // TODO(erikkay) it would be nice if we could just return and send no
+ // notification if the list is empty. However, UserScriptMaster depends on
+ // getting an initial notification after the first extensions have finished
+ // loading, so even if it's an empty message, we send it anyway. We should
+ // come up with a way to do a "started" notification that has the semantics
+ // that UserScriptMaster is looking for.
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSIONS_LOADED,
+ NotificationService::AllSources(),
+ Details<ExtensionList>(&enabled_extensions));
}
void ExtensionsService::OnExtensionInstalled(Extension* extension,
Extension::InstallType install_type) {
- extension_prefs_->OnExtensionInstalled(extension);
+ std::wstring id = ASCIIToWide(extension->id());
+ UpdateExtensionPref(id, kPrefState,
+ Value::CreateIntegerValue(Extension::ENABLED), false);
+ UpdateExtensionPref(id, kPrefLocation,
+ Value::CreateIntegerValue(extension->location()), false);
+ UpdateExtensionPref(id, kPrefPath,
+ Value::CreateStringValue(extension->path().value()), true);
// If the extension is a theme, tell the profile (and therefore ThemeProvider)
// to apply it.
@@ -433,6 +474,60 @@ Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
return GetExtensionById(host);
}
+void ExtensionsService::GetExternalExtensions(
+ DictionaryValue* external_extensions,
+ std::set<std::string>* killed_extensions) {
+ const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
+ if (!dict || dict->GetSize() == 0)
+ return;
+
+ for (DictionaryValue::key_iterator i = dict->begin_keys();
+ i != dict->end_keys(); ++i) {
+ std::wstring key_name = *i;
+ if (!Extension::IdIsValid(WideToASCII(key_name))) {
+ LOG(WARNING) << "Invalid external extension ID encountered: "
+ << WideToASCII(key_name);
+ continue;
+ }
+
+ DictionaryValue* extension = NULL;
+ if (!dict->GetDictionary(key_name, &extension)) {
+ NOTREACHED();
+ continue;
+ }
+
+ // Check to see if the extension has been killed.
+ int state;
+ if (extension->GetInteger(kPrefState, &state) &&
+ state == static_cast<int>(Extension::KILLBIT)) {
+ if (killed_extensions) {
+ StringToLowerASCII(&key_name);
+ killed_extensions->insert(WideToASCII(key_name));
+ }
+ }
+ // Return all extensions found.
+ if (external_extensions) {
+ DictionaryValue* result =
+ static_cast<DictionaryValue*>(extension->DeepCopy());
+ StringToLowerASCII(&key_name);
+ external_extensions->Set(key_name, result);
+ }
+ }
+}
+
+DictionaryValue* ExtensionsService::GetOrCreateExtensionPref(
+ const std::wstring& extension_id) {
+ DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
+ DictionaryValue* extension = NULL;
+ if (!dict->GetDictionary(extension_id, &extension)) {
+ // Extension pref does not exist, create it.
+ extension = new DictionaryValue();
+ dict->Set(extension_id, extension);
+ }
+
+ return extension;
+}
+
void ExtensionsService::ClearProvidersForTesting() {
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
&ExtensionsServiceBackend::ClearProvidersForTesting));
@@ -445,6 +540,32 @@ void ExtensionsService::SetProviderForTesting(
location, test_provider));
}
+bool ExtensionsService::UpdateExtensionPref(const std::wstring& extension_id,
+ const std::wstring& key,
+ Value* data_value,
+ bool schedule_save) {
+ DictionaryValue* extension = GetOrCreateExtensionPref(extension_id);
+ if (!extension->Set(key, data_value)) {
+ NOTREACHED() << L"Cannot modify key: '" << key.c_str()
+ << "' for extension: '" << extension_id.c_str() << "'";
+ return false;
+ }
+
+ if (schedule_save)
+ prefs_->ScheduleSavePersistentPrefs();
+ return true;
+}
+
+void ExtensionsService::DeleteExtensionPrefs(
+ const std::wstring& extension_id) {
+ DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
+ if (dict->HasKey(extension_id)) {
+ dict->Remove(extension_id, NULL);
+ prefs_->ScheduleSavePersistentPrefs();
+ }
+}
+
+
// ExtensionsServicesBackend
ExtensionsServiceBackend::ExtensionsServiceBackend(
@@ -468,20 +589,53 @@ ExtensionsServiceBackend::ExtensionsServiceBackend(
ExtensionsServiceBackend::~ExtensionsServiceBackend() {
}
-void ExtensionsServiceBackend::LoadInstalledExtensions(
+void ExtensionsServiceBackend::LoadExtensionsFromPrefs(
scoped_refptr<ExtensionsService> frontend,
- InstalledExtensions* installed) {
- scoped_ptr<InstalledExtensions> cleanup(installed);
+ DictionaryValue* extension_prefs) {
+ scoped_ptr<DictionaryValue> prefs(extension_prefs); // for cleanup
frontend_ = frontend;
alert_on_error_ = false;
-
- // Call LoadInstalledExtension for each extension |installed| knows about.
- scoped_ptr<InstalledExtensions::Callback> callback(
- NewCallback(this, &ExtensionsServiceBackend::LoadInstalledExtension));
- installed->VisitInstalledExtensions(callback.get());
-
- frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- frontend_, &ExtensionsService::OnLoadedInstalledExtensions));
+ scoped_ptr<ExtensionList> extensions(new ExtensionList);
+ DictionaryValue::key_iterator extension_id = extension_prefs->begin_keys();
+ for (; extension_id != extension_prefs->end_keys(); ++extension_id) {
+ DictionaryValue* ext;
+ if (!extension_prefs->GetDictionary(*extension_id, &ext)) {
+ NOTREACHED();
+ continue;
+ }
+ FilePath::StringType path;
+ if (ext->GetString(kPrefPath, &path)) {
+ Extension::Location location = Extension::INVALID;
+ int location_value;
+ DictionaryValue* pref = NULL;
+ extension_prefs->GetDictionary(*extension_id, &pref);
+ if (!pref || !pref->GetInteger(kPrefLocation, &location_value)) {
+ // TODO(erikkay) try to recover?
+ continue;
+ } else {
+ location = static_cast<Extension::Location>(location_value);
+ }
+ std::string id = WideToASCII(*extension_id);
+ if (Extension::IsExternalLocation(location) &&
+ CheckExternalUninstall(extension_prefs, FilePath(path), id)) {
+ // TODO(erikkay): Possibly defer this operation to avoid slowing initial
+ // load of extensions.
+ UninstallExtension(id);
+
+ // No error needs to be reported. The extension effectively doesn't
+ // exist.
+ continue;
+ }
+ Extension* extension =
+ LoadExtension(FilePath(path), location, true); // require id
+ if (extension)
+ extensions->push_back(extension);
+ } else {
+ // TODO(erikkay) bootstrap?
+ }
+ }
+ LOG(INFO) << "Done.";
+ ReportExtensionsLoaded(extensions.release());
}
void ExtensionsServiceBackend::GarbageCollectExtensions(
@@ -554,7 +708,7 @@ void ExtensionsServiceBackend::LoadSingleExtension(
Extension* extension = LoadExtension(extension_path,
Extension::LOAD,
- false); // Don't require id.
+ false); // don't require ID
if (extension) {
ExtensionList* extensions = new ExtensionList;
extensions->push_back(extension);
@@ -562,28 +716,6 @@ void ExtensionsServiceBackend::LoadSingleExtension(
}
}
-void ExtensionsServiceBackend::LoadInstalledExtension(
- const std::string& id, const FilePath& path, Extension::Location location) {
- if (CheckExternalUninstall(id, location)) {
- // TODO(erikkay): Possibly defer this operation to avoid slowing initial
- // load of extensions.
- UninstallExtension(id);
-
- // No error needs to be reported. The extension effectively doesn't exist.
- return;
- }
-
- Extension* extension =
- LoadExtension(FilePath(path), location, true); // Require id.
-
- // TODO(erikkay) now we only report a single extension loaded at a time.
- // Perhaps we should change the notifications to remove ExtensionList.
- ExtensionList* extensions = new ExtensionList;
- if (extension)
- extensions->push_back(extension);
- ReportExtensionsLoaded(extensions);
-}
-
DictionaryValue* ExtensionsServiceBackend::ReadManifest(FilePath manifest_path,
std::string* error) {
JSONFileValueSerializer serializer(manifest_path);
@@ -1199,7 +1331,23 @@ void ExtensionsServiceBackend::CheckForExternalUpdates(
}
bool ExtensionsServiceBackend::CheckExternalUninstall(
- const std::string& id, Extension::Location location) {
+ const DictionaryValue* extension_prefs, const FilePath& version_path,
+ const std::string& id) {
+ // First check the preferences for the kill-bit.
+ int location_value = Extension::INVALID;
+ DictionaryValue* extension = NULL;
+ if (!extension_prefs->GetDictionary(ASCIIToWide(id), &extension))
+ return false;
+ int state;
+ if (extension->GetInteger(kPrefLocation, &location_value) &&
+ location_value == Extension::EXTERNAL_PREF) {
+ return extension->GetInteger(kPrefState, &state) &&
+ state == Extension::KILLBIT;
+ }
+
+ Extension::Location location =
+ static_cast<Extension::Location>(location_value);
+
// Check if the providers know about this extension.
ProviderMap::const_iterator i = external_extension_providers_.find(location);
if (i != external_extension_providers_.end()) {
@@ -1207,9 +1355,6 @@ bool ExtensionsServiceBackend::CheckExternalUninstall(
version.reset(i->second->RegisteredVersion(id, NULL));
if (version.get())
return false; // Yup, known extension, don't uninstall.
- } else {
- // Not from an external provider, so it's fine.
- return false;
}
return true; // This is not a known extension, uninstall.
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index d8fa0d0..8bf49f8 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -15,7 +15,6 @@
#include "base/ref_counted.h"
#include "base/tuple.h"
#include "base/values.h"
-#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/external_extension_provider.h"
#include "chrome/common/extensions/extension.h"
@@ -121,6 +120,29 @@ class ExtensionsService
// Lookup an extension by |url|. This uses the host of the URL as the id.
Extension* GetExtensionByURL(const GURL& url);
+ // Gets a list of external extensions. If |external_extensions| is non-null,
+ // a dictionary with all external extensions (including extensions installed
+ // through the registry on Windows builds) and their preferences are
+ // returned. If |killed_extensions| is non-null, a set of string IDs
+ // containing all external extension IDs with the killbit set are returned.
+ void GetExternalExtensions(DictionaryValue* external_extensions,
+ std::set<std::string>* killed_extensions);
+
+ // Gets the settings for an extension from preferences. If the key doesn't
+ // exist, this function creates it (don't need to check return for NULL).
+ DictionaryValue* GetOrCreateExtensionPref(const std::wstring& extension_id);
+
+ // Writes a preference value for a particular extension |extension_id| under
+ // the |key| specified. If |schedule_save| is true, it will also ask the
+ // preference system to schedule a save to disk.
+ bool UpdateExtensionPref(const std::wstring& extension_id,
+ const std::wstring& key,
+ Value* data_value,
+ bool schedule_save);
+
+ // Removes the entire tree of prefs for |extension_id|.
+ void DeleteExtensionPrefs(const std::wstring& extension_id);
+
// Clear all ExternalExtensionProviders.
void ClearProvidersForTesting();
@@ -147,9 +169,6 @@ class ExtensionsService
// OnExtensionVersionReinstalled.
friend class ExtensionsServiceBackend;
- // Called by the backend when the initial extension load has completed.
- void OnLoadedInstalledExtensions();
-
// Called by the backend when extensions have been loaded.
void OnExtensionsLoaded(ExtensionList* extensions);
@@ -166,7 +185,7 @@ class ExtensionsService
static const char* kInstallDirectoryName;
// Preferences for the owning profile.
- scoped_ptr<ExtensionPrefs> extension_prefs_;
+ PrefService* prefs_;
// The message loop to use with the backend.
MessageLoop* backend_loop_;
@@ -205,11 +224,12 @@ class ExtensionsServiceBackend
virtual ~ExtensionsServiceBackend();
- // Loads the installed extensions.
+ // Loads extensions from the prefs.
// Errors are reported through ExtensionErrorReporter. On completion,
// OnExtensionsLoaded() is called with any successfully loaded extensions.
- void LoadInstalledExtensions(scoped_refptr<ExtensionsService> frontend,
- InstalledExtensions* installed);
+ void LoadExtensionsFromPrefs(
+ scoped_refptr<ExtensionsService> frontend,
+ DictionaryValue* extension_prefs);
// Scans the extension installation directory to look for partially installed
// or extensions to uninstall.
@@ -258,10 +278,6 @@ class ExtensionsServiceBackend
class UnpackerClient;
friend class UnpackerClient;
- // Loads a single installed extension.
- void LoadInstalledExtension(const std::string& id, const FilePath& path,
- Extension::Location location);
-
// Utility function to read an extension manifest and return it as a
// DictionaryValue. If it fails, NULL is returned and |error| contains an
// appropriate message.
@@ -363,8 +379,9 @@ class ExtensionsServiceBackend
// For the extension in |version_path| with |id|, check to see if it's an
// externally managed extension. If so return true if it should be
// uninstalled.
- bool CheckExternalUninstall(const std::string& id,
- Extension::Location location);
+ bool CheckExternalUninstall(const DictionaryValue* extension_prefs,
+ const FilePath& version_path,
+ const std::string& id);
// Should an extension of |id| and |version| be installed?
// Returns true if no extension of type |id| is installed or if |version|
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
index 2a4c104..b3dfe7e 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -999,9 +999,9 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
ValidatePref(good_crx, L"state", Extension::ENABLED);
ValidatePref(good_crx, L"location", Extension::EXTERNAL_PREF);
- // Now uninstall the extension and verify that it doesn't get reinstalled.
- service_->UninstallExtension(id);
- loop_.RunAllPending();
+ // Now set the kill bit and watch the extension go away.
+ SetPref(good_crx, L"state", Extension::KILLBIT);
+ profile_->GetPrefs()->ScheduleSavePersistentPrefs();
loaded_.clear();
service_->ReloadExtensions();
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 0c1a4b0..5cf3696 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -259,13 +259,10 @@ UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
const FilePath& script_dir)
: user_script_dir_(script_dir),
worker_loop_(worker_loop),
- extensions_service_ready_(false),
pending_scan_(false) {
if (!user_script_dir_.value().empty())
AddWatchedPath(script_dir);
- registrar_.Add(this, NotificationType::EXTENSIONS_READY,
- NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSIONS_LOADED,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
@@ -330,10 +327,6 @@ void UserScriptMaster::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type.value) {
- case NotificationType::EXTENSIONS_READY:
- extensions_service_ready_ = true;
- StartScan();
- break;
case NotificationType::EXTENSIONS_LOADED: {
// TODO(aa): Fix race here. A page could need a content script on startup,
// before the extension has loaded. We need to freeze the renderer in
@@ -351,8 +344,7 @@ void UserScriptMaster::Observe(NotificationType type,
lone_scripts_.push_back(*iter);
}
}
- if (!extensions_service_ready_)
- StartScan();
+ StartScan();
break;
}
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index ab87631..7a73323 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -148,10 +148,6 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
// List of scripts outside of script directories we should also load.
UserScriptList lone_scripts_;
- // If the extensions service has finished loading its initial set of
- // extensions.
- bool extensions_service_ready_;
-
// If the script directory is modified while we're rescanning it, we note
// that we're currently mid-scan and then start over again once the scan
// finishes. This boolean tracks whether another scan is pending.