1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/files/file_path.h"
6 #include "base/lazy_instance.h"
7 #include "base/path_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/plugin_manager.h"
11 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/chrome_paths.h"
14 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
15 #include "content/public/browser/plugin_service.h"
16 #include "content/public/common/pepper_plugin_info.h"
17 #include "extensions/browser/extension_registry.h"
18 #include "extensions/common/extension.h"
19 #include "extensions/common/manifest_handlers/mime_types_handler.h"
22 #if !defined(DISABLE_NACL)
23 #include "components/nacl/common/nacl_constants.h"
26 using content::PluginService
;
28 namespace extensions
{
30 PluginManager::PluginManager(content::BrowserContext
* context
)
31 : profile_(Profile::FromBrowserContext(context
)),
32 extension_registry_observer_(this) {
33 extension_registry_observer_
.Add(ExtensionRegistry::Get(profile_
));
36 PluginManager::~PluginManager() {
39 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<PluginManager
> >
40 g_factory
= LAZY_INSTANCE_INITIALIZER
;
43 BrowserContextKeyedAPIFactory
<PluginManager
>*
44 PluginManager::GetFactoryInstance() {
45 return g_factory
.Pointer();
48 void PluginManager::OnExtensionLoaded(content::BrowserContext
* browser_context
,
49 const Extension
* extension
) {
50 bool plugins_or_nacl_changed
= false;
51 if (PluginInfo::HasPlugins(extension
)) {
52 const PluginInfo::PluginVector
* plugins
= PluginInfo::GetPlugins(extension
);
54 plugins_or_nacl_changed
= true;
55 for (PluginInfo::PluginVector::const_iterator plugin
= plugins
->begin();
56 plugin
!= plugins
->end();
58 PluginService::GetInstance()->RefreshPlugins();
59 PluginService::GetInstance()->AddExtraPluginPath(plugin
->path
);
60 ChromePluginServiceFilter
* filter
=
61 ChromePluginServiceFilter::GetInstance();
62 if (plugin
->is_public
) {
63 filter
->RestrictPluginToProfileAndOrigin(
64 plugin
->path
, profile_
, GURL());
66 filter
->RestrictPluginToProfileAndOrigin(
67 plugin
->path
, profile_
, extension
->url());
72 #if !defined(DISABLE_NACL)
73 const NaClModuleInfo::List
* nacl_modules
=
74 NaClModuleInfo::GetNaClModules(extension
);
76 plugins_or_nacl_changed
= true;
77 for (NaClModuleInfo::List::const_iterator module
= nacl_modules
->begin();
78 module
!= nacl_modules
->end();
80 RegisterNaClModule(*module
);
82 UpdatePluginListWithNaClModules();
86 const MimeTypesHandler
* handler
= MimeTypesHandler::GetHandler(extension
);
87 if (handler
&& !handler
->handler_url().empty()) {
88 plugins_or_nacl_changed
= true;
90 content::WebPluginInfo info
;
91 info
.type
= content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN
;
92 info
.name
= base::UTF8ToUTF16(extension
->name());
93 info
.path
= base::FilePath::FromUTF8Unsafe(extension
->url().spec());
95 for (std::set
<std::string
>::const_iterator mime_type
=
96 handler
->mime_type_set().begin();
97 mime_type
!= handler
->mime_type_set().end(); ++mime_type
) {
98 content::WebPluginMimeType mime_type_info
;
99 mime_type_info
.mime_type
= *mime_type
;
100 base::FilePath::StringType file_extension
;
101 if (net::GetPreferredExtensionForMimeType(*mime_type
, &file_extension
)) {
102 mime_type_info
.file_extensions
.push_back(
103 base::FilePath(file_extension
).AsUTF8Unsafe());
105 info
.mime_types
.push_back(mime_type_info
);
108 PluginService::GetInstance()->RefreshPlugins();
109 PluginService::GetInstance()->RegisterInternalPlugin(info
, true);
112 if (plugins_or_nacl_changed
)
113 PluginService::GetInstance()->PurgePluginListCache(profile_
, false);
116 void PluginManager::OnExtensionUnloaded(
117 content::BrowserContext
* browser_context
,
118 const Extension
* extension
,
119 UnloadedExtensionInfo::Reason reason
) {
120 bool plugins_or_nacl_changed
= false;
121 if (PluginInfo::HasPlugins(extension
)) {
122 const PluginInfo::PluginVector
* plugins
= PluginInfo::GetPlugins(extension
);
123 plugins_or_nacl_changed
= true;
124 for (PluginInfo::PluginVector::const_iterator plugin
= plugins
->begin();
125 plugin
!= plugins
->end();
127 PluginService::GetInstance()->ForcePluginShutdown(plugin
->path
);
128 PluginService::GetInstance()->RefreshPlugins();
129 PluginService::GetInstance()->RemoveExtraPluginPath(plugin
->path
);
130 ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin
->path
);
134 #if !defined(DISABLE_NACL)
135 const NaClModuleInfo::List
* nacl_modules
=
136 NaClModuleInfo::GetNaClModules(extension
);
138 plugins_or_nacl_changed
= true;
139 for (NaClModuleInfo::List::const_iterator module
= nacl_modules
->begin();
140 module
!= nacl_modules
->end();
142 UnregisterNaClModule(*module
);
144 UpdatePluginListWithNaClModules();
148 const MimeTypesHandler
* handler
= MimeTypesHandler::GetHandler(extension
);
149 if (handler
&& !handler
->handler_url().empty()) {
150 plugins_or_nacl_changed
= true;
151 base::FilePath path
=
152 base::FilePath::FromUTF8Unsafe(extension
->url().spec());
153 PluginService::GetInstance()->UnregisterInternalPlugin(path
);
154 PluginService::GetInstance()->ForcePluginShutdown(path
);
155 PluginService::GetInstance()->RefreshPlugins();
158 if (plugins_or_nacl_changed
)
159 PluginService::GetInstance()->PurgePluginListCache(profile_
, false);
162 #if !defined(DISABLE_NACL)
164 void PluginManager::RegisterNaClModule(const NaClModuleInfo
& info
) {
165 DCHECK(FindNaClModule(info
.url
) == nacl_module_list_
.end());
166 nacl_module_list_
.push_front(info
);
169 void PluginManager::UnregisterNaClModule(const NaClModuleInfo
& info
) {
170 NaClModuleInfo::List::iterator iter
= FindNaClModule(info
.url
);
171 DCHECK(iter
!= nacl_module_list_
.end());
172 nacl_module_list_
.erase(iter
);
175 void PluginManager::UpdatePluginListWithNaClModules() {
176 // An extension has been added which has a nacl_module component, which means
177 // there is a MIME type that module wants to handle, so we need to add that
178 // MIME type to plugins which handle NaCl modules in order to allow the
179 // individual modules to handle these types.
181 if (!PathService::Get(chrome::FILE_NACL_PLUGIN
, &path
))
183 const content::PepperPluginInfo
* pepper_info
=
184 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path
);
188 std::vector
<content::WebPluginMimeType
>::const_iterator mime_iter
;
189 // Check each MIME type the plugins handle for the NaCl MIME type.
190 for (mime_iter
= pepper_info
->mime_types
.begin();
191 mime_iter
!= pepper_info
->mime_types
.end(); ++mime_iter
) {
192 if (mime_iter
->mime_type
== nacl::kNaClPluginMimeType
) {
193 // This plugin handles "application/x-nacl".
195 PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info
->path
);
197 content::WebPluginInfo info
= pepper_info
->ToWebPluginInfo();
199 for (NaClModuleInfo::List::const_iterator iter
=
200 nacl_module_list_
.begin();
201 iter
!= nacl_module_list_
.end(); ++iter
) {
202 // Add the MIME type specified in the extension to this NaCl plugin,
203 // With an extra "nacl" argument to specify the location of the NaCl
205 content::WebPluginMimeType mime_type_info
;
206 mime_type_info
.mime_type
= iter
->mime_type
;
207 mime_type_info
.additional_param_names
.push_back(
208 base::UTF8ToUTF16("nacl"));
209 mime_type_info
.additional_param_values
.push_back(
210 base::UTF8ToUTF16(iter
->url
.spec()));
211 info
.mime_types
.push_back(mime_type_info
);
214 PluginService::GetInstance()->RefreshPlugins();
215 PluginService::GetInstance()->RegisterInternalPlugin(info
, true);
216 // This plugin has been modified, no need to check the rest of its
217 // types, but continue checking other plugins.
223 NaClModuleInfo::List::iterator
PluginManager::FindNaClModule(const GURL
& url
) {
224 for (NaClModuleInfo::List::iterator iter
= nacl_module_list_
.begin();
225 iter
!= nacl_module_list_
.end(); ++iter
) {
226 if (iter
->url
== url
)
229 return nacl_module_list_
.end();
232 #endif // !defined(DISABLE_NACL)
234 } // namespace extensions