blob: dabd26dfae7aedbaee98692c6f7ba9dca78dfc60 [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]91d9f3d2011-08-14 05:24:4433#include "webkit/plugins/webplugininfo.h"
[email protected]191eb3f72010-12-21 06:27:5034
[email protected]3b91edbe2012-09-27 22:49:2335#if defined(OS_WIN)
36#include "webkit/plugins/npapi/plugin_constants_win.h"
37#endif
38
39#if defined(OS_POSIX)
40#include "content/browser/plugin_loader_posix.h"
41#endif
42
[email protected]52348b22012-11-07 10:19:3443#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]493c8002011-04-14 16:56:0144using ::base::files::FilePathWatcher;
45#endif
46
[email protected]130757672012-10-24 00:26:1947namespace content {
[email protected]d33e7cc2011-09-23 01:43:5648namespace {
49
[email protected]49125952011-09-27 18:05:1550// Callback set on the PluginList to assert that plugin loading happens on the
51// correct thread.
[email protected]6a0dc7a2011-11-02 14:37:0752#if defined(OS_WIN)
[email protected]a33fa9d2012-05-16 14:47:4953void WillLoadPluginsCallbackWin(
54 base::SequencedWorkerPool::SequenceToken token) {
55 CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
56 token));
[email protected]a79912252012-05-16 11:52:1957}
[email protected]a33fa9d2012-05-16 14:47:4958#else
59void WillLoadPluginsCallbackPosix() {
60 CHECK(false) << "Plugin loading should happen out-of-process.";
61}
62#endif
[email protected]49125952011-09-27 18:05:1563
[email protected]d33e7cc2011-09-23 01:43:5664} // namespace
65
[email protected]a96ec6a2009-11-04 17:27:0866#if defined(OS_MACOSX)
67static void NotifyPluginsOfActivation() {
[email protected]f8b3ef82010-10-11 02:45:5268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]a96ec6a2009-11-04 17:27:0869
[email protected]4967f792012-01-20 22:14:4070 for (PluginProcessHostIterator iter; !iter.Done(); ++iter)
71 iter->OnAppActivation();
[email protected]a96ec6a2009-11-04 17:27:0872}
[email protected]3b48dbc2012-01-06 16:34:1773#endif
[email protected]52348b22012-11-07 10:19:3474#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:1975// Delegate class for monitoring directories.
76class PluginDirWatcherDelegate : public FilePathWatcher::Delegate {
[email protected]7b3ee8b2011-04-01 18:48:1977 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1978 VLOG(1) << "Watched path changed: " << path.value();
79 // Make the plugin list update itself
80 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
[email protected]ee6fcb22011-10-22 01:27:0681 BrowserThread::PostTask(
82 BrowserThread::UI, FROM_HERE,
[email protected]130757672012-10-24 00:26:1983 base::Bind(&PluginService::PurgePluginListCache,
84 static_cast<BrowserContext*>(NULL), false));
[email protected]634d23d2011-01-19 10:38:1985 }
[email protected]45a22e62011-10-12 09:48:0286
[email protected]7b3ee8b2011-04-01 18:48:1987 virtual void OnFilePathError(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1988 // TODO(pastarmovj): Add some sensible error handling. Maybe silently
89 // stopping the watcher would be enough. Or possibly restart it.
90 NOTREACHED();
91 }
[email protected]fb90c942012-04-27 23:40:5092
93 protected:
94 virtual ~PluginDirWatcherDelegate() {}
[email protected]634d23d2011-01-19 10:38:1995};
96#endif
97
[email protected]3a5180ae2011-12-21 02:39:3898// static
99PluginService* PluginService::GetInstance() {
[email protected]e67385f2011-12-21 06:00:56100 return PluginServiceImpl::GetInstance();
[email protected]3a5180ae2011-12-21 02:39:38101}
102
103void PluginService::PurgePluginListCache(BrowserContext* browser_context,
104 bool reload_pages) {
105 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
106 !it.IsAtEnd(); it.Advance()) {
107 RenderProcessHost* host = it.GetCurrentValue();
108 if (!browser_context || host->GetBrowserContext() == browser_context)
109 host->Send(new ViewMsg_PurgePluginListCache(reload_pages));
110 }
111}
112
initial.commit09911bf2008-07-26 23:55:29113// static
[email protected]e67385f2011-12-21 06:00:56114PluginServiceImpl* PluginServiceImpl::GetInstance() {
115 return Singleton<PluginServiceImpl>::get();
initial.commit09911bf2008-07-26 23:55:29116}
117
[email protected]e67385f2011-12-21 06:00:56118PluginServiceImpl::PluginServiceImpl()
[email protected]99907362012-01-11 05:41:40119 : plugin_list_(NULL), filter_(NULL) {
[email protected]ee066172011-11-10 23:20:05120}
121
[email protected]e67385f2011-12-21 06:00:56122PluginServiceImpl::~PluginServiceImpl() {
[email protected]ee066172011-11-10 23:20:05123#if defined(OS_WIN)
124 // Release the events since they're owned by RegKey, not WaitableEvent.
125 hkcu_watcher_.StopWatching();
126 hklm_watcher_.StopWatching();
127 if (hkcu_event_.get())
128 hkcu_event_->Release();
129 if (hklm_event_.get())
130 hklm_event_->Release();
131#endif
132 // Make sure no plugin channel requests have been leaked.
133 DCHECK(pending_plugin_clients_.empty());
134}
135
[email protected]e67385f2011-12-21 06:00:56136void PluginServiceImpl::Init() {
[email protected]ee066172011-11-10 23:20:05137 if (!plugin_list_)
138 plugin_list_ = webkit::npapi::PluginList::Singleton();
139
[email protected]a33fa9d2012-05-16 14:47:49140#if defined(OS_WIN)
141 plugin_list_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
[email protected]3a5180ae2011-12-21 02:39:38142 plugin_list_->set_will_load_plugins_callback(
[email protected]a33fa9d2012-05-16 14:47:49143 base::Bind(&WillLoadPluginsCallbackWin, plugin_list_token_));
144#else
145 plugin_list_->set_will_load_plugins_callback(
146 base::Bind(&WillLoadPluginsCallbackPosix));
147#endif
[email protected]49125952011-09-27 18:05:15148
[email protected]4e0616e2010-05-28 14:55:53149 RegisterPepperPlugins();
150
[email protected]130757672012-10-24 00:26:19151 GetContentClient()->AddNPAPIPlugins(plugin_list_);
[email protected]f520b5b2011-11-08 02:42:14152
[email protected]9a1c4262010-06-29 21:50:27153 // Load any specified on the command line as well.
[email protected]d48f1e0c2009-02-12 20:57:54154 const CommandLine* command_line = CommandLine::ForCurrentProcess();
[email protected]c4e52f0d2009-11-06 19:55:16155 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
[email protected]7bf795d92010-05-22 00:14:28156 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14157 AddExtraPluginPath(path);
[email protected]9a1c4262010-06-29 21:50:27158 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
159 if (!path.empty())
[email protected]3a5180ae2011-12-21 02:39:38160 plugin_list_->AddExtraPluginDir(path);
[email protected]dfba8762011-09-02 12:49:54161}
162
[email protected]e67385f2011-12-21 06:00:56163void PluginServiceImpl::StartWatchingPlugins() {
[email protected]634d23d2011-01-19 10:38:19164 // Start watching for changes in the plugin list. This means watching
165 // for changes in the Windows registry keys and on both Windows and POSIX
166 // watch for changes in the paths that are expected to contain plugins.
[email protected]b547fd42009-04-23 23:16:27167#if defined(OS_WIN)
[email protected]86ec4f6e2011-04-20 16:21:19168 if (hkcu_key_.Create(HKEY_CURRENT_USER,
169 webkit::npapi::kRegistryMozillaPlugins,
170 KEY_NOTIFY) == ERROR_SUCCESS) {
171 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
172 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
173 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
174 }
[email protected]b547fd42009-04-23 23:16:27175 }
[email protected]86ec4f6e2011-04-20 16:21:19176 if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
177 webkit::npapi::kRegistryMozillaPlugins,
178 KEY_NOTIFY) == ERROR_SUCCESS) {
179 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
180 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
181 hklm_watcher_.StartWatching(hklm_event_.get(), this);
182 }
[email protected]b547fd42009-04-23 23:16:27183 }
[email protected]a33fa9d2012-05-16 14:47:49184#endif
[email protected]52348b22012-11-07 10:19:34185#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19186// On ChromeOS the user can't install plugins anyway and on Windows all
187// important plugins register themselves in the registry so no need to do that.
[email protected]634d23d2011-01-19 10:38:19188 file_watcher_delegate_ = new PluginDirWatcherDelegate();
189 // Get the list of all paths for registering the FilePathWatchers
190 // that will track and if needed reload the list of plugins on runtime.
191 std::vector<FilePath> plugin_dirs;
[email protected]3a5180ae2011-12-21 02:39:38192 plugin_list_->GetPluginDirectories(&plugin_dirs);
[email protected]894bb502009-05-21 22:39:57193
[email protected]634d23d2011-01-19 10:38:19194 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
[email protected]634d23d2011-01-19 10:38:19195 // FilePathWatcher can not handle non-absolute paths under windows.
196 // We don't watch for file changes in windows now but if this should ever
197 // be extended to Windows these lines might save some time of debugging.
198#if defined(OS_WIN)
199 if (!plugin_dirs[i].IsAbsolute())
200 continue;
201#endif
[email protected]493c8002011-04-14 16:56:01202 FilePathWatcher* watcher = new FilePathWatcher();
[email protected]634d23d2011-01-19 10:38:19203 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
204 BrowserThread::PostTask(
205 BrowserThread::FILE, FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56206 base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher,
[email protected]81050512011-12-19 19:32:51207 plugin_dirs[i], file_watcher_delegate_));
[email protected]634d23d2011-01-19 10:38:19208 file_watchers_.push_back(watcher);
209 }
210#endif
initial.commit09911bf2008-07-26 23:55:29211}
212
[email protected]e67385f2011-12-21 06:00:56213PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess(
[email protected]28ab7f92009-01-06 21:39:04214 const FilePath& plugin_path) {
[email protected]4967f792012-01-20 22:14:40215 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
216 if (iter->info().path == plugin_path)
217 return *iter;
[email protected]a436d922009-02-13 23:16:42218 }
219
initial.commit09911bf2008-07-26 23:55:29220 return NULL;
221}
222
[email protected]e67385f2011-12-21 06:00:56223PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31224 const FilePath& plugin_path,
225 const FilePath& profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40226 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
[email protected]dd9a0952012-05-31 20:11:31227 if (iter->plugin_path() == plugin_path &&
228 iter->profile_data_directory() == profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40229 return *iter;
[email protected]dd9a0952012-05-31 20:11:31230 }
[email protected]a08ebea2011-02-13 17:50:20231 }
[email protected]a08ebea2011-02-13 17:50:20232 return NULL;
233}
234
[email protected]e67385f2011-12-21 06:00:56235PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42236 const FilePath& broker_path) {
[email protected]4967f792012-01-20 22:14:40237 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) {
238 if (iter->plugin_path() == broker_path)
239 return *iter;
[email protected]eb415bf0e2011-04-14 02:45:42240 }
241
242 return NULL;
243}
244
[email protected]e67385f2011-12-21 06:00:56245PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
[email protected]a08ebea2011-02-13 17:50:20246 const FilePath& plugin_path) {
247 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
248
249 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
initial.commit09911bf2008-07-26 23:55:29250 if (plugin_host)
251 return plugin_host;
252
[email protected]91d9f3d2011-08-14 05:24:44253 webkit::WebPluginInfo info;
[email protected]88ca4912011-10-12 14:00:43254 if (!GetPluginInfoByPath(plugin_path, &info)) {
[email protected]a27a9382009-02-11 23:55:10255 return NULL;
256 }
257
initial.commit09911bf2008-07-26 23:55:29258 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]8b8a554d2010-11-18 13:26:40259 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
[email protected]99907362012-01-11 05:41:40260 if (!new_host->Init(info)) {
[email protected]a08ebea2011-02-13 17:50:20261 NOTREACHED(); // Init is not expected to fail.
initial.commit09911bf2008-07-26 23:55:29262 return NULL;
263 }
[email protected]8b8a554d2010-11-18 13:26:40264 return new_host.release();
initial.commit09911bf2008-07-26 23:55:29265}
266
[email protected]e67385f2011-12-21 06:00:56267PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
[email protected]d259a8e2011-05-18 22:31:09268 const FilePath& plugin_path,
[email protected]dd9a0952012-05-31 20:11:31269 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14270 PpapiPluginProcessHost::PluginClient* client) {
[email protected]a08ebea2011-02-13 17:50:20271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
272
[email protected]dd9a0952012-05-31 20:11:31273 PpapiPluginProcessHost* plugin_host =
274 FindPpapiPluginProcess(plugin_path, profile_data_directory);
[email protected]a08ebea2011-02-13 17:50:20275 if (plugin_host)
276 return plugin_host;
277
[email protected]eb415bf0e2011-04-14 02:45:42278 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19279 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]a08ebea2011-02-13 17:50:20280 if (!info)
281 return NULL;
282
283 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14284 return PpapiPluginProcessHost::CreatePluginHost(
[email protected]dd9a0952012-05-31 20:11:31285 *info, profile_data_directory,
[email protected]df02aca2012-02-09 21:03:20286 client->GetResourceContext()->GetHostResolver());
[email protected]a08ebea2011-02-13 17:50:20287}
288
[email protected]e67385f2011-12-21 06:00:56289PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42290 const FilePath& plugin_path) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292
[email protected]a50432d2011-09-30 16:32:14293 PpapiPluginProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42294 if (plugin_host)
295 return plugin_host;
296
297 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19298 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42299 if (!info)
300 return NULL;
301
302 // TODO(ddorwin): Uncomment once out of process is supported.
303 // DCHECK(info->is_out_of_process);
304
305 // This broker isn't loaded by any broker process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14306 return PpapiPluginProcessHost::CreateBrokerHost(*info);
[email protected]eb415bf0e2011-04-14 02:45:42307}
308
[email protected]e67385f2011-12-21 06:00:56309void PluginServiceImpl::OpenChannelToNpapiPlugin(
[email protected]c8f73ab2011-01-22 00:05:17310 int render_process_id,
311 int render_view_id,
[email protected]610c0892009-09-08 19:46:18312 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54313 const GURL& page_url,
[email protected]610c0892009-09-08 19:46:18314 const std::string& mime_type,
[email protected]46b69e42010-11-02 12:26:39315 PluginProcessHost::Client* client) {
[email protected]76b70f92011-11-21 19:31:14316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]4befe7592011-09-14 22:49:09317 DCHECK(!ContainsKey(pending_plugin_clients_, client));
318 pending_plugin_clients_.insert(client);
[email protected]88ca4912011-10-12 14:00:43319
320 // Make sure plugins are loaded if necessary.
[email protected]209f2ae2012-03-13 01:28:08321 PluginServiceFilterParams params = {
[email protected]88ca4912011-10-12 14:00:43322 render_process_id,
323 render_view_id,
324 page_url,
[email protected]df02aca2012-02-09 21:03:20325 client->GetResourceContext()
[email protected]88ca4912011-10-12 14:00:43326 };
[email protected]e67385f2011-12-21 06:00:56327 GetPlugins(base::Bind(
328 &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin,
329 base::Unretained(this), params, url, mime_type, client));
[email protected]6fdd4182010-10-14 23:59:26330}
331
[email protected]e67385f2011-12-21 06:00:56332void PluginServiceImpl::OpenChannelToPpapiPlugin(
[email protected]dd9a0952012-05-31 20:11:31333 const FilePath& plugin_path,
334 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14335 PpapiPluginProcessHost::PluginClient* client) {
[email protected]d259a8e2011-05-18 22:31:09336 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31337 plugin_path, profile_data_directory, client);
[email protected]1bf0fb22012-04-12 21:44:16338 if (plugin_host) {
[email protected]a08ebea2011-02-13 17:50:20339 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16340 } else {
341 // Send error.
[email protected]f0ecb552012-05-11 22:09:11342 client->OnPpapiChannelOpened(IPC::ChannelHandle(), 0);
[email protected]1bf0fb22012-04-12 21:44:16343 }
[email protected]a08ebea2011-02-13 17:50:20344}
345
[email protected]e67385f2011-12-21 06:00:56346void PluginServiceImpl::OpenChannelToPpapiBroker(
[email protected]eb415bf0e2011-04-14 02:45:42347 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14348 PpapiPluginProcessHost::BrokerClient* client) {
349 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
[email protected]1bf0fb22012-04-12 21:44:16350 if (plugin_host) {
[email protected]a50432d2011-09-30 16:32:14351 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16352 } else {
353 // Send error.
[email protected]f0ecb552012-05-11 22:09:11354 client->OnPpapiChannelOpened(IPC::ChannelHandle(), 0);
[email protected]1bf0fb22012-04-12 21:44:16355 }
[email protected]eb415bf0e2011-04-14 02:45:42356}
357
[email protected]e67385f2011-12-21 06:00:56358void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
[email protected]4befe7592011-09-14 22:49:09359 PluginProcessHost::Client* client) {
360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
361 DCHECK(ContainsKey(pending_plugin_clients_, client));
362 pending_plugin_clients_.erase(client);
363}
364
[email protected]e67385f2011-12-21 06:00:56365void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin(
[email protected]209f2ae2012-03-13 01:28:08366 const PluginServiceFilterParams& params,
[email protected]88ca4912011-10-12 14:00:43367 const GURL& url,
368 const std::string& mime_type,
369 PluginProcessHost::Client* client,
370 const std::vector<webkit::WebPluginInfo>&) {
371 GetAllowedPluginForOpenChannelToPlugin(params.render_process_id,
372 params.render_view_id, url, params.page_url, mime_type, client,
373 params.resource_context);
374}
375
[email protected]e67385f2011-12-21 06:00:56376void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
[email protected]c8f73ab2011-01-22 00:05:17377 int render_process_id,
378 int render_view_id,
[email protected]6fdd4182010-10-14 23:59:26379 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54380 const GURL& page_url,
[email protected]6fdd4182010-10-14 23:59:26381 const std::string& mime_type,
[email protected]87c4be42011-09-16 01:10:59382 PluginProcessHost::Client* client,
[email protected]130757672012-10-24 00:26:19383 ResourceContext* resource_context) {
[email protected]91d9f3d2011-08-14 05:24:44384 webkit::WebPluginInfo info;
[email protected]dfba8762011-09-02 12:49:54385 bool allow_wildcard = true;
[email protected]11e1c182011-05-17 20:26:27386 bool found = GetPluginInfo(
[email protected]df02aca2012-02-09 21:03:20387 render_process_id, render_view_id, resource_context,
[email protected]dfba8762011-09-02 12:49:54388 url, page_url, mime_type, allow_wildcard,
389 NULL, &info, NULL);
[email protected]6fdd4182010-10-14 23:59:26390 FilePath plugin_path;
[email protected]68598072011-07-29 08:21:28391 if (found)
[email protected]dfba8762011-09-02 12:49:54392 plugin_path = info.path;
[email protected]6fdd4182010-10-14 23:59:26393
394 // Now we jump back to the IO thread to finish opening the channel.
[email protected]e67385f2011-12-21 06:00:56395 BrowserThread::PostTask(
396 BrowserThread::IO, FROM_HERE,
397 base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin,
[email protected]88ca4912011-10-12 14:00:43398 base::Unretained(this), plugin_path, client));
[email protected]6fdd4182010-10-14 23:59:26399}
400
[email protected]e67385f2011-12-21 06:00:56401void PluginServiceImpl::FinishOpenChannelToPlugin(
[email protected]6fdd4182010-10-14 23:59:26402 const FilePath& plugin_path,
[email protected]46b69e42010-11-02 12:26:39403 PluginProcessHost::Client* client) {
[email protected]f8b3ef82010-10-11 02:45:52404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20a793e2010-10-12 06:50:08405
[email protected]4befe7592011-09-14 22:49:09406 // Make sure it hasn't been canceled yet.
407 if (!ContainsKey(pending_plugin_clients_, client))
408 return;
409 pending_plugin_clients_.erase(client);
410
[email protected]a08ebea2011-02-13 17:50:20411 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
[email protected]4befe7592011-09-14 22:49:09412 if (plugin_host) {
413 client->OnFoundPluginProcessHost(plugin_host);
[email protected]46b69e42010-11-02 12:26:39414 plugin_host->OpenChannelToPlugin(client);
[email protected]4befe7592011-09-14 22:49:09415 } else {
[email protected]46b69e42010-11-02 12:26:39416 client->OnError();
[email protected]4befe7592011-09-14 22:49:09417 }
initial.commit09911bf2008-07-26 23:55:29418}
419
[email protected]e67385f2011-12-21 06:00:56420bool PluginServiceImpl::GetPluginInfoArray(
[email protected]51b63f62011-10-05 18:55:42421 const GURL& url,
422 const std::string& mime_type,
423 bool allow_wildcard,
424 std::vector<webkit::WebPluginInfo>* plugins,
425 std::vector<std::string>* actual_mime_types) {
426 bool use_stale = false;
[email protected]3a5180ae2011-12-21 02:39:38427 plugin_list_->GetPluginInfoArray(url, mime_type, allow_wildcard,
428 &use_stale, plugins, actual_mime_types);
[email protected]51b63f62011-10-05 18:55:42429 return use_stale;
430}
431
[email protected]e67385f2011-12-21 06:00:56432bool PluginServiceImpl::GetPluginInfo(int render_process_id,
433 int render_view_id,
[email protected]130757672012-10-24 00:26:19434 ResourceContext* context,
[email protected]e67385f2011-12-21 06:00:56435 const GURL& url,
436 const GURL& page_url,
437 const std::string& mime_type,
438 bool allow_wildcard,
439 bool* is_stale,
440 webkit::WebPluginInfo* info,
441 std::string* actual_mime_type) {
[email protected]91d9f3d2011-08-14 05:24:44442 std::vector<webkit::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28443 std::vector<std::string> mime_types;
[email protected]88ca4912011-10-12 14:00:43444 bool stale = GetPluginInfoArray(
445 url, mime_type, allow_wildcard, &plugins, &mime_types);
446 if (is_stale)
447 *is_stale = stale;
[email protected]dfba8762011-09-02 12:49:54448
[email protected]68598072011-07-29 08:21:28449 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]dfba8762011-09-02 12:49:54450 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
451 render_view_id,
[email protected]df02aca2012-02-09 21:03:20452 context,
[email protected]dfba8762011-09-02 12:49:54453 url,
454 page_url,
455 &plugins[i])) {
[email protected]68598072011-07-29 08:21:28456 *info = plugins[i];
457 if (actual_mime_type)
458 *actual_mime_type = mime_types[i];
459 return true;
460 }
461 }
462 return false;
[email protected]6fdd4182010-10-14 23:59:26463}
464
[email protected]e67385f2011-12-21 06:00:56465bool PluginServiceImpl::GetPluginInfoByPath(const FilePath& plugin_path,
466 webkit::WebPluginInfo* info) {
[email protected]88ca4912011-10-12 14:00:43467 std::vector<webkit::WebPluginInfo> plugins;
[email protected]480c7cc2012-06-29 17:38:44468 plugin_list_->GetPluginsNoRefresh(&plugins);
[email protected]88ca4912011-10-12 14:00:43469
470 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
471 it != plugins.end();
472 ++it) {
473 if (it->path == plugin_path) {
474 *info = *it;
475 return true;
476 }
477 }
478
479 return false;
480}
481
[email protected]8be45842012-04-13 19:49:29482string16 PluginServiceImpl::GetPluginDisplayNameByPath(const FilePath& path) {
483 string16 plugin_name = path.LossyDisplayName();
484 webkit::WebPluginInfo info;
485 if (PluginService::GetInstance()->GetPluginInfoByPath(path, &info) &&
486 !info.name.empty()) {
487 plugin_name = info.name;
488#if defined(OS_MACOSX)
489 // Many plugins on the Mac have .plugin in the actual name, which looks
490 // terrible, so look for that and strip it off if present.
491 const std::string kPluginExtension = ".plugin";
492 if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
493 plugin_name.erase(plugin_name.length() - kPluginExtension.length());
494#endif // OS_MACOSX
495 }
496 return plugin_name;
497}
498
[email protected]e67385f2011-12-21 06:00:56499void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
[email protected]49125952011-09-27 18:05:15500 scoped_refptr<base::MessageLoopProxy> target_loop(
501 MessageLoop::current()->message_loop_proxy());
502
[email protected]6a0dc7a2011-11-02 14:37:07503#if defined(OS_WIN)
[email protected]a33fa9d2012-05-16 14:47:49504 BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
505 plugin_list_token_,
[email protected]00b25432012-04-07 04:21:37506 FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56507 base::Bind(&PluginServiceImpl::GetPluginsInternal, base::Unretained(this),
[email protected]00b25432012-04-07 04:21:37508 target_loop, callback),
509 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
[email protected]a33fa9d2012-05-16 14:47:49510#elif defined(OS_POSIX)
[email protected]49125952011-09-27 18:05:15511 std::vector<webkit::WebPluginInfo> cached_plugins;
[email protected]480c7cc2012-06-29 17:38:44512 if (plugin_list_->GetPluginsNoRefresh(&cached_plugins)) {
[email protected]49125952011-09-27 18:05:15513 // Can't assume the caller is reentrant.
514 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37515 base::Bind(callback, cached_plugins));
[email protected]49125952011-09-27 18:05:15516 } else {
[email protected]4bb85b92011-11-05 02:53:29517 // If we switch back to loading plugins in process, then we need to make
518 // sure g_thread_init() gets called since plugins may call glib at load.
[email protected]d4af1e72011-10-21 17:45:43519 if (!plugin_loader_.get())
520 plugin_loader_ = new PluginLoaderPosix;
[email protected]49125952011-09-27 18:05:15521 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]d4af1e72011-10-21 17:45:43522 base::Bind(&PluginLoaderPosix::LoadPlugins, plugin_loader_,
523 target_loop, callback));
[email protected]49125952011-09-27 18:05:15524 }
[email protected]a33fa9d2012-05-16 14:47:49525#else
526#error Not implemented
[email protected]49125952011-09-27 18:05:15527#endif
[email protected]d33e7cc2011-09-23 01:43:56528}
529
[email protected]a33fa9d2012-05-16 14:47:49530#if defined(OS_WIN)
[email protected]e67385f2011-12-21 06:00:56531void PluginServiceImpl::GetPluginsInternal(
[email protected]d33e7cc2011-09-23 01:43:56532 base::MessageLoopProxy* target_loop,
533 const PluginService::GetPluginsCallback& callback) {
[email protected]a33fa9d2012-05-16 14:47:49534 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
535 plugin_list_token_));
[email protected]d33e7cc2011-09-23 01:43:56536
537 std::vector<webkit::WebPluginInfo> plugins;
[email protected]3a5180ae2011-12-21 02:39:38538 plugin_list_->GetPlugins(&plugins);
[email protected]d33e7cc2011-09-23 01:43:56539
540 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37541 base::Bind(callback, plugins));
[email protected]dfba8762011-09-02 12:49:54542}
[email protected]a33fa9d2012-05-16 14:47:49543#endif
[email protected]dfba8762011-09-02 12:49:54544
[email protected]e67385f2011-12-21 06:00:56545void PluginServiceImpl::OnWaitableEventSignaled(
[email protected]580522632009-08-17 21:55:55546 base::WaitableEvent* waitable_event) {
[email protected]b547fd42009-04-23 23:16:27547#if defined(OS_WIN)
548 if (waitable_event == hkcu_event_.get()) {
549 hkcu_key_.StartWatching();
550 } else {
551 hklm_key_.StartWatching();
552 }
553
[email protected]3a5180ae2011-12-21 02:39:38554 plugin_list_->RefreshPlugins();
[email protected]45a22e62011-10-12 09:48:02555 PurgePluginListCache(NULL, false);
[email protected]634d23d2011-01-19 10:38:19556#else
557 // This event should only get signaled on a Windows machine.
558 NOTREACHED();
[email protected]9de09f82009-08-17 20:13:53559#endif // defined(OS_WIN)
[email protected]b547fd42009-04-23 23:16:27560}
[email protected]894bb502009-05-21 22:39:57561
[email protected]e67385f2011-12-21 06:00:56562void PluginServiceImpl::RegisterPepperPlugins() {
[email protected]84396dbc2011-04-14 06:33:42563 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
[email protected]a08ebea2011-02-13 17:50:20564 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
565 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
[email protected]c6f3dea2012-01-14 02:23:11566 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);
[email protected]4e0616e2010-05-28 14:55:53567 }
568}
[email protected]634d23d2011-01-19 10:38:19569
[email protected]eb415bf0e2011-04-14 02:45:42570// There should generally be very few plugins so a brute-force search is fine.
[email protected]130757672012-10-24 00:26:19571PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
[email protected]eb415bf0e2011-04-14 02:45:42572 const FilePath& plugin_path) {
[email protected]130757672012-10-24 00:26:19573 PepperPluginInfo* info = NULL;
[email protected]eb415bf0e2011-04-14 02:45:42574 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
[email protected]6b14feb2011-08-16 11:22:56575 if (ppapi_plugins_[i].path == plugin_path) {
576 info = &ppapi_plugins_[i];
577 break;
578 }
[email protected]eb415bf0e2011-04-14 02:45:42579 }
[email protected]076117592011-08-17 03:16:41580 if (info)
581 return info;
582 // We did not find the plugin in our list. But wait! the plugin can also
583 // be a latecomer, as it happens with pepper flash. This information
584 // can be obtained from the PluginList singleton and we can use it to
585 // construct it and add it to the list. This same deal needs to be done
586 // in the renderer side in PepperPluginRegistry.
587 webkit::WebPluginInfo webplugin_info;
[email protected]88ca4912011-10-12 14:00:43588 if (!GetPluginInfoByPath(plugin_path, &webplugin_info))
[email protected]076117592011-08-17 03:16:41589 return NULL;
[email protected]130757672012-10-24 00:26:19590 PepperPluginInfo new_pepper_info;
[email protected]076117592011-08-17 03:16:41591 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
592 return NULL;
593 ppapi_plugins_.push_back(new_pepper_info);
594 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
[email protected]eb415bf0e2011-04-14 02:45:42595}
596
[email protected]52348b22012-11-07 10:19:34597#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19598// static
[email protected]e67385f2011-12-21 06:00:56599void PluginServiceImpl::RegisterFilePathWatcher(
[email protected]3b91edbe2012-09-27 22:49:23600 FilePathWatcher* watcher,
[email protected]634d23d2011-01-19 10:38:19601 const FilePath& path,
602 FilePathWatcher::Delegate* delegate) {
[email protected]7b3ee8b2011-04-01 18:48:19603 bool result = watcher->Watch(path, delegate);
[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,
693 base::Bind(&NotifyPluginsOfActivation));
694}
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