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); |
Jeffrey Yasskin
2013/05/14 02:26:32
This Remove() call isn't working anymore, at least
|
+ |
+ 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 |