blob: 962415f4b81304710288a876e13285f54fdf5386 [file] [log] [blame]
// Copyright 2013 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/plugin_manager.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/mime_types_handler.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_NACL)
#include "components/nacl/common/nacl_constants.h"
#endif
using content::PluginService;
namespace extensions {
PluginManager::PluginManager(content::BrowserContext* context)
: profile_(Profile::FromBrowserContext(context)),
extension_registry_observer_(this) {
extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
}
PluginManager::~PluginManager() {
}
static base::LazyInstance<BrowserContextKeyedAPIFactory<PluginManager>>::
DestructorAtExit g_plugin_manager_factory = LAZY_INSTANCE_INITIALIZER;
// static
BrowserContextKeyedAPIFactory<PluginManager>*
PluginManager::GetFactoryInstance() {
return g_plugin_manager_factory.Pointer();
}
void PluginManager::OnExtensionLoaded(content::BrowserContext* browser_context,
const Extension* extension) {
bool plugins_or_nacl_changed = false;
#if BUILDFLAG(ENABLE_NACL)
const NaClModuleInfo::List* nacl_modules =
NaClModuleInfo::GetNaClModules(extension);
if (nacl_modules) {
plugins_or_nacl_changed = true;
for (auto module = nacl_modules->begin(); module != nacl_modules->end();
++module) {
RegisterNaClModule(*module);
}
UpdatePluginListWithNaClModules();
}
#endif
const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
if (handler && handler->HasPlugin()) {
plugins_or_nacl_changed = true;
content::WebPluginInfo info;
info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
info.name = base::UTF8ToUTF16(extension->name());
info.path = handler->GetPluginPath();
info.background_color = handler->GetBackgroundColor();
for (auto mime_type = handler->mime_type_set().begin();
mime_type != handler->mime_type_set().end(); ++mime_type) {
content::WebPluginMimeType mime_type_info;
mime_type_info.mime_type = *mime_type;
base::FilePath::StringType file_extension;
if (net::GetPreferredExtensionForMimeType(*mime_type, &file_extension)) {
mime_type_info.file_extensions.push_back(
base::FilePath(file_extension).AsUTF8Unsafe());
}
info.mime_types.push_back(mime_type_info);
}
PluginService::GetInstance()->RefreshPlugins();
PluginService::GetInstance()->RegisterInternalPlugin(info, true);
}
if (plugins_or_nacl_changed)
PluginService::GetInstance()->PurgePluginListCache(profile_, false);
}
void PluginManager::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionReason reason) {
bool plugins_or_nacl_changed = false;
#if BUILDFLAG(ENABLE_NACL)
const NaClModuleInfo::List* nacl_modules =
NaClModuleInfo::GetNaClModules(extension);
if (nacl_modules) {
plugins_or_nacl_changed = true;
for (auto module = nacl_modules->begin(); module != nacl_modules->end();
++module) {
UnregisterNaClModule(*module);
}
UpdatePluginListWithNaClModules();
}
#endif
const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
if (handler && handler->HasPlugin()) {
plugins_or_nacl_changed = true;
base::FilePath path = handler->GetPluginPath();
PluginService::GetInstance()->UnregisterInternalPlugin(path);
PluginService::GetInstance()->RefreshPlugins();
}
if (plugins_or_nacl_changed)
PluginService::GetInstance()->PurgePluginListCache(profile_, false);
}
#if BUILDFLAG(ENABLE_NACL)
void PluginManager::RegisterNaClModule(const NaClModuleInfo& info) {
DCHECK(FindNaClModule(info.url) == nacl_module_list_.end());
nacl_module_list_.push_front(info);
}
void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) {
auto iter = FindNaClModule(info.url);
DCHECK(iter != nacl_module_list_.end());
nacl_module_list_.erase(iter);
}
void PluginManager::UpdatePluginListWithNaClModules() {
// An extension has been added which has a nacl_module component, which means
// there is a MIME type that module wants to handle, so we need to add that
// MIME type to plugins which handle NaCl modules in order to allow the
// individual modules to handle these types.
static const base::FilePath path(ChromeContentClient::kNaClPluginFileName);
const content::PepperPluginInfo* pepper_info =
PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
if (!pepper_info)
return;
std::vector<content::WebPluginMimeType>::const_iterator mime_iter;
// Check each MIME type the plugins handle for the NaCl MIME type.
for (mime_iter = pepper_info->mime_types.begin();
mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
if (mime_iter->mime_type == nacl::kNaClPluginMimeType) {
// This plugin handles "application/x-nacl".
PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path);
content::WebPluginInfo info = pepper_info->ToWebPluginInfo();
for (NaClModuleInfo::List::const_iterator iter =
nacl_module_list_.begin();
iter != nacl_module_list_.end(); ++iter) {
// Add the MIME type specified in the extension to this NaCl plugin,
// With an extra "nacl" argument to specify the location of the NaCl
// manifest file.
content::WebPluginMimeType mime_type_info;
mime_type_info.mime_type = iter->mime_type;
mime_type_info.additional_params.emplace_back(
base::UTF8ToUTF16("nacl"), base::UTF8ToUTF16(iter->url.spec()));
info.mime_types.emplace_back(std::move(mime_type_info));
}
PluginService::GetInstance()->RefreshPlugins();
PluginService::GetInstance()->RegisterInternalPlugin(info, true);
// This plugin has been modified, no need to check the rest of its
// types, but continue checking other plugins.
break;
}
}
}
NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) {
for (auto iter = nacl_module_list_.begin(); iter != nacl_module_list_.end();
++iter) {
if (iter->url == url)
return iter;
}
return nacl_module_list_.end();
}
#endif // BUILDFLAG(ENABLE_NACL)
} // namespace extensions