blob: 5e0e910656076fa2394cec4f57f871b1f52a079b [file] [log] [blame]
[email protected]a08ebea2011-02-13 17:50:201// Copyright (c) 2011 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]a0421732011-02-23 03:55:405#include "content/browser/plugin_service.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]6be08ae2011-10-18 02:23:2319#include "content/browser/plugin_loader_posix.h"
[email protected]dfba8762011-09-02 12:49:5420#include "content/browser/plugin_service_filter.h"
[email protected]a01efd22011-03-01 00:38:3221#include "content/browser/ppapi_plugin_process_host.h"
[email protected]a0421732011-02-23 03:55:4022#include "content/browser/renderer_host/render_process_host.h"
23#include "content/browser/renderer_host/render_view_host.h"
[email protected]d259a8e2011-05-18 22:31:0924#include "content/browser/resource_context.h"
[email protected]49125952011-09-27 18:05:1525#include "content/browser/utility_process_host.h"
[email protected]cebc3dc2011-04-18 17:15:0026#include "content/common/pepper_plugin_registry.h"
[email protected]105303e2011-03-14 22:16:1027#include "content/common/plugin_messages.h"
[email protected]49125952011-09-27 18:05:1528#include "content/common/utility_messages.h"
[email protected]38b592902011-04-16 02:08:4229#include "content/common/view_messages.h"
[email protected]c38831a12011-10-28 12:44:4930#include "content/public/browser/browser_thread.h"
[email protected]87f3c082011-10-19 18:07:4431#include "content/public/browser/content_browser_client.h"
[email protected]c38831a12011-10-28 12:44:4932#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:1633#include "content/public/browser/notification_types.h"
[email protected]c08950d22011-10-13 22:20:2934#include "content/public/common/content_switches.h"
[email protected]191eb3f72010-12-21 06:27:5035#include "webkit/plugins/npapi/plugin_constants_win.h"
[email protected]d33e7cc2011-09-23 01:43:5636#include "webkit/plugins/npapi/plugin_group.h"
[email protected]191eb3f72010-12-21 06:27:5037#include "webkit/plugins/npapi/plugin_list.h"
[email protected]91d9f3d2011-08-14 05:24:4438#include "webkit/plugins/webplugininfo.h"
[email protected]191eb3f72010-12-21 06:27:5039
[email protected]e63c4d72011-05-31 22:38:2940#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]493c8002011-04-14 16:56:0141using ::base::files::FilePathWatcher;
42#endif
43
[email protected]631bb742011-11-02 11:29:3944using content::BrowserThread;
[email protected]dfba8762011-09-02 12:49:5445using content::PluginServiceFilter;
46
[email protected]d33e7cc2011-09-23 01:43:5647namespace {
48
49// Helper function that merely runs the callback with the result. Called on the
50// thread on which the original GetPlugins() call was made.
51static void RunGetPluginsCallback(
52 const PluginService::GetPluginsCallback& callback,
53 const std::vector<webkit::WebPluginInfo>& result) {
54 callback.Run(result);
55}
56
57// A callback for GetPlugins() that then gets the freshly loaded plugin groups
58// and runs the callback for GetPluginGroups().
59static void GetPluginsForGroupsCallback(
60 const PluginService::GetPluginGroupsCallback& callback,
61 const std::vector<webkit::WebPluginInfo>& plugins) {
62 std::vector<webkit::npapi::PluginGroup> groups;
63 webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, &groups);
64 callback.Run(groups);
65}
66
[email protected]49125952011-09-27 18:05:1567// Callback set on the PluginList to assert that plugin loading happens on the
68// correct thread.
69void WillLoadPluginsCallback() {
[email protected]6a0dc7a2011-11-02 14:37:0770#if defined(OS_WIN)
[email protected]88ca4912011-10-12 14:00:4371 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]49125952011-09-27 18:05:1572#else
[email protected]88ca4912011-10-12 14:00:4373 CHECK(false) << "Plugin loading should happen out-of-process.";
[email protected]49125952011-09-27 18:05:1574#endif
75}
76
[email protected]d33e7cc2011-09-23 01:43:5677} // namespace
78
[email protected]a96ec6a2009-11-04 17:27:0879#if defined(OS_MACOSX)
80static void NotifyPluginsOfActivation() {
[email protected]f8b3ef82010-10-11 02:45:5281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]a96ec6a2009-11-04 17:27:0882
[email protected]d27893f62010-07-03 05:47:4283 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
[email protected]a96ec6a2009-11-04 17:27:0884 !iter.Done(); ++iter) {
85 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
86 plugin->OnAppActivation();
87 }
88}
[email protected]e63c4d72011-05-31 22:38:2989#elif defined(OS_POSIX)
[email protected]634d23d2011-01-19 10:38:1990// Delegate class for monitoring directories.
91class PluginDirWatcherDelegate : public FilePathWatcher::Delegate {
[email protected]7b3ee8b2011-04-01 18:48:1992 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:1993 VLOG(1) << "Watched path changed: " << path.value();
94 // Make the plugin list update itself
95 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
[email protected]ee6fcb22011-10-22 01:27:0696 BrowserThread::PostTask(
97 BrowserThread::UI, FROM_HERE,
98 base::Bind(&PluginService::PurgePluginListCache,
99 static_cast<content::BrowserContext*>(NULL), false));
[email protected]634d23d2011-01-19 10:38:19100 }
[email protected]45a22e62011-10-12 09:48:02101
[email protected]7b3ee8b2011-04-01 18:48:19102 virtual void OnFilePathError(const FilePath& path) OVERRIDE {
[email protected]634d23d2011-01-19 10:38:19103 // TODO(pastarmovj): Add some sensible error handling. Maybe silently
104 // stopping the watcher would be enough. Or possibly restart it.
105 NOTREACHED();
106 }
107};
108#endif
109
initial.commit09911bf2008-07-26 23:55:29110// static
111PluginService* PluginService::GetInstance() {
112 return Singleton<PluginService>::get();
113}
114
115PluginService::PluginService()
[email protected]de23f3f2011-05-18 16:20:23116 : ui_locale_(
[email protected]dfba8762011-09-02 12:49:54117 content::GetContentClient()->browser()->GetApplicationLocale()),
118 filter_(NULL) {
[email protected]f520b5b2011-11-08 02:42:14119 plugin_list()->set_will_load_plugins_callback(
[email protected]49125952011-09-27 18:05:15120 base::Bind(&WillLoadPluginsCallback));
121
[email protected]4e0616e2010-05-28 14:55:53122 RegisterPepperPlugins();
123
[email protected]f520b5b2011-11-08 02:42:14124 content::GetContentClient()->AddNPAPIPlugins(plugin_list());
125
[email protected]9a1c4262010-06-29 21:50:27126 // Load any specified on the command line as well.
[email protected]d48f1e0c2009-02-12 20:57:54127 const CommandLine* command_line = CommandLine::ForCurrentProcess();
[email protected]c4e52f0d2009-11-06 19:55:16128 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
[email protected]7bf795d92010-05-22 00:14:28129 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14130 AddExtraPluginPath(path);
[email protected]9a1c4262010-06-29 21:50:27131 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
132 if (!path.empty())
[email protected]f520b5b2011-11-08 02:42:14133 plugin_list()->AddExtraPluginDir(path);
[email protected]7bf795d92010-05-22 00:14:28134
[email protected]dfba8762011-09-02 12:49:54135#if defined(OS_MACOSX)
136 // We need to know when the browser comes forward so we can bring modal plugin
137 // windows forward too.
138 registrar_.Add(this, content::NOTIFICATION_APP_ACTIVATED,
[email protected]ad50def52011-10-19 23:17:07139 content::NotificationService::AllSources());
[email protected]dfba8762011-09-02 12:49:54140#endif
141}
142
143PluginService::~PluginService() {
144#if defined(OS_WIN)
145 // Release the events since they're owned by RegKey, not WaitableEvent.
146 hkcu_watcher_.StopWatching();
147 hklm_watcher_.StopWatching();
148 if (hkcu_event_.get())
149 hkcu_event_->Release();
150 if (hklm_event_.get())
151 hklm_event_->Release();
152#endif
[email protected]4befe7592011-09-14 22:49:09153 // Make sure no plugin channel requests have been leaked.
154 DCHECK(pending_plugin_clients_.empty());
[email protected]dfba8762011-09-02 12:49:54155}
156
157void PluginService::StartWatchingPlugins() {
[email protected]634d23d2011-01-19 10:38:19158 // Start watching for changes in the plugin list. This means watching
159 // for changes in the Windows registry keys and on both Windows and POSIX
160 // watch for changes in the paths that are expected to contain plugins.
[email protected]b547fd42009-04-23 23:16:27161#if defined(OS_WIN)
[email protected]86ec4f6e2011-04-20 16:21:19162 if (hkcu_key_.Create(HKEY_CURRENT_USER,
163 webkit::npapi::kRegistryMozillaPlugins,
164 KEY_NOTIFY) == ERROR_SUCCESS) {
165 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
166 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
167 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
168 }
[email protected]b547fd42009-04-23 23:16:27169 }
[email protected]86ec4f6e2011-04-20 16:21:19170 if (hklm_key_.Create(HKEY_LOCAL_MACHINE,
171 webkit::npapi::kRegistryMozillaPlugins,
172 KEY_NOTIFY) == ERROR_SUCCESS) {
173 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
174 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
175 hklm_watcher_.StartWatching(hklm_event_.get(), this);
176 }
[email protected]b547fd42009-04-23 23:16:27177 }
[email protected]dfba8762011-09-02 12:49:54178#elif defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]634d23d2011-01-19 10:38:19179// The FilePathWatcher produces too many false positives on MacOS (access time
180// updates?) which will lead to enforcing updates of the plugins way too often.
181// On ChromeOS the user can't install plugins anyway and on Windows all
182// important plugins register themselves in the registry so no need to do that.
[email protected]634d23d2011-01-19 10:38:19183 file_watcher_delegate_ = new PluginDirWatcherDelegate();
184 // Get the list of all paths for registering the FilePathWatchers
185 // that will track and if needed reload the list of plugins on runtime.
186 std::vector<FilePath> plugin_dirs;
[email protected]f520b5b2011-11-08 02:42:14187 plugin_list()->GetPluginDirectories(&plugin_dirs);
[email protected]894bb502009-05-21 22:39:57188
[email protected]634d23d2011-01-19 10:38:19189 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
[email protected]634d23d2011-01-19 10:38:19190 // FilePathWatcher can not handle non-absolute paths under windows.
191 // We don't watch for file changes in windows now but if this should ever
192 // be extended to Windows these lines might save some time of debugging.
193#if defined(OS_WIN)
194 if (!plugin_dirs[i].IsAbsolute())
195 continue;
196#endif
[email protected]493c8002011-04-14 16:56:01197 FilePathWatcher* watcher = new FilePathWatcher();
[email protected]634d23d2011-01-19 10:38:19198 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
199 BrowserThread::PostTask(
200 BrowserThread::FILE, FROM_HERE,
201 NewRunnableFunction(
202 &PluginService::RegisterFilePathWatcher,
203 watcher, plugin_dirs[i], file_watcher_delegate_));
204 file_watchers_.push_back(watcher);
205 }
206#endif
initial.commit09911bf2008-07-26 23:55:29207}
208
[email protected]f77d87622010-07-30 17:43:17209const std::string& PluginService::GetUILocale() {
initial.commit09911bf2008-07-26 23:55:29210 return ui_locale_;
211}
212
[email protected]a08ebea2011-02-13 17:50:20213PluginProcessHost* PluginService::FindNpapiPluginProcess(
[email protected]28ab7f92009-01-06 21:39:04214 const FilePath& plugin_path) {
[email protected]f8b3ef82010-10-11 02:45:52215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
initial.commit09911bf2008-07-26 23:55:29216
[email protected]d27893f62010-07-03 05:47:42217 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
[email protected]a436d922009-02-13 23:16:42218 !iter.Done(); ++iter) {
219 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
220 if (plugin->info().path == plugin_path)
221 return plugin;
222 }
223
initial.commit09911bf2008-07-26 23:55:29224 return NULL;
225}
226
[email protected]a08ebea2011-02-13 17:50:20227PpapiPluginProcessHost* PluginService::FindPpapiPluginProcess(
[email protected]610c0892009-09-08 19:46:18228 const FilePath& plugin_path) {
[email protected]f8b3ef82010-10-11 02:45:52229 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
initial.commit09911bf2008-07-26 23:55:29230
[email protected]a08ebea2011-02-13 17:50:20231 for (BrowserChildProcessHost::Iterator iter(
232 ChildProcessInfo::PPAPI_PLUGIN_PROCESS);
233 !iter.Done(); ++iter) {
234 PpapiPluginProcessHost* plugin =
235 static_cast<PpapiPluginProcessHost*>(*iter);
236 if (plugin->plugin_path() == plugin_path)
237 return plugin;
238 }
239
240 return NULL;
241}
242
[email protected]a50432d2011-09-30 16:32:14243PpapiPluginProcessHost* PluginService::FindPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42244 const FilePath& broker_path) {
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
246
247 for (BrowserChildProcessHost::Iterator iter(
248 ChildProcessInfo::PPAPI_BROKER_PROCESS);
249 !iter.Done(); ++iter) {
[email protected]a50432d2011-09-30 16:32:14250 PpapiPluginProcessHost* broker =
251 static_cast<PpapiPluginProcessHost*>(*iter);
252 if (broker->plugin_path() == broker_path)
[email protected]eb415bf0e2011-04-14 02:45:42253 return broker;
254 }
255
256 return NULL;
257}
258
[email protected]a08ebea2011-02-13 17:50:20259PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess(
260 const FilePath& plugin_path) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
262
263 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
initial.commit09911bf2008-07-26 23:55:29264 if (plugin_host)
265 return plugin_host;
266
[email protected]91d9f3d2011-08-14 05:24:44267 webkit::WebPluginInfo info;
[email protected]88ca4912011-10-12 14:00:43268 if (!GetPluginInfoByPath(plugin_path, &info)) {
[email protected]a27a9382009-02-11 23:55:10269 return NULL;
270 }
271
initial.commit09911bf2008-07-26 23:55:29272 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]8b8a554d2010-11-18 13:26:40273 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
274 if (!new_host->Init(info, ui_locale_)) {
[email protected]a08ebea2011-02-13 17:50:20275 NOTREACHED(); // Init is not expected to fail.
initial.commit09911bf2008-07-26 23:55:29276 return NULL;
277 }
[email protected]8b8a554d2010-11-18 13:26:40278 return new_host.release();
initial.commit09911bf2008-07-26 23:55:29279}
280
[email protected]a08ebea2011-02-13 17:50:20281PpapiPluginProcessHost* PluginService::FindOrStartPpapiPluginProcess(
[email protected]d259a8e2011-05-18 22:31:09282 const FilePath& plugin_path,
[email protected]a50432d2011-09-30 16:32:14283 PpapiPluginProcessHost::PluginClient* client) {
[email protected]a08ebea2011-02-13 17:50:20284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
285
286 PpapiPluginProcessHost* plugin_host = FindPpapiPluginProcess(plugin_path);
287 if (plugin_host)
288 return plugin_host;
289
[email protected]eb415bf0e2011-04-14 02:45:42290 // Validate that the plugin is actually registered.
[email protected]738a7212011-10-21 17:33:52291 content::PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]a08ebea2011-02-13 17:50:20292 if (!info)
293 return NULL;
294
295 // This plugin isn't loaded by any plugin process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14296 return PpapiPluginProcessHost::CreatePluginHost(
297 *info,
298 client->GetResourceContext()->host_resolver());
[email protected]a08ebea2011-02-13 17:50:20299}
300
[email protected]a50432d2011-09-30 16:32:14301PpapiPluginProcessHost* PluginService::FindOrStartPpapiBrokerProcess(
[email protected]eb415bf0e2011-04-14 02:45:42302 const FilePath& plugin_path) {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
304
[email protected]a50432d2011-09-30 16:32:14305 PpapiPluginProcessHost* plugin_host = FindPpapiBrokerProcess(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42306 if (plugin_host)
307 return plugin_host;
308
309 // Validate that the plugin is actually registered.
[email protected]738a7212011-10-21 17:33:52310 content::PepperPluginInfo* info = GetRegisteredPpapiPluginInfo(plugin_path);
[email protected]eb415bf0e2011-04-14 02:45:42311 if (!info)
312 return NULL;
313
314 // TODO(ddorwin): Uncomment once out of process is supported.
315 // DCHECK(info->is_out_of_process);
316
317 // This broker isn't loaded by any broker process, so create a new process.
[email protected]a50432d2011-09-30 16:32:14318 return PpapiPluginProcessHost::CreateBrokerHost(*info);
[email protected]eb415bf0e2011-04-14 02:45:42319}
320
[email protected]a08ebea2011-02-13 17:50:20321void PluginService::OpenChannelToNpapiPlugin(
[email protected]c8f73ab2011-01-22 00:05:17322 int render_process_id,
323 int render_view_id,
[email protected]610c0892009-09-08 19:46:18324 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54325 const GURL& page_url,
[email protected]610c0892009-09-08 19:46:18326 const std::string& mime_type,
[email protected]46b69e42010-11-02 12:26:39327 PluginProcessHost::Client* client) {
[email protected]4befe7592011-09-14 22:49:09328 DCHECK(!ContainsKey(pending_plugin_clients_, client));
329 pending_plugin_clients_.insert(client);
[email protected]88ca4912011-10-12 14:00:43330
331 // Make sure plugins are loaded if necessary.
332 content::PluginServiceFilterParams params = {
333 render_process_id,
334 render_view_id,
335 page_url,
336 &client->GetResourceContext()
337 };
338 GetPlugins(
339 base::Bind(&PluginService::ForwardGetAllowedPluginForOpenChannelToPlugin,
340 base::Unretained(this), params, url, mime_type, client));
[email protected]6fdd4182010-10-14 23:59:26341}
342
[email protected]a08ebea2011-02-13 17:50:20343void PluginService::OpenChannelToPpapiPlugin(
344 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14345 PpapiPluginProcessHost::PluginClient* client) {
[email protected]d259a8e2011-05-18 22:31:09346 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
347 path, client);
[email protected]a08ebea2011-02-13 17:50:20348 if (plugin_host)
349 plugin_host->OpenChannelToPlugin(client);
350 else // Send error.
351 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle());
352}
353
[email protected]eb415bf0e2011-04-14 02:45:42354void PluginService::OpenChannelToPpapiBroker(
355 const FilePath& path,
[email protected]a50432d2011-09-30 16:32:14356 PpapiPluginProcessHost::BrokerClient* client) {
357 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess(path);
[email protected]eb415bf0e2011-04-14 02:45:42358 if (plugin_host)
[email protected]a50432d2011-09-30 16:32:14359 plugin_host->OpenChannelToPlugin(client);
[email protected]eb415bf0e2011-04-14 02:45:42360 else // Send error.
361 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle());
362}
363
[email protected]4befe7592011-09-14 22:49:09364void PluginService::CancelOpenChannelToNpapiPlugin(
365 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]88ca4912011-10-12 14:00:43371void PluginService::ForwardGetAllowedPluginForOpenChannelToPlugin(
372 const content::PluginServiceFilterParams& params,
373 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]6fdd4182010-10-14 23:59:26382void PluginService::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,
389 const 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]87c4be42011-09-16 01:10:59393 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]88ca4912011-10-12 14:00:43401 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
402 base::Bind(&PluginService::FinishOpenChannelToPlugin,
403 base::Unretained(this), plugin_path, client));
[email protected]6fdd4182010-10-14 23:59:26404}
405
406void PluginService::FinishOpenChannelToPlugin(
[email protected]6fdd4182010-10-14 23:59:26407 const FilePath& plugin_path,
[email protected]46b69e42010-11-02 12:26:39408 PluginProcessHost::Client* client) {
[email protected]f8b3ef82010-10-11 02:45:52409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]20a793e2010-10-12 06:50:08410
[email protected]4befe7592011-09-14 22:49:09411 // Make sure it hasn't been canceled yet.
412 if (!ContainsKey(pending_plugin_clients_, client))
413 return;
414 pending_plugin_clients_.erase(client);
415
[email protected]a08ebea2011-02-13 17:50:20416 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
[email protected]4befe7592011-09-14 22:49:09417 if (plugin_host) {
418 client->OnFoundPluginProcessHost(plugin_host);
[email protected]46b69e42010-11-02 12:26:39419 plugin_host->OpenChannelToPlugin(client);
[email protected]4befe7592011-09-14 22:49:09420 } else {
[email protected]46b69e42010-11-02 12:26:39421 client->OnError();
[email protected]4befe7592011-09-14 22:49:09422 }
initial.commit09911bf2008-07-26 23:55:29423}
424
[email protected]51b63f62011-10-05 18:55:42425bool PluginService::GetPluginInfoArray(
426 const GURL& url,
427 const std::string& mime_type,
428 bool allow_wildcard,
429 std::vector<webkit::WebPluginInfo>* plugins,
430 std::vector<std::string>* actual_mime_types) {
431 bool use_stale = false;
[email protected]f520b5b2011-11-08 02:42:14432 plugin_list()->GetPluginInfoArray(url, mime_type, allow_wildcard,
433 &use_stale, plugins, actual_mime_types);
[email protected]51b63f62011-10-05 18:55:42434 return use_stale;
435}
436
[email protected]11e1c182011-05-17 20:26:27437bool PluginService::GetPluginInfo(int render_process_id,
438 int render_view_id,
[email protected]dfba8762011-09-02 12:49:54439 const content::ResourceContext& context,
[email protected]11e1c182011-05-17 20:26:27440 const GURL& url,
[email protected]dfba8762011-09-02 12:49:54441 const GURL& page_url,
[email protected]11e1c182011-05-17 20:26:27442 const std::string& mime_type,
[email protected]dfba8762011-09-02 12:49:54443 bool allow_wildcard,
[email protected]88ca4912011-10-12 14:00:43444 bool* is_stale,
[email protected]91d9f3d2011-08-14 05:24:44445 webkit::WebPluginInfo* info,
[email protected]11e1c182011-05-17 20:26:27446 std::string* actual_mime_type) {
[email protected]91d9f3d2011-08-14 05:24:44447 std::vector<webkit::WebPluginInfo> plugins;
[email protected]68598072011-07-29 08:21:28448 std::vector<std::string> mime_types;
[email protected]88ca4912011-10-12 14:00:43449 bool stale = GetPluginInfoArray(
450 url, mime_type, allow_wildcard, &plugins, &mime_types);
451 if (is_stale)
452 *is_stale = stale;
[email protected]dfba8762011-09-02 12:49:54453 if (plugins.size() > 1 &&
454 plugins.back().path ==
455 FilePath(webkit::npapi::kDefaultPluginLibraryName)) {
456 // If there is at least one plug-in handling the required MIME type (apart
457 // from the default plug-in), we don't need the default plug-in.
458 plugins.pop_back();
459 }
460
[email protected]68598072011-07-29 08:21:28461 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]dfba8762011-09-02 12:49:54462 if (!filter_ || filter_->ShouldUsePlugin(render_process_id,
463 render_view_id,
464 &context,
465 url,
466 page_url,
467 &plugins[i])) {
[email protected]68598072011-07-29 08:21:28468 *info = plugins[i];
469 if (actual_mime_type)
470 *actual_mime_type = mime_types[i];
471 return true;
472 }
473 }
474 return false;
[email protected]6fdd4182010-10-14 23:59:26475}
476
[email protected]88ca4912011-10-12 14:00:43477bool PluginService::GetPluginInfoByPath(const FilePath& plugin_path,
478 webkit::WebPluginInfo* info) {
479 std::vector<webkit::WebPluginInfo> plugins;
[email protected]f520b5b2011-11-08 02:42:14480 plugin_list()->GetPluginsIfNoRefreshNeeded(&plugins);
[email protected]88ca4912011-10-12 14:00:43481
482 for (std::vector<webkit::WebPluginInfo>::iterator it = plugins.begin();
483 it != plugins.end();
484 ++it) {
485 if (it->path == plugin_path) {
486 *info = *it;
487 return true;
488 }
489 }
490
491 return false;
492}
493
[email protected]d33e7cc2011-09-23 01:43:56494void PluginService::GetPlugins(const GetPluginsCallback& callback) {
[email protected]49125952011-09-27 18:05:15495 scoped_refptr<base::MessageLoopProxy> target_loop(
496 MessageLoop::current()->message_loop_proxy());
497
[email protected]6a0dc7a2011-11-02 14:37:07498#if defined(OS_WIN)
[email protected]d33e7cc2011-09-23 01:43:56499 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
500 base::Bind(&PluginService::GetPluginsInternal, base::Unretained(this),
[email protected]49125952011-09-27 18:05:15501 target_loop, callback));
502#else
503 std::vector<webkit::WebPluginInfo> cached_plugins;
[email protected]f520b5b2011-11-08 02:42:14504 if (plugin_list()->GetPluginsIfNoRefreshNeeded(&cached_plugins)) {
[email protected]49125952011-09-27 18:05:15505 // Can't assume the caller is reentrant.
506 target_loop->PostTask(FROM_HERE,
507 base::Bind(&RunGetPluginsCallback, callback, cached_plugins));
508 } else {
[email protected]4bb85b92011-11-05 02:53:29509 // If we switch back to loading plugins in process, then we need to make
510 // sure g_thread_init() gets called since plugins may call glib at load.
[email protected]d4af1e72011-10-21 17:45:43511 if (!plugin_loader_.get())
512 plugin_loader_ = new PluginLoaderPosix;
[email protected]49125952011-09-27 18:05:15513 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
[email protected]d4af1e72011-10-21 17:45:43514 base::Bind(&PluginLoaderPosix::LoadPlugins, plugin_loader_,
515 target_loop, callback));
[email protected]49125952011-09-27 18:05:15516 }
517#endif
[email protected]d33e7cc2011-09-23 01:43:56518}
519
520void PluginService::GetPluginGroups(const GetPluginGroupsCallback& callback) {
521 GetPlugins(base::Bind(&GetPluginsForGroupsCallback, callback));
522}
523
524void PluginService::GetPluginsInternal(
525 base::MessageLoopProxy* target_loop,
526 const PluginService::GetPluginsCallback& callback) {
527 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
528
529 std::vector<webkit::WebPluginInfo> plugins;
[email protected]f520b5b2011-11-08 02:42:14530 plugin_list()->GetPlugins(&plugins);
[email protected]d33e7cc2011-09-23 01:43:56531
532 target_loop->PostTask(FROM_HERE,
533 base::Bind(&RunGetPluginsCallback, callback, plugins));
[email protected]dfba8762011-09-02 12:49:54534}
535
[email protected]580522632009-08-17 21:55:55536void PluginService::OnWaitableEventSignaled(
537 base::WaitableEvent* waitable_event) {
[email protected]b547fd42009-04-23 23:16:27538#if defined(OS_WIN)
539 if (waitable_event == hkcu_event_.get()) {
540 hkcu_key_.StartWatching();
541 } else {
542 hklm_key_.StartWatching();
543 }
544
[email protected]f520b5b2011-11-08 02:42:14545 plugin_list()->RefreshPlugins();
[email protected]45a22e62011-10-12 09:48:02546 PurgePluginListCache(NULL, false);
[email protected]634d23d2011-01-19 10:38:19547#else
548 // This event should only get signaled on a Windows machine.
549 NOTREACHED();
[email protected]9de09f82009-08-17 20:13:53550#endif // defined(OS_WIN)
[email protected]b547fd42009-04-23 23:16:27551}
[email protected]894bb502009-05-21 22:39:57552
[email protected]432115822011-07-10 15:52:27553void PluginService::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:53554 const content::NotificationSource& source,
555 const content::NotificationDetails& details) {
[email protected]a96ec6a2009-11-04 17:27:08556#if defined(OS_MACOSX)
[email protected]dfba8762011-09-02 12:49:54557 if (type == content::NOTIFICATION_APP_ACTIVATED) {
558 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
559 NewRunnableFunction(&NotifyPluginsOfActivation));
560 return;
[email protected]894bb502009-05-21 22:39:57561 }
[email protected]dfba8762011-09-02 12:49:54562#endif
563 NOTREACHED();
[email protected]c8f73ab2011-01-22 00:05:17564}
565
[email protected]45a22e62011-10-12 09:48:02566void PluginService::PurgePluginListCache(
567 content::BrowserContext* browser_context,
568 bool reload_pages) {
[email protected]2de307592011-04-05 21:16:58569 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
570 !it.IsAtEnd(); it.Advance()) {
[email protected]45a22e62011-10-12 09:48:02571 RenderProcessHost* host = it.GetCurrentValue();
572 if (!browser_context || host->browser_context() == browser_context)
573 host->Send(new ViewMsg_PurgePluginListCache(reload_pages));
[email protected]2de307592011-04-05 21:16:58574 }
575}
576
[email protected]4e0616e2010-05-28 14:55:53577void PluginService::RegisterPepperPlugins() {
[email protected]84396dbc2011-04-14 06:33:42578 // TODO(abarth): It seems like the PepperPluginRegistry should do this work.
[email protected]a08ebea2011-02-13 17:50:20579 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
580 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
[email protected]f520b5b2011-11-08 02:42:14581 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo());
[email protected]4e0616e2010-05-28 14:55:53582 }
583}
[email protected]634d23d2011-01-19 10:38:19584
[email protected]eb415bf0e2011-04-14 02:45:42585// There should generally be very few plugins so a brute-force search is fine.
[email protected]738a7212011-10-21 17:33:52586content::PepperPluginInfo* PluginService::GetRegisteredPpapiPluginInfo(
[email protected]eb415bf0e2011-04-14 02:45:42587 const FilePath& plugin_path) {
[email protected]738a7212011-10-21 17:33:52588 content::PepperPluginInfo* info = NULL;
[email protected]eb415bf0e2011-04-14 02:45:42589 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
[email protected]6b14feb2011-08-16 11:22:56590 if (ppapi_plugins_[i].path == plugin_path) {
591 info = &ppapi_plugins_[i];
592 break;
593 }
[email protected]eb415bf0e2011-04-14 02:45:42594 }
[email protected]076117592011-08-17 03:16:41595 if (info)
596 return info;
597 // We did not find the plugin in our list. But wait! the plugin can also
598 // be a latecomer, as it happens with pepper flash. This information
599 // can be obtained from the PluginList singleton and we can use it to
600 // construct it and add it to the list. This same deal needs to be done
601 // in the renderer side in PepperPluginRegistry.
602 webkit::WebPluginInfo webplugin_info;
[email protected]88ca4912011-10-12 14:00:43603 if (!GetPluginInfoByPath(plugin_path, &webplugin_info))
[email protected]076117592011-08-17 03:16:41604 return NULL;
[email protected]738a7212011-10-21 17:33:52605 content::PepperPluginInfo new_pepper_info;
[email protected]076117592011-08-17 03:16:41606 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info))
607 return NULL;
608 ppapi_plugins_.push_back(new_pepper_info);
609 return &ppapi_plugins_[ppapi_plugins_.size() - 1];
[email protected]eb415bf0e2011-04-14 02:45:42610}
611
[email protected]e63c4d72011-05-31 22:38:29612#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]634d23d2011-01-19 10:38:19613// static
614void PluginService::RegisterFilePathWatcher(
615 FilePathWatcher *watcher,
616 const FilePath& path,
617 FilePathWatcher::Delegate* delegate) {
[email protected]7b3ee8b2011-04-01 18:48:19618 bool result = watcher->Watch(path, delegate);
[email protected]634d23d2011-01-19 10:38:19619 DCHECK(result);
620}
621#endif
[email protected]f520b5b2011-11-08 02:42:14622
623void PluginService::RefreshPlugins() {
624 plugin_list()->RefreshPlugins();
625}
626
627void PluginService::AddExtraPluginPath(const FilePath& path) {
628 plugin_list()->AddExtraPluginPath(path);
629}
630
631void PluginService::RemoveExtraPluginPath(const FilePath& path) {
632 plugin_list()->RemoveExtraPluginPath(path);
633}
634
635void PluginService::UnregisterInternalPlugin(const FilePath& path) {
636 plugin_list()->UnregisterInternalPlugin(path);
637}
638
639webkit::npapi::PluginList* PluginService::plugin_list() {
640 return webkit::npapi::PluginList::Singleton();
641}
642
643void PluginService::RegisterInternalPlugin(const webkit::WebPluginInfo& info) {
644 plugin_list()->RegisterInternalPlugin(info);
645}
646
647string16 PluginService::GetPluginGroupName(const std::string& plugin_name) {
648 return plugin_list()->GetPluginGroupName(plugin_name);
649}