blob: 2cd2eb16f94dd83f7952e49e1f4fe5ec459f2db5 [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]130757672012-10-24 00:26:19150 GetContentClient()->AddNPAPIPlugins(plugin_list_);
[email protected]f520b5b2011-11-08 02:42:14151
[email protected]9a1c4262010-06-29 21:50:27152 // Load any specified on the command line as well.
[email protected]d48f1e0c2009-02-12 20:57:54153 const CommandLine* command_line = CommandLine::ForCurrentProcess();
[email protected]c4e52f0d2009-11-06 19:55:16154 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
[email protected]7bf795d92010-05-22 00:14:28155 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14156 AddExtraPluginPath(path);
[email protected]9a1c4262010-06-29 21:50:27157 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
158 if (!path.empty())
[email protected]3a5180ae2011-12-21 02:39:38159 plugin_list_->AddExtraPluginDir(path);
[email protected]dfba8762011-09-02 12:49:54160}
161
[email protected]e67385f2011-12-21 06:00:56162void PluginServiceImpl::StartWatchingPlugins() {
[email protected]634d23d2011-01-19 10:38:19163 // Start watching for changes in the plugin list. This means watching
164 // for changes in the Windows registry keys and on both Windows and POSIX
165 // watch for changes in the paths that are expected to contain plugins.
[email protected]b547fd42009-04-23 23:16:27166#if defined(OS_WIN)
[email protected]86ec4f6e2011-04-20 16:21:19167 if (hkcu_key_.Create(HKEY_CURRENT_USER,
168 webkit::npapi::kRegistryMozillaPlugins,
169 KEY_NOTIFY) == ERROR_SUCCESS) {
170 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
171 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
172 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
173 }
[email protected]b547fd42009-04-23 23:16:27174 }
[email protected]86ec4f6e2011-04-20 16:21:19175 if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
176 webkit::npapi::kRegistryMozillaPlugins,
177 KEY_NOTIFY) == ERROR_SUCCESS) {
178 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
179 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
180 hklm_watcher_.StartWatching(hklm_event_.get(), this);
181 }
[email protected]b547fd42009-04-23 23:16:27182 }
[email protected]a33fa9d2012-05-16 14:47:49183#endif
[email protected]52348b22012-11-07 10:19:34184#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19185// On ChromeOS the user can't install plugins anyway and on Windows all
186// important plugins register themselves in the registry so no need to do that.
[email protected]07b71c82013-01-08 19:07:31187
[email protected]634d23d2011-01-19 10:38:19188 // Get the list of all paths for registering the FilePathWatchers
189 // that will track and if needed reload the list of plugins on runtime.
190 std::vector<FilePath> plugin_dirs;
[email protected]3a5180ae2011-12-21 02:39:38191 plugin_list_->GetPluginDirectories(&plugin_dirs);
[email protected]894bb502009-05-21 22:39:57192
[email protected]634d23d2011-01-19 10:38:19193 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
[email protected]634d23d2011-01-19 10:38:19194 // FilePathWatcher can not handle non-absolute paths under windows.
195 // We don't watch for file changes in windows now but if this should ever
196 // be extended to Windows these lines might save some time of debugging.
197#if defined(OS_WIN)
198 if (!plugin_dirs[i].IsAbsolute())
199 continue;
200#endif
[email protected]493c8002011-04-14 16:56:01201 FilePathWatcher* watcher = new FilePathWatcher();
[email protected]634d23d2011-01-19 10:38:19202 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
203 BrowserThread::PostTask(
204 BrowserThread::FILE, FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56205 base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher,
[email protected]07b71c82013-01-08 19:07:31206 plugin_dirs[i]));
[email protected]634d23d2011-01-19 10:38:19207 file_watchers_.push_back(watcher);
208 }
209#endif
initial.commit09911bf2008-07-26 23:55:29210}
211
[email protected]e67385f2011-12-21 06:00:56212PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess(
[email protected]28ab7f92009-01-06 21:39:04213 const FilePath& plugin_path) {
[email protected]4967f792012-01-20 22:14:40214 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
215 if (iter->info().path == plugin_path)
216 return *iter;
[email protected]a436d922009-02-13 23:16:42217 }
218
initial.commit09911bf2008-07-26 23:55:29219 return NULL;
220}
221
[email protected]e67385f2011-12-21 06:00:56222PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31223 const FilePath& plugin_path,
224 const FilePath& profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40225 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
[email protected]dd9a0952012-05-31 20:11:31226 if (iter->plugin_path() == plugin_path &&
227 iter->profile_data_directory() == profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40228 return *iter;
[email protected]dd9a0952012-05-31 20:11:31229 }
[email protected]a08ebea2011-02-13 17:50:20230 }
[email protected]a08ebea2011-02-13 17:50:20231 return NULL;
232}
233
[email protected]e67385f2011-12-21 06:00:56234PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42235 const FilePath& broker_path) {
[email protected]4967f792012-01-20 22:14:40236 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) {
237 if (iter->plugin_path() == broker_path)
238 return *iter;
[email protected]eb415bf0e2011-04-14 02:45:42239 }
240
241 return NULL;
242}
243
[email protected]e67385f2011-12-21 06:00:56244PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
[email protected]a08ebea2011-02-13 17:50:20245 const FilePath& plugin_path) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
247
248 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
initial.commit09911bf2008-07-26 23:55:29249 if (plugin_host)
250 return plugin_host;
251
[email protected]91d9f3d2011-08-14 05:24:44252 webkit::WebPluginInfo info;
[email protected]88ca4912011-10-12 14:00:43253 if (!GetPluginInfoByPath(plugin_path, &info)) {
[email protected]a27a9382009-02-11 23:55:10254 return NULL;
255 }
256
initial.commit09911bf2008-07-26 23:55:29257 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]8b8a554d2010-11-18 13:26:40258 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
[email protected]99907362012-01-11 05:41:40259 if (!new_host->Init(info)) {
[email protected]a08ebea2011-02-13 17:50:20260 NOTREACHED(); // Init is not expected to fail.
initial.commit09911bf2008-07-26 23:55:29261 return NULL;
262 }
[email protected]8b8a554d2010-11-18 13:26:40263 return new_host.release();
initial.commit09911bf2008-07-26 23:55:29264}
265
[email protected]e67385f2011-12-21 06:00:56266PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
[email protected]d259a8e2011-05-18 22:31:09267 const FilePath& plugin_path,
[email protected]dd9a0952012-05-31 20:11:31268 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14269 PpapiPluginProcessHost::PluginClient* client) {
[email protected]a08ebea2011-02-13 17:50:20270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
271
[email protected]dd9a0952012-05-31 20:11:31272 PpapiPluginProcessHost* plugin_host =
273 FindPpapiPluginProcess(plugin_path, profile_data_directory);
[email protected]a08ebea2011-02-13 17:50:20274 if (plugin_host)
275 return plugin_host;
276
[email protected]eb415bf0e2011-04-14 02:45:42277 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19278 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]a08ebea2011-02-13 17:50:20279 if (!info)
280 return NULL;
281
282 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14283 return PpapiPluginProcessHost::CreatePluginHost(
[email protected]dd9a0952012-05-31 20:11:31284 *info, profile_data_directory,
[email protected]df02aca2012-02-09 21:03:20285 client->GetResourceContext()->GetHostResolver());
[email protected]a08ebea2011-02-13 17:50:20286}
287
[email protected]e67385f2011-12-21 06:00:56288PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42289 const FilePath& plugin_path) {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
291
[email protected]a50432d2011-09-30 16:32:14292 PpapiPluginProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42293 if (plugin_host)
294 return plugin_host;
295
296 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19297 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42298 if (!info)
299 return NULL;
300
301 // TODO(ddorwin): Uncomment once out of process is supported.
302 // DCHECK(info->is_out_of_process);
303
304 // This broker isn't loaded by any broker process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14305 return PpapiPluginProcessHost::CreateBrokerHost(*info);
[email protected]eb415bf0e2011-04-14 02:45:42306}
307
[email protected]e67385f2011-12-21 06:00:56308void PluginServiceImpl::OpenChannelToNpapiPlugin(
[email protected]c8f73ab2011-01-22 00:05:17309 int render_process_id,
310 int render_view_id,
[email protected]610c0892009-09-08 19:46:18311 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54312 const GURL& page_url,
[email protected]610c0892009-09-08 19:46:18313 const std::string& mime_type,
[email protected]46b69e42010-11-02 12:26:39314 PluginProcessHost::Client* client) {
[email protected]76b70f92011-11-21 19:31:14315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]4befe7592011-09-14 22:49:09316 DCHECK(!ContainsKey(pending_plugin_clients_, client));
317 pending_plugin_clients_.insert(client);
[email protected]88ca4912011-10-12 14:00:43318
319 // Make sure plugins are loaded if necessary.
[email protected]209f2ae2012-03-13 01:28:08320 PluginServiceFilterParams params = {
[email protected]88ca4912011-10-12 14:00:43321 render_process_id,
322 render_view_id,
323 page_url,
[email protected]df02aca2012-02-09 21:03:20324 client->GetResourceContext()
[email protected]88ca4912011-10-12 14:00:43325 };
[email protected]e67385f2011-12-21 06:00:56326 GetPlugins(base::Bind(
327 &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin,
328 base::Unretained(this), params, url, mime_type, client));
[email protected]6fdd4182010-10-14 23:59:26329}
330
[email protected]e67385f2011-12-21 06:00:56331void PluginServiceImpl::OpenChannelToPpapiPlugin(
[email protected]dd9a0952012-05-31 20:11:31332 const FilePath& plugin_path,
333 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14334 PpapiPluginProcessHost::PluginClient* client) {
[email protected]d259a8e2011-05-18 22:31:09335 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31336 plugin_path, profile_data_directory, client);
[email protected]1bf0fb22012-04-12 21:44:16337 if (plugin_host) {
[email protected]a08ebea2011-02-13 17:50:20338 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16339 } else {
340 // Send error.
[email protected]108fd342013-01-04 20:46:54341 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0);
[email protected]1bf0fb22012-04-12 21:44:16342 }
[email protected]a08ebea2011-02-13 17:50:20343}
344
[email protected]e67385f2011-12-21 06:00:56345void PluginServiceImpl::OpenChannelToPpapiBroker(
[email protected]eb415bf0e2011-04-14 02:45:42346 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14347 PpapiPluginProcessHost::BrokerClient* client) {
348 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
[email protected]1bf0fb22012-04-12 21:44:16349 if (plugin_host) {
[email protected]a50432d2011-09-30 16:32:14350 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16351 } else {
352 // Send error.
[email protected]108fd342013-01-04 20:46:54353 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0);
[email protected]1bf0fb22012-04-12 21:44:16354 }
[email protected]eb415bf0e2011-04-14 02:45:42355}
356
[email protected]e67385f2011-12-21 06:00:56357void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
[email protected]4befe7592011-09-14 22:49:09358 PluginProcessHost::Client* client) {
359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
360 DCHECK(ContainsKey(pending_plugin_clients_, client));
361 pending_plugin_clients_.erase(client);
362}
363
[email protected]e67385f2011-12-21 06:00:56364void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin(
[email protected]209f2ae2012-03-13 01:28:08365 const PluginServiceFilterParams& params,
[email protected]88ca4912011-10-12 14:00:43366 const GURL& url,
367 const std::string& mime_type,
368 PluginProcessHost::Client* client,
369 const std::vector<webkit::WebPluginInfo>&) {
370 GetAllowedPluginForOpenChannelToPlugin(params.render_process_id,
371 params.render_view_id, url, params.page_url, mime_type, client,
372 params.resource_context);
373}
374
[email protected]e67385f2011-12-21 06:00:56375void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
[email protected]c8f73ab2011-01-22 00:05:17376 int render_process_id,
377 int render_view_id,
[email protected]6fdd4182010-10-14 23:59:26378 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54379 const GURL& page_url,
[email protected]6fdd4182010-10-14 23:59:26380 const std::string& mime_type,
[email protected]87c4be42011-09-16 01:10:59381 PluginProcessHost::Client* client,
[email protected]130757672012-10-24 00:26:19382 ResourceContext* resource_context) {
[email protected]91d9f3d2011-08-14 05:24:44383 webkit::WebPluginInfo info;
[email protected]dfba8762011-09-02 12:49:54384 bool allow_wildcard = true;
[email protected]11e1c182011-05-17 20:26:27385 bool found = GetPluginInfo(
[email protected]df02aca2012-02-09 21:03:20386 render_process_id, render_view_id, resource_context,
[email protected]dfba8762011-09-02 12:49:54387 url, page_url, mime_type, allow_wildcard,
388 NULL, &info, NULL);
[email protected]6fdd4182010-10-14 23:59:26389 FilePath plugin_path;
[email protected]68598072011-07-29 08:21:28390 if (found)
[email protected]dfba8762011-09-02 12:49:54391 plugin_path = info.path;
[email protected]6fdd4182010-10-14 23:59:26392
393 // Now we jump back to the IO thread to finish opening the channel.
[email protected]e67385f2011-12-21 06:00:56394 BrowserThread::PostTask(
395 BrowserThread::IO, FROM_HERE,
396 base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin,
[email protected]88ca4912011-10-12 14:00:43397 base::Unretained(this), plugin_path, client));
[email protected]6fdd4182010-10-14 23:59:26398}
399
[email protected]e67385f2011-12-21 06:00:56400void PluginServiceImpl::FinishOpenChannelToPlugin(
[email protected]6fdd4182010-10-14 23:59:26401 const FilePath& plugin_path,
[email protected]46b69e42010-11-02 12:26:39402 PluginProcessHost::Client* client) {
[email protected]f8b3ef82010-10-11 02:45:52403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20a793e2010-10-12 06:50:08404
[email protected]4befe7592011-09-14 22:49:09405 // Make sure it hasn't been canceled yet.
406 if (!ContainsKey(pending_plugin_clients_, client))
407 return;
408 pending_plugin_clients_.erase(client);
409
[email protected]a08ebea2011-02-13 17:50:20410 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
[email protected]4befe7592011-09-14 22:49:09411 if (plugin_host) {
412 client->OnFoundPluginProcessHost(plugin_host);
[email protected]46b69e42010-11-02 12:26:39413 plugin_host->OpenChannelToPlugin(client);
[email protected]4befe7592011-09-14 22:49:09414 } else {
[email protected]46b69e42010-11-02 12:26:39415 client->OnError();
[email protected]4befe7592011-09-14 22:49:09416 }
initial.commit09911bf2008-07-26 23:55:29417}
418
[email protected]e67385f2011-12-21 06:00:56419bool PluginServiceImpl::GetPluginInfoArray(
[email protected]51b63f62011-10-05 18:55:42420 const GURL& url,
421 const std::string& mime_type,
422 bool allow_wildcard,
423 std::vector<webkit::WebPluginInfo>* plugins,
424 std::vector<std::string>* actual_mime_types) {
425 bool use_stale = false;
[email protected]3a5180ae2011-12-21 02:39:38426 plugin_list_->GetPluginInfoArray(url, mime_type, allow_wildcard,
427 &use_stale, plugins, actual_mime_types);
[email protected]51b63f62011-10-05 18:55:42428 return use_stale;
429}
430
[email protected]e67385f2011-12-21 06:00:56431bool PluginServiceImpl::GetPluginInfo(int render_process_id,
432 int render_view_id,
[email protected]130757672012-10-24 00:26:19433 ResourceContext* context,
[email protected]e67385f2011-12-21 06:00:56434 const GURL& url,
435 const GURL& page_url,
436 const std::string& mime_type,
437 bool allow_wildcard,
438 bool* is_stale,
439 webkit::WebPluginInfo* info,
440 std::string* actual_mime_type) {
[email protected]91d9f3d2011-08-14 05:24:44441 std::vector<webkit::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28442 std::vector<std::string> mime_types;
[email protected]88ca4912011-10-12 14:00:43443 bool stale = GetPluginInfoArray(
444 url, mime_type, allow_wildcard, &plugins, &mime_types);
445 if (is_stale)
446 *is_stale = stale;
[email protected]dfba8762011-09-02 12:49:54447
[email protected]68598072011-07-29 08:21:28448 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]dfba8762011-09-02 12:49:54449 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
450 render_view_id,
[email protected]df02aca2012-02-09 21:03:20451 context,
[email protected]dfba8762011-09-02 12:49:54452 url,
453 page_url,
454 &plugins[i])) {
[email protected]68598072011-07-29 08:21:28455 *info = plugins[i];
456 if (actual_mime_type)
457 *actual_mime_type = mime_types[i];
458 return true;
459 }
460 }
461 return false;
[email protected]6fdd4182010-10-14 23:59:26462}
463
[email protected]e67385f2011-12-21 06:00:56464bool PluginServiceImpl::GetPluginInfoByPath(const FilePath& plugin_path,
465 webkit::WebPluginInfo* info) {
[email protected]88ca4912011-10-12 14:00:43466 std::vector<webkit::WebPluginInfo> plugins;
[email protected]480c7cc2012-06-29 17:38:44467 plugin_list_->GetPluginsNoRefresh(&plugins);
[email protected]88ca4912011-10-12 14:00:43468
469 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
470 it != plugins.end();
471 ++it) {
472 if (it->path == plugin_path) {
473 *info = *it;
474 return true;
475 }
476 }
477
478 return false;
479}
480
[email protected]8be45842012-04-13 19:49:29481string16 PluginServiceImpl::GetPluginDisplayNameByPath(const FilePath& path) {
482 string16 plugin_name = path.LossyDisplayName();
483 webkit::WebPluginInfo info;
484 if (PluginService::GetInstance()->GetPluginInfoByPath(path, &info) &&
485 !info.name.empty()) {
486 plugin_name = info.name;
487#if defined(OS_MACOSX)
488 // Many plugins on the Mac have .plugin in the actual name, which looks
489 // terrible, so look for that and strip it off if present.
490 const std::string kPluginExtension = ".plugin";
491 if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
492 plugin_name.erase(plugin_name.length() - kPluginExtension.length());
493#endif // OS_MACOSX
494 }
495 return plugin_name;
496}
497
[email protected]e67385f2011-12-21 06:00:56498void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
[email protected]49125952011-09-27 18:05:15499 scoped_refptr<base::MessageLoopProxy> target_loop(
500 MessageLoop::current()->message_loop_proxy());
501
[email protected]1b517202012-12-19 17:16:10502 if (LoadPluginListInProcess()) {
503 BrowserThread::GetBlockingPool()->
504 PostSequencedWorkerTaskWithShutdownBehavior(
505 plugin_list_token_,
506 FROM_HERE,
507 base::Bind(&PluginServiceImpl::GetPluginsInternal,
508 base::Unretained(this),
509 target_loop, callback),
510 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
511 return;
512 }
513#if defined(OS_POSIX)
[email protected]49125952011-09-27 18:05:15514 std::vector<webkit::WebPluginInfo> cached_plugins;
[email protected]480c7cc2012-06-29 17:38:44515 if (plugin_list_->GetPluginsNoRefresh(&cached_plugins)) {
[email protected]49125952011-09-27 18:05:15516 // Can't assume the caller is reentrant.
517 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37518 base::Bind(callback, cached_plugins));
[email protected]49125952011-09-27 18:05:15519 } else {
[email protected]4bb85b92011-11-05 02:53:29520 // If we switch back to loading plugins in process, then we need to make
521 // sure g_thread_init() gets called since plugins may call glib at load.
[email protected]d4af1e72011-10-21 17:45:43522 if (!plugin_loader_.get())
523 plugin_loader_ = new PluginLoaderPosix;
[email protected]49125952011-09-27 18:05:15524 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]d4af1e72011-10-21 17:45:43525 base::Bind(&PluginLoaderPosix::LoadPlugins, plugin_loader_,
526 target_loop, callback));
[email protected]49125952011-09-27 18:05:15527 }
[email protected]a33fa9d2012-05-16 14:47:49528#else
[email protected]1b517202012-12-19 17:16:10529 NOTREACHED();
[email protected]49125952011-09-27 18:05:15530#endif
[email protected]d33e7cc2011-09-23 01:43:56531}
532
[email protected]e67385f2011-12-21 06:00:56533void PluginServiceImpl::GetPluginsInternal(
[email protected]d33e7cc2011-09-23 01:43:56534 base::MessageLoopProxy* target_loop,
535 const PluginService::GetPluginsCallback& callback) {
[email protected]a33fa9d2012-05-16 14:47:49536 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
537 plugin_list_token_));
[email protected]d33e7cc2011-09-23 01:43:56538
539 std::vector<webkit::WebPluginInfo> plugins;
[email protected]3a5180ae2011-12-21 02:39:38540 plugin_list_->GetPlugins(&plugins);
[email protected]d33e7cc2011-09-23 01:43:56541
542 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37543 base::Bind(callback, plugins));
[email protected]dfba8762011-09-02 12:49:54544}
545
[email protected]e67385f2011-12-21 06:00:56546void PluginServiceImpl::OnWaitableEventSignaled(
[email protected]580522632009-08-17 21:55:55547 base::WaitableEvent* waitable_event) {
[email protected]b547fd42009-04-23 23:16:27548#if defined(OS_WIN)
549 if (waitable_event == hkcu_event_.get()) {
550 hkcu_key_.StartWatching();
551 } else {
552 hklm_key_.StartWatching();
553 }
554
[email protected]3a5180ae2011-12-21 02:39:38555 plugin_list_->RefreshPlugins();
[email protected]45a22e62011-10-12 09:48:02556 PurgePluginListCache(NULL, false);
[email protected]634d23d2011-01-19 10:38:19557#else
558 // This event should only get signaled on a Windows machine.
559 NOTREACHED();
[email protected]9de09f82009-08-17 20:13:53560#endif // defined(OS_WIN)
[email protected]b547fd42009-04-23 23:16:27561}
[email protected]894bb502009-05-21 22:39:57562
[email protected]e67385f2011-12-21 06:00:56563void PluginServiceImpl::RegisterPepperPlugins() {
[email protected]84396dbc2011-04-14 06:33:42564 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
[email protected]a08ebea2011-02-13 17:50:20565 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
566 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
[email protected]c6f3dea2012-01-14 02:23:11567 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);
[email protected]4e0616e2010-05-28 14:55:53568 }
569}
[email protected]634d23d2011-01-19 10:38:19570
[email protected]eb415bf0e2011-04-14 02:45:42571// There should generally be very few plugins so a brute-force search is fine.
[email protected]130757672012-10-24 00:26:19572PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
[email protected]eb415bf0e2011-04-14 02:45:42573 const FilePath& plugin_path) {
[email protected]130757672012-10-24 00:26:19574 PepperPluginInfo* info = NULL;
[email protected]eb415bf0e2011-04-14 02:45:42575 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
[email protected]6b14feb2011-08-16 11:22:56576 if (ppapi_plugins_[i].path == plugin_path) {
577 info = &ppapi_plugins_[i];
578 break;
579 }
[email protected]eb415bf0e2011-04-14 02:45:42580 }
[email protected]076117592011-08-17 03:16:41581 if (info)
582 return info;
583 // We did not find the plugin in our list. But wait! the plugin can also
584 // be a latecomer, as it happens with pepper flash. This information
585 // can be obtained from the PluginList singleton and we can use it to
586 // construct it and add it to the list. This same deal needs to be done
587 // in the renderer side in PepperPluginRegistry.
588 webkit::WebPluginInfo webplugin_info;
[email protected]88ca4912011-10-12 14:00:43589 if (!GetPluginInfoByPath(plugin_path, &webplugin_info))
[email protected]076117592011-08-17 03:16:41590 return NULL;
[email protected]130757672012-10-24 00:26:19591 PepperPluginInfo new_pepper_info;
[email protected]076117592011-08-17 03:16:41592 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
593 return NULL;
594 ppapi_plugins_.push_back(new_pepper_info);
595 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
[email protected]eb415bf0e2011-04-14 02:45:42596}
597
[email protected]52348b22012-11-07 10:19:34598#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19599// static
[email protected]07b71c82013-01-08 19:07:31600void PluginServiceImpl::RegisterFilePathWatcher(FilePathWatcher* watcher,
601 const FilePath& path) {
602 bool result = watcher->Watch(path, false,
603 base::Bind(&NotifyPluginDirChanged));
[email protected]634d23d2011-01-19 10:38:19604 DCHECK(result);
605}
606#endif
[email protected]f520b5b2011-11-08 02:42:14607
[email protected]130757672012-10-24 00:26:19608void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) {
[email protected]3a5180ae2011-12-21 02:39:38609 filter_ = filter;
610}
611
[email protected]130757672012-10-24 00:26:19612PluginServiceFilter* PluginServiceImpl::GetFilter() {
[email protected]3a5180ae2011-12-21 02:39:38613 return filter_;
614}
615
[email protected]b6a2f8de2012-01-31 17:28:49616void PluginServiceImpl::ForcePluginShutdown(const FilePath& plugin_path) {
617 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
618 BrowserThread::PostTask(
619 BrowserThread::IO, FROM_HERE,
620 base::Bind(&PluginServiceImpl::ForcePluginShutdown,
621 base::Unretained(this), plugin_path));
622 return;
623 }
624
625 PluginProcessHost* plugin = FindNpapiPluginProcess(plugin_path);
626 if (plugin)
627 plugin->ForceShutdown();
628}
629
[email protected]47214d882012-02-29 06:28:48630static const unsigned int kMaxCrashesPerInterval = 3;
631static const unsigned int kCrashesInterval = 120;
632
633void PluginServiceImpl::RegisterPluginCrash(const FilePath& path) {
634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
635 std::map<FilePath, std::vector<base::Time> >::iterator i =
636 crash_times_.find(path);
637 if (i == crash_times_.end()) {
638 crash_times_[path] = std::vector<base::Time>();
639 i = crash_times_.find(path);
640 }
641 if (i->second.size() == kMaxCrashesPerInterval) {
642 i->second.erase(i->second.begin());
643 }
644 base::Time time = base::Time::Now();
645 i->second.push_back(time);
646}
647
648bool PluginServiceImpl::IsPluginUnstable(const FilePath& path) {
649 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
650 std::map<FilePath, std::vector<base::Time> >::const_iterator i =
651 crash_times_.find(path);
652 if (i == crash_times_.end()) {
653 return false;
654 }
655 if (i->second.size() != kMaxCrashesPerInterval) {
656 return false;
657 }
658 base::TimeDelta delta = base::Time::Now() - i->second[0];
659 if (delta.InSeconds() <= kCrashesInterval) {
660 return true;
661 }
662 return false;
663}
664
[email protected]e67385f2011-12-21 06:00:56665void PluginServiceImpl::RefreshPlugins() {
[email protected]3a5180ae2011-12-21 02:39:38666 plugin_list_->RefreshPlugins();
[email protected]f520b5b2011-11-08 02:42:14667}
668
[email protected]e67385f2011-12-21 06:00:56669void PluginServiceImpl::AddExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38670 plugin_list_->AddExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14671}
672
[email protected]c6f3dea2012-01-14 02:23:11673void PluginServiceImpl::AddExtraPluginDir(const FilePath& path) {
674 plugin_list_->AddExtraPluginDir(path);
675}
676
[email protected]e67385f2011-12-21 06:00:56677void PluginServiceImpl::RemoveExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38678 plugin_list_->RemoveExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14679}
680
[email protected]e67385f2011-12-21 06:00:56681void PluginServiceImpl::UnregisterInternalPlugin(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38682 plugin_list_->UnregisterInternalPlugin(path);
[email protected]f520b5b2011-11-08 02:42:14683}
684
[email protected]e67385f2011-12-21 06:00:56685void PluginServiceImpl::SetPluginListForTesting(
[email protected]ee066172011-11-10 23:20:05686 webkit::npapi::PluginList* plugin_list) {
687 plugin_list_ = plugin_list;
688}
689
[email protected]5904cb42012-09-24 15:05:20690#if defined(OS_MACOSX)
691void PluginServiceImpl::AppActivated() {
692 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]07b71c82013-01-08 19:07:31693 base::Bind(&NotifyPluginsOfActivation));
[email protected]5904cb42012-09-24 15:05:20694}
695#endif
696
[email protected]e67385f2011-12-21 06:00:56697void PluginServiceImpl::RegisterInternalPlugin(
[email protected]c6f3dea2012-01-14 02:23:11698 const webkit::WebPluginInfo& info,
699 bool add_at_beginning) {
700 plugin_list_->RegisterInternalPlugin(info, add_at_beginning);
[email protected]f520b5b2011-11-08 02:42:14701}
702
[email protected]57aece22012-10-10 22:10:27703void PluginServiceImpl::GetInternalPlugins(
704 std::vector<webkit::WebPluginInfo>* plugins) {
705 plugin_list_->GetInternalPlugins(plugins);
706}
707
[email protected]e67385f2011-12-21 06:00:56708webkit::npapi::PluginList* PluginServiceImpl::GetPluginList() {
[email protected]3a5180ae2011-12-21 02:39:38709 return plugin_list_;
[email protected]f520b5b2011-11-08 02:42:14710}
[email protected]130757672012-10-24 00:26:19711
712} // namespace content