summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 17:21:51 +0000
committererikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 17:21:51 +0000
commite72e8eb8fb4eb2daf5c4fd0e003e2eee04611ba6 (patch)
tree9b7258965b4e35bd5bc1cfafcc8ee7f26ce5c1e1
parenta5e2b71f09b590801b82c8a1ba48ee84893a4512 (diff)
downloadchromium_src-e72e8eb8fb4eb2daf5c4fd0e003e2eee04611ba6.zip
chromium_src-e72e8eb8fb4eb2daf5c4fd0e003e2eee04611ba6.tar.gz
chromium_src-e72e8eb8fb4eb2daf5c4fd0e003e2eee04611ba6.tar.bz2
Abstract ExtensionPrefs into their own class.
Relands http://codereview.chromium.org/126281 which had been reverted due to a leak. The only difference is in extension_prefs.h where extension_data_ is now a scoped_ptr. Review URL: http://codereview.chromium.org/131040 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18717 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_prefs.cc187
-rw-r--r--chrome/browser/extensions/extension_prefs.h86
-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
-rw-r--r--chrome/chrome.gyp2
-rw-r--r--chrome/common/notification_type.h5
9 files changed, 374 insertions, 244 deletions
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
new file mode 100644
index 0000000..56754fe
--- /dev/null
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -0,0 +1,187 @@
+// 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_.reset(prefs->CopyCurrentExtensions());
+}
+
+InstalledExtensions::~InstalledExtensions() {
+}
+
+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
new file mode 100644
index 0000000..8244234
--- /dev/null
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -0,0 +1,86 @@
+// 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);
+ ~InstalledExtensions();
+
+ 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.
+ scoped_ptr<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 a39a4cd..2e655d10 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -60,24 +60,6 @@ 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";
@@ -231,22 +213,18 @@ class ExtensionsServiceBackend::UnpackerClient
ExtensionsService::ExtensionsService(Profile* profile,
MessageLoop* frontend_loop,
MessageLoop* backend_loop)
- : prefs_(profile->GetPrefs()),
+ : extension_prefs_(new ExtensionPrefs(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* external_extensions = new DictionaryValue;
- GetExternalExtensions(external_extensions, NULL);
+ DictionaryValue* extensions = extension_prefs_->CopyCurrentExtensions();
backend_ = new ExtensionsServiceBackend(
install_directory_, g_browser_process->resource_dispatcher_host(),
- frontend_loop, external_extensions);
+ frontend_loop, extensions);
}
ExtensionsService::~ExtensionsService() {
@@ -280,22 +258,12 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id) {
Extension* extension = GetExtensionById(extension_id);
// Callers should not send us nonexistant extensions.
- CHECK(extension);
+ DCHECK(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));
- }
+ extension_prefs_->OnExtensionUninstalled(extension);
// Tell the backend to start deleting installed extensions on the file thread.
- if (location == Extension::INTERNAL ||
- Extension::IsExternalLocation(location)) {
+ if (Extension::LOAD != extension->location()) {
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
&ExtensionsServiceBackend::UninstallExtension, extension_id));
}
@@ -310,22 +278,17 @@ void ExtensionsService::LoadExtension(const FilePath& extension_path) {
}
void ExtensionsService::LoadAllExtensions() {
- // 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));
- }
+ // Load the previously installed extensions.
+ backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
+ &ExtensionsServiceBackend::LoadInstalledExtensions,
+ scoped_refptr<ExtensionsService>(this),
+ new InstalledExtensions(extension_prefs_.get())));
}
void ExtensionsService::CheckForUpdates() {
// This installs or updates externally provided extensions.
std::set<std::string> killed_extensions;
- GetExternalExtensions(NULL, &killed_extensions);
+ extension_prefs_->GetKilledExtensionIds(&killed_extensions);
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
&ExtensionsServiceBackend::CheckForExternalUpdates,
killed_extensions,
@@ -379,6 +342,13 @@ 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);
@@ -412,28 +382,17 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_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));
+ if (enabled_extensions.size()) {
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSIONS_LOADED,
+ NotificationService::AllSources(),
+ Details<ExtensionList>(&enabled_extensions));
+ }
}
void ExtensionsService::OnExtensionInstalled(Extension* extension,
Extension::InstallType install_type) {
- 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);
+ extension_prefs_->OnExtensionInstalled(extension);
// If the extension is a theme, tell the profile (and therefore ThemeProvider)
// to apply it.
@@ -474,60 +433,6 @@ 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));
@@ -540,32 +445,6 @@ 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(
@@ -589,53 +468,20 @@ ExtensionsServiceBackend::ExtensionsServiceBackend(
ExtensionsServiceBackend::~ExtensionsServiceBackend() {
}
-void ExtensionsServiceBackend::LoadExtensionsFromPrefs(
+void ExtensionsServiceBackend::LoadInstalledExtensions(
scoped_refptr<ExtensionsService> frontend,
- DictionaryValue* extension_prefs) {
- scoped_ptr<DictionaryValue> prefs(extension_prefs); // for cleanup
+ InstalledExtensions* installed) {
+ scoped_ptr<InstalledExtensions> cleanup(installed);
frontend_ = frontend;
alert_on_error_ = false;
- 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());
+
+ // 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));
}
void ExtensionsServiceBackend::GarbageCollectExtensions(
@@ -708,7 +554,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);
@@ -716,6 +562,28 @@ 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);
@@ -1331,23 +1199,7 @@ void ExtensionsServiceBackend::CheckForExternalUpdates(
}
bool ExtensionsServiceBackend::CheckExternalUninstall(
- 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);
-
+ const std::string& id, Extension::Location location) {
// Check if the providers know about this extension.
ProviderMap::const_iterator i = external_extension_providers_.find(location);
if (i != external_extension_providers_.end()) {
@@ -1355,6 +1207,9 @@ 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 8bf49f8..d8fa0d0 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -15,6 +15,7 @@
#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"
@@ -120,29 +121,6 @@ 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();
@@ -169,6 +147,9 @@ 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);
@@ -185,7 +166,7 @@ class ExtensionsService
static const char* kInstallDirectoryName;
// Preferences for the owning profile.
- PrefService* prefs_;
+ scoped_ptr<ExtensionPrefs> extension_prefs_;
// The message loop to use with the backend.
MessageLoop* backend_loop_;
@@ -224,12 +205,11 @@ class ExtensionsServiceBackend
virtual ~ExtensionsServiceBackend();
- // Loads extensions from the prefs.
+ // Loads the installed extensions.
// Errors are reported through ExtensionErrorReporter. On completion,
// OnExtensionsLoaded() is called with any successfully loaded extensions.
- void LoadExtensionsFromPrefs(
- scoped_refptr<ExtensionsService> frontend,
- DictionaryValue* extension_prefs);
+ void LoadInstalledExtensions(scoped_refptr<ExtensionsService> frontend,
+ InstalledExtensions* installed);
// Scans the extension installation directory to look for partially installed
// or extensions to uninstall.
@@ -278,6 +258,10 @@ 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.
@@ -379,9 +363,8 @@ 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 DictionaryValue* extension_prefs,
- const FilePath& version_path,
- const std::string& id);
+ bool CheckExternalUninstall(const std::string& id,
+ Extension::Location location);
// 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 b3dfe7e..2a4c104 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 set the kill bit and watch the extension go away.
- SetPref(good_crx, L"state", Extension::KILLBIT);
- profile_->GetPrefs()->ScheduleSavePersistentPrefs();
+ // Now uninstall the extension and verify that it doesn't get reinstalled.
+ service_->UninstallExtension(id);
+ loop_.RunAllPending();
loaded_.clear();
service_->ReloadExtensions();
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 5cf3696..0c1a4b0 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -259,10 +259,13 @@ 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,
@@ -327,6 +330,10 @@ 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
@@ -344,7 +351,8 @@ void UserScriptMaster::Observe(NotificationType type,
lone_scripts_.push_back(*iter);
}
}
- StartScan();
+ if (!extensions_service_ready_)
+ StartScan();
break;
}
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index 7a73323..ab87631 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -148,6 +148,10 @@ 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.
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index e3b614f..b0e0cd4 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -870,6 +870,8 @@
'browser/extensions/extension_page_actions_module.h',
'browser/extensions/extension_page_actions_module_constants.cc',
'browser/extensions/extension_page_actions_module_constants.h',
+ 'browser/extensions/extension_prefs.cc',
+ 'browser/extensions/extension_prefs.h',
'browser/extensions/extension_process_manager.cc',
'browser/extensions/extension_process_manager.h',
'browser/extensions/extension_protocols.cc',
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index 678c942..e6efd5d 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -563,6 +563,11 @@ class NotificationType {
// Extensions --------------------------------------------------------------
+ // Sent when the known installed extensions have all been loaded. In
+ // testing scenarios this can happen multiple times if extensions are
+ // unloaded and reloaded.
+ EXTENSIONS_READY,
+
// Sent when new extensions are loaded. The details are an ExtensionList*.
EXTENSIONS_LOADED,