plugin_manager.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_path.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/lazy_instance.h"
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/path_service.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/plugin_manager.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/chrome_paths.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/api/plugins/plugins_handler.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/plugin_service.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/common/pepper_plugin_info.h"
160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/browser/extension_registry.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using content::PluginService;
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstatic const char kNaClPluginMimeType[] = "application/x-nacl";
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace extensions {
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PluginManager::PluginManager(content::BrowserContext* context)
270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : profile_(Profile::FromBrowserContext(context)),
280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      extension_registry_observer_(this) {
290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)PluginManager::~PluginManager() {
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<PluginManager> >
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<PluginManager>*
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PluginManager::GetFactoryInstance() {
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid PluginManager::OnExtensionLoaded(content::BrowserContext* browser_context,
450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                      const Extension* extension) {
460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool plugins_or_nacl_changed = false;
470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (PluginInfo::HasPlugins(extension)) {
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension);
490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    CHECK(plugins);
500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    plugins_or_nacl_changed = true;
510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         plugin != plugins->end();
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++plugin) {
540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      PluginService::GetInstance()->RefreshPlugins();
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      PluginService::GetInstance()->AddExtraPluginPath(plugin->path);
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ChromePluginServiceFilter* filter =
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          ChromePluginServiceFilter::GetInstance();
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if (plugin->is_public) {
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        filter->RestrictPluginToProfileAndOrigin(
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            plugin->path, profile_, GURL());
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      } else {
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        filter->RestrictPluginToProfileAndOrigin(
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            plugin->path, profile_, extension->url());
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const NaClModuleInfo::List* nacl_modules =
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      NaClModuleInfo::GetNaClModules(extension);
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (nacl_modules) {
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    plugins_or_nacl_changed = true;
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         module != nacl_modules->end();
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++module) {
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      RegisterNaClModule(*module);
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    UpdatePluginListWithNaClModules();
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (plugins_or_nacl_changed)
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    PluginService::GetInstance()->PurgePluginListCache(profile_, false);
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid PluginManager::OnExtensionUnloaded(
850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    content::BrowserContext* browser_context,
860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const Extension* extension,
870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    UnloadedExtensionInfo::Reason reason) {
880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool plugins_or_nacl_changed = false;
890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (PluginInfo::HasPlugins(extension)) {
900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const PluginInfo::PluginVector* plugins = PluginInfo::GetPlugins(extension);
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    plugins_or_nacl_changed = true;
920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         plugin != plugins->end();
940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++plugin) {
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      PluginService::GetInstance()->ForcePluginShutdown(plugin->path);
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      PluginService::GetInstance()->RefreshPlugins();
970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      PluginService::GetInstance()->RemoveExtraPluginPath(plugin->path);
980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin->path);
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const NaClModuleInfo::List* nacl_modules =
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      NaClModuleInfo::GetNaClModules(extension);
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (nacl_modules) {
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    plugins_or_nacl_changed = true;
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         module != nacl_modules->end();
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch         ++module) {
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      UnregisterNaClModule(*module);
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    UpdatePluginListWithNaClModules();
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (plugins_or_nacl_changed)
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    PluginService::GetInstance()->PurgePluginListCache(profile_, false);
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::RegisterNaClModule(const NaClModuleInfo& info) {
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(FindNaClModule(info.url) == nacl_module_list_.end());
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  nacl_module_list_.push_front(info);
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) {
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  NaClModuleInfo::List::iterator iter = FindNaClModule(info.url);
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(iter != nacl_module_list_.end());
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  nacl_module_list_.erase(iter);
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::UpdatePluginListWithNaClModules() {
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // An extension has been added which has a nacl_module component, which means
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // there is a MIME type that module wants to handle, so we need to add that
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // MIME type to plugins which handle NaCl modules in order to allow the
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // individual modules to handle these types.
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FilePath path;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path))
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const content::PepperPluginInfo* pepper_info =
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!pepper_info)
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
142ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::vector<content::WebPluginMimeType>::const_iterator mime_iter;
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Check each MIME type the plugins handle for the NaCl MIME type.
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (mime_iter = pepper_info->mime_types.begin();
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (mime_iter->mime_type == kNaClPluginMimeType) {
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // This plugin handles "application/x-nacl".
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path);
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      content::WebPluginInfo info = pepper_info->ToWebPluginInfo();
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (NaClModuleInfo::List::const_iterator iter =
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               nacl_module_list_.begin();
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           iter != nacl_module_list_.end(); ++iter) {
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // Add the MIME type specified in the extension to this NaCl plugin,
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // With an extra "nacl" argument to specify the location of the NaCl
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // manifest file.
159ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        content::WebPluginMimeType mime_type_info;
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mime_type_info.mime_type = iter->mime_type;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        mime_type_info.additional_param_names.push_back(
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::UTF8ToUTF16("nacl"));
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mime_type_info.additional_param_values.push_back(
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::UTF8ToUTF16(iter->url.spec()));
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        info.mime_types.push_back(mime_type_info);
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->RefreshPlugins();
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->RegisterInternalPlugin(info, true);
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // This plugin has been modified, no need to check the rest of its
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // types, but continue checking other plugins.
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) {
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (NaClModuleInfo::List::iterator iter = nacl_module_list_.begin();
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       iter != nacl_module_list_.end(); ++iter) {
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (iter->url == url)
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return iter;
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return nacl_module_list_.end();
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace extensions
187