blob: 40fd937eb7385059ad6a381a9ae60e412907e467 [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]493c8002011-04-14 16:56:0145using ::base::files::FilePathWatcher;
46#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} // namespace
73
[email protected]a96ec6a2009-11-04 17:27:0874#if defined(OS_MACOSX)
75static void NotifyPluginsOfActivation() {
[email protected]f8b3ef82010-10-11 02:45:5276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]a96ec6a2009-11-04 17:27:0877
[email protected]4967f792012-01-20 22:14:4078 for (PluginProcessHostIterator iter; !iter.Done(); ++iter)
79 iter->OnAppActivation();
[email protected]a96ec6a2009-11-04 17:27:0880}
[email protected]3b48dbc2012-01-06 16:34:1781#endif
[email protected]52348b22012-11-07 10:19:3482#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:1983// Delegate class for monitoring directories.
84class PluginDirWatcherDelegate : public FilePathWatcher::Delegate {
[email protected]7b3ee8b2011-04-01 18:48:1985 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1986 VLOG(1) << "Watched path changed: " << path.value();
87 // Make the plugin list update itself
88 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
[email protected]ee6fcb22011-10-22 01:27:0689 BrowserThread::PostTask(
90 BrowserThread::UI, FROM_HERE,
[email protected]130757672012-10-24 00:26:1991 base::Bind(&PluginService::PurgePluginListCache,
92 static_cast<BrowserContext*>(NULL), false));
[email protected]634d23d2011-01-19 10:38:1993 }
[email protected]45a22e62011-10-12 09:48:0294
[email protected]7b3ee8b2011-04-01 18:48:1995 virtual void OnFilePathError(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1996 // TODO(pastarmovj): Add some sensible error handling. Maybe silently
97 // stopping the watcher would be enough. Or possibly restart it.
98 NOTREACHED();
99 }
[email protected]fb90c942012-04-27 23:40:50100
101 protected:
102 virtual ~PluginDirWatcherDelegate() {}
[email protected]634d23d2011-01-19 10:38:19103};
104#endif
105
[email protected]3a5180ae2011-12-21 02:39:38106// static
107PluginService* PluginService::GetInstance() {
[email protected]e67385f2011-12-21 06:00:56108 return PluginServiceImpl::GetInstance();
[email protected]3a5180ae2011-12-21 02:39:38109}
110
111void PluginService::PurgePluginListCache(BrowserContext* browser_context,
112 bool reload_pages) {
113 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
114 !it.IsAtEnd(); it.Advance()) {
115 RenderProcessHost* host = it.GetCurrentValue();
116 if (!browser_context || host->GetBrowserContext() == browser_context)
117 host->Send(new ViewMsg_PurgePluginListCache(reload_pages));
118 }
119}
120
initial.commit09911bf2008-07-26 23:55:29121// static
[email protected]e67385f2011-12-21 06:00:56122PluginServiceImpl* PluginServiceImpl::GetInstance() {
123 return Singleton<PluginServiceImpl>::get();
initial.commit09911bf2008-07-26 23:55:29124}
125
[email protected]e67385f2011-12-21 06:00:56126PluginServiceImpl::PluginServiceImpl()
[email protected]99907362012-01-11 05:41:40127 : plugin_list_(NULL), filter_(NULL) {
[email protected]ee066172011-11-10 23:20:05128}
129
[email protected]e67385f2011-12-21 06:00:56130PluginServiceImpl::~PluginServiceImpl() {
[email protected]ee066172011-11-10 23:20:05131#if defined(OS_WIN)
132 // Release the events since they're owned by RegKey, not WaitableEvent.
133 hkcu_watcher_.StopWatching();
134 hklm_watcher_.StopWatching();
135 if (hkcu_event_.get())
136 hkcu_event_->Release();
137 if (hklm_event_.get())
138 hklm_event_->Release();
139#endif
140 // Make sure no plugin channel requests have been leaked.
141 DCHECK(pending_plugin_clients_.empty());
142}
143
[email protected]e67385f2011-12-21 06:00:56144void PluginServiceImpl::Init() {
[email protected]ee066172011-11-10 23:20:05145 if (!plugin_list_)
146 plugin_list_ = webkit::npapi::PluginList::Singleton();
147
[email protected]a33fa9d2012-05-16 14:47:49148 plugin_list_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
[email protected]3a5180ae2011-12-21 02:39:38149 plugin_list_->set_will_load_plugins_callback(
[email protected]1b517202012-12-19 17:16:10150 base::Bind(&WillLoadPluginsCallback, plugin_list_token_));
[email protected]49125952011-09-27 18:05:15151
[email protected]4e0616e2010-05-28 14:55:53152 RegisterPepperPlugins();
153
[email protected]130757672012-10-24 00:26:19154 GetContentClient()->AddNPAPIPlugins(plugin_list_);
[email protected]f520b5b2011-11-08 02:42:14155
[email protected]9a1c4262010-06-29 21:50:27156 // Load any specified on the command line as well.
[email protected]d48f1e0c2009-02-12 20:57:54157 const CommandLine* command_line = CommandLine::ForCurrentProcess();
[email protected]c4e52f0d2009-11-06 19:55:16158 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
[email protected]7bf795d92010-05-22 00:14:28159 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14160 AddExtraPluginPath(path);
[email protected]9a1c4262010-06-29 21:50:27161 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
162 if (!path.empty())
[email protected]3a5180ae2011-12-21 02:39:38163 plugin_list_->AddExtraPluginDir(path);
[email protected]dfba8762011-09-02 12:49:54164}
165
[email protected]e67385f2011-12-21 06:00:56166void PluginServiceImpl::StartWatchingPlugins() {
[email protected]634d23d2011-01-19 10:38:19167 // Start watching for changes in the plugin list. This means watching
168 // for changes in the Windows registry keys and on both Windows and POSIX
169 // watch for changes in the paths that are expected to contain plugins.
[email protected]b547fd42009-04-23 23:16:27170#if defined(OS_WIN)
[email protected]86ec4f6e2011-04-20 16:21:19171 if (hkcu_key_.Create(HKEY_CURRENT_USER,
172 webkit::npapi::kRegistryMozillaPlugins,
173 KEY_NOTIFY) == ERROR_SUCCESS) {
174 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
175 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
176 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
177 }
[email protected]b547fd42009-04-23 23:16:27178 }
[email protected]86ec4f6e2011-04-20 16:21:19179 if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
180 webkit::npapi::kRegistryMozillaPlugins,
181 KEY_NOTIFY) == ERROR_SUCCESS) {
182 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
183 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
184 hklm_watcher_.StartWatching(hklm_event_.get(), this);
185 }
[email protected]b547fd42009-04-23 23:16:27186 }
[email protected]a33fa9d2012-05-16 14:47:49187#endif
[email protected]52348b22012-11-07 10:19:34188#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19189// On ChromeOS the user can't install plugins anyway and on Windows all
190// important plugins register themselves in the registry so no need to do that.
[email protected]634d23d2011-01-19 10:38:19191 file_watcher_delegate_ = new PluginDirWatcherDelegate();
192 // Get the list of all paths for registering the FilePathWatchers
193 // that will track and if needed reload the list of plugins on runtime.
194 std::vector<FilePath> plugin_dirs;
[email protected]3a5180ae2011-12-21 02:39:38195 plugin_list_->GetPluginDirectories(&plugin_dirs);
[email protected]894bb502009-05-21 22:39:57196
[email protected]634d23d2011-01-19 10:38:19197 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
[email protected]634d23d2011-01-19 10:38:19198 // FilePathWatcher can not handle non-absolute paths under windows.
199 // We don't watch for file changes in windows now but if this should ever
200 // be extended to Windows these lines might save some time of debugging.
201#if defined(OS_WIN)
202 if (!plugin_dirs[i].IsAbsolute())
203 continue;
204#endif
[email protected]493c8002011-04-14 16:56:01205 FilePathWatcher* watcher = new FilePathWatcher();
[email protected]634d23d2011-01-19 10:38:19206 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
207 BrowserThread::PostTask(
208 BrowserThread::FILE, FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56209 base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher,
[email protected]81050512011-12-19 19:32:51210 plugin_dirs[i], file_watcher_delegate_));
[email protected]634d23d2011-01-19 10:38:19211 file_watchers_.push_back(watcher);
212 }
213#endif
initial.commit09911bf2008-07-26 23:55:29214}
215
[email protected]e67385f2011-12-21 06:00:56216PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess(
[email protected]28ab7f92009-01-06 21:39:04217 const FilePath& plugin_path) {
[email protected]4967f792012-01-20 22:14:40218 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
219 if (iter->info().path == plugin_path)
220 return *iter;
[email protected]a436d922009-02-13 23:16:42221 }
222
initial.commit09911bf2008-07-26 23:55:29223 return NULL;
224}
225
[email protected]e67385f2011-12-21 06:00:56226PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31227 const FilePath& plugin_path,
228 const FilePath& profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40229 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
[email protected]dd9a0952012-05-31 20:11:31230 if (iter->plugin_path() == plugin_path &&
231 iter->profile_data_directory() == profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40232 return *iter;
[email protected]dd9a0952012-05-31 20:11:31233 }
[email protected]a08ebea2011-02-13 17:50:20234 }
[email protected]a08ebea2011-02-13 17:50:20235 return NULL;
236}
237
[email protected]e67385f2011-12-21 06:00:56238PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42239 const FilePath& broker_path) {
[email protected]4967f792012-01-20 22:14:40240 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) {
241 if (iter->plugin_path() == broker_path)
242 return *iter;
[email protected]eb415bf0e2011-04-14 02:45:42243 }
244
245 return NULL;
246}
247
[email protected]e67385f2011-12-21 06:00:56248PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
[email protected]a08ebea2011-02-13 17:50:20249 const FilePath& plugin_path) {
250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
251
252 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
initial.commit09911bf2008-07-26 23:55:29253 if (plugin_host)
254 return plugin_host;
255
[email protected]91d9f3d2011-08-14 05:24:44256 webkit::WebPluginInfo info;
[email protected]88ca4912011-10-12 14:00:43257 if (!GetPluginInfoByPath(plugin_path, &info)) {
[email protected]a27a9382009-02-11 23:55:10258 return NULL;
259 }
260
initial.commit09911bf2008-07-26 23:55:29261 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]8b8a554d2010-11-18 13:26:40262 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
[email protected]99907362012-01-11 05:41:40263 if (!new_host->Init(info)) {
[email protected]a08ebea2011-02-13 17:50:20264 NOTREACHED(); // Init is not expected to fail.
initial.commit09911bf2008-07-26 23:55:29265 return NULL;
266 }
[email protected]8b8a554d2010-11-18 13:26:40267 return new_host.release();
initial.commit09911bf2008-07-26 23:55:29268}
269
[email protected]e67385f2011-12-21 06:00:56270PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
[email protected]d259a8e2011-05-18 22:31:09271 const FilePath& plugin_path,
[email protected]dd9a0952012-05-31 20:11:31272 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14273 PpapiPluginProcessHost::PluginClient* client) {
[email protected]a08ebea2011-02-13 17:50:20274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
275
[email protected]dd9a0952012-05-31 20:11:31276 PpapiPluginProcessHost* plugin_host =
277 FindPpapiPluginProcess(plugin_path, profile_data_directory);
[email protected]a08ebea2011-02-13 17:50:20278 if (plugin_host)
279 return plugin_host;
280
[email protected]eb415bf0e2011-04-14 02:45:42281 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19282 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]a08ebea2011-02-13 17:50:20283 if (!info)
284 return NULL;
285
286 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14287 return PpapiPluginProcessHost::CreatePluginHost(
[email protected]dd9a0952012-05-31 20:11:31288 *info, profile_data_directory,
[email protected]df02aca2012-02-09 21:03:20289 client->GetResourceContext()->GetHostResolver());
[email protected]a08ebea2011-02-13 17:50:20290}
291
[email protected]e67385f2011-12-21 06:00:56292PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42293 const FilePath& plugin_path) {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
295
[email protected]a50432d2011-09-30 16:32:14296 PpapiPluginProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42297 if (plugin_host)
298 return plugin_host;
299
300 // Validate that the plugin is actually registered.
[email protected]130757672012-10-24 00:26:19301 PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42302 if (!info)
303 return NULL;
304
305 // TODO(ddorwin): Uncomment once out of process is supported.
306 // DCHECK(info->is_out_of_process);
307
308 // This broker isn't loaded by any broker process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14309 return PpapiPluginProcessHost::CreateBrokerHost(*info);
[email protected]eb415bf0e2011-04-14 02:45:42310}
311
[email protected]e67385f2011-12-21 06:00:56312void PluginServiceImpl::OpenChannelToNpapiPlugin(
[email protected]c8f73ab2011-01-22 00:05:17313 int render_process_id,
314 int render_view_id,
[email protected]610c0892009-09-08 19:46:18315 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54316 const GURL& page_url,
[email protected]610c0892009-09-08 19:46:18317 const std::string& mime_type,
[email protected]46b69e42010-11-02 12:26:39318 PluginProcessHost::Client* client) {
[email protected]76b70f92011-11-21 19:31:14319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]4befe7592011-09-14 22:49:09320 DCHECK(!ContainsKey(pending_plugin_clients_, client));
321 pending_plugin_clients_.insert(client);
[email protected]88ca4912011-10-12 14:00:43322
323 // Make sure plugins are loaded if necessary.
[email protected]209f2ae2012-03-13 01:28:08324 PluginServiceFilterParams params = {
[email protected]88ca4912011-10-12 14:00:43325 render_process_id,
326 render_view_id,
327 page_url,
[email protected]df02aca2012-02-09 21:03:20328 client->GetResourceContext()
[email protected]88ca4912011-10-12 14:00:43329 };
[email protected]e67385f2011-12-21 06:00:56330 GetPlugins(base::Bind(
331 &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin,
332 base::Unretained(this), params, url, mime_type, client));
[email protected]6fdd4182010-10-14 23:59:26333}
334
[email protected]e67385f2011-12-21 06:00:56335void PluginServiceImpl::OpenChannelToPpapiPlugin(
[email protected]dd9a0952012-05-31 20:11:31336 const FilePath& plugin_path,
337 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14338 PpapiPluginProcessHost::PluginClient* client) {
[email protected]d259a8e2011-05-18 22:31:09339 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31340 plugin_path, profile_data_directory, client);
[email protected]1bf0fb22012-04-12 21:44:16341 if (plugin_host) {
[email protected]a08ebea2011-02-13 17:50:20342 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16343 } else {
344 // Send error.
[email protected]108fd342013-01-04 20:46:54345 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0);
[email protected]1bf0fb22012-04-12 21:44:16346 }
[email protected]a08ebea2011-02-13 17:50:20347}
348
[email protected]e67385f2011-12-21 06:00:56349void PluginServiceImpl::OpenChannelToPpapiBroker(
[email protected]eb415bf0e2011-04-14 02:45:42350 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14351 PpapiPluginProcessHost::BrokerClient* client) {
352 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
[email protected]1bf0fb22012-04-12 21:44:16353 if (plugin_host) {
[email protected]a50432d2011-09-30 16:32:14354 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16355 } else {
356 // Send error.
[email protected]108fd342013-01-04 20:46:54357 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0);
[email protected]1bf0fb22012-04-12 21:44:16358 }
[email protected]eb415bf0e2011-04-14 02:45:42359}
360
[email protected]e67385f2011-12-21 06:00:56361void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
[email protected]4befe7592011-09-14 22:49:09362 PluginProcessHost::Client* client) {
363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
364 DCHECK(ContainsKey(pending_plugin_clients_, client));
365 pending_plugin_clients_.erase(client);
366}
367
[email protected]e67385f2011-12-21 06:00:56368void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin(
[email protected]209f2ae2012-03-13 01:28:08369 const PluginServiceFilterParams& params,
[email protected]88ca4912011-10-12 14:00:43370 const GURL& url,
371 const std::string& mime_type,
372 PluginProcessHost::Client* client,
373 const std::vector<webkit::WebPluginInfo>&) {
374 GetAllowedPluginForOpenChannelToPlugin(params.render_process_id,
375 params.render_view_id, url, params.page_url, mime_type, client,
376 params.resource_context);
377}
378
[email protected]e67385f2011-12-21 06:00:56379void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
[email protected]c8f73ab2011-01-22 00:05:17380 int render_process_id,
381 int render_view_id,
[email protected]6fdd4182010-10-14 23:59:26382 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54383 const GURL& page_url,
[email protected]6fdd4182010-10-14 23:59:26384 const std::string& mime_type,
[email protected]87c4be42011-09-16 01:10:59385 PluginProcessHost::Client* client,
[email protected]130757672012-10-24 00:26:19386 ResourceContext* resource_context) {
[email protected]91d9f3d2011-08-14 05:24:44387 webkit::WebPluginInfo info;
[email protected]dfba8762011-09-02 12:49:54388 bool allow_wildcard = true;
[email protected]11e1c182011-05-17 20:26:27389 bool found = GetPluginInfo(
[email protected]df02aca2012-02-09 21:03:20390 render_process_id, render_view_id, resource_context,
[email protected]dfba8762011-09-02 12:49:54391 url, page_url, mime_type, allow_wildcard,
392 NULL, &info, NULL);
[email protected]6fdd4182010-10-14 23:59:26393 FilePath plugin_path;
[email protected]68598072011-07-29 08:21:28394 if (found)
[email protected]dfba8762011-09-02 12:49:54395 plugin_path = info.path;
[email protected]6fdd4182010-10-14 23:59:26396
397 // Now we jump back to the IO thread to finish opening the channel.
[email protected]e67385f2011-12-21 06:00:56398 BrowserThread::PostTask(
399 BrowserThread::IO, FROM_HERE,
400 base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin,
[email protected]88ca4912011-10-12 14:00:43401 base::Unretained(this), plugin_path, client));
[email protected]6fdd4182010-10-14 23:59:26402}
403
[email protected]e67385f2011-12-21 06:00:56404void PluginServiceImpl::FinishOpenChannelToPlugin(
[email protected]6fdd4182010-10-14 23:59:26405 const FilePath& plugin_path,
[email protected]46b69e42010-11-02 12:26:39406 PluginProcessHost::Client* client) {
[email protected]f8b3ef82010-10-11 02:45:52407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20a793e2010-10-12 06:50:08408
[email protected]4befe7592011-09-14 22:49:09409 // Make sure it hasn't been canceled yet.
410 if (!ContainsKey(pending_plugin_clients_, client))
411 return;
412 pending_plugin_clients_.erase(client);
413
[email protected]a08ebea2011-02-13 17:50:20414 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
[email protected]4befe7592011-09-14 22:49:09415 if (plugin_host) {
416 client->OnFoundPluginProcessHost(plugin_host);
[email protected]46b69e42010-11-02 12:26:39417 plugin_host->OpenChannelToPlugin(client);
[email protected]4befe7592011-09-14 22:49:09418 } else {
[email protected]46b69e42010-11-02 12:26:39419 client->OnError();
[email protected]4befe7592011-09-14 22:49:09420 }
initial.commit09911bf2008-07-26 23:55:29421}
422
[email protected]e67385f2011-12-21 06:00:56423bool PluginServiceImpl::GetPluginInfoArray(
[email protected]51b63f62011-10-05 18:55:42424 const GURL& url,
425 const std::string& mime_type,
426 bool allow_wildcard,
427 std::vector<webkit::WebPluginInfo>* plugins,
428 std::vector<std::string>* actual_mime_types) {
429 bool use_stale = false;
[email protected]3a5180ae2011-12-21 02:39:38430 plugin_list_->GetPluginInfoArray(url, mime_type, allow_wildcard,
431 &use_stale, plugins, actual_mime_types);
[email protected]51b63f62011-10-05 18:55:42432 return use_stale;
433}
434
[email protected]e67385f2011-12-21 06:00:56435bool PluginServiceImpl::GetPluginInfo(int render_process_id,
436 int render_view_id,
[email protected]130757672012-10-24 00:26:19437 ResourceContext* context,
[email protected]e67385f2011-12-21 06:00:56438 const GURL& url,
439 const GURL& page_url,
440 const std::string& mime_type,
441 bool allow_wildcard,
442 bool* is_stale,
443 webkit::WebPluginInfo* info,
444 std::string* actual_mime_type) {
[email protected]91d9f3d2011-08-14 05:24:44445 std::vector<webkit::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28446 std::vector<std::string> mime_types;
[email protected]88ca4912011-10-12 14:00:43447 bool stale = GetPluginInfoArray(
448 url, mime_type, allow_wildcard, &plugins, &mime_types);
449 if (is_stale)
450 *is_stale = stale;
[email protected]dfba8762011-09-02 12:49:54451
[email protected]68598072011-07-29 08:21:28452 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]dfba8762011-09-02 12:49:54453 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
454 render_view_id,
[email protected]df02aca2012-02-09 21:03:20455 context,
[email protected]dfba8762011-09-02 12:49:54456 url,
457 page_url,
458 &plugins[i])) {
[email protected]68598072011-07-29 08:21:28459 *info = plugins[i];
460 if (actual_mime_type)
461 *actual_mime_type = mime_types[i];
462 return true;
463 }
464 }
465 return false;
[email protected]6fdd4182010-10-14 23:59:26466}
467
[email protected]e67385f2011-12-21 06:00:56468bool PluginServiceImpl::GetPluginInfoByPath(const FilePath& plugin_path,
469 webkit::WebPluginInfo* info) {
[email protected]88ca4912011-10-12 14:00:43470 std::vector<webkit::WebPluginInfo> plugins;
[email protected]480c7cc2012-06-29 17:38:44471 plugin_list_->GetPluginsNoRefresh(&plugins);
[email protected]88ca4912011-10-12 14:00:43472
473 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
474 it != plugins.end();
475 ++it) {
476 if (it->path == plugin_path) {
477 *info = *it;
478 return true;
479 }
480 }
481
482 return false;
483}
484
[email protected]8be45842012-04-13 19:49:29485string16 PluginServiceImpl::GetPluginDisplayNameByPath(const FilePath& path) {
486 string16 plugin_name = path.LossyDisplayName();
487 webkit::WebPluginInfo info;
488 if (PluginService::GetInstance()->GetPluginInfoByPath(path, &info) &&
489 !info.name.empty()) {
490 plugin_name = info.name;
491#if defined(OS_MACOSX)
492 // Many plugins on the Mac have .plugin in the actual name, which looks
493 // terrible, so look for that and strip it off if present.
494 const std::string kPluginExtension = ".plugin";
495 if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
496 plugin_name.erase(plugin_name.length() - kPluginExtension.length());
497#endif // OS_MACOSX
498 }
499 return plugin_name;
500}
501
[email protected]e67385f2011-12-21 06:00:56502void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
[email protected]49125952011-09-27 18:05:15503 scoped_refptr<base::MessageLoopProxy> target_loop(
504 MessageLoop::current()->message_loop_proxy());
505
[email protected]1b517202012-12-19 17:16:10506 if (LoadPluginListInProcess()) {
507 BrowserThread::GetBlockingPool()->
508 PostSequencedWorkerTaskWithShutdownBehavior(
509 plugin_list_token_,
510 FROM_HERE,
511 base::Bind(&PluginServiceImpl::GetPluginsInternal,
512 base::Unretained(this),
513 target_loop, callback),
514 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
515 return;
516 }
517#if defined(OS_POSIX)
[email protected]49125952011-09-27 18:05:15518 std::vector<webkit::WebPluginInfo> cached_plugins;
[email protected]480c7cc2012-06-29 17:38:44519 if (plugin_list_->GetPluginsNoRefresh(&cached_plugins)) {
[email protected]49125952011-09-27 18:05:15520 // Can't assume the caller is reentrant.
521 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37522 base::Bind(callback, cached_plugins));
[email protected]49125952011-09-27 18:05:15523 } else {
[email protected]4bb85b92011-11-05 02:53:29524 // If we switch back to loading plugins in process, then we need to make
525 // sure g_thread_init() gets called since plugins may call glib at load.
[email protected]d4af1e72011-10-21 17:45:43526 if (!plugin_loader_.get())
527 plugin_loader_ = new PluginLoaderPosix;
[email protected]49125952011-09-27 18:05:15528 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]d4af1e72011-10-21 17:45:43529 base::Bind(&PluginLoaderPosix::LoadPlugins, plugin_loader_,
530 target_loop, callback));
[email protected]49125952011-09-27 18:05:15531 }
[email protected]a33fa9d2012-05-16 14:47:49532#else
[email protected]1b517202012-12-19 17:16:10533 NOTREACHED();
[email protected]49125952011-09-27 18:05:15534#endif
[email protected]d33e7cc2011-09-23 01:43:56535}
536
[email protected]e67385f2011-12-21 06:00:56537void PluginServiceImpl::GetPluginsInternal(
[email protected]d33e7cc2011-09-23 01:43:56538 base::MessageLoopProxy* target_loop,
539 const PluginService::GetPluginsCallback& callback) {
[email protected]a33fa9d2012-05-16 14:47:49540 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
541 plugin_list_token_));
[email protected]d33e7cc2011-09-23 01:43:56542
543 std::vector<webkit::WebPluginInfo> plugins;
[email protected]3a5180ae2011-12-21 02:39:38544 plugin_list_->GetPlugins(&plugins);
[email protected]d33e7cc2011-09-23 01:43:56545
546 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37547 base::Bind(callback, plugins));
[email protected]dfba8762011-09-02 12:49:54548}
549
[email protected]e67385f2011-12-21 06:00:56550void PluginServiceImpl::OnWaitableEventSignaled(
[email protected]580522632009-08-17 21:55:55551 base::WaitableEvent* waitable_event) {
[email protected]b547fd42009-04-23 23:16:27552#if defined(OS_WIN)
553 if (waitable_event == hkcu_event_.get()) {
554 hkcu_key_.StartWatching();
555 } else {
556 hklm_key_.StartWatching();
557 }
558
[email protected]3a5180ae2011-12-21 02:39:38559 plugin_list_->RefreshPlugins();
[email protected]45a22e62011-10-12 09:48:02560 PurgePluginListCache(NULL, false);
[email protected]634d23d2011-01-19 10:38:19561#else
562 // This event should only get signaled on a Windows machine.
563 NOTREACHED();
[email protected]9de09f82009-08-17 20:13:53564#endif // defined(OS_WIN)
[email protected]b547fd42009-04-23 23:16:27565}
[email protected]894bb502009-05-21 22:39:57566
[email protected]e67385f2011-12-21 06:00:56567void PluginServiceImpl::RegisterPepperPlugins() {
[email protected]84396dbc2011-04-14 06:33:42568 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
[email protected]a08ebea2011-02-13 17:50:20569 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
570 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
[email protected]c6f3dea2012-01-14 02:23:11571 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);
[email protected]4e0616e2010-05-28 14:55:53572 }
573}
[email protected]634d23d2011-01-19 10:38:19574
[email protected]eb415bf0e2011-04-14 02:45:42575// There should generally be very few plugins so a brute-force search is fine.
[email protected]130757672012-10-24 00:26:19576PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
[email protected]eb415bf0e2011-04-14 02:45:42577 const FilePath& plugin_path) {
[email protected]130757672012-10-24 00:26:19578 PepperPluginInfo* info = NULL;
[email protected]eb415bf0e2011-04-14 02:45:42579 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
[email protected]6b14feb2011-08-16 11:22:56580 if (ppapi_plugins_[i].path == plugin_path) {
581 info = &ppapi_plugins_[i];
582 break;
583 }
[email protected]eb415bf0e2011-04-14 02:45:42584 }
[email protected]076117592011-08-17 03:16:41585 if (info)
586 return info;
587 // We did not find the plugin in our list. But wait! the plugin can also
588 // be a latecomer, as it happens with pepper flash. This information
589 // can be obtained from the PluginList singleton and we can use it to
590 // construct it and add it to the list. This same deal needs to be done
591 // in the renderer side in PepperPluginRegistry.
592 webkit::WebPluginInfo webplugin_info;
[email protected]88ca4912011-10-12 14:00:43593 if (!GetPluginInfoByPath(plugin_path, &webplugin_info))
[email protected]076117592011-08-17 03:16:41594 return NULL;
[email protected]130757672012-10-24 00:26:19595 PepperPluginInfo new_pepper_info;
[email protected]076117592011-08-17 03:16:41596 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
597 return NULL;
598 ppapi_plugins_.push_back(new_pepper_info);
599 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
[email protected]eb415bf0e2011-04-14 02:45:42600}
601
[email protected]52348b22012-11-07 10:19:34602#if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID)
[email protected]634d23d2011-01-19 10:38:19603// static
[email protected]e67385f2011-12-21 06:00:56604void PluginServiceImpl::RegisterFilePathWatcher(
[email protected]3b91edbe2012-09-27 22:49:23605 FilePathWatcher* watcher,
[email protected]634d23d2011-01-19 10:38:19606 const FilePath& path,
607 FilePathWatcher::Delegate* delegate) {
[email protected]7b3ee8b2011-04-01 18:48:19608 bool result = watcher->Watch(path, delegate);
[email protected]634d23d2011-01-19 10:38:19609 DCHECK(result);
610}
611#endif
[email protected]f520b5b2011-11-08 02:42:14612
[email protected]130757672012-10-24 00:26:19613void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) {
[email protected]3a5180ae2011-12-21 02:39:38614 filter_ = filter;
615}
616
[email protected]130757672012-10-24 00:26:19617PluginServiceFilter* PluginServiceImpl::GetFilter() {
[email protected]3a5180ae2011-12-21 02:39:38618 return filter_;
619}
620
[email protected]b6a2f8de2012-01-31 17:28:49621void PluginServiceImpl::ForcePluginShutdown(const FilePath& plugin_path) {
622 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
623 BrowserThread::PostTask(
624 BrowserThread::IO, FROM_HERE,
625 base::Bind(&PluginServiceImpl::ForcePluginShutdown,
626 base::Unretained(this), plugin_path));
627 return;
628 }
629
630 PluginProcessHost* plugin = FindNpapiPluginProcess(plugin_path);
631 if (plugin)
632 plugin->ForceShutdown();
633}
634
[email protected]47214d882012-02-29 06:28:48635static const unsigned int kMaxCrashesPerInterval = 3;
636static const unsigned int kCrashesInterval = 120;
637
638void PluginServiceImpl::RegisterPluginCrash(const FilePath& path) {
639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
640 std::map<FilePath, std::vector<base::Time> >::iterator i =
641 crash_times_.find(path);
642 if (i == crash_times_.end()) {
643 crash_times_[path] = std::vector<base::Time>();
644 i = crash_times_.find(path);
645 }
646 if (i->second.size() == kMaxCrashesPerInterval) {
647 i->second.erase(i->second.begin());
648 }
649 base::Time time = base::Time::Now();
650 i->second.push_back(time);
651}
652
653bool PluginServiceImpl::IsPluginUnstable(const FilePath& path) {
654 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
655 std::map<FilePath, std::vector<base::Time> >::const_iterator i =
656 crash_times_.find(path);
657 if (i == crash_times_.end()) {
658 return false;
659 }
660 if (i->second.size() != kMaxCrashesPerInterval) {
661 return false;
662 }
663 base::TimeDelta delta = base::Time::Now() - i->second[0];
664 if (delta.InSeconds() <= kCrashesInterval) {
665 return true;
666 }
667 return false;
668}
669
[email protected]e67385f2011-12-21 06:00:56670void PluginServiceImpl::RefreshPlugins() {
[email protected]3a5180ae2011-12-21 02:39:38671 plugin_list_->RefreshPlugins();
[email protected]f520b5b2011-11-08 02:42:14672}
673
[email protected]e67385f2011-12-21 06:00:56674void PluginServiceImpl::AddExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38675 plugin_list_->AddExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14676}
677
[email protected]c6f3dea2012-01-14 02:23:11678void PluginServiceImpl::AddExtraPluginDir(const FilePath& path) {
679 plugin_list_->AddExtraPluginDir(path);
680}
681
[email protected]e67385f2011-12-21 06:00:56682void PluginServiceImpl::RemoveExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38683 plugin_list_->RemoveExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14684}
685
[email protected]e67385f2011-12-21 06:00:56686void PluginServiceImpl::UnregisterInternalPlugin(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38687 plugin_list_->UnregisterInternalPlugin(path);
[email protected]f520b5b2011-11-08 02:42:14688}
689
[email protected]e67385f2011-12-21 06:00:56690void PluginServiceImpl::SetPluginListForTesting(
[email protected]ee066172011-11-10 23:20:05691 webkit::npapi::PluginList* plugin_list) {
692 plugin_list_ = plugin_list;
693}
694
[email protected]5904cb42012-09-24 15:05:20695#if defined(OS_MACOSX)
696void PluginServiceImpl::AppActivated() {
697 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
698 base::Bind(&NotifyPluginsOfActivation));
699}
700#endif
701
[email protected]e67385f2011-12-21 06:00:56702void PluginServiceImpl::RegisterInternalPlugin(
[email protected]c6f3dea2012-01-14 02:23:11703 const webkit::WebPluginInfo& info,
704 bool add_at_beginning) {
705 plugin_list_->RegisterInternalPlugin(info, add_at_beginning);
[email protected]f520b5b2011-11-08 02:42:14706}
707
[email protected]57aece22012-10-10 22:10:27708void PluginServiceImpl::GetInternalPlugins(
709 std::vector<webkit::WebPluginInfo>* plugins) {
710 plugin_list_->GetInternalPlugins(plugins);
711}
712
[email protected]e67385f2011-12-21 06:00:56713webkit::npapi::PluginList* PluginServiceImpl::GetPluginList() {
[email protected]3a5180ae2011-12-21 02:39:38714 return plugin_list_;
[email protected]f520b5b2011-11-08 02:42:14715}
[email protected]130757672012-10-24 00:26:19716
717} // namespace content