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. 4 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 "chrome/common/extensions/manifest_handlers/mime_types_handler.h" 16 #include "content/public/browser/plugin_service.h" 17 #include "content/public/common/pepper_plugin_info.h" 18 #include "extensions/browser/extension_registry.h" 19 #include "extensions/common/extension.h" 20 #include "url/gurl.h" 21 22 #if !defined(DISABLE_NACL) 23 #include "components/nacl/common/nacl_constants.h" 24 #endif 25 26 using content::PluginService; 27 28 namespace extensions { 29 30 PluginManager::PluginManager(content::BrowserContext* context) 31 : profile_(Profile::FromBrowserContext(context)), 32 extension_registry_observer_(this) { 33 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); 34 } 35 36 PluginManager::~PluginManager() { 37 } 38 39 static base::LazyInstance<BrowserContextKeyedAPIFactory<PluginManager> > 40 g_factory = LAZY_INSTANCE_INITIALIZER; 41 42 // static 43 BrowserContextKeyedAPIFactory<PluginManager>* 44 PluginManager::GetFactoryInstance() { 45 return g_factory.Pointer(); 46 } 47 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); 53 CHECK(plugins); 54 plugins_or_nacl_changed = true; 55 for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin(); 56 plugin != plugins->end(); 57 ++plugin) { 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()); 65 } else { 66 filter->RestrictPluginToProfileAndOrigin( 67 plugin->path, profile_, extension->url()); 68 } 69 } 70 } 71 72 #if !defined(DISABLE_NACL) 73 const NaClModuleInfo::List* nacl_modules = 74 NaClModuleInfo::GetNaClModules(extension); 75 if (nacl_modules) { 76 plugins_or_nacl_changed = true; 77 for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin(); 78 module != nacl_modules->end(); 79 ++module) { 80 RegisterNaClModule(*module); 81 } 82 UpdatePluginListWithNaClModules(); 83 } 84 #endif 85 86 const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension); 87 if (handler && !handler->handler_url().empty()) { 88 plugins_or_nacl_changed = true; 89 90 content::WebPluginInfo info; 91 info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN; 92 info.name = base::UTF8ToUTF16(handler->extension_id()); 93 info.path = base::FilePath::FromUTF8Unsafe(handler->extension_id()); 94 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 info.mime_types.push_back(mime_type_info); 101 } 102 103 PluginService::GetInstance()->RefreshPlugins(); 104 PluginService::GetInstance()->RegisterInternalPlugin(info, true); 105 } 106 107 if (plugins_or_nacl_changed) 108 PluginService::GetInstance()->PurgePluginListCache(profile_, false); 109 } 110 111 void PluginManager::OnExtensionUnloaded( 112 content::BrowserContext* browser_context, 113 const Extension* extension, 114 UnloadedExtensionInfo::Reason reason) { 115 bool plugins_or_nacl_changed = false; 116 if (PluginInfo::HasPlugins(extension)) { 117 const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension); 118 plugins_or_nacl_changed = true; 119 for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin(); 120 plugin != plugins->end(); 121 ++plugin) { 122 PluginService::GetInstance()->ForcePluginShutdown(plugin->path); 123 PluginService::GetInstance()->RefreshPlugins(); 124 PluginService::GetInstance()->RemoveExtraPluginPath(plugin->path); 125 ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin->path); 126 } 127 } 128 129 #if !defined(DISABLE_NACL) 130 const NaClModuleInfo::List* nacl_modules = 131 NaClModuleInfo::GetNaClModules(extension); 132 if (nacl_modules) { 133 plugins_or_nacl_changed = true; 134 for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin(); 135 module != nacl_modules->end(); 136 ++module) { 137 UnregisterNaClModule(*module); 138 } 139 UpdatePluginListWithNaClModules(); 140 } 141 #endif 142 143 const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension); 144 if (handler && !handler->handler_url().empty()) { 145 plugins_or_nacl_changed = true; 146 base::FilePath path = 147 base::FilePath::FromUTF8Unsafe(handler->extension_id()); 148 PluginService::GetInstance()->UnregisterInternalPlugin(path); 149 PluginService::GetInstance()->ForcePluginShutdown(path); 150 PluginService::GetInstance()->RefreshPlugins(); 151 } 152 153 if (plugins_or_nacl_changed) 154 PluginService::GetInstance()->PurgePluginListCache(profile_, false); 155 } 156 157 #if !defined(DISABLE_NACL) 158 159 void PluginManager::RegisterNaClModule(const NaClModuleInfo& info) { 160 DCHECK(FindNaClModule(info.url) == nacl_module_list_.end()); 161 nacl_module_list_.push_front(info); 162 } 163 164 void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) { 165 NaClModuleInfo::List::iterator iter = FindNaClModule(info.url); 166 DCHECK(iter != nacl_module_list_.end()); 167 nacl_module_list_.erase(iter); 168 } 169 170 void PluginManager::UpdatePluginListWithNaClModules() { 171 // An extension has been added which has a nacl_module component, which means 172 // there is a MIME type that module wants to handle, so we need to add that 173 // MIME type to plugins which handle NaCl modules in order to allow the 174 // individual modules to handle these types. 175 base::FilePath path; 176 if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) 177 return; 178 const content::PepperPluginInfo* pepper_info = 179 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path); 180 if (!pepper_info) 181 return; 182 183 std::vector<content::WebPluginMimeType>::const_iterator mime_iter; 184 // Check each MIME type the plugins handle for the NaCl MIME type. 185 for (mime_iter = pepper_info->mime_types.begin(); 186 mime_iter != pepper_info->mime_types.end(); ++mime_iter) { 187 if (mime_iter->mime_type == nacl::kNaClPluginMimeType) { 188 // This plugin handles "application/x-nacl". 189 190 PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path); 191 192 content::WebPluginInfo info = pepper_info->ToWebPluginInfo(); 193 194 for (NaClModuleInfo::List::const_iterator iter = 195 nacl_module_list_.begin(); 196 iter != nacl_module_list_.end(); ++iter) { 197 // Add the MIME type specified in the extension to this NaCl plugin, 198 // With an extra "nacl" argument to specify the location of the NaCl 199 // manifest file. 200 content::WebPluginMimeType mime_type_info; 201 mime_type_info.mime_type = iter->mime_type; 202 mime_type_info.additional_param_names.push_back( 203 base::UTF8ToUTF16("nacl")); 204 mime_type_info.additional_param_values.push_back( 205 base::UTF8ToUTF16(iter->url.spec())); 206 info.mime_types.push_back(mime_type_info); 207 } 208 209 PluginService::GetInstance()->RefreshPlugins(); 210 PluginService::GetInstance()->RegisterInternalPlugin(info, true); 211 // This plugin has been modified, no need to check the rest of its 212 // types, but continue checking other plugins. 213 break; 214 } 215 } 216 } 217 218 NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) { 219 for (NaClModuleInfo::List::iterator iter = nacl_module_list_.begin(); 220 iter != nacl_module_list_.end(); ++iter) { 221 if (iter->url == url) 222 return iter; 223 } 224 return nacl_module_list_.end(); 225 } 226 227 #endif // !defined(DISABLE_NACL) 228 229 } // namespace extensions 230