blob: 6f7a30342e21d0f4ceed16f94d677274c6450531 [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]3b48dbc2012-01-06 16:34:1743#if defined(OS_POSIX) && !defined(OS_OPENBSD)
[email protected]493c8002011-04-14 16:56:0144using ::base::files::FilePathWatcher;
45#endif
46
[email protected]631bb742011-11-02 11:29:3947using content::BrowserThread;
[email protected]e67385f2011-12-21 06:00:5648using content::PluginService;
[email protected]dfba8762011-09-02 12:49:5449using content::PluginServiceFilter;
50
[email protected]d33e7cc2011-09-23 01:43:5651namespace {
52
[email protected]49125952011-09-27 18:05:1553// Callback set on the PluginList to assert that plugin loading happens on the
54// correct thread.
[email protected]6a0dc7a2011-11-02 14:37:0755#if defined(OS_WIN)
[email protected]a33fa9d2012-05-16 14:47:4956void WillLoadPluginsCallbackWin(
57 base::SequencedWorkerPool::SequenceToken token) {
58 CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
59 token));
[email protected]a79912252012-05-16 11:52:1960}
[email protected]a33fa9d2012-05-16 14:47:4961#else
62void WillLoadPluginsCallbackPosix() {
63 CHECK(false) << "Plugin loading should happen out-of-process.";
64}
65#endif
[email protected]49125952011-09-27 18:05:1566
[email protected]d33e7cc2011-09-23 01:43:5667} // namespace
68
[email protected]a96ec6a2009-11-04 17:27:0869#if defined(OS_MACOSX)
70static void NotifyPluginsOfActivation() {
[email protected]f8b3ef82010-10-11 02:45:5271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]a96ec6a2009-11-04 17:27:0872
[email protected]4967f792012-01-20 22:14:4073 for (PluginProcessHostIterator iter; !iter.Done(); ++iter)
74 iter->OnAppActivation();
[email protected]a96ec6a2009-11-04 17:27:0875}
[email protected]3b48dbc2012-01-06 16:34:1776#endif
77#if defined(OS_POSIX) && !defined(OS_OPENBSD)
[email protected]634d23d2011-01-19 10:38:1978// Delegate class for monitoring directories.
79class PluginDirWatcherDelegate : public FilePathWatcher::Delegate {
[email protected]7b3ee8b2011-04-01 18:48:1980 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1981 VLOG(1) << "Watched path changed: " << path.value();
82 // Make the plugin list update itself
83 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
[email protected]ee6fcb22011-10-22 01:27:0684 BrowserThread::PostTask(
85 BrowserThread::UI, FROM_HERE,
[email protected]3a5180ae2011-12-21 02:39:3886 base::Bind(&content::PluginService::PurgePluginListCache,
[email protected]ee6fcb22011-10-22 01:27:0687 static_cast<content::BrowserContext*>(NULL), false));
[email protected]634d23d2011-01-19 10:38:1988 }
[email protected]45a22e62011-10-12 09:48:0289
[email protected]7b3ee8b2011-04-01 18:48:1990 virtual void OnFilePathError(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1991 // TODO(pastarmovj): Add some sensible error handling. Maybe silently
92 // stopping the watcher would be enough. Or possibly restart it.
93 NOTREACHED();
94 }
[email protected]fb90c942012-04-27 23:40:5095
96 protected:
97 virtual ~PluginDirWatcherDelegate() {}
[email protected]634d23d2011-01-19 10:38:1998};
99#endif
100
[email protected]3a5180ae2011-12-21 02:39:38101namespace content {
102// 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
117} // namespace content
118
initial.commit09911bf2008-07-26 23:55:29119// static
[email protected]e67385f2011-12-21 06:00:56120PluginServiceImpl* PluginServiceImpl::GetInstance() {
121 return Singleton<PluginServiceImpl>::get();
initial.commit09911bf2008-07-26 23:55:29122}
123
[email protected]e67385f2011-12-21 06:00:56124PluginServiceImpl::PluginServiceImpl()
[email protected]99907362012-01-11 05:41:40125 : plugin_list_(NULL), filter_(NULL) {
[email protected]ee066172011-11-10 23:20:05126}
127
[email protected]e67385f2011-12-21 06:00:56128PluginServiceImpl::~PluginServiceImpl() {
[email protected]ee066172011-11-10 23:20:05129#if defined(OS_WIN)
130 // Release the events since they're owned by RegKey, not WaitableEvent.
131 hkcu_watcher_.StopWatching();
132 hklm_watcher_.StopWatching();
133 if (hkcu_event_.get())
134 hkcu_event_->Release();
135 if (hklm_event_.get())
136 hklm_event_->Release();
137#endif
138 // Make sure no plugin channel requests have been leaked.
139 DCHECK(pending_plugin_clients_.empty());
140}
141
[email protected]e67385f2011-12-21 06:00:56142void PluginServiceImpl::Init() {
[email protected]ee066172011-11-10 23:20:05143 if (!plugin_list_)
144 plugin_list_ = webkit::npapi::PluginList::Singleton();
145
[email protected]a33fa9d2012-05-16 14:47:49146#if defined(OS_WIN)
147 plugin_list_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
[email protected]3a5180ae2011-12-21 02:39:38148 plugin_list_->set_will_load_plugins_callback(
[email protected]a33fa9d2012-05-16 14:47:49149 base::Bind(&WillLoadPluginsCallbackWin, plugin_list_token_));
150#else
151 plugin_list_->set_will_load_plugins_callback(
152 base::Bind(&WillLoadPluginsCallbackPosix));
153#endif
[email protected]49125952011-09-27 18:05:15154
[email protected]4e0616e2010-05-28 14:55:53155 RegisterPepperPlugins();
156
[email protected]3a5180ae2011-12-21 02:39:38157 content::GetContentClient()->AddNPAPIPlugins(plugin_list_);
[email protected]f520b5b2011-11-08 02:42:14158
[email protected]9a1c4262010-06-29 21:50:27159 // Load any specified on the command line as well.
[email protected]d48f1e0c2009-02-12 20:57:54160 const CommandLine* command_line = CommandLine::ForCurrentProcess();
[email protected]c4e52f0d2009-11-06 19:55:16161 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
[email protected]7bf795d92010-05-22 00:14:28162 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14163 AddExtraPluginPath(path);
[email protected]9a1c4262010-06-29 21:50:27164 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
165 if (!path.empty())
[email protected]3a5180ae2011-12-21 02:39:38166 plugin_list_->AddExtraPluginDir(path);
[email protected]dfba8762011-09-02 12:49:54167}
168
[email protected]e67385f2011-12-21 06:00:56169void PluginServiceImpl::StartWatchingPlugins() {
[email protected]634d23d2011-01-19 10:38:19170 // Start watching for changes in the plugin list. This means watching
171 // for changes in the Windows registry keys and on both Windows and POSIX
172 // watch for changes in the paths that are expected to contain plugins.
[email protected]b547fd42009-04-23 23:16:27173#if defined(OS_WIN)
[email protected]86ec4f6e2011-04-20 16:21:19174 if (hkcu_key_.Create(HKEY_CURRENT_USER,
175 webkit::npapi::kRegistryMozillaPlugins,
176 KEY_NOTIFY) == ERROR_SUCCESS) {
177 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
178 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
179 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
180 }
[email protected]b547fd42009-04-23 23:16:27181 }
[email protected]86ec4f6e2011-04-20 16:21:19182 if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
183 webkit::npapi::kRegistryMozillaPlugins,
184 KEY_NOTIFY) == ERROR_SUCCESS) {
185 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
186 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
187 hklm_watcher_.StartWatching(hklm_event_.get(), this);
188 }
[email protected]b547fd42009-04-23 23:16:27189 }
[email protected]a33fa9d2012-05-16 14:47:49190#endif
191#if defined(OS_POSIX) && !defined(OS_OPENBSD)
[email protected]634d23d2011-01-19 10:38:19192// On ChromeOS the user can't install plugins anyway and on Windows all
193// important plugins register themselves in the registry so no need to do that.
[email protected]634d23d2011-01-19 10:38:19194 file_watcher_delegate_ = new PluginDirWatcherDelegate();
195 // Get the list of all paths for registering the FilePathWatchers
196 // that will track and if needed reload the list of plugins on runtime.
197 std::vector<FilePath> plugin_dirs;
[email protected]3a5180ae2011-12-21 02:39:38198 plugin_list_->GetPluginDirectories(&plugin_dirs);
[email protected]894bb502009-05-21 22:39:57199
[email protected]634d23d2011-01-19 10:38:19200 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
[email protected]634d23d2011-01-19 10:38:19201 // FilePathWatcher can not handle non-absolute paths under windows.
202 // We don't watch for file changes in windows now but if this should ever
203 // be extended to Windows these lines might save some time of debugging.
204#if defined(OS_WIN)
205 if (!plugin_dirs[i].IsAbsolute())
206 continue;
207#endif
[email protected]493c8002011-04-14 16:56:01208 FilePathWatcher* watcher = new FilePathWatcher();
[email protected]634d23d2011-01-19 10:38:19209 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
210 BrowserThread::PostTask(
211 BrowserThread::FILE, FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56212 base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher,
[email protected]81050512011-12-19 19:32:51213 plugin_dirs[i], file_watcher_delegate_));
[email protected]634d23d2011-01-19 10:38:19214 file_watchers_.push_back(watcher);
215 }
216#endif
initial.commit09911bf2008-07-26 23:55:29217}
218
[email protected]e67385f2011-12-21 06:00:56219PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess(
[email protected]28ab7f92009-01-06 21:39:04220 const FilePath& plugin_path) {
[email protected]4967f792012-01-20 22:14:40221 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) {
222 if (iter->info().path == plugin_path)
223 return *iter;
[email protected]a436d922009-02-13 23:16:42224 }
225
initial.commit09911bf2008-07-26 23:55:29226 return NULL;
227}
228
[email protected]e67385f2011-12-21 06:00:56229PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31230 const FilePath& plugin_path,
231 const FilePath& profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40232 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
[email protected]dd9a0952012-05-31 20:11:31233 if (iter->plugin_path() == plugin_path &&
234 iter->profile_data_directory() == profile_data_directory) {
[email protected]4967f792012-01-20 22:14:40235 return *iter;
[email protected]dd9a0952012-05-31 20:11:31236 }
[email protected]a08ebea2011-02-13 17:50:20237 }
[email protected]a08ebea2011-02-13 17:50:20238 return NULL;
239}
240
[email protected]e67385f2011-12-21 06:00:56241PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42242 const FilePath& broker_path) {
[email protected]4967f792012-01-20 22:14:40243 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) {
244 if (iter->plugin_path() == broker_path)
245 return *iter;
[email protected]eb415bf0e2011-04-14 02:45:42246 }
247
248 return NULL;
249}
250
[email protected]e67385f2011-12-21 06:00:56251PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess(
[email protected]a08ebea2011-02-13 17:50:20252 const FilePath& plugin_path) {
253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
254
255 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
initial.commit09911bf2008-07-26 23:55:29256 if (plugin_host)
257 return plugin_host;
258
[email protected]91d9f3d2011-08-14 05:24:44259 webkit::WebPluginInfo info;
[email protected]88ca4912011-10-12 14:00:43260 if (!GetPluginInfoByPath(plugin_path, &info)) {
[email protected]a27a9382009-02-11 23:55:10261 return NULL;
262 }
263
initial.commit09911bf2008-07-26 23:55:29264 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]8b8a554d2010-11-18 13:26:40265 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
[email protected]99907362012-01-11 05:41:40266 if (!new_host->Init(info)) {
[email protected]a08ebea2011-02-13 17:50:20267 NOTREACHED(); // Init is not expected to fail.
initial.commit09911bf2008-07-26 23:55:29268 return NULL;
269 }
[email protected]8b8a554d2010-11-18 13:26:40270 return new_host.release();
initial.commit09911bf2008-07-26 23:55:29271}
272
[email protected]e67385f2011-12-21 06:00:56273PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess(
[email protected]d259a8e2011-05-18 22:31:09274 const FilePath& plugin_path,
[email protected]dd9a0952012-05-31 20:11:31275 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14276 PpapiPluginProcessHost::PluginClient* client) {
[email protected]a08ebea2011-02-13 17:50:20277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
278
[email protected]dd9a0952012-05-31 20:11:31279 PpapiPluginProcessHost* plugin_host =
280 FindPpapiPluginProcess(plugin_path, profile_data_directory);
[email protected]a08ebea2011-02-13 17:50:20281 if (plugin_host)
282 return plugin_host;
283
[email protected]eb415bf0e2011-04-14 02:45:42284 // Validate that the plugin is actually registered.
[email protected]738a7212011-10-21 17:33:52285 content::PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]a08ebea2011-02-13 17:50:20286 if (!info)
287 return NULL;
288
289 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14290 return PpapiPluginProcessHost::CreatePluginHost(
[email protected]dd9a0952012-05-31 20:11:31291 *info, profile_data_directory,
[email protected]df02aca2012-02-09 21:03:20292 client->GetResourceContext()->GetHostResolver());
[email protected]a08ebea2011-02-13 17:50:20293}
294
[email protected]e67385f2011-12-21 06:00:56295PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42296 const FilePath& plugin_path) {
297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
298
[email protected]a50432d2011-09-30 16:32:14299 PpapiPluginProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42300 if (plugin_host)
301 return plugin_host;
302
303 // Validate that the plugin is actually registered.
[email protected]738a7212011-10-21 17:33:52304 content::PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42305 if (!info)
306 return NULL;
307
308 // TODO(ddorwin): Uncomment once out of process is supported.
309 // DCHECK(info->is_out_of_process);
310
311 // This broker isn't loaded by any broker process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14312 return PpapiPluginProcessHost::CreateBrokerHost(*info);
[email protected]eb415bf0e2011-04-14 02:45:42313}
314
[email protected]e67385f2011-12-21 06:00:56315void PluginServiceImpl::OpenChannelToNpapiPlugin(
[email protected]c8f73ab2011-01-22 00:05:17316 int render_process_id,
317 int render_view_id,
[email protected]610c0892009-09-08 19:46:18318 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54319 const GURL& page_url,
[email protected]610c0892009-09-08 19:46:18320 const std::string& mime_type,
[email protected]46b69e42010-11-02 12:26:39321 PluginProcessHost::Client* client) {
[email protected]76b70f92011-11-21 19:31:14322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]4befe7592011-09-14 22:49:09323 DCHECK(!ContainsKey(pending_plugin_clients_, client));
324 pending_plugin_clients_.insert(client);
[email protected]88ca4912011-10-12 14:00:43325
326 // Make sure plugins are loaded if necessary.
[email protected]209f2ae2012-03-13 01:28:08327 PluginServiceFilterParams params = {
[email protected]88ca4912011-10-12 14:00:43328 render_process_id,
329 render_view_id,
330 page_url,
[email protected]df02aca2012-02-09 21:03:20331 client->GetResourceContext()
[email protected]88ca4912011-10-12 14:00:43332 };
[email protected]e67385f2011-12-21 06:00:56333 GetPlugins(base::Bind(
334 &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin,
335 base::Unretained(this), params, url, mime_type, client));
[email protected]6fdd4182010-10-14 23:59:26336}
337
[email protected]e67385f2011-12-21 06:00:56338void PluginServiceImpl::OpenChannelToPpapiPlugin(
[email protected]dd9a0952012-05-31 20:11:31339 const FilePath& plugin_path,
340 const FilePath& profile_data_directory,
[email protected]a50432d2011-09-30 16:32:14341 PpapiPluginProcessHost::PluginClient* client) {
[email protected]d259a8e2011-05-18 22:31:09342 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
[email protected]dd9a0952012-05-31 20:11:31343 plugin_path, profile_data_directory, client);
[email protected]1bf0fb22012-04-12 21:44:16344 if (plugin_host) {
[email protected]a08ebea2011-02-13 17:50:20345 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16346 } else {
347 // Send error.
[email protected]f0ecb552012-05-11 22:09:11348 client->OnPpapiChannelOpened(IPC::ChannelHandle(), 0);
[email protected]1bf0fb22012-04-12 21:44:16349 }
[email protected]a08ebea2011-02-13 17:50:20350}
351
[email protected]e67385f2011-12-21 06:00:56352void PluginServiceImpl::OpenChannelToPpapiBroker(
[email protected]eb415bf0e2011-04-14 02:45:42353 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14354 PpapiPluginProcessHost::BrokerClient* client) {
355 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
[email protected]1bf0fb22012-04-12 21:44:16356 if (plugin_host) {
[email protected]a50432d2011-09-30 16:32:14357 plugin_host->OpenChannelToPlugin(client);
[email protected]1bf0fb22012-04-12 21:44:16358 } else {
359 // Send error.
[email protected]f0ecb552012-05-11 22:09:11360 client->OnPpapiChannelOpened(IPC::ChannelHandle(), 0);
[email protected]1bf0fb22012-04-12 21:44:16361 }
[email protected]eb415bf0e2011-04-14 02:45:42362}
363
[email protected]e67385f2011-12-21 06:00:56364void PluginServiceImpl::CancelOpenChannelToNpapiPlugin(
[email protected]4befe7592011-09-14 22:49:09365 PluginProcessHost::Client* client) {
366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
367 DCHECK(ContainsKey(pending_plugin_clients_, client));
368 pending_plugin_clients_.erase(client);
369}
370
[email protected]e67385f2011-12-21 06:00:56371void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin(
[email protected]209f2ae2012-03-13 01:28:08372 const PluginServiceFilterParams& params,
[email protected]88ca4912011-10-12 14:00:43373 const GURL& url,
374 const std::string& mime_type,
375 PluginProcessHost::Client* client,
376 const std::vector<webkit::WebPluginInfo>&) {
377 GetAllowedPluginForOpenChannelToPlugin(params.render_process_id,
378 params.render_view_id, url, params.page_url, mime_type, client,
379 params.resource_context);
380}
381
[email protected]e67385f2011-12-21 06:00:56382void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin(
[email protected]c8f73ab2011-01-22 00:05:17383 int render_process_id,
384 int render_view_id,
[email protected]6fdd4182010-10-14 23:59:26385 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54386 const GURL& page_url,
[email protected]6fdd4182010-10-14 23:59:26387 const std::string& mime_type,
[email protected]87c4be42011-09-16 01:10:59388 PluginProcessHost::Client* client,
[email protected]df02aca2012-02-09 21:03:20389 content::ResourceContext* resource_context) {
[email protected]91d9f3d2011-08-14 05:24:44390 webkit::WebPluginInfo info;
[email protected]dfba8762011-09-02 12:49:54391 bool allow_wildcard = true;
[email protected]11e1c182011-05-17 20:26:27392 bool found = GetPluginInfo(
[email protected]df02aca2012-02-09 21:03:20393 render_process_id, render_view_id, resource_context,
[email protected]dfba8762011-09-02 12:49:54394 url, page_url, mime_type, allow_wildcard,
395 NULL, &info, NULL);
[email protected]6fdd4182010-10-14 23:59:26396 FilePath plugin_path;
[email protected]68598072011-07-29 08:21:28397 if (found)
[email protected]dfba8762011-09-02 12:49:54398 plugin_path = info.path;
[email protected]6fdd4182010-10-14 23:59:26399
400 // Now we jump back to the IO thread to finish opening the channel.
[email protected]e67385f2011-12-21 06:00:56401 BrowserThread::PostTask(
402 BrowserThread::IO, FROM_HERE,
403 base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin,
[email protected]88ca4912011-10-12 14:00:43404 base::Unretained(this), plugin_path, client));
[email protected]6fdd4182010-10-14 23:59:26405}
406
[email protected]e67385f2011-12-21 06:00:56407void PluginServiceImpl::FinishOpenChannelToPlugin(
[email protected]6fdd4182010-10-14 23:59:26408 const FilePath& plugin_path,
[email protected]46b69e42010-11-02 12:26:39409 PluginProcessHost::Client* client) {
[email protected]f8b3ef82010-10-11 02:45:52410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20a793e2010-10-12 06:50:08411
[email protected]4befe7592011-09-14 22:49:09412 // Make sure it hasn't been canceled yet.
413 if (!ContainsKey(pending_plugin_clients_, client))
414 return;
415 pending_plugin_clients_.erase(client);
416
[email protected]a08ebea2011-02-13 17:50:20417 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
[email protected]4befe7592011-09-14 22:49:09418 if (plugin_host) {
419 client->OnFoundPluginProcessHost(plugin_host);
[email protected]46b69e42010-11-02 12:26:39420 plugin_host->OpenChannelToPlugin(client);
[email protected]4befe7592011-09-14 22:49:09421 } else {
[email protected]46b69e42010-11-02 12:26:39422 client->OnError();
[email protected]4befe7592011-09-14 22:49:09423 }
initial.commit09911bf2008-07-26 23:55:29424}
425
[email protected]e67385f2011-12-21 06:00:56426bool PluginServiceImpl::GetPluginInfoArray(
[email protected]51b63f62011-10-05 18:55:42427 const GURL& url,
428 const std::string& mime_type,
429 bool allow_wildcard,
430 std::vector<webkit::WebPluginInfo>* plugins,
431 std::vector<std::string>* actual_mime_types) {
432 bool use_stale = false;
[email protected]3a5180ae2011-12-21 02:39:38433 plugin_list_->GetPluginInfoArray(url, mime_type, allow_wildcard,
434 &use_stale, plugins, actual_mime_types);
[email protected]51b63f62011-10-05 18:55:42435 return use_stale;
436}
437
[email protected]e67385f2011-12-21 06:00:56438bool PluginServiceImpl::GetPluginInfo(int render_process_id,
439 int render_view_id,
[email protected]df02aca2012-02-09 21:03:20440 content::ResourceContext* context,
[email protected]e67385f2011-12-21 06:00:56441 const GURL& url,
442 const GURL& page_url,
443 const std::string& mime_type,
444 bool allow_wildcard,
445 bool* is_stale,
446 webkit::WebPluginInfo* info,
447 std::string* actual_mime_type) {
[email protected]91d9f3d2011-08-14 05:24:44448 std::vector<webkit::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28449 std::vector<std::string> mime_types;
[email protected]88ca4912011-10-12 14:00:43450 bool stale = GetPluginInfoArray(
451 url, mime_type, allow_wildcard, &plugins, &mime_types);
452 if (is_stale)
453 *is_stale = stale;
[email protected]dfba8762011-09-02 12:49:54454
[email protected]68598072011-07-29 08:21:28455 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]dfba8762011-09-02 12:49:54456 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
457 render_view_id,
[email protected]df02aca2012-02-09 21:03:20458 context,
[email protected]dfba8762011-09-02 12:49:54459 url,
460 page_url,
461 &plugins[i])) {
[email protected]68598072011-07-29 08:21:28462 *info = plugins[i];
463 if (actual_mime_type)
464 *actual_mime_type = mime_types[i];
465 return true;
466 }
467 }
468 return false;
[email protected]6fdd4182010-10-14 23:59:26469}
470
[email protected]e67385f2011-12-21 06:00:56471bool PluginServiceImpl::GetPluginInfoByPath(const FilePath& plugin_path,
472 webkit::WebPluginInfo* info) {
[email protected]88ca4912011-10-12 14:00:43473 std::vector<webkit::WebPluginInfo> plugins;
[email protected]480c7cc2012-06-29 17:38:44474 plugin_list_->GetPluginsNoRefresh(&plugins);
[email protected]88ca4912011-10-12 14:00:43475
476 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
477 it != plugins.end();
478 ++it) {
479 if (it->path == plugin_path) {
480 *info = *it;
481 return true;
482 }
483 }
484
485 return false;
486}
487
[email protected]8be45842012-04-13 19:49:29488string16 PluginServiceImpl::GetPluginDisplayNameByPath(const FilePath& path) {
489 string16 plugin_name = path.LossyDisplayName();
490 webkit::WebPluginInfo info;
491 if (PluginService::GetInstance()->GetPluginInfoByPath(path, &info) &&
492 !info.name.empty()) {
493 plugin_name = info.name;
494#if defined(OS_MACOSX)
495 // Many plugins on the Mac have .plugin in the actual name, which looks
496 // terrible, so look for that and strip it off if present.
497 const std::string kPluginExtension = ".plugin";
498 if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
499 plugin_name.erase(plugin_name.length() - kPluginExtension.length());
500#endif // OS_MACOSX
501 }
502 return plugin_name;
503}
504
[email protected]e67385f2011-12-21 06:00:56505void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
[email protected]49125952011-09-27 18:05:15506 scoped_refptr<base::MessageLoopProxy> target_loop(
507 MessageLoop::current()->message_loop_proxy());
508
[email protected]6a0dc7a2011-11-02 14:37:07509#if defined(OS_WIN)
[email protected]a33fa9d2012-05-16 14:47:49510 BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior(
511 plugin_list_token_,
[email protected]00b25432012-04-07 04:21:37512 FROM_HERE,
[email protected]e67385f2011-12-21 06:00:56513 base::Bind(&PluginServiceImpl::GetPluginsInternal, base::Unretained(this),
[email protected]00b25432012-04-07 04:21:37514 target_loop, callback),
515 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
[email protected]a33fa9d2012-05-16 14:47:49516#elif defined(OS_POSIX)
[email protected]49125952011-09-27 18:05:15517 std::vector<webkit::WebPluginInfo> cached_plugins;
[email protected]480c7cc2012-06-29 17:38:44518 if (plugin_list_->GetPluginsNoRefresh(&cached_plugins)) {
[email protected]49125952011-09-27 18:05:15519 // Can't assume the caller is reentrant.
520 target_loop->PostTask(FROM_HERE,
[email protected]00b25432012-04-07 04:21:37521 base::Bind(callback, cached_plugins));
[email protected]49125952011-09-27 18:05:15522 } else {
[email protected]4bb85b92011-11-05 02:53:29523 // If we switch back to loading plugins in process, then we need to make
524 // sure g_thread_init() gets called since plugins may call glib at load.
[email protected]d4af1e72011-10-21 17:45:43525 if (!plugin_loader_.get())
526 plugin_loader_ = new PluginLoaderPosix;
[email protected]49125952011-09-27 18:05:15527 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]d4af1e72011-10-21 17:45:43528 base::Bind(&PluginLoaderPosix::LoadPlugins, plugin_loader_,
529 target_loop, callback));
[email protected]49125952011-09-27 18:05:15530 }
[email protected]a33fa9d2012-05-16 14:47:49531#else
532#error Not implemented
[email protected]49125952011-09-27 18:05:15533#endif
[email protected]d33e7cc2011-09-23 01:43:56534}
535
[email protected]a33fa9d2012-05-16 14:47:49536#if defined(OS_WIN)
[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}
[email protected]a33fa9d2012-05-16 14:47:49549#endif
[email protected]dfba8762011-09-02 12:49:54550
[email protected]e67385f2011-12-21 06:00:56551void PluginServiceImpl::OnWaitableEventSignaled(
[email protected]580522632009-08-17 21:55:55552 base::WaitableEvent* waitable_event) {
[email protected]b547fd42009-04-23 23:16:27553#if defined(OS_WIN)
554 if (waitable_event == hkcu_event_.get()) {
555 hkcu_key_.StartWatching();
556 } else {
557 hklm_key_.StartWatching();
558 }
559
[email protected]3a5180ae2011-12-21 02:39:38560 plugin_list_->RefreshPlugins();
[email protected]45a22e62011-10-12 09:48:02561 PurgePluginListCache(NULL, false);
[email protected]634d23d2011-01-19 10:38:19562#else
563 // This event should only get signaled on a Windows machine.
564 NOTREACHED();
[email protected]9de09f82009-08-17 20:13:53565#endif // defined(OS_WIN)
[email protected]b547fd42009-04-23 23:16:27566}
[email protected]894bb502009-05-21 22:39:57567
[email protected]e67385f2011-12-21 06:00:56568void PluginServiceImpl::RegisterPepperPlugins() {
[email protected]84396dbc2011-04-14 06:33:42569 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
[email protected]a08ebea2011-02-13 17:50:20570 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
571 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
[email protected]c6f3dea2012-01-14 02:23:11572 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true);
[email protected]4e0616e2010-05-28 14:55:53573 }
574}
[email protected]634d23d2011-01-19 10:38:19575
[email protected]eb415bf0e2011-04-14 02:45:42576// There should generally be very few plugins so a brute-force search is fine.
[email protected]e67385f2011-12-21 06:00:56577content::PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo(
[email protected]eb415bf0e2011-04-14 02:45:42578 const FilePath& plugin_path) {
[email protected]738a7212011-10-21 17:33:52579 content::PepperPluginInfo* info = NULL;
[email protected]eb415bf0e2011-04-14 02:45:42580 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
[email protected]6b14feb2011-08-16 11:22:56581 if (ppapi_plugins_[i].path == plugin_path) {
582 info = &ppapi_plugins_[i];
583 break;
584 }
[email protected]eb415bf0e2011-04-14 02:45:42585 }
[email protected]076117592011-08-17 03:16:41586 if (info)
587 return info;
588 // We did not find the plugin in our list. But wait! the plugin can also
589 // be a latecomer, as it happens with pepper flash. This information
590 // can be obtained from the PluginList singleton and we can use it to
591 // construct it and add it to the list. This same deal needs to be done
592 // in the renderer side in PepperPluginRegistry.
593 webkit::WebPluginInfo webplugin_info;
[email protected]88ca4912011-10-12 14:00:43594 if (!GetPluginInfoByPath(plugin_path, &webplugin_info))
[email protected]076117592011-08-17 03:16:41595 return NULL;
[email protected]738a7212011-10-21 17:33:52596 content::PepperPluginInfo new_pepper_info;
[email protected]076117592011-08-17 03:16:41597 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
598 return NULL;
599 ppapi_plugins_.push_back(new_pepper_info);
600 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
[email protected]eb415bf0e2011-04-14 02:45:42601}
602
[email protected]3b48dbc2012-01-06 16:34:17603#if defined(OS_POSIX) && !defined(OS_OPENBSD)
[email protected]634d23d2011-01-19 10:38:19604// static
[email protected]e67385f2011-12-21 06:00:56605void PluginServiceImpl::RegisterFilePathWatcher(
[email protected]3b91edbe2012-09-27 22:49:23606 FilePathWatcher* watcher,
[email protected]634d23d2011-01-19 10:38:19607 const FilePath& path,
608 FilePathWatcher::Delegate* delegate) {
[email protected]7b3ee8b2011-04-01 18:48:19609 bool result = watcher->Watch(path, delegate);
[email protected]634d23d2011-01-19 10:38:19610 DCHECK(result);
611}
612#endif
[email protected]f520b5b2011-11-08 02:42:14613
[email protected]e67385f2011-12-21 06:00:56614void PluginServiceImpl::SetFilter(content::PluginServiceFilter* filter) {
[email protected]3a5180ae2011-12-21 02:39:38615 filter_ = filter;
616}
617
[email protected]e67385f2011-12-21 06:00:56618content::PluginServiceFilter* PluginServiceImpl::GetFilter() {
[email protected]3a5180ae2011-12-21 02:39:38619 return filter_;
620}
621
[email protected]b6a2f8de2012-01-31 17:28:49622void PluginServiceImpl::ForcePluginShutdown(const FilePath& plugin_path) {
623 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
624 BrowserThread::PostTask(
625 BrowserThread::IO, FROM_HERE,
626 base::Bind(&PluginServiceImpl::ForcePluginShutdown,
627 base::Unretained(this), plugin_path));
628 return;
629 }
630
631 PluginProcessHost* plugin = FindNpapiPluginProcess(plugin_path);
632 if (plugin)
633 plugin->ForceShutdown();
634}
635
[email protected]47214d882012-02-29 06:28:48636static const unsigned int kMaxCrashesPerInterval = 3;
637static const unsigned int kCrashesInterval = 120;
638
639void PluginServiceImpl::RegisterPluginCrash(const FilePath& path) {
640 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
641 std::map<FilePath, std::vector<base::Time> >::iterator i =
642 crash_times_.find(path);
643 if (i == crash_times_.end()) {
644 crash_times_[path] = std::vector<base::Time>();
645 i = crash_times_.find(path);
646 }
647 if (i->second.size() == kMaxCrashesPerInterval) {
648 i->second.erase(i->second.begin());
649 }
650 base::Time time = base::Time::Now();
651 i->second.push_back(time);
652}
653
654bool PluginServiceImpl::IsPluginUnstable(const FilePath& path) {
655 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
656 std::map<FilePath, std::vector<base::Time> >::const_iterator i =
657 crash_times_.find(path);
658 if (i == crash_times_.end()) {
659 return false;
660 }
661 if (i->second.size() != kMaxCrashesPerInterval) {
662 return false;
663 }
664 base::TimeDelta delta = base::Time::Now() - i->second[0];
665 if (delta.InSeconds() <= kCrashesInterval) {
666 return true;
667 }
668 return false;
669}
670
[email protected]e67385f2011-12-21 06:00:56671void PluginServiceImpl::RefreshPlugins() {
[email protected]3a5180ae2011-12-21 02:39:38672 plugin_list_->RefreshPlugins();
[email protected]f520b5b2011-11-08 02:42:14673}
674
[email protected]e67385f2011-12-21 06:00:56675void PluginServiceImpl::AddExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38676 plugin_list_->AddExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14677}
678
[email protected]c6f3dea2012-01-14 02:23:11679void PluginServiceImpl::AddExtraPluginDir(const FilePath& path) {
680 plugin_list_->AddExtraPluginDir(path);
681}
682
[email protected]e67385f2011-12-21 06:00:56683void PluginServiceImpl::RemoveExtraPluginPath(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38684 plugin_list_->RemoveExtraPluginPath(path);
[email protected]f520b5b2011-11-08 02:42:14685}
686
[email protected]e67385f2011-12-21 06:00:56687void PluginServiceImpl::UnregisterInternalPlugin(const FilePath& path) {
[email protected]3a5180ae2011-12-21 02:39:38688 plugin_list_->UnregisterInternalPlugin(path);
[email protected]f520b5b2011-11-08 02:42:14689}
690
[email protected]e67385f2011-12-21 06:00:56691void PluginServiceImpl::SetPluginListForTesting(
[email protected]ee066172011-11-10 23:20:05692 webkit::npapi::PluginList* plugin_list) {
693 plugin_list_ = plugin_list;
694}
695
[email protected]5904cb42012-09-24 15:05:20696#if defined(OS_MACOSX)
697void PluginServiceImpl::AppActivated() {
698 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
699 base::Bind(&NotifyPluginsOfActivation));
700}
701#endif
702
[email protected]e67385f2011-12-21 06:00:56703void PluginServiceImpl::RegisterInternalPlugin(
[email protected]c6f3dea2012-01-14 02:23:11704 const webkit::WebPluginInfo& info,
705 bool add_at_beginning) {
706 plugin_list_->RegisterInternalPlugin(info, add_at_beginning);
[email protected]f520b5b2011-11-08 02:42:14707}
708
[email protected]e67385f2011-12-21 06:00:56709webkit::npapi::PluginList* PluginServiceImpl::GetPluginList() {
[email protected]3a5180ae2011-12-21 02:39:38710 return plugin_list_;
[email protected]f520b5b2011-11-08 02:42:14711}