plugin_manager.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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"
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/plugin_manager.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/chrome_paths.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/api/plugins/plugins_handler.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/notification_details.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/notification_source.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/plugin_service.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/common/pepper_plugin_info.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using content::PluginService;
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const char* kNaClPluginMimeType = "application/x-nacl";
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace extensions {
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PluginManager::PluginManager(content::BrowserContext* context)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : profile_(Profile::FromBrowserContext(context)) {
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  registrar_.Add(this,
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSION_LOADED,
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 content::Source<Profile>(profile_));
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  registrar_.Add(this,
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 content::Source<Profile>(profile_));
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)PluginManager::~PluginManager() {
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<PluginManager> >
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<PluginManager>*
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PluginManager::GetFactoryInstance() {
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::Observe(int type,
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            const content::NotificationSource& source,
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            const content::NotificationDetails& details) {
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (type == chrome::NOTIFICATION_EXTENSION_LOADED) {
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const Extension* extension =
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        content::Details<const Extension>(details).ptr();
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool plugins_or_nacl_changed = false;
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (PluginInfo::HasPlugins(extension)) {
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const PluginInfo::PluginVector* plugins =
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          PluginInfo::GetPlugins(extension);
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      CHECK(plugins);
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      plugins_or_nacl_changed = true;
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           plugin != plugins->end(); ++plugin) {
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        PluginService::GetInstance()->RefreshPlugins();
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        PluginService::GetInstance()->AddExtraPluginPath(plugin->path);
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ChromePluginServiceFilter* filter =
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            ChromePluginServiceFilter::GetInstance();
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (plugin->is_public) {
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          filter->RestrictPluginToProfileAndOrigin(
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              plugin->path, profile_, GURL());
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        } else {
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          filter->RestrictPluginToProfileAndOrigin(
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              plugin->path, profile_, extension->url());
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const NaClModuleInfo::List* nacl_modules =
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        NaClModuleInfo::GetNaClModules(extension);
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (nacl_modules) {
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      plugins_or_nacl_changed = true;
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           module != nacl_modules->end(); ++module) {
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        RegisterNaClModule(*module);
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      UpdatePluginListWithNaClModules();
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (plugins_or_nacl_changed)
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->PurgePluginListCache(profile_, false);
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) {
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const Extension* extension =
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        content::Details<UnloadedExtensionInfo>(details)->extension;
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool plugins_or_nacl_changed = false;
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (PluginInfo::HasPlugins(extension)) {
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const PluginInfo::PluginVector* plugins =
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          PluginInfo::GetPlugins(extension);
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      plugins_or_nacl_changed = true;
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (PluginInfo::PluginVector::const_iterator plugin = plugins->begin();
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           plugin != plugins->end(); ++plugin) {
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        PluginService::GetInstance()->ForcePluginShutdown(plugin->path);
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        PluginService::GetInstance()->RefreshPlugins();
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        PluginService::GetInstance()->RemoveExtraPluginPath(plugin->path);
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            plugin->path);
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const NaClModuleInfo::List* nacl_modules =
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        NaClModuleInfo::GetNaClModules(extension);
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (nacl_modules) {
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      plugins_or_nacl_changed = true;
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           module != nacl_modules->end(); ++module) {
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        UnregisterNaClModule(*module);
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      UpdatePluginListWithNaClModules();
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (plugins_or_nacl_changed)
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->PurgePluginListCache(profile_, false);
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    NOTREACHED();
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::RegisterNaClModule(const NaClModuleInfo& info) {
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(FindNaClModule(info.url) == nacl_module_list_.end());
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  nacl_module_list_.push_front(info);
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) {
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  NaClModuleInfo::List::iterator iter = FindNaClModule(info.url);
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(iter != nacl_module_list_.end());
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  nacl_module_list_.erase(iter);
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void PluginManager::UpdatePluginListWithNaClModules() {
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // An extension has been added which has a nacl_module component, which means
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // there is a MIME type that module wants to handle, so we need to add that
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // MIME type to plugins which handle NaCl modules in order to allow the
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // individual modules to handle these types.
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FilePath path;
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path))
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const content::PepperPluginInfo* pepper_info =
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!pepper_info)
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
155ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::vector<content::WebPluginMimeType>::const_iterator mime_iter;
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Check each MIME type the plugins handle for the NaCl MIME type.
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (mime_iter = pepper_info->mime_types.begin();
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (mime_iter->mime_type == kNaClPluginMimeType) {
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // This plugin handles "application/x-nacl".
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->UnregisterInternalPlugin(pepper_info->path);
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
164ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      content::WebPluginInfo info = pepper_info->ToWebPluginInfo();
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (NaClModuleInfo::List::const_iterator iter =
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               nacl_module_list_.begin();
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           iter != nacl_module_list_.end(); ++iter) {
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // Add the MIME type specified in the extension to this NaCl plugin,
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // With an extra "nacl" argument to specify the location of the NaCl
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // manifest file.
172ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        content::WebPluginMimeType mime_type_info;
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mime_type_info.mime_type = iter->mime_type;
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        mime_type_info.additional_param_names.push_back(
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::UTF8ToUTF16("nacl"));
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        mime_type_info.additional_param_values.push_back(
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            base::UTF8ToUTF16(iter->url.spec()));
178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        info.mime_types.push_back(mime_type_info);
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->RefreshPlugins();
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      PluginService::GetInstance()->RegisterInternalPlugin(info, true);
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // This plugin has been modified, no need to check the rest of its
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // types, but continue checking other plugins.
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) {
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (NaClModuleInfo::List::iterator iter = nacl_module_list_.begin();
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       iter != nacl_module_list_.end(); ++iter) {
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (iter->url == url)
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return iter;
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return nacl_module_list_.end();
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace extensions
200