OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/plugin_service_impl.h" | 5 #include "content/browser/plugin_service_impl.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "content/common/view_messages.h" | 27 #include "content/common/view_messages.h" |
28 #include "content/public/browser/browser_thread.h" | 28 #include "content/public/browser/browser_thread.h" |
29 #include "content/public/browser/content_browser_client.h" | 29 #include "content/public/browser/content_browser_client.h" |
30 #include "content/public/browser/plugin_service_filter.h" | 30 #include "content/public/browser/plugin_service_filter.h" |
31 #include "content/public/browser/resource_context.h" | 31 #include "content/public/browser/resource_context.h" |
32 #include "content/public/common/content_constants.h" | 32 #include "content/public/common/content_constants.h" |
33 #include "content/public/common/content_switches.h" | 33 #include "content/public/common/content_switches.h" |
34 #include "content/public/common/process_type.h" | 34 #include "content/public/common/process_type.h" |
35 #include "content/public/common/webplugininfo.h" | 35 #include "content/public/common/webplugininfo.h" |
36 | 36 |
37 #if defined(OS_WIN) | |
38 #include "content/common/plugin_constants_win.h" | |
39 #include "ui/gfx/win/hwnd_util.h" | |
40 #endif | |
41 | |
42 #if defined(OS_POSIX) | |
43 #include "content/browser/plugin_loader_posix.h" | |
44 #endif | |
45 | |
46 #if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID) | |
47 using ::base::FilePathWatcher; | |
48 #endif | |
49 | |
50 namespace content { | 37 namespace content { |
51 namespace { | 38 namespace { |
52 | 39 |
53 // This enum is used to collect Flash usage data. | 40 // This enum is used to collect Flash usage data. |
54 enum FlashUsage { | 41 enum FlashUsage { |
55 // Number of browser processes that have started at least one NPAPI Flash | |
56 // process during their lifetime. | |
57 START_NPAPI_FLASH_AT_LEAST_ONCE, | |
58 // Number of browser processes that have started at least one PPAPI Flash | 42 // Number of browser processes that have started at least one PPAPI Flash |
59 // process during their lifetime. | 43 // process during their lifetime. |
60 START_PPAPI_FLASH_AT_LEAST_ONCE, | 44 START_PPAPI_FLASH_AT_LEAST_ONCE = 1, |
61 // Total number of browser processes. | 45 // Total number of browser processes. |
62 TOTAL_BROWSER_PROCESSES, | 46 TOTAL_BROWSER_PROCESSES, |
63 FLASH_USAGE_ENUM_COUNT | 47 FLASH_USAGE_ENUM_COUNT |
64 }; | 48 }; |
65 | 49 |
66 enum NPAPIPluginStatus { | |
67 // Platform does not support NPAPI. | |
68 NPAPI_STATUS_UNSUPPORTED, | |
69 // Platform supports NPAPI and NPAPI is disabled. | |
70 NPAPI_STATUS_DISABLED, | |
71 // Platform supports NPAPI and NPAPI is enabled. | |
72 NPAPI_STATUS_ENABLED, | |
73 NPAPI_STATUS_ENUM_COUNT | |
74 }; | |
75 | |
76 bool LoadPluginListInProcess() { | |
77 #if defined(OS_WIN) | |
78 return true; | |
79 #else | |
80 // If on POSIX, we don't want to load the list of NPAPI plugins in-process as | |
81 // that causes instability. | |
82 | |
83 // Can't load the plugins on the utility thread when in single process mode | |
84 // since that requires GTK which can only be used on the main thread. | |
85 if (RenderProcessHost::run_renderer_in_process()) | |
86 return true; | |
87 | |
88 return !PluginService::GetInstance()->NPAPIPluginsSupported(); | |
89 #endif | |
90 } | |
91 | |
92 // Callback set on the PluginList to assert that plugin loading happens on the | 50 // Callback set on the PluginList to assert that plugin loading happens on the |
93 // correct thread. | 51 // correct thread. |
94 void WillLoadPluginsCallback( | 52 void WillLoadPluginsCallback( |
95 base::SequencedWorkerPool::SequenceToken token) { | 53 base::SequencedWorkerPool::SequenceToken token) { |
96 if (LoadPluginListInProcess()) { | 54 CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( |
97 CHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( | 55 token)); |
98 token)); | |
99 } else { | |
100 CHECK(false) << "Plugin loading should happen out-of-process."; | |
101 } | |
102 } | 56 } |
103 | 57 |
104 #if defined(OS_MACOSX) | |
105 void NotifyPluginsOfActivation() { | |
106 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
107 | |
108 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) | |
109 iter->OnAppActivation(); | |
110 } | |
111 #endif | |
112 | |
113 #if defined(OS_POSIX) | |
114 #if !defined(OS_OPENBSD) && !defined(OS_ANDROID) | |
115 void NotifyPluginDirChanged(const base::FilePath& path, bool error) { | |
116 if (error) { | |
117 // TODO(pastarmovj): Add some sensible error handling. Maybe silently | |
118 // stopping the watcher would be enough. Or possibly restart it. | |
119 NOTREACHED(); | |
120 return; | |
121 } | |
122 VLOG(1) << "Watched path changed: " << path.value(); | |
123 // Make the plugin list update itself | |
124 PluginList::Singleton()->RefreshPlugins(); | |
125 BrowserThread::PostTask( | |
126 BrowserThread::UI, FROM_HERE, | |
127 base::Bind(&PluginService::PurgePluginListCache, | |
128 static_cast<BrowserContext*>(NULL), false)); | |
129 } | |
130 #endif // !defined(OS_OPENBSD) && !defined(OS_ANDROID) | |
131 | |
132 void ForwardCallback(base::SingleThreadTaskRunner* target_task_runner, | |
133 const PluginService::GetPluginsCallback& callback, | |
134 const std::vector<WebPluginInfo>& plugins) { | |
135 target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins)); | |
136 } | |
137 #endif // defined(OS_POSIX) | |
138 | |
139 } // namespace | 58 } // namespace |
140 | 59 |
141 // static | 60 // static |
142 PluginService* PluginService::GetInstance() { | 61 PluginService* PluginService::GetInstance() { |
143 return PluginServiceImpl::GetInstance(); | 62 return PluginServiceImpl::GetInstance(); |
144 } | 63 } |
145 | 64 |
146 void PluginService::PurgePluginListCache(BrowserContext* browser_context, | 65 void PluginService::PurgePluginListCache(BrowserContext* browser_context, |
147 bool reload_pages) { | 66 bool reload_pages) { |
148 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); | 67 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); |
149 !it.IsAtEnd(); it.Advance()) { | 68 !it.IsAtEnd(); it.Advance()) { |
150 RenderProcessHost* host = it.GetCurrentValue(); | 69 RenderProcessHost* host = it.GetCurrentValue(); |
151 if (!browser_context || host->GetBrowserContext() == browser_context) | 70 if (!browser_context || host->GetBrowserContext() == browser_context) |
152 host->Send(new ViewMsg_PurgePluginListCache(reload_pages)); | 71 host->Send(new ViewMsg_PurgePluginListCache(reload_pages)); |
153 } | 72 } |
154 } | 73 } |
155 | 74 |
156 // static | 75 // static |
157 PluginServiceImpl* PluginServiceImpl::GetInstance() { | 76 PluginServiceImpl* PluginServiceImpl::GetInstance() { |
158 return base::Singleton<PluginServiceImpl>::get(); | 77 return base::Singleton<PluginServiceImpl>::get(); |
159 } | 78 } |
160 | 79 |
161 PluginServiceImpl::PluginServiceImpl() | 80 PluginServiceImpl::PluginServiceImpl() |
162 : npapi_plugins_enabled_(false), filter_(NULL) { | 81 : filter_(NULL) { |
163 // Collect the total number of browser processes (which create | 82 // Collect the total number of browser processes (which create |
164 // PluginServiceImpl objects, to be precise). The number is used to normalize | 83 // PluginServiceImpl objects, to be precise). The number is used to normalize |
165 // the number of processes which start at least one NPAPI/PPAPI Flash process. | 84 // the number of processes which start at least one NPAPI/PPAPI Flash process. |
166 static bool counted = false; | 85 static bool counted = false; |
167 if (!counted) { | 86 if (!counted) { |
168 counted = true; | 87 counted = true; |
169 UMA_HISTOGRAM_ENUMERATION("Plugin.FlashUsage", TOTAL_BROWSER_PROCESSES, | 88 UMA_HISTOGRAM_ENUMERATION("Plugin.FlashUsage", TOTAL_BROWSER_PROCESSES, |
170 FLASH_USAGE_ENUM_COUNT); | 89 FLASH_USAGE_ENUM_COUNT); |
171 } | 90 } |
172 } | 91 } |
173 | 92 |
174 PluginServiceImpl::~PluginServiceImpl() { | 93 PluginServiceImpl::~PluginServiceImpl() { |
175 // Make sure no plugin channel requests have been leaked. | |
176 DCHECK(pending_plugin_clients_.empty()); | |
177 } | 94 } |
178 | 95 |
179 void PluginServiceImpl::Init() { | 96 void PluginServiceImpl::Init() { |
180 plugin_list_token_ = base::SequencedWorkerPool::GetSequenceToken(); | 97 plugin_list_token_ = base::SequencedWorkerPool::GetSequenceToken(); |
181 PluginList::Singleton()->set_will_load_plugins_callback( | 98 PluginList::Singleton()->set_will_load_plugins_callback( |
182 base::Bind(&WillLoadPluginsCallback, plugin_list_token_)); | 99 base::Bind(&WillLoadPluginsCallback, plugin_list_token_)); |
183 | 100 |
184 RegisterPepperPlugins(); | 101 RegisterPepperPlugins(); |
185 | |
186 // Load any specified on the command line as well. | |
187 const base::CommandLine* command_line = | |
188 base::CommandLine::ForCurrentProcess(); | |
189 base::FilePath path = | |
190 command_line->GetSwitchValuePath(switches::kLoadPlugin); | |
191 if (!path.empty()) | |
192 AddExtraPluginPath(path); | |
193 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir); | |
194 if (!path.empty()) | |
195 PluginList::Singleton()->AddExtraPluginDir(path); | |
196 | |
197 if (command_line->HasSwitch(switches::kDisablePluginsDiscovery)) | |
198 PluginList::Singleton()->DisablePluginsDiscovery(); | |
199 } | |
200 | |
201 void PluginServiceImpl::StartWatchingPlugins() { | |
202 // Start watching for changes in the plugin list. This means watching | |
203 // for changes in the Windows registry keys and on both Windows and POSIX | |
204 // watch for changes in the paths that are expected to contain plugins. | |
205 #if defined(OS_WIN) | |
206 if (hkcu_key_.Create(HKEY_CURRENT_USER, | |
207 kRegistryMozillaPlugins, | |
208 KEY_NOTIFY) == ERROR_SUCCESS) { | |
209 base::win::RegKey::ChangeCallback callback = | |
210 base::Bind(&PluginServiceImpl::OnKeyChanged, base::Unretained(this), | |
211 base::Unretained(&hkcu_key_)); | |
212 hkcu_key_.StartWatching(callback); | |
213 } | |
214 if (hklm_key_.Create(HKEY_LOCAL_MACHINE, | |
215 kRegistryMozillaPlugins, | |
216 KEY_NOTIFY) == ERROR_SUCCESS) { | |
217 base::win::RegKey::ChangeCallback callback = | |
218 base::Bind(&PluginServiceImpl::OnKeyChanged, base::Unretained(this), | |
219 base::Unretained(&hklm_key_)); | |
220 hklm_key_.StartWatching(callback); | |
221 } | |
222 #endif | |
223 #if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID) | |
224 // On ChromeOS the user can't install plugins anyway and on Windows all | |
225 // important plugins register themselves in the registry so no need to do that. | |
226 | |
227 // Get the list of all paths for registering the FilePathWatchers | |
228 // that will track and if needed reload the list of plugins on runtime. | |
229 std::vector<base::FilePath> plugin_dirs; | |
230 PluginList::Singleton()->GetPluginDirectories(&plugin_dirs); | |
231 | |
232 for (size_t i = 0; i < plugin_dirs.size(); ++i) { | |
233 // FilePathWatcher can not handle non-absolute paths under windows. | |
234 // We don't watch for file changes in windows now but if this should ever | |
235 // be extended to Windows these lines might save some time of debugging. | |
236 #if defined(OS_WIN) | |
237 if (!plugin_dirs[i].IsAbsolute()) | |
238 continue; | |
239 #endif | |
240 FilePathWatcher* watcher = new FilePathWatcher(); | |
241 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value(); | |
242 BrowserThread::PostTask( | |
243 BrowserThread::FILE, FROM_HERE, | |
244 base::Bind(&PluginServiceImpl::RegisterFilePathWatcher, watcher, | |
245 plugin_dirs[i])); | |
246 file_watchers_.push_back(watcher); | |
247 } | |
248 #endif | |
249 } | |
250 | |
251 PluginProcessHost* PluginServiceImpl::FindNpapiPluginProcess( | |
252 const base::FilePath& plugin_path) { | |
253 for (PluginProcessHostIterator iter; !iter.Done(); ++iter) { | |
254 if (iter->info().path == plugin_path) | |
255 return *iter; | |
256 } | |
257 | |
258 return NULL; | |
259 } | 102 } |
260 | 103 |
261 PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess( | 104 PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess( |
262 const base::FilePath& plugin_path, | 105 const base::FilePath& plugin_path, |
263 const base::FilePath& profile_data_directory) { | 106 const base::FilePath& profile_data_directory) { |
264 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) { | 107 for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) { |
265 if (iter->plugin_path() == plugin_path && | 108 if (iter->plugin_path() == plugin_path && |
266 iter->profile_data_directory() == profile_data_directory) { | 109 iter->profile_data_directory() == profile_data_directory) { |
267 return *iter; | 110 return *iter; |
268 } | 111 } |
269 } | 112 } |
270 return NULL; | 113 return NULL; |
271 } | 114 } |
272 | 115 |
273 PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess( | 116 PpapiPluginProcessHost* PluginServiceImpl::FindPpapiBrokerProcess( |
274 const base::FilePath& broker_path) { | 117 const base::FilePath& broker_path) { |
275 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) { | 118 for (PpapiBrokerProcessHostIterator iter; !iter.Done(); ++iter) { |
276 if (iter->plugin_path() == broker_path) | 119 if (iter->plugin_path() == broker_path) |
277 return *iter; | 120 return *iter; |
278 } | 121 } |
279 | 122 |
280 return NULL; | 123 return NULL; |
281 } | 124 } |
282 | 125 |
283 PluginProcessHost* PluginServiceImpl::FindOrStartNpapiPluginProcess( | |
284 int render_process_id, | |
285 const base::FilePath& plugin_path) { | |
286 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
287 | |
288 if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path)) | |
289 return NULL; | |
290 | |
291 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path); | |
292 if (plugin_host) | |
293 return plugin_host; | |
294 | |
295 WebPluginInfo info; | |
296 if (!GetPluginInfoByPath(plugin_path, &info)) { | |
297 return NULL; | |
298 } | |
299 | |
300 // Record when NPAPI Flash process is started for the first time. | |
301 static bool counted = false; | |
302 if (!counted && base::UTF16ToUTF8(info.name) == kFlashPluginName) { | |
303 counted = true; | |
304 UMA_HISTOGRAM_ENUMERATION("Plugin.FlashUsage", | |
305 START_NPAPI_FLASH_AT_LEAST_ONCE, | |
306 FLASH_USAGE_ENUM_COUNT); | |
307 } | |
308 #if defined(OS_CHROMEOS) | |
309 // TODO(ihf): Move to an earlier place once crbug.com/314301 is fixed. For now | |
310 // we still want Plugin.FlashUsage recorded if we end up here. | |
311 LOG(WARNING) << "Refusing to start npapi plugin on ChromeOS."; | |
312 return NULL; | |
313 #endif | |
314 // This plugin isn't loaded by any plugin process, so create a new process. | |
315 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost()); | |
316 if (!new_host->Init(info)) { | |
317 NOTREACHED(); // Init is not expected to fail. | |
318 return NULL; | |
319 } | |
320 return new_host.release(); | |
321 } | |
322 | |
323 PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess( | 126 PpapiPluginProcessHost* PluginServiceImpl::FindOrStartPpapiPluginProcess( |
324 int render_process_id, | 127 int render_process_id, |
325 const base::FilePath& plugin_path, | 128 const base::FilePath& plugin_path, |
326 const base::FilePath& profile_data_directory) { | 129 const base::FilePath& profile_data_directory) { |
327 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 130 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
328 | 131 |
329 if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path)) { | 132 if (filter_ && !filter_->CanLoadPlugin(render_process_id, plugin_path)) { |
330 VLOG(1) << "Unable to load ppapi plugin: " << plugin_path.MaybeAsASCII(); | 133 VLOG(1) << "Unable to load ppapi plugin: " << plugin_path.MaybeAsASCII(); |
331 return NULL; | 134 return NULL; |
332 } | 135 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 if (!info) | 184 if (!info) |
382 return NULL; | 185 return NULL; |
383 | 186 |
384 // TODO(ddorwin): Uncomment once out of process is supported. | 187 // TODO(ddorwin): Uncomment once out of process is supported. |
385 // DCHECK(info->is_out_of_process); | 188 // DCHECK(info->is_out_of_process); |
386 | 189 |
387 // This broker isn't loaded by any broker process, so create a new process. | 190 // This broker isn't loaded by any broker process, so create a new process. |
388 return PpapiPluginProcessHost::CreateBrokerHost(*info); | 191 return PpapiPluginProcessHost::CreateBrokerHost(*info); |
389 } | 192 } |
390 | 193 |
391 void PluginServiceImpl::OpenChannelToNpapiPlugin( | |
392 int render_process_id, | |
393 int render_frame_id, | |
394 const GURL& url, | |
395 const GURL& page_url, | |
396 const std::string& mime_type, | |
397 PluginProcessHost::Client* client) { | |
398 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
399 DCHECK(!ContainsKey(pending_plugin_clients_, client)); | |
400 pending_plugin_clients_.insert(client); | |
401 | |
402 // Make sure plugins are loaded if necessary. | |
403 PluginServiceFilterParams params = { | |
404 render_process_id, | |
405 render_frame_id, | |
406 page_url, | |
407 client->GetResourceContext() | |
408 }; | |
409 GetPlugins(base::Bind( | |
410 &PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin, | |
411 base::Unretained(this), params, url, mime_type, client)); | |
412 } | |
413 | |
414 void PluginServiceImpl::OpenChannelToPpapiPlugin( | 194 void PluginServiceImpl::OpenChannelToPpapiPlugin( |
415 int render_process_id, | 195 int render_process_id, |
416 const base::FilePath& plugin_path, | 196 const base::FilePath& plugin_path, |
417 const base::FilePath& profile_data_directory, | 197 const base::FilePath& profile_data_directory, |
418 PpapiPluginProcessHost::PluginClient* client) { | 198 PpapiPluginProcessHost::PluginClient* client) { |
419 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess( | 199 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess( |
420 render_process_id, plugin_path, profile_data_directory); | 200 render_process_id, plugin_path, profile_data_directory); |
421 if (plugin_host) { | 201 if (plugin_host) { |
422 plugin_host->OpenChannelToPlugin(client); | 202 plugin_host->OpenChannelToPlugin(client); |
423 } else { | 203 } else { |
424 // Send error. | 204 // Send error. |
425 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0); | 205 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0); |
426 } | 206 } |
427 } | 207 } |
428 | 208 |
429 void PluginServiceImpl::OpenChannelToPpapiBroker( | 209 void PluginServiceImpl::OpenChannelToPpapiBroker( |
430 int render_process_id, | 210 int render_process_id, |
431 const base::FilePath& path, | 211 const base::FilePath& path, |
432 PpapiPluginProcessHost::BrokerClient* client) { | 212 PpapiPluginProcessHost::BrokerClient* client) { |
433 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess( | 213 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiBrokerProcess( |
434 render_process_id, path); | 214 render_process_id, path); |
435 if (plugin_host) { | 215 if (plugin_host) { |
436 plugin_host->OpenChannelToPlugin(client); | 216 plugin_host->OpenChannelToPlugin(client); |
437 } else { | 217 } else { |
438 // Send error. | 218 // Send error. |
439 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0); | 219 client->OnPpapiChannelOpened(IPC::ChannelHandle(), base::kNullProcessId, 0); |
440 } | 220 } |
441 } | 221 } |
442 | 222 |
443 void PluginServiceImpl::CancelOpenChannelToNpapiPlugin( | |
444 PluginProcessHost::Client* client) { | |
445 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
446 DCHECK(ContainsKey(pending_plugin_clients_, client)); | |
447 pending_plugin_clients_.erase(client); | |
448 } | |
449 | |
450 void PluginServiceImpl::ForwardGetAllowedPluginForOpenChannelToPlugin( | |
451 const PluginServiceFilterParams& params, | |
452 const GURL& url, | |
453 const std::string& mime_type, | |
454 PluginProcessHost::Client* client, | |
455 const std::vector<WebPluginInfo>&) { | |
456 GetAllowedPluginForOpenChannelToPlugin( | |
457 params.render_process_id, params.render_frame_id, url, params.page_url, | |
458 mime_type, client, params.resource_context); | |
459 } | |
460 | |
461 void PluginServiceImpl::GetAllowedPluginForOpenChannelToPlugin( | |
462 int render_process_id, | |
463 int render_frame_id, | |
464 const GURL& url, | |
465 const GURL& page_url, | |
466 const std::string& mime_type, | |
467 PluginProcessHost::Client* client, | |
468 ResourceContext* resource_context) { | |
469 WebPluginInfo info; | |
470 bool allow_wildcard = true; | |
471 bool found = GetPluginInfo( | |
472 render_process_id, render_frame_id, resource_context, | |
473 url, page_url, mime_type, allow_wildcard, | |
474 NULL, &info, NULL); | |
475 base::FilePath plugin_path; | |
476 if (found) | |
477 plugin_path = info.path; | |
478 | |
479 // Now we jump back to the IO thread to finish opening the channel. | |
480 BrowserThread::PostTask( | |
481 BrowserThread::IO, FROM_HERE, | |
482 base::Bind(&PluginServiceImpl::FinishOpenChannelToPlugin, | |
483 base::Unretained(this), | |
484 render_process_id, | |
485 plugin_path, | |
486 client)); | |
487 if (filter_) { | |
488 DCHECK_EQ(WebPluginInfo::PLUGIN_TYPE_NPAPI, info.type); | |
489 filter_->NPAPIPluginLoaded(render_process_id, render_frame_id, mime_type, | |
490 info); | |
491 } | |
492 } | |
493 | |
494 void PluginServiceImpl::FinishOpenChannelToPlugin( | |
495 int render_process_id, | |
496 const base::FilePath& plugin_path, | |
497 PluginProcessHost::Client* client) { | |
498 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
499 | |
500 // Make sure it hasn't been canceled yet. | |
501 if (!ContainsKey(pending_plugin_clients_, client)) | |
502 return; | |
503 pending_plugin_clients_.erase(client); | |
504 | |
505 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess( | |
506 render_process_id, plugin_path); | |
507 if (plugin_host) { | |
508 client->OnFoundPluginProcessHost(plugin_host); | |
509 plugin_host->OpenChannelToPlugin(client); | |
510 } else { | |
511 client->OnError(); | |
512 } | |
513 } | |
514 | |
515 bool PluginServiceImpl::GetPluginInfoArray( | 223 bool PluginServiceImpl::GetPluginInfoArray( |
516 const GURL& url, | 224 const GURL& url, |
517 const std::string& mime_type, | 225 const std::string& mime_type, |
518 bool allow_wildcard, | 226 bool allow_wildcard, |
519 std::vector<WebPluginInfo>* plugins, | 227 std::vector<WebPluginInfo>* plugins, |
520 std::vector<std::string>* actual_mime_types) { | 228 std::vector<std::string>* actual_mime_types) { |
521 bool use_stale = false; | 229 bool use_stale = false; |
522 PluginList::Singleton()->GetPluginInfoArray( | 230 PluginList::Singleton()->GetPluginInfoArray( |
523 url, mime_type, allow_wildcard, &use_stale, NPAPIPluginsSupported(), | 231 url, mime_type, allow_wildcard, &use_stale, plugins, actual_mime_types); |
524 plugins, actual_mime_types); | |
525 return use_stale; | 232 return use_stale; |
526 } | 233 } |
527 | 234 |
528 bool PluginServiceImpl::GetPluginInfo(int render_process_id, | 235 bool PluginServiceImpl::GetPluginInfo(int render_process_id, |
529 int render_frame_id, | 236 int render_frame_id, |
530 ResourceContext* context, | 237 ResourceContext* context, |
531 const GURL& url, | 238 const GURL& url, |
532 const GURL& page_url, | 239 const GURL& page_url, |
533 const std::string& mime_type, | 240 const std::string& mime_type, |
534 bool allow_wildcard, | 241 bool allow_wildcard, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 plugin_name.erase(plugin_name.length() - kPluginExtension.length()); | 298 plugin_name.erase(plugin_name.length() - kPluginExtension.length()); |
592 #endif // OS_MACOSX | 299 #endif // OS_MACOSX |
593 } | 300 } |
594 return plugin_name; | 301 return plugin_name; |
595 } | 302 } |
596 | 303 |
597 void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) { | 304 void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) { |
598 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner( | 305 scoped_refptr<base::SingleThreadTaskRunner> target_task_runner( |
599 base::ThreadTaskRunnerHandle::Get()); | 306 base::ThreadTaskRunnerHandle::Get()); |
600 | 307 |
601 if (LoadPluginListInProcess()) { | 308 BrowserThread::GetBlockingPool()->PostSequencedWorkerTaskWithShutdownBehavior( |
602 BrowserThread::GetBlockingPool() | 309 plugin_list_token_, FROM_HERE, |
603 ->PostSequencedWorkerTaskWithShutdownBehavior( | 310 base::Bind(&PluginServiceImpl::GetPluginsInternal, base::Unretained(this), |
604 plugin_list_token_, FROM_HERE, | 311 base::RetainedRef(target_task_runner), callback), |
605 base::Bind(&PluginServiceImpl::GetPluginsInternal, | 312 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); |
606 base::Unretained(this), | |
607 base::RetainedRef(target_task_runner), callback), | |
608 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
609 return; | |
610 } | |
611 #if defined(OS_POSIX) | |
612 BrowserThread::PostTask( | |
613 BrowserThread::IO, FROM_HERE, | |
614 base::Bind(&PluginServiceImpl::GetPluginsOnIOThread, | |
615 base::Unretained(this), base::RetainedRef(target_task_runner), | |
616 callback)); | |
617 #else | |
618 NOTREACHED(); | |
619 #endif | |
620 } | 313 } |
621 | 314 |
622 void PluginServiceImpl::GetPluginsInternal( | 315 void PluginServiceImpl::GetPluginsInternal( |
623 base::SingleThreadTaskRunner* target_task_runner, | 316 base::SingleThreadTaskRunner* target_task_runner, |
624 const PluginService::GetPluginsCallback& callback) { | 317 const PluginService::GetPluginsCallback& callback) { |
625 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( | 318 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( |
626 plugin_list_token_)); | 319 plugin_list_token_)); |
627 | 320 |
628 std::vector<WebPluginInfo> plugins; | 321 std::vector<WebPluginInfo> plugins; |
629 PluginList::Singleton()->GetPlugins(&plugins, NPAPIPluginsSupported()); | 322 PluginList::Singleton()->GetPlugins(&plugins); |
630 | 323 |
631 target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins)); | 324 target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins)); |
632 } | 325 } |
633 | 326 |
634 #if defined(OS_POSIX) | |
635 void PluginServiceImpl::GetPluginsOnIOThread( | |
636 base::SingleThreadTaskRunner* target_task_runner, | |
637 const GetPluginsCallback& callback) { | |
638 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
639 | |
640 // If we switch back to loading plugins in process, then we need to make | |
641 // sure g_thread_init() gets called since plugins may call glib at load. | |
642 | |
643 if (!plugin_loader_.get()) | |
644 plugin_loader_ = new PluginLoaderPosix; | |
645 | |
646 plugin_loader_->GetPlugins(base::Bind( | |
647 &ForwardCallback, base::RetainedRef(target_task_runner), callback)); | |
648 } | |
649 #endif | |
650 | |
651 #if defined(OS_WIN) | |
652 void PluginServiceImpl::OnKeyChanged(base::win::RegKey* key) { | |
653 key->StartWatching(base::Bind(&PluginServiceImpl::OnKeyChanged, | |
654 base::Unretained(this), | |
655 base::Unretained(key))); | |
656 | |
657 PluginList::Singleton()->RefreshPlugins(); | |
658 PurgePluginListCache(NULL, false); | |
659 } | |
660 #endif // defined(OS_WIN) | |
661 | |
662 void PluginServiceImpl::RegisterPepperPlugins() { | 327 void PluginServiceImpl::RegisterPepperPlugins() { |
663 ComputePepperPluginList(&ppapi_plugins_); | 328 ComputePepperPluginList(&ppapi_plugins_); |
664 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) { | 329 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) { |
665 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true); | 330 RegisterInternalPlugin(ppapi_plugins_[i].ToWebPluginInfo(), true); |
666 } | 331 } |
667 } | 332 } |
668 | 333 |
669 // There should generally be very few plugins so a brute-force search is fine. | 334 // There should generally be very few plugins so a brute-force search is fine. |
670 PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo( | 335 PepperPluginInfo* PluginServiceImpl::GetRegisteredPpapiPluginInfo( |
671 const base::FilePath& plugin_path) { | 336 const base::FilePath& plugin_path) { |
(...skipping 14 matching lines...) Expand all Loading... |
686 WebPluginInfo webplugin_info; | 351 WebPluginInfo webplugin_info; |
687 if (!GetPluginInfoByPath(plugin_path, &webplugin_info)) | 352 if (!GetPluginInfoByPath(plugin_path, &webplugin_info)) |
688 return NULL; | 353 return NULL; |
689 PepperPluginInfo new_pepper_info; | 354 PepperPluginInfo new_pepper_info; |
690 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info)) | 355 if (!MakePepperPluginInfo(webplugin_info, &new_pepper_info)) |
691 return NULL; | 356 return NULL; |
692 ppapi_plugins_.push_back(new_pepper_info); | 357 ppapi_plugins_.push_back(new_pepper_info); |
693 return &ppapi_plugins_[ppapi_plugins_.size() - 1]; | 358 return &ppapi_plugins_[ppapi_plugins_.size() - 1]; |
694 } | 359 } |
695 | 360 |
696 #if defined(OS_POSIX) && !defined(OS_OPENBSD) && !defined(OS_ANDROID) | |
697 // static | |
698 void PluginServiceImpl::RegisterFilePathWatcher(FilePathWatcher* watcher, | |
699 const base::FilePath& path) { | |
700 bool result = watcher->Watch(path, false, | |
701 base::Bind(&NotifyPluginDirChanged)); | |
702 DCHECK(result); | |
703 } | |
704 #endif | |
705 | |
706 void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) { | 361 void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) { |
707 filter_ = filter; | 362 filter_ = filter; |
708 } | 363 } |
709 | 364 |
710 PluginServiceFilter* PluginServiceImpl::GetFilter() { | 365 PluginServiceFilter* PluginServiceImpl::GetFilter() { |
711 return filter_; | 366 return filter_; |
712 } | 367 } |
713 | 368 |
714 void PluginServiceImpl::ForcePluginShutdown(const base::FilePath& plugin_path) { | |
715 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
716 BrowserThread::PostTask( | |
717 BrowserThread::IO, FROM_HERE, | |
718 base::Bind(&PluginServiceImpl::ForcePluginShutdown, | |
719 base::Unretained(this), plugin_path)); | |
720 return; | |
721 } | |
722 | |
723 PluginProcessHost* plugin = FindNpapiPluginProcess(plugin_path); | |
724 if (plugin) | |
725 plugin->ForceShutdown(); | |
726 } | |
727 | |
728 static const unsigned int kMaxCrashesPerInterval = 3; | 369 static const unsigned int kMaxCrashesPerInterval = 3; |
729 static const unsigned int kCrashesInterval = 120; | 370 static const unsigned int kCrashesInterval = 120; |
730 | 371 |
731 void PluginServiceImpl::RegisterPluginCrash(const base::FilePath& path) { | 372 void PluginServiceImpl::RegisterPluginCrash(const base::FilePath& path) { |
732 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 373 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
733 std::map<base::FilePath, std::vector<base::Time> >::iterator i = | 374 std::map<base::FilePath, std::vector<base::Time> >::iterator i = |
734 crash_times_.find(path); | 375 crash_times_.find(path); |
735 if (i == crash_times_.end()) { | 376 if (i == crash_times_.end()) { |
736 crash_times_[path] = std::vector<base::Time>(); | 377 crash_times_[path] = std::vector<base::Time>(); |
737 i = crash_times_.find(path); | 378 i = crash_times_.find(path); |
(...skipping 16 matching lines...) Expand all Loading... |
754 return false; | 395 return false; |
755 } | 396 } |
756 base::TimeDelta delta = base::Time::Now() - i->second[0]; | 397 base::TimeDelta delta = base::Time::Now() - i->second[0]; |
757 return delta.InSeconds() <= kCrashesInterval; | 398 return delta.InSeconds() <= kCrashesInterval; |
758 } | 399 } |
759 | 400 |
760 void PluginServiceImpl::RefreshPlugins() { | 401 void PluginServiceImpl::RefreshPlugins() { |
761 PluginList::Singleton()->RefreshPlugins(); | 402 PluginList::Singleton()->RefreshPlugins(); |
762 } | 403 } |
763 | 404 |
764 void PluginServiceImpl::AddExtraPluginPath(const base::FilePath& path) { | |
765 if (!NPAPIPluginsSupported()) { | |
766 // TODO(jam): remove and just have CHECK once we're sure this doesn't get | |
767 // triggered. | |
768 DVLOG(0) << "NPAPI plugins not supported"; | |
769 return; | |
770 } | |
771 PluginList::Singleton()->AddExtraPluginPath(path); | |
772 } | |
773 | |
774 void PluginServiceImpl::RemoveExtraPluginPath(const base::FilePath& path) { | |
775 PluginList::Singleton()->RemoveExtraPluginPath(path); | |
776 } | |
777 | |
778 void PluginServiceImpl::AddExtraPluginDir(const base::FilePath& path) { | |
779 PluginList::Singleton()->AddExtraPluginDir(path); | |
780 } | |
781 | |
782 void PluginServiceImpl::RegisterInternalPlugin( | 405 void PluginServiceImpl::RegisterInternalPlugin( |
783 const WebPluginInfo& info, | 406 const WebPluginInfo& info, |
784 bool add_at_beginning) { | 407 bool add_at_beginning) { |
785 // Internal plugins should never be NPAPI. | |
786 CHECK_NE(info.type, WebPluginInfo::PLUGIN_TYPE_NPAPI); | |
787 if (info.type == WebPluginInfo::PLUGIN_TYPE_NPAPI) { | |
788 DVLOG(0) << "Don't register NPAPI plugins when they're not supported"; | |
789 return; | |
790 } | |
791 PluginList::Singleton()->RegisterInternalPlugin(info, add_at_beginning); | 408 PluginList::Singleton()->RegisterInternalPlugin(info, add_at_beginning); |
792 } | 409 } |
793 | 410 |
794 void PluginServiceImpl::UnregisterInternalPlugin(const base::FilePath& path) { | 411 void PluginServiceImpl::UnregisterInternalPlugin(const base::FilePath& path) { |
795 PluginList::Singleton()->UnregisterInternalPlugin(path); | 412 PluginList::Singleton()->UnregisterInternalPlugin(path); |
796 } | 413 } |
797 | 414 |
798 void PluginServiceImpl::GetInternalPlugins( | 415 void PluginServiceImpl::GetInternalPlugins( |
799 std::vector<WebPluginInfo>* plugins) { | 416 std::vector<WebPluginInfo>* plugins) { |
800 PluginList::Singleton()->GetInternalPlugins(plugins); | 417 PluginList::Singleton()->GetInternalPlugins(plugins); |
801 } | 418 } |
802 | 419 |
803 bool PluginServiceImpl::NPAPIPluginsSupported() { | |
804 #if defined(OS_WIN) || defined(OS_MACOSX) | |
805 npapi_plugins_enabled_ = GetContentClient()->browser()->IsNPAPIEnabled(); | |
806 #if defined(OS_WIN) | |
807 // NPAPI plugins don't play well with Win32k renderer lockdown. | |
808 if (npapi_plugins_enabled_) | |
809 DisableWin32kRendererLockdown(); | |
810 #endif | |
811 NPAPIPluginStatus status = | |
812 npapi_plugins_enabled_ ? NPAPI_STATUS_ENABLED : NPAPI_STATUS_DISABLED; | |
813 #else | |
814 NPAPIPluginStatus status = NPAPI_STATUS_UNSUPPORTED; | |
815 #endif | |
816 UMA_HISTOGRAM_ENUMERATION("Plugin.NPAPIStatus", status, | |
817 NPAPI_STATUS_ENUM_COUNT); | |
818 | |
819 return npapi_plugins_enabled_; | |
820 } | |
821 | |
822 void PluginServiceImpl::DisablePluginsDiscoveryForTesting() { | |
823 PluginList::Singleton()->DisablePluginsDiscovery(); | |
824 } | |
825 | |
826 #if defined(OS_MACOSX) | |
827 void PluginServiceImpl::AppActivated() { | |
828 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
829 base::Bind(&NotifyPluginsOfActivation)); | |
830 } | |
831 #endif | |
832 | |
833 bool PluginServiceImpl::PpapiDevChannelSupported( | 420 bool PluginServiceImpl::PpapiDevChannelSupported( |
834 BrowserContext* browser_context, | 421 BrowserContext* browser_context, |
835 const GURL& document_url) { | 422 const GURL& document_url) { |
836 return GetContentClient()->browser()->IsPluginAllowedToUseDevChannelAPIs( | 423 return GetContentClient()->browser()->IsPluginAllowedToUseDevChannelAPIs( |
837 browser_context, document_url); | 424 browser_context, document_url); |
838 } | 425 } |
839 | 426 |
840 } // namespace content | 427 } // namespace content |
OLD | NEW |