blob: 9b90fe08e797fc5f831e11d3c796597744a08d14 [file] [log] [blame]
[email protected]3b48dbc2012-01-06 16:34:171// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]e67385f2011-12-21 06:00:565#include "content/browser/plugin_service_impl.h"
initial.commit09911bf2008-07-26 23:55:296
[email protected]d33e7cc2011-09-23 01:43:567#include "base/bind.h"
[email protected]d48f1e0c2009-02-12 20:57:548#include "base/command_line.h"
[email protected]7b3ee8b2011-04-01 18:48:199#include "base/compiler_specific.h"
[email protected]dfba8762011-09-02 12:49:5410#include "base/file_path.h"
[email protected]d33e7cc2011-09-23 01:43:5611#include "base/message_loop.h"
12#include "base/message_loop_proxy.h"
[email protected]9c49ff02010-01-27 01:20:5513#include "base/path_service.h"
[email protected]d70539de2009-06-24 22:17:0614#include "base/string_util.h"
[email protected]7f070d42011-03-09 20:25:3215#include "base/synchronization/waitable_event.h"
[email protected]34b99632011-01-01 01:01:0616#include "base/threading/thread.h"
[email protected]be1ce6a72010-08-03 14:35:2217#include "base/utf_string_conversions.h"
[email protected]cec1b8d2010-03-24 00:21:3418#include "base/values.h"
[email protected]a01efd22011-03-01 00:38:3219#include "content/browser/ppapi_plugin_process_host.h"
[email protected]f3b1a082011-11-18 00:34:3020#include "content/browser/renderer_host/render_process_host_impl.h"
[email protected]b3c41c0b2012-03-06 15:48:3221#include "content/browser/renderer_host/render_view_host_impl.h"
[email protected]cebc3dc2011-04-18 17:15:0022#include "content/common/pepper_plugin_registry.h"
[email protected]105303e2011-03-14 22:16:1023#include "content/common/plugin_messages.h"
[email protected]49125952011-09-27 18:05:1524#include "content/common/utility_messages.h"
[email protected]38b592902011-04-16 02:08:4225#include "content/common/view_messages.h"
[email protected]c38831a12011-10-28 12:44:4926#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4427#include "content/public/browser/content_browser_client.h"
[email protected]31f376c2012-03-13 16:43:0928#include "content/public/browser/plugin_service_filter.h"
[email protected]ce967862012-02-09 22:47:0529#include "content/public/browser/resource_context.h"
[email protected]c08950d22011-10-13 22:20:2930#include "content/public/common/content_switches.h"
[email protected]bd5d6cf2011-12-01 00:39:1231#include "content/public/common/process_type.h"
[email protected]191eb3f72010-12-21 06:27:5032#include "webkit/plugins/npapi/plugin_list.h"
[email protected]1b517202012-12-19 17:16:1033#include "webkit/plugins/npapi/plugin_utils.h"
[email protected]91d9f3d2011-08-14 05:24:4434#include "webkit/plugins/webplugininfo.h"
[email protected]191eb3f72010-12-21 06:27:5035
[email protected]3b91edbe2012-09-27 22:49:2336#if defined(OS_WIN)
37#include "webkit/plugins/npapi/plugin_constants_win.h"
38#endif
39
40#if defined(OS_POSIX)
41#include "content/browser/plugin_loader_posix.h"
42#endif
43
[email protected]52348b22012-11-07 10:19:3444#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]6665571f2013-01-15 07:59:5245using ::base::FilePathWatcher;
[email protected]493c8002011-04-14 16:56:0146#endif
47
[email protected]130757672012-10-24 00:26:1948namespace content {
[email protected]d33e7cc2011-09-23 01:43:5649namespace {
50
[email protected]1b517202012-12-19 17:16:1051bool LoadPluginListInProcess() {
52#if defined(OS_WIN)
53 return true;
54#else
55 // If on POSIX, we don't want to load the list of NPAPI plugins in-process as
56 // that causes instability.
57 return !webkit::npapi::NPAPIPluginsSupported();
58#endif
59}
60
[email protected]49125952011-09-27 18:05:1561// Callback set on the PluginList to assert that plugin loading happens on the
62// correct thread.
[email protected]1b517202012-12-19 17:16:1063void WillLoadPluginsCallback(
[email protected]a33fa9d2012-05-16 14:47:4964 base::SequencedWorkerPool::SequenceToken token) {
[email protected]1b517202012-12-19 17:16:1065 if (LoadPluginListInProcess()) {
66 CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
67 token));
68 } else {
69 CHECK(false) << "Plugin loading should happen out-of-process.";
70 }
[email protected]a79912252012-05-16 11:52:1971}
[email protected]d33e7cc2011-09-23 01:43:5672
[email protected]a96ec6a2009-11-04 17:27:0873#if defined(OS_MACOSX)
[email protected]07b71c82013-01-08 19:07:3174void NotifyPluginsOfActivation() {
[email protected]f8b3ef82010-10-11 02:45:5275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]a96ec6a2009-11-04 17:27:0876
[email protected]4967f792012-01-20 22:14:4077 for (PluginProcessHostIterator iter; !iter.Done(); ++iter)
78 iter->OnAppActivation();
[email protected]a96ec6a2009-11-04 17:27:0879}
[email protected]3b48dbc2012-01-06 16:34:1780#endif
[email protected]45a22e62011-10-12 09:48:0281
[email protected]07b71c82013-01-08 19:07:3182#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
83void NotifyPluginDirChanged(const FilePath& path, bool error) {
84 if (error) {
[email protected]634d23d2011-01-19 10:38:1985 // TODO(pastarmovj): Add some sensible error handling. Maybe silently
86 // stopping the watcher would be enough. Or possibly restart it.
87 NOTREACHED();
[email protected]07b71c82013-01-08 19:07:3188 return;
[email protected]634d23d2011-01-19 10:38:1989 }
[email protected]07b71c82013-01-08 19:07:3190 VLOG(1) << "Watched path changed: " << path.value();
91 // Make the plugin list update itself
92 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
93 BrowserThread::PostTask(
94 BrowserThread::UI, FROM_HERE,
95 base::Bind(&PluginService::PurgePluginListCache,
96 static_cast<BrowserContext*>(NULL), false));
97}
[email protected]634d23d2011-01-19 10:38:1998#endif
99
[email protected]07b71c82013-01-08 19:07:31100} // namespace
101
[email protected]3a5180ae2011-12-21 02:39:38102// static
103PluginService* PluginService::GetInstance() {
[email protected]e67385f2011-12-21 06:00:56104 return PluginServiceImpl::GetInstance();
[email protected]3a5180ae2011-12-21 02:39:38105}
106
107void PluginService::PurgePluginListCache(BrowserContext* browser_context,
108 bool reload_pages) {
109 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
110 !it.IsAtEnd(); it.Advance()) {
111 RenderProcessHost* host = it.GetCurrentValue();
112 if (!browser_context || host->GetBrowserContext() == browser_context)
113 host->Send(new ViewMsg_PurgePluginListCache(reload_pages));
114 }
115}
116
initial.commit09911bf2008-07-26 23:55:29117// static
[email protected]e67385f2011-12-21 06:00:56118PluginServiceImpl* PluginServiceImpl::GetInstance() {
119 return Singleton<PluginServiceImpl>::get();
initial.commit09911bf2008-07-26 23:55:29120}
121
[email protected]e67385f2011-12-21 06:00:56122PluginServiceImpl::PluginServiceImpl()
[email protected]99907362012-01-11 05:41:40123 : plugin_list_(NULL), filter_(NULL) {
[email protected]ee066172011-11-10 23:20:05124}
125
[email protected]e67385f2011-12-21 06:00:56126PluginServiceImpl::~PluginServiceImpl() {
[email protected]ee066172011-11-10 23:20:05127#if defined(OS_WIN)
128 // Release the events since they're owned by RegKey, not WaitableEvent.
129 hkcu_watcher_.StopWatching();
130 hklm_watcher_.StopWatching();
131 if (hkcu_event_.get())
132 hkcu_event_->Release();
133 if (hklm_event_.get())
134 hklm_event_->Release();
135#endif
136 // Make sure no plugin channel requests have been leaked.
137 DCHECK(pending_plugin_clients_.empty());
138}
139
[email protected]e67385f2011-12-21 06:00:56140void PluginServiceImpl::Init() {
[email protected]ee066172011-11-10 23:20:05141 if (!plugin_list_)
142 plugin_list_ = webkit::npapi::PluginList::Singleton();
143
[email protected]a33fa9d2012-05-16 14:47:49144 plugin_list_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
[email protected]3a5180ae2011-12-21 02:39:38145 plugin_list_->set_will_load_plugins_callback(
[email protected]1b517202012-12-19 17:16:10146 base::Bind(&WillLoadPluginsCallback, plugin_list_token_));
[email protected]49125952011-09-27 18:05:15147
[email protected]4e0616e2010-05-28 14:55:53148 RegisterPepperPlugins();
149
[email protected]0f7d449e2013-01-23 15:12:35150 // The --site-per-process flag enables an out-of-process iframes
151 // prototype, which uses WebView for rendering. We need to register the MIME
152 // type we use with the plugin, so the renderer can instantiate it.
153 const CommandLine* command_line = CommandLine::ForCurrentProcess();
154 if (command_line->HasSwitch(switches::kSitePerProcess)) {
155 webkit::WebPluginInfo webview_plugin(
156 ASCIIToUTF16("WebView Tag"),
157 FilePath(FILE_PATH_LITERAL("")),
158 ASCIIToUTF16("1.2.3.4"),
159 ASCIIToUTF16("Browser Plugin."));
160 webview_plugin.type = webkit::WebPluginInfo::PLUGIN_TYPE_NPAPI;
161 webkit::WebPluginMimeType webview_plugin_mime_type;
162 webview_plugin_mime_type.mime_type = "application/browser-plugin";
163 webview_plugin_mime_type.file_extensions.push_back("*");
164 webview_plugin.mime_types.push_back(webview_plugin_mime_type);
165 RegisterInternalPlugin(webview_plugin, true);
166 }
167
[email protected]130757672012-10-24 00:26:19168 GetContentClient()->AddNPAPIPlugins(plugin_list_);
[email protected]f520b5b2011-11-08 02:42:14169
[email protected]9a1c4262010-06-29 21:50:27170 // Load any specified on the command line as well.
[email protected]c4e52f0d2009-11-06 19:55:16171 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
[email protected]7bf795d92010-05-22 00:14:28172 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14173 AddExtraPluginPath(path);
[email protected]9a1c4262010-06-29 21:50:27174 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
175 if (!path.empty())
[email protected]3a5180ae2011-12-21 02:39:38176 plugin_list_->AddExtraPluginDir(path);
[email protected]dfba8762011-09-02 12:49:54177}
178
[email protected]e67385f2011-12-21 06:00:56179void PluginServiceImpl::StartWatchingPlugins() {
[email protected]634d23d2011-01-19 10:38:19180 // Start watching for changes in the plugin list. This means watching
181 // for changes in the Windows registry keys and on both Windows and POSIX
182 // watch for changes in the paths that are expected to contain plugins.
[email protected]b547fd42009-04-23 23:16:27183#if defined(OS_WIN)
[email protected]86ec4f6e2011-04-20 16:21:19184 if (hkcu_key_.Create(HKEY_CURRENT_USER,
185 webkit::npapi::kRegistryMozillaPlugins,
186 KEY_NOTIFY) == ERROR_SUCCESS) {
187 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
188 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
189 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
190 }
[email protected]b547fd42009-04-23 23:16:27191 }
[email protected]86ec4f6e2011-04-20 16:21:19192 if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
193 webkit::npapi::kRegistryMozillaPlugins,
194 KEY_NOTIFY) == ERROR_SUCCESS) {
195 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
196 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
197 hklm_watcher_.StartWatching(hklm_event_.get(), this);
198 }
[email protected]b547fd42009-04-23 23:16:27199 }
[email protected]a33fa9d2012-05-16 14:47:49200#endif
[email protected]52348b22012-11-07 10:19:34201#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19202// On ChromeOS the user can't install plugins anyway and on Windows all
203// important plugins register themselves in the registry so no need to do that.
[email protected]07b71c82013-01-08 19:07:31204
[email protected]634d23d2011-01-19 10:38:19205 // Get the list of all paths for registering the FilePathWatchers
206 // that will track and if needed reload the list of plugins on runtime.
207 std::vector<FilePath> plugin_dirs;
[email protected]3a5180ae2011-12-21 02:39:38208 plugin_list_->GetPluginDirectories(&plugin_dirs);
[email protected]894bb502009-05-21 22:39:57209
[email protected]634d23d2011-01-19 10:38:19210 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
[email protected]634d23d2011-01-19 10:38:19211 // FilePathWatcher can not handle non-absolute paths under windows.
212 // We don't watch for file changes in windows now but if this should ever
213 // be extended to Windows these lines might save some time of debugging.
214#if defined(OS_WIN)
215 if (!plugin_dirs[i].IsAbsolute())
216 continue;
217#endif
[email protected]493c8002011-04-14 16:56:01218 FilePathWatcher* watcher = new FilePathWatcher();
[email protected]634d23d2011-01-19 10:38:19219 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
220 BrowserThread::PostTask(
221 BrowserThread::FILE, FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56222 base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher,
[email protected]07b71c82013-01-08 19:07:31223 plugin_dirs[i]));
[email protected]634d23d2011-01-19 10:38:19224 file_watchers_.push_back(watcher);
225 }
226#endif
initial.commit09911bf2008-07-26 23:55:29227}
228
[email protected]e67385f2011-12-21 06:00:56229PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess(
[email protected]28ab7f92009-01-06 21:39:04230 const FilePath& plugin_path) {
[email protected]4967f792012-01-20 22:14:40231 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
232 if (iter->info().path == plugin_path)
233 return *iter;
[email protected]a436d922009-02-13 23:16:42234 }
235
initial.commit09911bf2008-07-26 23:55:29236 return NULL;
237}
238
[email protected]e67385f2011-12-21 06:00:56239PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31240 const FilePath& plugin_path,
241 const FilePath& profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40242 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
[email protected]dd9a0952012-05-31 20:11:31243 if (iter->plugin_path() == plugin_path &&
244 iter->profile_data_directory() == profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40245 return *iter;
[email protected]dd9a0952012-05-31 20:11:31246 }
[email protected]a08ebea2011-02-13 17:50:20247 }
[email protected]a08ebea2011-02-13 17:50:20248 return NULL;
249}
250
[email protected]e67385f2011-12-21 06:00:56251PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42252 const FilePath& broker_path) {
[email protected]4967f792012-01-20 22:14:40253 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) {
254 if (iter->plugin_path() == broker_path)
255 return *iter;
[email protected]eb415bf0e2011-04-14 02:45:42256 }
257
258 return NULL;
259}
260
[email protected]e67385f2011-12-21 06:00:56261PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
[email protected]a08ebea2011-02-13 17:50:20262 const FilePath& plugin_path) {
263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
264
265 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
initial.commit09911bf2008-07-26 23:55:29266 if (plugin_host)
267 return plugin_host;
268
[email protected]91d9f3d2011-08-14 05:24:44269 webkit::WebPluginInfo info;
[email protected]88ca4912011-10-12 14:00:43270 if (!GetPluginInfoByPath(plugin_path, &info)) {
[email protected]a27a9382009-02-11 23:55:10271 return NULL;
272 }
273
initial.commit09911bf2008-07-26 23:55:29274 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]8b8a554d2010-11-18 13:26:40275 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
[email protected]99907362012-01-11 05:41:40276 if (!new_host->Init(info)) {
[email protected]a08ebea2011-02-13 17:50:20277 NOTREACHED(); // Init is not expected to fail.
initial.commit09911bf2008-07-26 23:55:29278 return NULL;
279 }
[email protected]8b8a554d2010-11-18 13:26:40280 return new_host.release();
initial.commit09911bf2008-07-26 23:55:29281}
282
[email protected]e67385f2011-12-21 06:00:56283PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
[email protected]d259a8e2011-05-18 22:31:09284 const FilePath& plugin_path,
[email protected]dd9a0952012-05-31 20:11:31285 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14286 PpapiPluginProcessHost::PluginClient* client) {
[email protected]a08ebea2011-02-13 17:50:20287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
288
[email protected]dd9a0952012-05-31 20:11:31289 PpapiPluginProcessHost* plugin_host =
290 FindPpapiPluginProcess(plugin_path, profile_data_directory);
[email protected]a08ebea2011-02-13 17:50:20291 if (plugin_host)
292 return plugin_host;
293
[email protected]eb415bf0e2011-04-14 02:45:42294 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19295 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]a08ebea2011-02-13 17:50:20296 if (!info)
297 return NULL;
298
299 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14300 return PpapiPluginProcessHost::CreatePluginHost(
[email protected]dd9a0952012-05-31 20:11:31301 *info, profile_data_directory,
[email protected]df02aca2012-02-09 21:03:20302 client->GetResourceContext()->GetHostResolver());
[email protected]a08ebea2011-02-13 17:50:20303}
304
[email protected]e67385f2011-12-21 06:00:56305PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42306 const FilePath& plugin_path) {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
308
[email protected]a50432d2011-09-30 16:32:14309 PpapiPluginProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42310 if (plugin_host)
311 return plugin_host;
312
313 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19314 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42315 if (!info)
316 return NULL;
317
318 // TODO(ddorwin): Uncomment once out of process is supported.
319 // DCHECK(info->is_out_of_process);
320
321 // This broker isn't loaded by any broker process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14322 return PpapiPluginProcessHost::CreateBrokerHost(*info);
[email protected]eb415bf0e2011-04-14 02:45:42323}
324
[email protected]e67385f2011-12-21 06:00:56325void PluginServiceImpl::OpenChannelToNpapiPlugin(
[email protected]c8f73ab2011-01-22 00:05:17326 int render_process_id,
327 int render_view_id,
[email protected]610c0892009-09-08 19:46:18328 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54329 const GURL& page_url,
[email protected]610c0892009-09-08 19:46:18330 const std::string& mime_type,
[email protected]46b69e42010-11-02 12:26:39331 PluginProcessHost::Client* client) {
[email protected]76b70f92011-11-21 19:31:14332 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]4befe7592011-09-14 22:49:09333 DCHECK(!ContainsKey(pending_plugin_clients_, client));
334 pending_plugin_clients_.insert(client);
[email protected]88ca4912011-10-12 14:00:43335
336 // Make sure plugins are loaded if necessary.
[email protected]209f2ae2012-03-13 01:28:08337 PluginServiceFilterParams params = {
[email protected]88ca4912011-10-12 14:00:43338 render_process_id,
339 render_view_id,
340 page_url,
[email protected]df02aca2012-02-09 21:03:20341 client->GetResourceContext()
[email protected]88ca4912011-10-12 14:00:43342 };
[email protected]e67385f2011-12-21 06:00:56343 GetPlugins(base::Bind(
344 &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin,
345 base::Unretained(this), params, url, mime_type, client));
[email protected]6fdd4182010-10-14 23:59:26346}
347
[email protected]e67385f2011-12-21 06:00:56348void PluginServiceImpl::OpenChannelToPpapiPlugin(
[email protected]dd9a0952012-05-31 20:11:31349 const FilePath& plugin_path,
350 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14351 PpapiPluginProcessHost::PluginClient* client) {
[email protected]d259a8e2011-05-18 22:31:09352 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31353 plugin_path, profile_data_directory, client);
[email protected]1bf0fb22012-04-12 21:44:16354 if (plugin_host) {
[email protected]a08ebea2011-02-13 17:50:20355 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16356 } else {
357 // Send error.
[email protected]108fd342013-01-04 20:46:54358 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0);
[email protected]1bf0fb22012-04-12 21:44:16359 }
[email protected]a08ebea2011-02-13 17:50:20360}
361
[email protected]e67385f2011-12-21 06:00:56362void PluginServiceImpl::OpenChannelToPpapiBroker(
[email protected]eb415bf0e2011-04-14 02:45:42363 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14364 PpapiPluginProcessHost::BrokerClient* client) {
365 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
[email protected]1bf0fb22012-04-12 21:44:16366 if (plugin_host) {
[email protected]a50432d2011-09-30 16:32:14367 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16368 } else {
369 // Send error.
[email protected]108fd342013-01-04 20:46:54370 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0);
[email protected]1bf0fb22012-04-12 21:44:16371 }
[email protected]eb415bf0e2011-04-14 02:45:42372}
373
[email protected]e67385f2011-12-21 06:00:56374void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
[email protected]4befe7592011-09-14 22:49:09375 PluginProcessHost::Client* client) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
377 DCHECK(ContainsKey(pending_plugin_clients_, client));
378 pending_plugin_clients_.erase(client);
379}
380
[email protected]e67385f2011-12-21 06:00:56381void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin(
[email protected]209f2ae2012-03-13 01:28:08382 const PluginServiceFilterParams& params,
[email protected]88ca4912011-10-12 14:00:43383 const GURL& url,
384 const std::string& mime_type,
385 PluginProcessHost::Client* client,
386 const std::vector<webkit::WebPluginInfo>&) {
387 GetAllowedPluginForOpenChannelToPlugin(params.render_process_id,
388 params.render_view_id, url, params.page_url, mime_type, client,
389 params.resource_context);
390}
391
[email protected]e67385f2011-12-21 06:00:56392void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
[email protected]c8f73ab2011-01-22 00:05:17393 int render_process_id,
394 int render_view_id,
[email protected]6fdd4182010-10-14 23:59:26395 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54396 const GURL& page_url,
[email protected]6fdd4182010-10-14 23:59:26397 const std::string& mime_type,
[email protected]87c4be42011-09-16 01:10:59398 PluginProcessHost::Client* client,
[email protected]130757672012-10-24 00:26:19399 ResourceContext* resource_context) {
[email protected]91d9f3d2011-08-14 05:24:44400 webkit::WebPluginInfo info;
[email protected]dfba8762011-09-02 12:49:54401 bool allow_wildcard = true;
[email protected]11e1c182011-05-17 20:26:27402 bool found = GetPluginInfo(
[email protected]df02aca2012-02-09 21:03:20403 render_process_id, render_view_id, resource_context,
[email protected]dfba8762011-09-02 12:49:54404 url, page_url, mime_type, allow_wildcard,
405 NULL, &info, NULL);
[email protected]6fdd4182010-10-14 23:59:26406 FilePath plugin_path;
[email protected]68598072011-07-29 08:21:28407 if (found)
[email protected]dfba8762011-09-02 12:49:54408 plugin_path = info.path;
[email protected]6fdd4182010-10-14 23:59:26409
410 // Now we jump back to the IO thread to finish opening the channel.
[email protected]e67385f2011-12-21 06:00:56411 BrowserThread::PostTask(
412 BrowserThread::IO, FROM_HERE,
413 base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin,
[email protected]88ca4912011-10-12 14:00:43414 base::Unretained(this), plugin_path, client));
[email protected]6fdd4182010-10-14 23:59:26415}
416
[email protected]e67385f2011-12-21 06:00:56417void PluginServiceImpl::FinishOpenChannelToPlugin(
[email protected]6fdd4182010-10-14 23:59:26418 const FilePath& plugin_path,
[email protected]46b69e42010-11-02 12:26:39419 PluginProcessHost::Client* client) {
[email protected]f8b3ef82010-10-11 02:45:52420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20a793e2010-10-12 06:50:08421
[email protected]4befe7592011-09-14 22:49:09422 // Make sure it hasn't been canceled yet.
423 if (!ContainsKey(pending_plugin_clients_, client))
424 return;
425 pending_plugin_clients_.erase(client);
426
[email protected]a08ebea2011-02-13 17:50:20427 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
[email protected]4befe7592011-09-14 22:49:09428 if (plugin_host) {
429 client->OnFoundPluginProcessHost(plugin_host);
[email protected]46b69e42010-11-02 12:26:39430 plugin_host->OpenChannelToPlugin(client);
[email protected]4befe7592011-09-14 22:49:09431 } else {
[email protected]46b69e42010-11-02 12:26:39432 client->OnError();
[email protected]4befe7592011-09-14 22:49:09433 }
initial.commit09911bf2008-07-26 23:55:29434}
435
[email protected]e67385f2011-12-21 06:00:56436bool PluginServiceImpl::GetPluginInfoArray(
[email protected]51b63f62011-10-05 18:55:42437 const GURL& url,
438 const std::string& mime_type,
439 bool allow_wildcard,
440 std::vector<webkit::WebPluginInfo>* plugins,
441 std::vector<std::string>* actual_mime_types) {
442 bool use_stale = false;
[email protected]3a5180ae2011-12-21 02:39:38443 plugin_list_->GetPluginInfoArray(url, mime_type, allow_wildcard,
444 &use_stale, plugins, actual_mime_types);
[email protected]51b63f62011-10-05 18:55:42445 return use_stale;
446}
447
[email protected]e67385f2011-12-21 06:00:56448bool PluginServiceImpl::GetPluginInfo(int render_process_id,
449 int render_view_id,
[email protected]130757672012-10-24 00:26:19450 ResourceContext* context,
[email protected]e67385f2011-12-21 06:00:56451 const GURL& url,
452 const GURL& page_url,
453 const std::string& mime_type,
454 bool allow_wildcard,
455 bool* is_stale,
456 webkit::WebPluginInfo* info,
457 std::string* actual_mime_type) {
[email protected]91d9f3d2011-08-14 05:24:44458 std::vector<webkit::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28459 std::vector<std::string> mime_types;
[email protected]88ca4912011-10-12 14:00:43460 bool stale = GetPluginInfoArray(
461 url, mime_type, allow_wildcard, &plugins, &mime_types);
462 if (is_stale)
463 *is_stale = stale;
[email protected]dfba8762011-09-02 12:49:54464
[email protected]68598072011-07-29 08:21:28465 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]dfba8762011-09-02 12:49:54466 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
467 render_view_id,
[email protected]df02aca2012-02-09 21:03:20468 context,
[email protected]dfba8762011-09-02 12:49:54469 url,
470 page_url,
471 &plugins[i])) {
[email protected]68598072011-07-29 08:21:28472 *info = plugins[i];
473 if (actual_mime_type)
474 *actual_mime_type = mime_types[i];
475 return true;
476 }
477 }
478 return false;
[email protected]6fdd4182010-10-14 23:59:26479}
480
[email protected]e67385f2011-12-21 06:00:56481bool PluginServiceImpl::GetPluginInfoByPath(const FilePath& plugin_path,
482 webkit::WebPluginInfo* info) {
[email protected]88ca4912011-10-12 14:00:43483 std::vector<webkit::WebPluginInfo> plugins;
[email protected]480c7cc2012-06-29 17:38:44484 plugin_list_->GetPluginsNoRefresh(&plugins);
[email protected]88ca4912011-10-12 14:00:43485
486 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
487 it != plugins.end();
488 ++it) {
489 if (it->path == plugin_path) {
490 *info = *it;
491 return true;
492 }
493 }
494
495 return false;
496}
497
[email protected]8be45842012-04-13 19:49:29498string16 PluginServiceImpl::GetPluginDisplayNameByPath(const FilePath& path) {
499 string16 plugin_name = path.LossyDisplayName();
500 webkit::WebPluginInfo info;
501 if (PluginService::GetInstance()->GetPluginInfoByPath(path, &info) &&
502 !info.name.empty()) {
503 plugin_name = info.name;
504#if defined(OS_MACOSX)
505 // Many plugins on the Mac have .plugin in the actual name, which looks
506 // terrible, so look for that and strip it off if present.
507 const std::string kPluginExtension = ".plugin";
508 if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
509 plugin_name.erase(plugin_name.length() - kPluginExtension.length());
510#endif // OS_MACOSX
511 }
512 return plugin_name;
513}
514
[email protected]e67385f2011-12-21 06:00:56515void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
[email protected]49125952011-09-27 18:05:15516 scoped_refptr<base::MessageLoopProxy> target_loop(
517 MessageLoop::current()->message_loop_proxy());
518
[email protected]1b517202012-12-19 17:16:10519 if (LoadPluginListInProcess()) {
520 BrowserThread::GetBlockingPool()->
521 PostSequencedWorkerTaskWithShutdownBehavior(
522 plugin_list_token_,
523 FROM_HERE,
524 base::Bind(&PluginServiceImpl::GetPluginsInternal,
525 base::Unretained(this),
526 target_loop, callback),
527 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
528 return;
529 }
530#if defined(OS_POSIX)
[email protected]49125952011-09-27 18:05:15531 std::vector<webkit::WebPluginInfo> cached_plugins;
[email protected]480c7cc2012-06-29 17:38:44532 if (plugin_list_->GetPluginsNoRefresh(&cached_plugins)) {
[email protected]49125952011-09-27 18:05:15533 // Can't assume the caller is reentrant.
534 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37535 base::Bind(callback, cached_plugins));
[email protected]49125952011-09-27 18:05:15536 } else {
[email protected]4bb85b92011-11-05 02:53:29537 // If we switch back to loading plugins in process, then we need to make
538 // sure g_thread_init() gets called since plugins may call glib at load.
[email protected]d4af1e72011-10-21 17:45:43539 if (!plugin_loader_.get())
540 plugin_loader_ = new PluginLoaderPosix;
[email protected]49125952011-09-27 18:05:15541 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]d4af1e72011-10-21 17:45:43542 base::Bind(&PluginLoaderPosix::LoadPlugins, plugin_loader_,
543 target_loop, callback));
[email protected]49125952011-09-27 18:05:15544 }
[email protected]a33fa9d2012-05-16 14:47:49545#else
[email protected]1b517202012-12-19 17:16:10546 NOTREACHED();
[email protected]49125952011-09-27 18:05:15547#endif
[email protected]d33e7cc2011-09-23 01:43:56548}
549
[email protected]e67385f2011-12-21 06:00:56550void PluginServiceImpl::GetPluginsInternal(
[email protected]d33e7cc2011-09-23 01:43:56551 base::MessageLoopProxy* target_loop,
552 const PluginService::GetPluginsCallback& callback) {
[email protected]a33fa9d2012-05-16 14:47:49553 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
554 plugin_list_token_));
[email protected]d33e7cc2011-09-23 01:43:56555
556 std::vector<webkit::WebPluginInfo> plugins;
[email protected]3a5180ae2011-12-21 02:39:38557 plugin_list_->GetPlugins(&plugins);
[email protected]d33e7cc2011-09-23 01:43:56558
559 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37560 base::Bind(callback, plugins));
[email protected]dfba8762011-09-02 12:49:54561}
562
[email protected]e67385f2011-12-21 06:00:56563void PluginServiceImpl::OnWaitableEventSignaled(
[email protected]580522632009-08-17 21:55:55564 base::WaitableEvent* waitable_event) {
[email protected]b547fd42009-04-23 23:16:27565#if defined(OS_WIN)
566 if (waitable_event == hkcu_event_.get()) {
567 hkcu_key_.StartWatching();
568 } else {
569 hklm_key_.StartWatching();
570 }
571
[email protected]3a5180ae2011-12-21 02:39:38572 plugin_list_->RefreshPlugins();
[email protected]45a22e62011-10-12 09:48:02573 PurgePluginListCache(NULL, false);
[email protected]634d23d2011-01-19 10:38:19574#else
575 // This event should only get signaled on a Windows machine.
576 NOTREACHED();
[email protected]9de09f82009-08-17 20:13:53577#endif // defined(OS_WIN)
[email protected]b547fd42009-04-23 23:16:27578}
[email protected]894bb502009-05-21 22:39:57579
[email protected]e67385f2011-12-21 06:00:56580void PluginServiceImpl::RegisterPepperPlugins() {
[email protected]84396dbc2011-04-14 06:33:42581 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
[email protected]a08ebea2011-02-13 17:50:20582 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
583 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
[email protected]c6f3dea2012-01-14 02:23:11584 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);
[email protected]4e0616e2010-05-28 14:55:53585 }
586}
[email protected]634d23d2011-01-19 10:38:19587
[email protected]eb415bf0e2011-04-14 02:45:42588// There should generally be very few plugins so a brute-force search is fine.
[email protected]130757672012-10-24 00:26:19589PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
[email protected]eb415bf0e2011-04-14 02:45:42590 const FilePath& plugin_path) {
[email protected]130757672012-10-24 00:26:19591 PepperPluginInfo* info = NULL;
[email protected]eb415bf0e2011-04-14 02:45:42592 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
[email protected]6b14feb2011-08-16 11:22:56593 if (ppapi_plugins_[i].path == plugin_path) {
594 info = &ppapi_plugins_[i];
595 break;
596 }
[email protected]eb415bf0e2011-04-14 02:45:42597 }
[email protected]076117592011-08-17 03:16:41598 if (info)
599 return info;
600 // We did not find the plugin in our list. But wait! the plugin can also
601 // be a latecomer, as it happens with pepper flash. This information
602 // can be obtained from the PluginList singleton and we can use it to
603 // construct it and add it to the list. This same deal needs to be done
604 // in the renderer side in PepperPluginRegistry.
605 webkit::WebPluginInfo webplugin_info;
[email protected]88ca4912011-10-12 14:00:43606 if (!GetPluginInfoByPath(plugin_path, &webplugin_info))
[email protected]076117592011-08-17 03:16:41607 return NULL;
[email protected]130757672012-10-24 00:26:19608 PepperPluginInfo new_pepper_info;
[email protected]076117592011-08-17 03:16:41609 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
610 return NULL;
611 ppapi_plugins_.push_back(new_pepper_info);
612 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
[email protected]eb415bf0e2011-04-14 02:45:42613}
614
[email protected]52348b22012-11-07 10:19:34615#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19616// static
[email protected]07b71c82013-01-08 19:07:31617void PluginServiceImpl::RegisterFilePathWatcher(FilePathWatcher* watcher,
618 const FilePath& path) {
619 bool result = watcher->Watch(path, false,
620 base::Bind(&NotifyPluginDirChanged));
[email protected]634d23d2011-01-19 10:38:19621 DCHECK(result);
622}
623#endif
[email protected]f520b5b2011-11-08 02:42:14624
[email protected]130757672012-10-24 00:26:19625void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) {
[email protected]3a5180ae2011-12-21 02:39:38626 filter_ = filter;
627}
628
[email protected]130757672012-10-24 00:26:19629PluginServiceFilter* PluginServiceImpl::GetFilter() {
[email protected]3a5180ae2011-12-21 02:39:38630 return filter_;
631}
632
[email protected]b6a2f8de2012-01-31 17:28:49633void PluginServiceImpl::ForcePluginShutdown(const FilePath& plugin_path) {
634 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
635 BrowserThread::PostTask(
636 BrowserThread::IO, FROM_HERE,
637 base::Bind(&PluginServiceImpl::ForcePluginShutdown,
638 base::Unretained(this), plugin_path));
639 return;
640 }
641
642 PluginProcessHost* plugin = FindNpapiPluginProcess(plugin_path);
643 if (plugin)
644 plugin->ForceShutdown();
645}
646
[email protected]47214d882012-02-29 06:28:48647static const unsigned int kMaxCrashesPerInterval = 3;
648static const unsigned int kCrashesInterval = 120;
649
650void PluginServiceImpl::RegisterPluginCrash(const FilePath& path) {
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
652 std::map<FilePath, std::vector<base::Time> >::iterator i =
653 crash_times_.find(path);
654 if (i == crash_times_.end()) {
655 crash_times_[path] = std::vector<base::Time>();
656 i = crash_times_.find(path);
657 }
658 if (i->second.size() == kMaxCrashesPerInterval) {
659 i->second.erase(i->second.begin());
660 }
661 base::Time time = base::Time::Now();
662 i->second.push_back(time);
663}
664
665bool PluginServiceImpl::IsPluginUnstable(const FilePath& path) {
666 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
667 std::map<FilePath, std::vector<base::Time> >::const_iterator i =
668 crash_times_.find(path);
669 if (i == crash_times_.end()) {
670 return false;
671 }
672 if (i->second.size() != kMaxCrashesPerInterval) {
673 return false;
674 }
675 base::TimeDelta delta = base::Time::Now() - i->second[0];
676 if (delta.InSeconds() <= kCrashesInterval) {
677 return true;
678 }
679 return false;
680}
681
[email protected]e67385f2011-12-21 06:00:56682void PluginServiceImpl::RefreshPlugins() {
[email protected]3a5180ae2011-12-21 02:39:38683 plugin_list_->RefreshPlugins();
[email protected]f520b5b2011-11-08 02:42:14684}
685
[email protected]e67385f2011-12-21 06:00:56686void PluginServiceImpl::AddExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38687 plugin_list_->AddExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14688}
689
[email protected]c6f3dea2012-01-14 02:23:11690void PluginServiceImpl::AddExtraPluginDir(const FilePath& path) {
691 plugin_list_->AddExtraPluginDir(path);
692}
693
[email protected]e67385f2011-12-21 06:00:56694void PluginServiceImpl::RemoveExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38695 plugin_list_->RemoveExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14696}
697
[email protected]e67385f2011-12-21 06:00:56698void PluginServiceImpl::UnregisterInternalPlugin(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38699 plugin_list_->UnregisterInternalPlugin(path);
[email protected]f520b5b2011-11-08 02:42:14700}
701
[email protected]e67385f2011-12-21 06:00:56702void PluginServiceImpl::SetPluginListForTesting(
[email protected]ee066172011-11-10 23:20:05703 webkit::npapi::PluginList* plugin_list) {
704 plugin_list_ = plugin_list;
705}
706
[email protected]5904cb42012-09-24 15:05:20707#if defined(OS_MACOSX)
708void PluginServiceImpl::AppActivated() {
709 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]07b71c82013-01-08 19:07:31710 base::Bind(&NotifyPluginsOfActivation));
[email protected]5904cb42012-09-24 15:05:20711}
712#endif
713
[email protected]e67385f2011-12-21 06:00:56714void PluginServiceImpl::RegisterInternalPlugin(
[email protected]c6f3dea2012-01-14 02:23:11715 const webkit::WebPluginInfo& info,
716 bool add_at_beginning) {
717 plugin_list_->RegisterInternalPlugin(info, add_at_beginning);
[email protected]f520b5b2011-11-08 02:42:14718}
719
[email protected]57aece22012-10-10 22:10:27720void PluginServiceImpl::GetInternalPlugins(
721 std::vector<webkit::WebPluginInfo>* plugins) {
722 plugin_list_->GetInternalPlugins(plugins);
723}
724
[email protected]e67385f2011-12-21 06:00:56725webkit::npapi::PluginList* PluginServiceImpl::GetPluginList() {
[email protected]3a5180ae2011-12-21 02:39:38726 return plugin_list_;
[email protected]f520b5b2011-11-08 02:42:14727}
[email protected]130757672012-10-24 00:26:19728
729} // namespace content