| Index: chrome/browser/extensions/component_loader.cc
|
| diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
|
| index 624befad35a4d33548f132dc5c65735e785e4ff7..87b48d7c1d3c07414b496928f796e893688bf2fe 100644
|
| --- a/chrome/browser/extensions/component_loader.cc
|
| +++ b/chrome/browser/extensions/component_loader.cc
|
| @@ -9,10 +9,16 @@
|
| #include "base/json/json_value_serializer.h"
|
| #include "chrome/browser/browser_process.h"
|
| #include "chrome/browser/extensions/extension_service.h"
|
| +#include "chrome/browser/prefs/pref_change_registrar.h"
|
| +#include "chrome/browser/prefs/pref_notifier.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/common/chrome_notification_types.h"
|
| #include "chrome/common/chrome_paths.h"
|
| #include "chrome/common/chrome_switches.h"
|
| #include "chrome/common/extensions/extension.h"
|
| #include "chrome/common/pref_names.h"
|
| +#include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_source.h"
|
| #include "grit/browser_resources.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
|
|
| @@ -20,41 +26,19 @@
|
| #include "chrome/browser/defaults.h"
|
| #endif
|
|
|
| -namespace {
|
| -
|
| -typedef std::list<std::pair<FilePath::StringType, int> >
|
| - ComponentExtensionList;
|
| -
|
| -#if defined(FILE_MANAGER_EXTENSION)
|
| -void AddFileManagerExtension(ComponentExtensionList* component_extensions) {
|
| -#ifndef NDEBUG
|
| - const CommandLine* command_line = CommandLine::ForCurrentProcess();
|
| - if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
|
| - FilePath filemgr_extension_path =
|
| - command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath);
|
| - component_extensions->push_back(std::make_pair(
|
| - filemgr_extension_path.value(),
|
| - IDR_FILEMANAGER_MANIFEST));
|
| - return;
|
| - }
|
| -#endif // NDEBUG
|
| - component_extensions->push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("file_manager"),
|
| - IDR_FILEMANAGER_MANIFEST));
|
| -}
|
| -#endif // defined(FILE_MANAGER_EXTENSION)
|
| -
|
| -} // namespace
|
| -
|
| namespace extensions {
|
|
|
| -bool ComponentLoader::ComponentExtensionInfo::Equals(
|
| - const ComponentExtensionInfo& other) const {
|
| - return other.manifest == manifest && other.root_directory == root_directory;
|
| -}
|
| +ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
|
| + PrefService* prefs,
|
| + PrefService* local_state)
|
| + : prefs_(prefs),
|
| + local_state_(local_state),
|
| + extension_service_(extension_service) {
|
| + pref_change_registrar_.Init(prefs);
|
|
|
| -ComponentLoader::ComponentLoader(ExtensionService* extension_service)
|
| - : extension_service_(extension_service) {
|
| + // This pref is set by policy. We have to watch it for change because on
|
| + // ChromeOS, policy isn't loaded until after the browser process is started.
|
| + pref_change_registrar_.Add(prefs::kEnterpriseWebStoreURL, this);
|
| }
|
|
|
| ComponentLoader::~ComponentLoader() {
|
| @@ -68,23 +52,60 @@ void ComponentLoader::LoadAll() {
|
| }
|
| }
|
|
|
| +DictionaryValue* ComponentLoader::ParseManifest(
|
| + const std::string& manifest_contents) const {
|
| + JSONStringValueSerializer serializer(manifest_contents);
|
| + scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
|
| +
|
| + if (!manifest.get() || !manifest->IsType(Value::TYPE_DICTIONARY)) {
|
| + LOG(ERROR) << "Failed to parse extension manifest.";
|
| + return NULL;
|
| + }
|
| + // Transfer ownership to the caller.
|
| + return static_cast<DictionaryValue*>(manifest.release());
|
| +}
|
| +
|
| +const Extension* ComponentLoader::Add(
|
| + int manifest_resource_id,
|
| + const FilePath& root_directory) {
|
| + std::string manifest_contents =
|
| + ResourceBundle::GetSharedInstance().GetRawDataResource(
|
| + manifest_resource_id).as_string();
|
| + return Add(manifest_contents, root_directory);
|
| +}
|
| +
|
| +const Extension* ComponentLoader::Add(
|
| + std::string& manifest_contents,
|
| + const FilePath& root_directory) {
|
| + // The Value is kept for the lifetime of the ComponentLoader. This is
|
| + // required in case LoadAll() is called again.
|
| + DictionaryValue* manifest = ParseManifest(manifest_contents);
|
| + if (manifest)
|
| + return Add(manifest, root_directory);
|
| + return NULL;
|
| +}
|
| +
|
| const Extension* ComponentLoader::Add(
|
| - const std::string& manifest, const FilePath& root_directory) {
|
| - ComponentExtensionInfo info(manifest, root_directory);
|
| - Register(info);
|
| + const DictionaryValue* parsed_manifest,
|
| + const FilePath& root_directory) {
|
| + // Get the absolute path to the extension.
|
| + FilePath absolute_path(root_directory);
|
| + if (!absolute_path.IsAbsolute()) {
|
| + if (PathService::Get(chrome::DIR_RESOURCES, &absolute_path)) {
|
| + absolute_path = absolute_path.Append(root_directory);
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| + }
|
| +
|
| + ComponentExtensionInfo info(parsed_manifest, absolute_path);
|
| + component_extensions_.push_back(info);
|
| if (extension_service_->is_ready())
|
| return Load(info);
|
| return NULL;
|
| }
|
|
|
| const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) {
|
| - JSONStringValueSerializer serializer(info.manifest);
|
| - scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
|
| - if (!manifest.get()) {
|
| - LOG(ERROR) << "Failed to parse manifest for extension";
|
| - return NULL;
|
| - }
|
| -
|
| int flags = Extension::REQUIRE_KEY;
|
| if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT))
|
| flags |= Extension::STRICT_ERROR_CHECKS;
|
| @@ -92,7 +113,7 @@ const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) {
|
| scoped_refptr<const Extension> extension(Extension::Create(
|
| info.root_directory,
|
| Extension::COMPONENT,
|
| - *static_cast<DictionaryValue*>(manifest.get()),
|
| + *info.manifest,
|
| flags,
|
| &error));
|
| if (!extension.get()) {
|
| @@ -103,19 +124,29 @@ const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) {
|
| return extension;
|
| }
|
|
|
| -void ComponentLoader::Remove(const std::string& manifest_str) {
|
| - // Unload the extension.
|
| - JSONStringValueSerializer serializer(manifest_str);
|
| - scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
|
| - if (!manifest.get()) {
|
| - LOG(ERROR) << "Failed to parse manifest for extension";
|
| - return;
|
| +void ComponentLoader::Remove(const FilePath& root_directory) {
|
| + // Find the ComponentExtensionInfo for the extension.
|
| + RegisteredComponentExtensions::iterator it = component_extensions_.begin();
|
| + for (; it != component_extensions_.end(); ++it) {
|
| + if (it->root_directory == root_directory)
|
| + break;
|
| }
|
| + // If the extension is not in the list, there's nothing to do.
|
| + if (it == component_extensions_.end())
|
| + return;
|
| +
|
| + const DictionaryValue* manifest = it->manifest;
|
| +
|
| + // Remove the extension from the list of registered extensions.
|
| + *it = component_extensions_.back();
|
| + component_extensions_.pop_back();
|
| +
|
| + // Determine the extension id and unload the extension.
|
| std::string public_key;
|
| std::string public_key_bytes;
|
| std::string id;
|
| - if (!static_cast<DictionaryValue*>(manifest.get())->
|
| - GetString(extension_manifest_keys::kPublicKey, &public_key) ||
|
| + if (!manifest->GetString(
|
| + extension_manifest_keys::kPublicKey, &public_key) ||
|
| !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) ||
|
| !Extension::GenerateId(public_key_bytes, &id)) {
|
| LOG(ERROR) << "Failed to get extension id";
|
| @@ -123,106 +154,129 @@ void ComponentLoader::Remove(const std::string& manifest_str) {
|
| }
|
| extension_service_->
|
| UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE);
|
| +}
|
|
|
| - // Unregister the extension.
|
| - RegisteredComponentExtensions new_component_extensions;
|
| - for (RegisteredComponentExtensions::iterator it =
|
| - component_extensions_.begin();
|
| - it != component_extensions_.end(); ++it) {
|
| - if (it->manifest != manifest_str)
|
| - new_component_extensions.push_back(*it);
|
| +void ComponentLoader::AddFileManagerExtension() {
|
| +#if defined(FILE_MANAGER_EXTENSION)
|
| +#ifndef NDEBUG
|
| + const CommandLine* command_line = CommandLine::ForCurrentProcess();
|
| + if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
|
| + FilePath filemgr_extension_path(
|
| + command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath));
|
| + Add(IDR_FILEMANAGER_MANIFEST, filemgr_extension_path);
|
| + return;
|
| }
|
| - component_extensions_.swap(new_component_extensions);
|
| +#endif // NDEBUG
|
| + Add(IDR_FILEMANAGER_MANIFEST, FilePath(FILE_PATH_LITERAL("file_manager")));
|
| +#endif // defined(FILE_MANAGER_EXTENSION)
|
| }
|
|
|
| -// We take ComponentExtensionList:
|
| -// path, manifest ID => full manifest, absolute path
|
| -void ComponentLoader::AddDefaultComponentExtensions() {
|
| - ComponentExtensionList component_extensions;
|
| +void ComponentLoader::AddOrReloadEnterpriseWebStore() {
|
| + FilePath path(FILE_PATH_LITERAL("enterprise_web_store"));
|
|
|
| - // Bookmark manager.
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("bookmark_manager"),
|
| - IDR_BOOKMARKS_MANIFEST));
|
| + // Remove the extension if it was already loaded.
|
| + Remove(path);
|
| +
|
| + std::string enterprise_webstore_url =
|
| + prefs_->GetString(prefs::kEnterpriseWebStoreURL);
|
| +
|
| + // Load the extension only if the URL preference is set.
|
| + if (!enterprise_webstore_url.empty()) {
|
| + std::string manifest_contents =
|
| + ResourceBundle::GetSharedInstance().GetRawDataResource(
|
| + IDR_ENTERPRISE_WEBSTORE_MANIFEST).as_string();
|
| +
|
| + // The manifest is missing some values that are provided by policy.
|
| + DictionaryValue* manifest = ParseManifest(manifest_contents);
|
| + if (manifest) {
|
| + std::string name = prefs_->GetString(prefs::kEnterpriseWebStoreName);
|
| + manifest->SetString("app.launch.web_url", enterprise_webstore_url);
|
| + manifest->SetString("name", name);
|
| + Add(manifest, path);
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ComponentLoader::AddDefaultComponentExtensions() {
|
| + Add(IDR_BOOKMARKS_MANIFEST, FilePath(FILE_PATH_LITERAL("bookmark_manager")));
|
|
|
| #if defined(FILE_MANAGER_EXTENSION)
|
| - AddFileManagerExtension(&component_extensions);
|
| + AddFileManagerExtension();
|
| #endif
|
|
|
| #if defined(USE_VIRTUAL_KEYBOARD)
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("keyboard"),
|
| - IDR_KEYBOARD_MANIFEST));
|
| + Add(IDR_KEYBOARD_MANIFEST, FilePath(FILE_PATH_LITERAL("keyboard")));
|
| #endif
|
|
|
| #if defined(OS_CHROMEOS)
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"),
|
| - IDR_MOBILE_MANIFEST));
|
| + Add(IDR_MOBILE_MANIFEST,
|
| + FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile")));
|
|
|
| const CommandLine* command_line = CommandLine::ForCurrentProcess();
|
| if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
|
| FilePath auth_extension_path =
|
| command_line->GetSwitchValuePath(switches::kAuthExtensionPath);
|
| - component_extensions.push_back(std::make_pair(
|
| - auth_extension_path.value(),
|
| - IDR_GAIA_TEST_AUTH_MANIFEST));
|
| + Add(IDR_GAIA_TEST_AUTH_MANIFEST, auth_extension_path);
|
| } else {
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth"),
|
| - IDR_GAIA_AUTH_MANIFEST));
|
| + Add(IDR_GAIA_AUTH_MANIFEST,
|
| + FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth")));
|
| }
|
|
|
| #if defined(OFFICIAL_BUILD)
|
| if (browser_defaults::enable_help_app) {
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp"),
|
| - IDR_HELP_MANIFEST));
|
| + Add(IDR_HELP_MANIFEST,
|
| + FilePath(FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp")));
|
| }
|
| #endif
|
| -#endif
|
| +#endif // !defined(OS_CHROMEOS)
|
|
|
| - // Web Store.
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("web_store"),
|
| - IDR_WEBSTORE_MANIFEST));
|
| + Add(IDR_WEBSTORE_MANIFEST, FilePath(FILE_PATH_LITERAL("web_store")));
|
|
|
| #if !defined(OS_CHROMEOS)
|
| // Cloud Print component app. Not required on Chrome OS.
|
| - component_extensions.push_back(std::make_pair(
|
| - FILE_PATH_LITERAL("cloud_print"),
|
| - IDR_CLOUDPRINT_MANIFEST));
|
| -#endif // !defined(OS_CHROMEOS)
|
| -
|
| - for (ComponentExtensionList::iterator iter = component_extensions.begin();
|
| - iter != component_extensions.end(); ++iter) {
|
| - FilePath path(iter->first);
|
| - if (!path.IsAbsolute()) {
|
| - if (PathService::Get(chrome::DIR_RESOURCES, &path)) {
|
| - path = path.Append(iter->first);
|
| - } else {
|
| - NOTREACHED();
|
| - }
|
| - }
|
| -
|
| - std::string manifest =
|
| - ResourceBundle::GetSharedInstance().GetRawDataResource(
|
| - iter->second).as_string();
|
| - Add(manifest, path);
|
| - }
|
| + Add(IDR_CLOUDPRINT_MANIFEST, FilePath(FILE_PATH_LITERAL("cloud_print")));
|
| +#endif
|
|
|
| #if defined(OS_CHROMEOS)
|
| // Register access extensions only if accessibility is enabled.
|
| - if (g_browser_process->local_state()->
|
| - GetBoolean(prefs::kAccessibilityEnabled)) {
|
| + if (local_state_->GetBoolean(prefs::kAccessibilityEnabled)) {
|
| FilePath path = FilePath(extension_misc::kAccessExtensionPath)
|
| .AppendASCII(extension_misc::kChromeVoxDirectoryName);
|
| - std::string manifest =
|
| - ResourceBundle::GetSharedInstance().GetRawDataResource(
|
| - IDR_CHROMEVOX_MANIFEST).as_string();
|
| - Add(manifest, path);
|
| + Add(IDR_CHROMEVOX_MANIFEST, path);
|
| }
|
| #endif
|
| +
|
| + // If a URL for the enterprise webstore has been specified, load the
|
| + // component extension. This extension might also be loaded later, because
|
| + // it is specified by policy, and on ChromeOS policies are loaded after
|
| + // the browser process has started.
|
| + AddOrReloadEnterpriseWebStore();
|
| +}
|
| +
|
| +void ComponentLoader::Observe(
|
| + int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| + if (type == chrome::NOTIFICATION_PREF_CHANGED) {
|
| + const std::string* name =
|
| + content::Details<const std::string>(details).ptr();
|
| + if (*name == prefs::kEnterpriseWebStoreURL)
|
| + AddOrReloadEnterpriseWebStore();
|
| + else
|
| + NOTREACHED();
|
| + } else {
|
| + NOTREACHED();
|
| + }
|
| +}
|
| +
|
| +// static
|
| +void ComponentLoader::RegisterUserPrefs(PrefService* prefs) {
|
| + prefs->RegisterStringPref(prefs::kEnterpriseWebStoreURL,
|
| + std::string() /* default_value */,
|
| + PrefService::UNSYNCABLE_PREF);
|
| + prefs->RegisterStringPref(prefs::kEnterpriseWebStoreName,
|
| + std::string() /* default_value */,
|
| + PrefService::UNSYNCABLE_PREF);
|
| }
|
|
|
| } // namespace extensions
|
|
|