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/chrome_notification_types.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/notification_details.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/plugin_service.h"
18 #include "content/public/common/pepper_plugin_info.h"
19 #include "extensions/common/extension.h"
22 using content::PluginService
;
24 static const char* kNaClPluginMimeType
= "application/x-nacl";
26 namespace extensions
{
28 PluginManager::PluginManager(Profile
* profile
) : profile_(profile
) {
29 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED
,
30 content::Source
<Profile
>(profile
));
31 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED
,
32 content::Source
<Profile
>(profile
));
35 PluginManager::~PluginManager() {
38 static base::LazyInstance
<ProfileKeyedAPIFactory
<PluginManager
> >
39 g_factory
= LAZY_INSTANCE_INITIALIZER
;
42 ProfileKeyedAPIFactory
<PluginManager
>* PluginManager::GetFactoryInstance() {
43 return &g_factory
.Get();
46 void PluginManager::Observe(int type
,
47 const content::NotificationSource
& source
,
48 const content::NotificationDetails
& details
) {
49 if (type
== chrome::NOTIFICATION_EXTENSION_LOADED
) {
50 const Extension
* extension
=
51 content::Details
<const Extension
>(details
).ptr();
53 bool plugins_or_nacl_changed
= false;
54 if (PluginInfo::HasPlugins(extension
)) {
55 const PluginInfo::PluginVector
* plugins
=
56 PluginInfo::GetPlugins(extension
);
58 plugins_or_nacl_changed
= true;
59 for (PluginInfo::PluginVector::const_iterator plugin
= plugins
->begin();
60 plugin
!= plugins
->end(); ++plugin
) {
61 PluginService::GetInstance()->RefreshPlugins();
62 PluginService::GetInstance()->AddExtraPluginPath(plugin
->path
);
63 ChromePluginServiceFilter
* filter
=
64 ChromePluginServiceFilter::GetInstance();
65 if (plugin
->is_public
) {
66 filter
->RestrictPluginToProfileAndOrigin(
67 plugin
->path
, profile_
, GURL());
69 filter
->RestrictPluginToProfileAndOrigin(
70 plugin
->path
, profile_
, extension
->url());
75 const NaClModuleInfo::List
* nacl_modules
=
76 NaClModuleInfo::GetNaClModules(extension
);
78 plugins_or_nacl_changed
= true;
79 for (NaClModuleInfo::List::const_iterator module
= nacl_modules
->begin();
80 module
!= nacl_modules
->end(); ++module
) {
81 RegisterNaClModule(*module
);
83 UpdatePluginListWithNaClModules();
86 if (plugins_or_nacl_changed
)
87 PluginService::GetInstance()->PurgePluginListCache(profile_
, false);
89 } else if (type
== chrome::NOTIFICATION_EXTENSION_UNLOADED
) {
90 const Extension
* extension
=
91 content::Details
<UnloadedExtensionInfo
>(details
)->extension
;
93 bool plugins_or_nacl_changed
= false;
94 if (PluginInfo::HasPlugins(extension
)) {
95 const PluginInfo::PluginVector
* plugins
=
96 PluginInfo::GetPlugins(extension
);
97 plugins_or_nacl_changed
= true;
98 for (PluginInfo::PluginVector::const_iterator plugin
= plugins
->begin();
99 plugin
!= plugins
->end(); ++plugin
) {
100 PluginService::GetInstance()->ForcePluginShutdown(plugin
->path
);
101 PluginService::GetInstance()->RefreshPlugins();
102 PluginService::GetInstance()->RemoveExtraPluginPath(plugin
->path
);
103 ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(
108 const NaClModuleInfo::List
* nacl_modules
=
109 NaClModuleInfo::GetNaClModules(extension
);
111 plugins_or_nacl_changed
= true;
112 for (NaClModuleInfo::List::const_iterator module
= nacl_modules
->begin();
113 module
!= nacl_modules
->end(); ++module
) {
114 UnregisterNaClModule(*module
);
116 UpdatePluginListWithNaClModules();
119 if (plugins_or_nacl_changed
)
120 PluginService::GetInstance()->PurgePluginListCache(profile_
, false);
127 void PluginManager::RegisterNaClModule(const NaClModuleInfo
& info
) {
128 DCHECK(FindNaClModule(info
.url
) == nacl_module_list_
.end());
129 nacl_module_list_
.push_front(info
);
132 void PluginManager::UnregisterNaClModule(const NaClModuleInfo
& info
) {
133 NaClModuleInfo::List::iterator iter
= FindNaClModule(info
.url
);
134 DCHECK(iter
!= nacl_module_list_
.end());
135 nacl_module_list_
.erase(iter
);
138 void PluginManager::UpdatePluginListWithNaClModules() {
139 // An extension has been added which has a nacl_module component, which means
140 // there is a MIME type that module wants to handle, so we need to add that
141 // MIME type to plugins which handle NaCl modules in order to allow the
142 // individual modules to handle these types.
144 if (!PathService::Get(chrome::FILE_NACL_PLUGIN
, &path
))
146 const content::PepperPluginInfo
* pepper_info
=
147 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path
);
151 std::vector
<content::WebPluginMimeType
>::const_iterator mime_iter
;
152 // Check each MIME type the plugins handle for the NaCl MIME type.
153 for (mime_iter
= pepper_info
->mime_types
.begin();
154 mime_iter
!= pepper_info
->mime_types
.end(); ++mime_iter
) {
155 if (mime_iter
->mime_type
== kNaClPluginMimeType
) {
156 // This plugin handles "application/x-nacl".
158 PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info
->path
);
160 content::WebPluginInfo info
= pepper_info
->ToWebPluginInfo();
162 for (NaClModuleInfo::List::const_iterator iter
=
163 nacl_module_list_
.begin();
164 iter
!= nacl_module_list_
.end(); ++iter
) {
165 // Add the MIME type specified in the extension to this NaCl plugin,
166 // With an extra "nacl" argument to specify the location of the NaCl
168 content::WebPluginMimeType mime_type_info
;
169 mime_type_info
.mime_type
= iter
->mime_type
;
170 mime_type_info
.additional_param_names
.push_back(
171 base::UTF8ToUTF16("nacl"));
172 mime_type_info
.additional_param_values
.push_back(
173 base::UTF8ToUTF16(iter
->url
.spec()));
174 info
.mime_types
.push_back(mime_type_info
);
177 PluginService::GetInstance()->RefreshPlugins();
178 PluginService::GetInstance()->RegisterInternalPlugin(info
, true);
179 // This plugin has been modified, no need to check the rest of its
180 // types, but continue checking other plugins.
186 NaClModuleInfo::List::iterator
PluginManager::FindNaClModule(const GURL
& url
) {
187 for (NaClModuleInfo::List::iterator iter
= nacl_module_list_
.begin();
188 iter
!= nacl_module_list_
.end(); ++iter
) {
189 if (iter
->url
== url
)
192 return nacl_module_list_
.end();
195 } // namespace extensions