summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-15 17:29:32 +0000
committererikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-15 17:29:32 +0000
commit9f1087e1370ecdbb3a9670a9ab542e317c00bb7d (patch)
treee2ca81d0d64c825a1eed007e3a28a50e0e27c231
parent4b5370ada28790dac39a1c21ac000ff750d28eac (diff)
downloadchromium_src-9f1087e1370ecdbb3a9670a9ab542e317c00bb7d.zip
chromium_src-9f1087e1370ecdbb3a9670a9ab542e317c00bb7d.tar.gz
chromium_src-9f1087e1370ecdbb3a9670a9ab542e317c00bb7d.tar.bz2
Clean up extension loading:
* load extensions from prefs rather than by scanning filesystem * fix multiple loading bug * in-place upgrade * split out Init() behavior into individual pieces that can be called by tests Also: * add look up of extension by URL * rename GetExtensionByID -> GetExtensionById BUG=12399 BUG=14053 TEST=ExtensionServiceTest.* Review URL: http://codereview.chromium.org/125102 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18397 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_page_actions_module.cc2
-rw-r--r--chrome/browser/extensions/extension_process_manager.cc13
-rw-r--r--chrome/browser/extensions/extension_process_manager.h1
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc2
-rw-r--r--chrome/browser/extensions/extensions_service.cc449
-rw-r--r--chrome/browser/extensions/extensions_service.h58
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc141
-rw-r--r--chrome/browser/extensions/external_pref_extension_provider.cc2
8 files changed, 365 insertions, 303 deletions
diff --git a/chrome/browser/extensions/extension_page_actions_module.cc b/chrome/browser/extensions/extension_page_actions_module.cc
index 5b128ea..ffc5aa2 100644
--- a/chrome/browser/extensions/extension_page_actions_module.cc
+++ b/chrome/browser/extensions/extension_page_actions_module.cc
@@ -50,7 +50,7 @@ bool EnablePageActionFunction::RunImpl() {
// Find our extension.
Extension* extension = NULL;
ExtensionsService* service = profile()->GetExtensionsService();
- extension = service->GetExtensionByID(extension_id());
+ extension = service->GetExtensionById(extension_id());
if (!extension) {
error_ = ExtensionErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
extension_id());
diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc
index dc068e6..a4f2df7 100644
--- a/chrome/browser/extensions/extension_process_manager.cc
+++ b/chrome/browser/extensions/extension_process_manager.cc
@@ -55,6 +55,19 @@ ExtensionHost* ExtensionProcessManager::CreateView(Extension* extension,
return host;
}
+ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url,
+ Browser* browser) {
+ DCHECK(browser);
+ ExtensionsService* service =
+ browsing_instance_->profile()->GetExtensionsService();
+ if (service) {
+ Extension* extension = service->GetExtensionByURL(url);
+ if (extension)
+ return CreateView(extension, url, browser);
+ }
+ return NULL;
+}
+
ExtensionHost* ExtensionProcessManager::CreateBackgroundHost(
Extension* extension, const GURL& url) {
ExtensionHost* host =
diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h
index f12b49e..9cd861c 100644
--- a/chrome/browser/extensions/extension_process_manager.h
+++ b/chrome/browser/extensions/extension_process_manager.h
@@ -34,6 +34,7 @@ class ExtensionProcessManager : public NotificationObserver {
ExtensionHost* CreateView(Extension* extension,
const GURL& url,
Browser* browser);
+ ExtensionHost* CreateView(const GURL& url, Browser* browser);
// Creates a new UI-less extension instance. Like CreateView, but not
// displayed anywhere.
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 2eb2432..b92677d 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -672,7 +672,7 @@ static Browser* GetBrowserInProfileWithId(Profile* profile,
static GURL AbsolutePath(Profile* profile, std::string extension_id,
std::string relative_url) {
ExtensionsService* service = profile->GetExtensionsService();
- Extension* extension = service->GetExtensionByID(extension_id);
+ Extension* extension = service->GetExtensionById(extension_id);
return Extension::GetResourceURL(extension->url(), relative_url);
}
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index aae153b..5d76b4d 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -60,13 +60,23 @@ const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL";
namespace {
-// A preference that keeps track of extension settings. This is a dictionary
+////////////////////
+// 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 kExternalExtensionsPref[] = L"extensions.settings";
+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";
-// A preference keeping track of how the extension was installed.
-const wchar_t kLocation[] = L"location";
-const wchar_t kState[] = 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";
@@ -93,11 +103,9 @@ class ExtensionsServiceBackend::UnpackerClient
UnpackerClient(ExtensionsServiceBackend* backend,
const FilePath& extension_path,
const std::string& public_key,
- const std::string& expected_id,
- bool from_external)
+ const std::string& expected_id)
: backend_(backend), extension_path_(extension_path),
- public_key_(public_key), expected_id_(expected_id),
- from_external_(from_external), got_response_(false) {
+ public_key_(public_key), expected_id_(expected_id), got_response_(false) {
}
// Starts the unpack task. We call back to the backend when the task is done,
@@ -174,8 +182,7 @@ class ExtensionsServiceBackend::UnpackerClient
FilePath extension_dir = temp_extension_path_.DirName().AppendASCII(
ExtensionsServiceBackend::kTempExtensionName);
backend_->OnExtensionUnpacked(extension_path_, extension_dir,
- expected_id_, from_external_,
- manifest, images);
+ expected_id_, manifest, images);
Cleanup();
}
@@ -216,9 +223,6 @@ class ExtensionsServiceBackend::UnpackerClient
// The ID we expect this extension to have, if any.
std::string expected_id_;
- // True if this is being installed from an external source.
- bool from_external_;
-
// True if we got a response from the utility process and have cleaned up
// already.
bool got_response_;
@@ -234,9 +238,11 @@ ExtensionsService::ExtensionsService(Profile* profile,
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;
- prefs_->RegisterDictionaryPref(kExternalExtensionsPref);
GetExternalExtensions(external_extensions, NULL);
backend_ = new ExtensionsServiceBackend(
install_directory_, g_browser_process->resource_dispatcher_host(),
@@ -244,46 +250,90 @@ ExtensionsService::ExtensionsService(Profile* profile,
}
ExtensionsService::~ExtensionsService() {
- for (ExtensionList::iterator iter = extensions_.begin();
- iter != extensions_.end(); ++iter) {
- delete *iter;
- }
+ UnloadAllExtensions();
}
-bool ExtensionsService::Init() {
+void ExtensionsService::Init() {
+ DCHECK(extensions_.size() == 0);
+
// Start up the extension event routers.
ExtensionBrowserEventRouter::GetInstance()->Init();
- scoped_ptr<DictionaryValue> external_extensions(new DictionaryValue);
- GetExternalExtensions(external_extensions.get(), NULL);
+ LoadAllExtensions();
- scoped_ptr< std::set<std::string> >
- killed_extensions(new std::set<std::string>);
- GetExternalExtensions(NULL, killed_extensions.get());
+ // TODO(erikkay) this should probably be deferred to a future point
+ // rather than running immediately at startup.
+ CheckForUpdates();
+ // TODO(erikkay) this should probably be deferred as well.
+ GarbageCollectExtensions();
+}
+
+void ExtensionsService::InstallExtension(const FilePath& extension_path) {
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
- &ExtensionsServiceBackend::CheckForExternalUpdates,
- *killed_extensions.get(),
+ &ExtensionsServiceBackend::InstallExtension,
+ extension_path,
scoped_refptr<ExtensionsService>(this)));
+}
+
+void ExtensionsService::UninstallExtension(const std::string& extension_id) {
+ Extension* extension = GetExtensionById(extension_id);
+ // Callers should not send us nonexistant extensions.
+ CHECK(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 (location == Extension::INTERNAL ||
+ Extension::IsExternalLocation(location)) {
+ backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
+ &ExtensionsServiceBackend::UninstallExtension, extension_id));
+ }
+
+ UnloadExtension(extension_id);
+}
+
+void ExtensionsService::LoadExtension(const FilePath& extension_path) {
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
- &ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory,
- scoped_refptr<ExtensionsService>(this),
- external_extensions.release()));
+ &ExtensionsServiceBackend::LoadSingleExtension,
+ extension_path, scoped_refptr<ExtensionsService>(this)));
+}
- return true;
+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));
+ }
}
-void ExtensionsService::InstallExtension(const FilePath& extension_path) {
+void ExtensionsService::CheckForUpdates() {
+ // This installs or updates externally provided extensions.
+ std::set<std::string> killed_extensions;
+ GetExternalExtensions(NULL, &killed_extensions);
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
- &ExtensionsServiceBackend::InstallExtension,
- extension_path,
+ &ExtensionsServiceBackend::CheckForExternalUpdates,
+ killed_extensions,
scoped_refptr<ExtensionsService>(this)));
}
-void ExtensionsService::UninstallExtension(const std::string& extension_id) {
+void ExtensionsService::UnloadExtension(const std::string& extension_id) {
Extension* extension = NULL;
-
ExtensionList::iterator iter;
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
if ((*iter)->id() == extension_id) {
@@ -303,33 +353,35 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id) {
NotificationService::AllSources(),
Details<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(ASCIIToWide(extension->id()), kState,
- Value::CreateIntegerValue(Extension::KILLBIT), true);
- } else {
- UpdateExtensionPref(ASCIIToWide(extension->id()), kState,
- Value::CreateIntegerValue(Extension::DISABLED), true);
- }
+ delete extension;
+}
- // Tell the backend to start deleting installed extensions on the file thread.
- if (extension->location() == Extension::INTERNAL ||
- Extension::IsExternalLocation(extension->location())) {
- backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
- &ExtensionsServiceBackend::UninstallExtension, extension_id));
+void ExtensionsService::UnloadAllExtensions() {
+ ExtensionList::iterator iter;
+ for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
+ // Tell other services the extension is gone.
+ NotificationService::current()->Notify(NotificationType::EXTENSION_UNLOADED,
+ NotificationService::AllSources(),
+ Details<Extension>(*iter));
+ delete *iter;
}
+ extensions_.clear();
+}
- delete extension;
+void ExtensionsService::ReloadExtensions() {
+ UnloadAllExtensions();
+ LoadAllExtensions();
}
-void ExtensionsService::LoadExtension(const FilePath& extension_path) {
+void ExtensionsService::GarbageCollectExtensions() {
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
- &ExtensionsServiceBackend::LoadSingleExtension,
- extension_path, scoped_refptr<ExtensionsService>(this)));
+ &ExtensionsServiceBackend::GarbageCollectExtensions,
+ scoped_refptr<ExtensionsService>(this)));
}
void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
+ scoped_ptr<ExtensionList> cleanup(new_extensions);
+
// Filter out any extensions we don't want to enable. Themes are always
// enabled, but other extensions are only loaded if --enable-extensions is
// present.
@@ -337,7 +389,22 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
for (ExtensionList::iterator iter = new_extensions->begin();
iter != new_extensions->end(); ++iter) {
if (extensions_enabled() || (*iter)->IsTheme()) {
+ Extension* old = GetExtensionById((*iter)->id());
+ if (old) {
+ if ((*iter)->version()->CompareTo(*(old->version())) > 0) {
+ // To upgrade an extension in place, unload the old one and
+ // then load the new one.
+ // TODO(erikkay) issue 12399
+ UnloadExtension(old->id());
+ } else {
+ // We already have the extension of the same or older version.
+ LOG(WARNING) << "Duplicate extension load attempt: " << (*iter)->id();
+ delete *iter;
+ continue;
+ }
+ }
enabled_extensions.push_back(*iter);
+ extensions_.push_back(*iter);
} else {
// Extensions that get enabled get added to extensions_ and deleted later.
// Anything skipped must be deleted now so we don't leak.
@@ -345,48 +412,28 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
}
}
- for (ExtensionList::const_iterator iter = enabled_extensions.begin();
- iter != enabled_extensions.end(); ++iter) {
- std::wstring extension_id = ASCIIToWide((*iter)->id());
- DictionaryValue* pref = GetOrCreateExtensionPref(extension_id);
- int location;
- int state;
-
- // Ensure all loaded extensions have a preference set. This deals with a
- // legacy problem where some extensions were installed before we were
- // storing state in the preferences.
- // TODO(aa): We should remove this eventually.
- if (!pref->GetInteger(kLocation, &location) ||
- !pref->GetInteger(kState, &state)) {
- UpdateExtensionPref(extension_id,
- kLocation, Value::CreateIntegerValue(Extension::INTERNAL), false);
- UpdateExtensionPref(extension_id,
- kState, Value::CreateIntegerValue(Extension::ENABLED), false);
- } else {
- // Sanity check: The kill-bit should only ever be set on external
- // extensions.
- DCHECK(state != Extension::KILLBIT ||
- Extension::IsExternalLocation(
- static_cast<Extension::Location>(location)));
- }
-
- extensions_.push_back(*iter);
- }
+ // 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));
-
- delete new_extensions;
}
void ExtensionsService::OnExtensionInstalled(Extension* extension,
Extension::InstallType install_type) {
- UpdateExtensionPref(ASCIIToWide(extension->id()), kState,
+ std::wstring id = ASCIIToWide(extension->id());
+ UpdateExtensionPref(id, kPrefState,
Value::CreateIntegerValue(Extension::ENABLED), false);
- UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation,
- Value::CreateIntegerValue(Extension::INTERNAL), true);
+ 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.
@@ -403,17 +450,8 @@ void ExtensionsService::OnExtensionInstalled(Extension* extension,
}
}
-void ExtensionsService::OnExternalExtensionInstalled(
- const std::string& id, Extension::Location location) {
- DCHECK(Extension::IsExternalLocation(location));
- UpdateExtensionPref(ASCIIToWide(id), kState,
- Value::CreateIntegerValue(Extension::ENABLED), false);
- UpdateExtensionPref(ASCIIToWide(id), kLocation,
- Value::CreateIntegerValue(location), true);
-}
-
void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) {
- Extension* extension = GetExtensionByID(id);
+ Extension* extension = GetExtensionById(id);
if (extension && extension->IsTheme()) {
NotificationService::current()->Notify(
NotificationType::THEME_INSTALLED,
@@ -422,7 +460,7 @@ void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) {
}
}
-Extension* ExtensionsService::GetExtensionByID(std::string id) {
+Extension* ExtensionsService::GetExtensionById(const std::string& id) {
for (ExtensionList::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
if ((*iter)->id() == id)
@@ -431,10 +469,15 @@ Extension* ExtensionsService::GetExtensionByID(std::string id) {
return NULL;
}
+Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
+ std::string host = url.host();
+ return GetExtensionById(host);
+}
+
void ExtensionsService::GetExternalExtensions(
DictionaryValue* external_extensions,
std::set<std::string>* killed_extensions) {
- const DictionaryValue* dict = prefs_->GetDictionary(kExternalExtensionsPref);
+ const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
if (!dict || dict->GetSize() == 0)
return;
@@ -455,7 +498,7 @@ void ExtensionsService::GetExternalExtensions(
// Check to see if the extension has been killed.
int state;
- if (extension->GetInteger(kState, &state) &&
+ if (extension->GetInteger(kPrefState, &state) &&
state == static_cast<int>(Extension::KILLBIT)) {
if (killed_extensions) {
StringToLowerASCII(&key_name);
@@ -474,7 +517,7 @@ void ExtensionsService::GetExternalExtensions(
DictionaryValue* ExtensionsService::GetOrCreateExtensionPref(
const std::wstring& extension_id) {
- DictionaryValue* dict = prefs_->GetMutableDictionary(kExternalExtensionsPref);
+ DictionaryValue* dict = prefs_->GetMutableDictionary(kExtensionsPref);
DictionaryValue* extension = NULL;
if (!dict->GetDictionary(extension_id, &extension)) {
// Extension pref does not exist, create it.
@@ -513,6 +556,16 @@ bool ExtensionsService::UpdateExtensionPref(const std::wstring& extension_id,
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(
@@ -536,37 +589,66 @@ ExtensionsServiceBackend::~ExtensionsServiceBackend() {
external_extension_providers_.end());
}
-void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory(
+void ExtensionsServiceBackend::LoadExtensionsFromPrefs(
scoped_refptr<ExtensionsService> frontend,
DictionaryValue* extension_prefs) {
+ scoped_ptr<DictionaryValue> prefs(extension_prefs); // for cleanup
frontend_ = frontend;
alert_on_error_ = false;
- scoped_ptr<DictionaryValue> external_extensions(extension_prefs);
-
-#if defined(OS_WIN)
- // On POSIX, AbsolutePath() calls realpath() which returns NULL if
- // it does not exist. Instead we absolute-ify after creation in
- // case that is needed.
- // TODO(port): does this really need to happen before
- // CreateDirectory() on Windows?
- if (!file_util::AbsolutePath(&install_directory_))
- NOTREACHED();
-#endif
-
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(
+ scoped_refptr<ExtensionsService> frontend) {
+ frontend_ = frontend;
+ alert_on_error_ = false;
- // Create the <Profile>/Extensions directory if it doesn't exist.
- if (!file_util::DirectoryExists(install_directory_)) {
- file_util::CreateDirectory(install_directory_);
- LOG(INFO) << "Created Extensions directory. No extensions to install.";
- ReportExtensionsLoaded(extensions.release());
+ // Nothing to clean up if it doesn't exist.
+ if (!file_util::DirectoryExists(install_directory_))
return;
- }
-#if !defined(OS_WIN)
if (!file_util::AbsolutePath(&install_directory_))
NOTREACHED();
-#endif
LOG(INFO) << "Loading installed extensions...";
@@ -586,13 +668,6 @@ void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory(
if (extension_id == kUnpackExtensionDir)
continue;
- // Ignore directories that aren't valid IDs.
- if (!Extension::IdIsValid(extension_id)) {
- LOG(WARNING) << "Invalid extension ID encountered in extensions "
- "directory: " << extension_id;
- continue;
- }
-
// If there is no Current Version file, just delete the directory and move
// on. This can legitimately happen when an uninstall does not complete, for
// example, when a plugin is in use at uninstall time.
@@ -605,45 +680,16 @@ void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory(
continue;
}
- std::string current_version;
- if (!ReadCurrentVersion(extension_path, &current_version))
- continue;
-
- Extension::Location location = Extension::INVALID;
- int location_value;
- DictionaryValue* pref = NULL;
- external_extensions->GetDictionary(ASCIIToWide(extension_id), &pref);
- if (!pref ||
- !pref->GetInteger(kLocation, &location_value)) {
- // Check with the external providers.
- if (!LookupExternalExtension(extension_id, NULL, &location))
- location = Extension::INTERNAL;
- } else {
- location = static_cast<Extension::Location>(location_value);
- }
-
- FilePath version_path = extension_path.AppendASCII(current_version);
- if (Extension::IsExternalLocation(location) &&
- CheckExternalUninstall(external_extensions.get(),
- version_path, extension_id)) {
- // TODO(erikkay): Possibly defer this operation to avoid slowing initial
- // load of extensions.
- UninstallExtension(extension_id);
-
- // No error needs to be reported. The extension effectively doesn't
- // exist.
+ // Ignore directories that aren't valid IDs.
+ if (!Extension::IdIsValid(extension_id)) {
+ LOG(WARNING) << "Invalid extension ID encountered in extensions "
+ "directory: " << extension_id;
+ // TODO(erikkay) delete these eventually too...
continue;
}
- Extension* extension = LoadExtension(version_path,
- location,
- true); // require id
- if (extension)
- extensions->push_back(extension);
+ // TODO(erikkay) check for extensions that aren't loaded?
}
-
- LOG(INFO) << "Done.";
- ReportExtensionsLoaded(extensions.release());
}
void ExtensionsServiceBackend::LoadSingleExtension(
@@ -924,20 +970,17 @@ void ExtensionsServiceBackend::InstallExtension(
frontend_ = frontend;
alert_on_error_ = true;
- bool from_external = false;
- InstallOrUpdateExtension(extension_path, std::string(), from_external);
+ InstallOrUpdateExtension(extension_path, std::string());
}
void ExtensionsServiceBackend::InstallOrUpdateExtension(
- const FilePath& extension_path,
- const std::string& expected_id,
- bool from_external) {
+ const FilePath& extension_path, const std::string& expected_id) {
std::string actual_public_key;
if (!ValidateSignature(extension_path, &actual_public_key))
return; // Failures reported within ValidateSignature().
UnpackerClient* client = new UnpackerClient(
- this, extension_path, actual_public_key, expected_id, from_external);
+ this, extension_path, actual_public_key, expected_id);
client->Start();
}
@@ -1034,7 +1077,6 @@ void ExtensionsServiceBackend::OnExtensionUnpacked(
const FilePath& extension_path,
const FilePath& temp_extension_dir,
const std::string expected_id,
- bool from_external,
const DictionaryValue& manifest,
const std::vector< Tuple2<SkBitmap, FilePath> >& images) {
Extension extension;
@@ -1062,7 +1104,11 @@ void ExtensionsServiceBackend::OnExtensionUnpacked(
return;
}
+ Extension::Location location = Extension::INTERNAL;
+ LookupExternalExtension(extension.id(), NULL, &location);
#if defined(OS_WIN)
+ bool from_external = Extension::IsExternalLocation(location);
+
if (!extension.IsTheme() && !from_external &&
frontend_->show_extensions_prompts() &&
win_util::MessageBox(GetActiveWindow(),
@@ -1188,40 +1234,22 @@ void ExtensionsServiceBackend::OnExtensionUnpacked(
if (!SetCurrentVersion(dest_dir, version))
return;
- Extension::Location location = Extension::INVALID;
- if (from_external)
- LookupExternalExtension(extension.id(), NULL, &location);
- else
- location = Extension::INTERNAL;
-
- // Load the extension immediately and then report installation success. We
- // don't load extensions for external installs because external installation
- // occurs before the normal startup so we just let startup pick them up. We
- // notify on installation of external extensions because we need to update
- // the preferences for these extensions to reflect that they've just been
- // installed.
- if (!from_external) {
- Extension* extension = LoadExtension(version_dir,
- location,
- true); // require id
- CHECK(extension);
-
- frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- frontend_, &ExtensionsService::OnExtensionInstalled, extension,
- install_type));
-
- // Only one extension, but ReportExtensionsLoaded can handle multiple,
- // so we need to construct a list.
- scoped_ptr<ExtensionList> extensions(new ExtensionList);
- extensions->push_back(extension);
- LOG(INFO) << "Done.";
- // Hand off ownership of the loaded extensions to the frontend.
- ReportExtensionsLoaded(extensions.release());
- } else {
- frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
- frontend_, &ExtensionsService::OnExternalExtensionInstalled,
- extension.id(), location));
- }
+ Extension* loaded = LoadExtension(version_dir,
+ location,
+ true); // require id
+ CHECK(loaded);
+
+ frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ frontend_, &ExtensionsService::OnExtensionInstalled, loaded,
+ install_type));
+
+ // Only one extension, but ReportExtensionsLoaded can handle multiple,
+ // so we need to construct a list.
+ scoped_ptr<ExtensionList> extensions(new ExtensionList);
+ extensions->push_back(loaded);
+
+ // Hand off ownership of the loaded extensions to the frontend.
+ ReportExtensionsLoaded(extensions.release());
scoped_version_dir.Take();
}
@@ -1255,9 +1283,9 @@ bool ExtensionsServiceBackend::ShouldSkipInstallingExtension(
void ExtensionsServiceBackend::CheckVersionAndInstallExtension(
const std::string& id, const Version* extension_version,
- const FilePath& extension_path, bool from_external) {
+ const FilePath& extension_path) {
if (ShouldInstall(id, extension_version))
- InstallOrUpdateExtension(FilePath(extension_path), id, from_external);
+ InstallOrUpdateExtension(FilePath(extension_path), id);
}
bool ExtensionsServiceBackend::LookupExternalExtension(
@@ -1303,7 +1331,7 @@ void ExtensionsServiceBackend::CheckForExternalUpdates(
}
bool ExtensionsServiceBackend::CheckExternalUninstall(
- DictionaryValue* extension_prefs, const FilePath& version_path,
+ 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;
@@ -1311,9 +1339,9 @@ bool ExtensionsServiceBackend::CheckExternalUninstall(
if (!extension_prefs->GetDictionary(ASCIIToWide(id), &extension))
return false;
int state;
- if (extension->GetInteger(kLocation, &location_value) &&
+ if (extension->GetInteger(kPrefLocation, &location_value) &&
location_value == Extension::EXTERNAL_PREF) {
- return extension->GetInteger(kState, &state) &&
+ return extension->GetInteger(kPrefState, &state) &&
state == Extension::KILLBIT;
}
@@ -1382,8 +1410,7 @@ void ExtensionsServiceBackend::SetProviderForTesting(
void ExtensionsServiceBackend::OnExternalExtensionFound(
const std::string& id, const Version* version, const FilePath& path) {
- bool from_external = true;
- CheckVersionAndInstallExtension(id, version, path, from_external);
+ CheckVersionAndInstallExtension(id, version, path);
}
bool ExtensionsServiceBackend::ShouldInstall(const std::string& id,
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index 7def6f1..b9b5e7e 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -82,7 +82,7 @@ class ExtensionsService
}
// Initialize and start all installed extensions.
- bool Init();
+ void Init();
// Install the extension file at |extension_path|. Will install as an
// update if an older version is already installed.
@@ -97,8 +97,29 @@ class ExtensionsService
// Load the extension from the directory |extension_path|.
void LoadExtension(const FilePath& extension_path);
+ // Load all known extensions (used by startup and testing code).
+ void LoadAllExtensions();
+
+ // Check for updates (or potentially new extensions from external providers)
+ void CheckForUpdates();
+
+ // Unload the specified extension.
+ void UnloadExtension(const std::string& extension_id);
+
+ // Unload all extensions.
+ void UnloadAllExtensions();
+
+ // Called only by testing.
+ void ReloadExtensions();
+
+ // Scan the extension directory and clean up the cruft.
+ void GarbageCollectExtensions();
+
// Lookup an extension by |id|.
- Extension* GetExtensionByID(std::string id);
+ Extension* GetExtensionById(const std::string& id);
+
+ // 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
@@ -120,6 +141,9 @@ class ExtensionsService
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();
@@ -153,10 +177,6 @@ class ExtensionsService
void OnExtensionInstalled(Extension* extension,
Extension::InstallType install_type);
- // Called by the backend when an external extension has been installed.
- void OnExternalExtensionInstalled(
- const std::string& id, Extension::Location location);
-
// Called by the backend when an attempt was made to reinstall the same
// version of an existing extension.
void OnExtensionOverinstallAttempted(const std::string& id);
@@ -205,14 +225,17 @@ class ExtensionsServiceBackend
virtual ~ExtensionsServiceBackend();
- // Loads extensions from the install directory. The extensions are assumed to
- // be unpacked in directories that are direct children of the specified path.
+ // Loads extensions from the prefs.
// Errors are reported through ExtensionErrorReporter. On completion,
// OnExtensionsLoaded() is called with any successfully loaded extensions.
- void LoadExtensionsFromInstallDirectory(
+ void LoadExtensionsFromPrefs(
scoped_refptr<ExtensionsService> frontend,
DictionaryValue* extension_prefs);
+ // Scans the extension installation directory to look for partially installed
+ // or extensions to uninstall.
+ void GarbageCollectExtensions(scoped_refptr<ExtensionsService> frontend);
+
// Loads a single extension from |path| where |path| is the top directory of
// a specific extension where its manifest file lives.
// Errors are reported through ExtensionErrorReporter. On completion,
@@ -272,14 +295,11 @@ class ExtensionsServiceBackend
Extension* LoadExtensionCurrentVersion(const FilePath& extension_path);
// Install a crx file at |extension_path|. If |expected_id| is not empty, it's
- // verified against the extension's manifest before installation. If
- // |from_external| is true, this extension install is from an external source,
- // ie the Windows registry, and will be marked as such. If the extension is
- // already installed, install the new version only if its version number is
- // greater than the current installed version.
+ // verified against the extension's manifest before installation. If the
+ // extension is already installed, install the new version only if its version
+ // number is greater than the current installed version.
void InstallOrUpdateExtension(const FilePath& extension_path,
- const std::string& expected_id,
- bool from_external);
+ const std::string& expected_id);
// Validates the signature of the extension in |extension_path|. Returns true
// and the public key (in |key|) if the signature validates, false otherwise.
@@ -294,7 +314,6 @@ class ExtensionsServiceBackend
const FilePath& extension_path,
const FilePath& temp_extension_dir,
const std::string expected_id,
- bool from_external,
const DictionaryValue& manifest,
const std::vector< Tuple2<SkBitmap, FilePath> >& images);
@@ -322,8 +341,7 @@ class ExtensionsServiceBackend
// extension hasn't been installed before.
void CheckVersionAndInstallExtension(const std::string& id,
const Version* extension_version,
- const FilePath& extension_path,
- bool from_external);
+ const FilePath& extension_path);
// Lookup an external extension by |id| by going through all registered
// external extension providers until we find a provider that contains an
@@ -362,7 +380,7 @@ 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(DictionaryValue* extension_prefs,
+ bool CheckExternalUninstall(const DictionaryValue* extension_prefs,
const FilePath& version_path,
const std::string& id);
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
index cca5299..1150dae 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -168,10 +168,18 @@ class ExtensionsServiceTest
break;
}
- case NotificationType::EXTENSION_UNLOADED:
- unloaded_id_ = Details<Extension>(details).ptr()->id();
+ case NotificationType::EXTENSION_UNLOADED: {
+ Extension* e = Details<Extension>(details).ptr();
+ unloaded_id_ = e->id();
+ ExtensionList::iterator i =
+ std::find(loaded_.begin(), loaded_.end(), e);
+ // TODO(erikkay) fix so this can be an assert. Right now the tests
+ // are manually calling clear() on loaded_, so this isn't doable.
+ if (i == loaded_.end())
+ return;
+ loaded_.erase(i);
break;
-
+ }
case NotificationType::EXTENSION_INSTALLED:
case NotificationType::THEME_INSTALLED:
installed_ = Details<Extension>(details).ptr();
@@ -207,7 +215,7 @@ class ExtensionsServiceTest
EXPECT_EQ(0u, errors.size()) << path.value();
EXPECT_EQ(total_successes_, service_->extensions()->size()) <<
path.value();
- EXPECT_TRUE(service_->GetExtensionByID(loaded_[0]->id())) <<
+ EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id())) <<
path.value();
for (std::vector<std::string>::iterator err = errors.begin();
err != errors.end(); ++err) {
@@ -274,7 +282,7 @@ class ExtensionsServiceTest
scoped_refptr<ExtensionsService> service_;
size_t total_successes_;
MessageLoop loop_;
- std::vector<Extension*> loaded_;
+ ExtensionList loaded_;
std::string unloaded_id_;
Extension* installed_;
@@ -282,8 +290,10 @@ class ExtensionsServiceTest
NotificationRegistrar registrar_;
};
+// TODO(erikkay) this test and the next need to be replaced with equivalent
+// versions that load from prefs.
// Test loading good extensions from the profile directory.
-TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
+TEST_F(ExtensionsServiceTest, DISABLED_LoadAllExtensionsFromDirectorySuccess) {
// Copy the test extensions into the test profile.
FilePath source_path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path));
@@ -293,7 +303,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
FilePath dest_path = profile_->GetPath().AppendASCII("Extensions");
file_util::CopyDirectory(source_path, dest_path, true); // Recursive.
- ASSERT_TRUE(service_->Init());
+ service_->Init();
loop_.RunAllPending();
std::vector<std::string> errors = GetErrors();
@@ -309,7 +319,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
EXPECT_EQ(std::string("The first extension that I made."),
loaded_[0]->description());
EXPECT_EQ(Extension::INTERNAL, loaded_[0]->location());
- EXPECT_TRUE(service_->GetExtensionByID(loaded_[0]->id()));
+ EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id()));
EXPECT_EQ(3u, service_->extensions()->size());
ValidatePrefKeyCount(3);
@@ -370,7 +380,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
};
// Test loading bad extensions from the profile directory.
-TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) {
+TEST_F(ExtensionsServiceTest, DISABLED_LoadAllExtensionsFromDirectoryFail) {
FilePath source_path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path));
source_path = source_path.AppendASCII("extensions");
@@ -379,7 +389,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) {
FilePath dest_path = profile_->GetPath().AppendASCII("Extensions");
file_util::CopyDirectory(source_path, dest_path, true); // Recursive.
- ASSERT_TRUE(service_->Init());
+ service_->Init();
loop_.RunAllPending();
EXPECT_EQ(3u, GetErrors().size());
@@ -414,25 +424,25 @@ TEST_F(ExtensionsServiceTest, CleanupOnStartup) {
// Simulate that one of them got partially deleted by deling the
// Current Version file.
- dest_path = dest_path.AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
- .AppendASCII(ExtensionsService::kCurrentVersionFileName);
- ASSERT_TRUE(file_util::Delete(dest_path, false)); // not recursive
+ FilePath vers = dest_path.AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
+ .AppendASCII(ExtensionsService::kCurrentVersionFileName);
+ ASSERT_TRUE(file_util::Delete(vers, false)); // not recursive
service_->Init();
loop_.RunAllPending();
+ file_util::FileEnumerator dirs(dest_path, false,
+ file_util::FileEnumerator::DIRECTORIES);
+ size_t count = 0;
+ while (!dirs.Next().empty())
+ count++;
+
// We should have only gotten two extensions now.
- EXPECT_EQ(2u, loaded_.size());
+ EXPECT_EQ(2u, count);
// And extension1 dir should now be toast.
- dest_path = dest_path.DirName();
- ASSERT_FALSE(file_util::PathExists(dest_path));
-
- ValidatePrefKeyCount(2);
- ValidatePref(good1, L"state", Extension::ENABLED);
- ValidatePref(good1, L"location", Extension::INTERNAL);
- ValidatePref(good2, L"state", Extension::ENABLED);
- ValidatePref(good2, L"location", Extension::INTERNAL);
+ vers = vers.DirName();
+ ASSERT_FALSE(file_util::PathExists(vers));
}
// Test installing extensions.
@@ -466,7 +476,7 @@ TEST_F(ExtensionsServiceTest, InstallExtension) {
ValidatePref(page_action, L"state", Extension::ENABLED);
ValidatePref(page_action, L"location", Extension::INTERNAL);
- // Bad signature.
+ // Bad signature.
path = extensions_path.AppendASCII("bad_signature.crx");
InstallExtension(path, false);
@@ -627,6 +637,7 @@ TEST_F(ExtensionsServiceTest, UpgradeSignedGood) {
ASSERT_TRUE(installed_);
ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
ASSERT_EQ(0u, GetErrors().size());
// Upgrade to version 2.0
@@ -635,7 +646,8 @@ TEST_F(ExtensionsServiceTest, UpgradeSignedGood) {
loop_.RunAllPending();
ASSERT_TRUE(installed_);
- ASSERT_EQ(2u, loaded_.size());
+ ASSERT_EQ(1u, loaded_.size());
+ ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
ASSERT_EQ(0u, GetErrors().size());
}
@@ -693,12 +705,10 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) {
ASSERT_TRUE(unloaded_id_.length());
EXPECT_EQ(extension_id, unloaded_id_);
- ValidatePrefKeyCount(1);
- ValidatePref(good_crx, L"state", Extension::DISABLED);
- ValidatePref(good_crx, L"location", Extension::INTERNAL);
+ ValidatePrefKeyCount(0);
// The extension should not be in the service anymore.
- ASSERT_FALSE(service_->GetExtensionByID(extension_id));
+ ASSERT_FALSE(service_->GetExtensionById(extension_id));
loop_.RunAllPending();
// The directory should be gone.
@@ -715,9 +725,7 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) {
loop_.RunAllPending();
EXPECT_FALSE(file_util::PathExists(extension_path));
- ValidatePrefKeyCount(1);
- ValidatePref(good_crx, L"state", Extension::DISABLED);
- ValidatePref(good_crx, L"location", Extension::INTERNAL);
+ ValidatePrefKeyCount(0);
}
// Tests loading single extensions (like --load-extension)
@@ -733,11 +741,11 @@ TEST_F(ExtensionsServiceTest, LoadExtension) {
loop_.RunAllPending();
EXPECT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
- ASSERT_EQ(Extension::LOAD, loaded_[0]->location());
+ EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
+ EXPECT_EQ(1u, service_->extensions()->size());
- ValidatePrefKeyCount(1);
- ValidatePref(good0, L"state", Extension::ENABLED);
- ValidatePref(good0, L"location", Extension::INTERNAL);
+ // --load-extension doesn't add entries to prefs
+ ValidatePrefKeyCount(0);
FilePath no_manifest = extensions_path.AppendASCII("bad")
.AppendASCII("no_manifest").AppendASCII("1");
@@ -745,8 +753,7 @@ TEST_F(ExtensionsServiceTest, LoadExtension) {
loop_.RunAllPending();
EXPECT_EQ(1u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
-
- ValidatePrefKeyCount(1);
+ EXPECT_EQ(1u, service_->extensions()->size());
// Test uninstall.
std::string id = loaded_[0]->id();
@@ -754,10 +761,8 @@ TEST_F(ExtensionsServiceTest, LoadExtension) {
service_->UninstallExtension(id);
loop_.RunAllPending();
EXPECT_EQ(id, unloaded_id_);
-
- ValidatePrefKeyCount(1);
- ValidatePref(good0, L"state", Extension::DISABLED);
- ValidatePref(good0, L"location", Extension::INTERNAL);
+ ASSERT_EQ(0u, loaded_.size());
+ EXPECT_EQ(0u, service_->extensions()->size());
}
// Tests that we generate IDs when they are not specified in the manifest for
@@ -775,24 +780,24 @@ TEST_F(ExtensionsServiceTest, GenerateID) {
EXPECT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
std::string id1 = loaded_[0]->id();
- ASSERT_EQ(all_zero, id1);
- ASSERT_EQ("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/",
+ EXPECT_EQ(all_zero, id1);
+ EXPECT_EQ("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/",
loaded_[0]->url().spec());
+ EXPECT_EQ(loaded_[0]->location(), Extension::LOAD);
- ValidatePrefKeyCount(1);
- ValidatePref(all_zero, L"state", Extension::ENABLED);
- ValidatePref(all_zero, L"location", Extension::INTERNAL);
+ // --load-extension doesn't add entries to prefs
+ ValidatePrefKeyCount(0);
service_->LoadExtension(no_id_ext);
loop_.RunAllPending();
std::string id2 = loaded_[1]->id();
- ASSERT_EQ(zero_n_one, id2);
- ASSERT_EQ("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab/",
+ EXPECT_EQ(zero_n_one, id2);
+ EXPECT_EQ("chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab/",
loaded_[1]->url().spec());
+ EXPECT_EQ(loaded_[1]->location(), Extension::LOAD);
- ValidatePrefKeyCount(2);
- ValidatePref(zero_n_one, L"state", Extension::ENABLED);
- ValidatePref(zero_n_one, L"location", Extension::INTERNAL);
+ // --load-extension doesn't add entries to prefs
+ ValidatePrefKeyCount(0);
}
// Tests the external installation feature
@@ -817,9 +822,9 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
// Add the extension.
reg_provider->UpdateOrAddExtension(good_crx, "1.0.0.0", source_path);
- // Start up the service, it should find our externally registered extension
+ // Reloading extensions should find our externally registered extension
// and install it.
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, GetErrors().size());
@@ -830,10 +835,10 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
ValidatePref(good_crx, L"state", Extension::ENABLED);
ValidatePref(good_crx, L"location", Extension::EXTERNAL_REGISTRY);
- // Reinit the service without changing anything. The extension should be
+ // Reload extensions without changing anything. The extension should be
// loaded again.
loaded_.clear();
- service_->Init();
+ service_->ReloadExtensions();
loop_.RunAllPending();
ASSERT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -846,7 +851,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
reg_provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path);
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -867,7 +872,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
ASSERT_FALSE(file_util::PathExists(install_path));
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
ValidatePrefKeyCount(1);
@@ -880,7 +885,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
profile_->GetPrefs()->ScheduleSavePersistentPrefs();
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(1u, loaded_.size());
ValidatePrefKeyCount(1);
@@ -890,7 +895,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) {
reg_provider->RemoveExtension(good_crx);
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
}
@@ -916,9 +921,9 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
// Add the extension.
pref_provider->UpdateOrAddExtension(good_crx, "1.0", source_path);
- // Start up the service, it should find our externally registered extension
+ // Checking for updates should find our externally registered extension
// and install it.
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, GetErrors().size());
@@ -930,10 +935,10 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
ValidatePref(good_crx, L"state", Extension::ENABLED);
ValidatePref(good_crx, L"location", Extension::EXTERNAL_PREF);
- // Reinit the service without changing anything. The extension should be
+ // Reload extensions without changing anything. The extension should be
// loaded again.
loaded_.clear();
- service_->Init();
+ service_->ReloadExtensions();
loop_.RunAllPending();
ASSERT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -947,7 +952,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
pref_provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path);
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -957,7 +962,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
ValidatePref(good_crx, L"state", Extension::ENABLED);
ValidatePref(good_crx, L"location", Extension::EXTERNAL_PREF);
- // Uninstall the extension and re-init. Nothing should happen because the
+ // Uninstall the extension and reload. Nothing should happen because the
// preference should prevent us from reinstalling.
std::string id = loaded_[0]->id();
service_->UninstallExtension(id);
@@ -969,7 +974,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
ASSERT_FALSE(file_util::PathExists(install_path));
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
@@ -982,7 +987,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
profile_->GetPrefs()->ScheduleSavePersistentPrefs();
loaded_.clear();
- service_->Init();
+ service_->CheckForUpdates();
loop_.RunAllPending();
ASSERT_EQ(1u, loaded_.size());
@@ -995,7 +1000,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) {
profile_->GetPrefs()->ScheduleSavePersistentPrefs();
loaded_.clear();
- service_->Init();
+ service_->ReloadExtensions();
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc
index 6db3355..ca18753 100644
--- a/chrome/browser/extensions/external_pref_extension_provider.cc
+++ b/chrome/browser/extensions/external_pref_extension_provider.cc
@@ -33,8 +33,6 @@ void ExternalPrefExtensionProvider::VisitRegisteredExtension(
DictionaryValue* extension = NULL;
if (!prefs_->GetDictionary(extension_id, &extension)) {
- NOTREACHED() << "Cannot read extension " << extension_id.c_str()
- << " from dictionary.";
continue;
}