| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/browser/plugin_service.h" | 5 #include "chrome/browser/plugin_service.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "base/values.h" | 14 #include "base/values.h" |
| 15 #include "base/synchronization/waitable_event.h" | 15 #include "base/synchronization/waitable_event.h" |
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/browser_thread.h" | 17 #include "chrome/browser/browser_thread.h" |
| 18 #include "chrome/browser/chrome_plugin_host.h" | 18 #include "chrome/browser/chrome_plugin_host.h" |
| 19 #include "chrome/browser/extensions/extension_service.h" | 19 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/plugin_updater.h" | 20 #include "chrome/browser/plugin_updater.h" |
| 21 #include "chrome/browser/ppapi_plugin_process_host.h" |
| 21 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/renderer_host/render_process_host.h" | 23 #include "chrome/browser/renderer_host/render_process_host.h" |
| 23 #include "chrome/browser/renderer_host/render_view_host.h" | 24 #include "chrome/browser/renderer_host/render_view_host.h" |
| 24 #include "chrome/common/chrome_plugin_lib.h" | 25 #include "chrome/common/chrome_plugin_lib.h" |
| 25 #include "chrome/common/chrome_paths.h" | 26 #include "chrome/common/chrome_paths.h" |
| 26 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" |
| 27 #include "chrome/common/default_plugin.h" | 28 #include "chrome/common/default_plugin.h" |
| 28 #include "chrome/common/extensions/extension.h" | 29 #include "chrome/common/extensions/extension.h" |
| 29 #include "chrome/common/gpu_plugin.h" | 30 #include "chrome/common/gpu_plugin.h" |
| 30 #include "chrome/common/logging_chrome.h" | 31 #include "chrome/common/logging_chrome.h" |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 } | 234 } |
| 234 | 235 |
| 235 const FilePath& PluginService::GetChromePluginDataDir() { | 236 const FilePath& PluginService::GetChromePluginDataDir() { |
| 236 return chrome_plugin_data_dir_; | 237 return chrome_plugin_data_dir_; |
| 237 } | 238 } |
| 238 | 239 |
| 239 const std::string& PluginService::GetUILocale() { | 240 const std::string& PluginService::GetUILocale() { |
| 240 return ui_locale_; | 241 return ui_locale_; |
| 241 } | 242 } |
| 242 | 243 |
| 243 PluginProcessHost* PluginService::FindPluginProcess( | 244 PluginProcessHost* PluginService::FindNpapiPluginProcess( |
| 244 const FilePath& plugin_path) { | 245 const FilePath& plugin_path) { |
| 245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 246 | 247 |
| 247 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); | 248 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); |
| 248 !iter.Done(); ++iter) { | 249 !iter.Done(); ++iter) { |
| 249 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); | 250 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); |
| 250 if (plugin->info().path == plugin_path) | 251 if (plugin->info().path == plugin_path) |
| 251 return plugin; | 252 return plugin; |
| 252 } | 253 } |
| 253 | 254 |
| 254 return NULL; | 255 return NULL; |
| 255 } | 256 } |
| 256 | 257 |
| 257 PluginProcessHost* PluginService::FindOrStartPluginProcess( | 258 PpapiPluginProcessHost* PluginService::FindPpapiPluginProcess( |
| 258 const FilePath& plugin_path) { | 259 const FilePath& plugin_path) { |
| 259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 260 | 261 |
| 261 PluginProcessHost* plugin_host = FindPluginProcess(plugin_path); | 262 for (BrowserChildProcessHost::Iterator iter( |
| 263 ChildProcessInfo::PPAPI_PLUGIN_PROCESS); |
| 264 !iter.Done(); ++iter) { |
| 265 PpapiPluginProcessHost* plugin = |
| 266 static_cast<PpapiPluginProcessHost*>(*iter); |
| 267 if (plugin->plugin_path() == plugin_path) |
| 268 return plugin; |
| 269 } |
| 270 |
| 271 return NULL; |
| 272 } |
| 273 |
| 274 PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess( |
| 275 const FilePath& plugin_path) { |
| 276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 277 |
| 278 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path); |
| 262 if (plugin_host) | 279 if (plugin_host) |
| 263 return plugin_host; | 280 return plugin_host; |
| 264 | 281 |
| 265 webkit::npapi::WebPluginInfo info; | 282 webkit::npapi::WebPluginInfo info; |
| 266 if (!webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath( | 283 if (!webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath( |
| 267 plugin_path, &info)) { | 284 plugin_path, &info)) { |
| 268 return NULL; | 285 return NULL; |
| 269 } | 286 } |
| 270 | 287 |
| 271 // This plugin isn't loaded by any plugin process, so create a new process. | 288 // This plugin isn't loaded by any plugin process, so create a new process. |
| 272 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost()); | 289 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost()); |
| 273 if (!new_host->Init(info, ui_locale_)) { | 290 if (!new_host->Init(info, ui_locale_)) { |
| 274 NOTREACHED(); // Init is not expected to fail | 291 NOTREACHED(); // Init is not expected to fail. |
| 275 return NULL; | 292 return NULL; |
| 276 } | 293 } |
| 277 | |
| 278 return new_host.release(); | 294 return new_host.release(); |
| 279 } | 295 } |
| 280 | 296 |
| 281 void PluginService::OpenChannelToPlugin( | 297 PpapiPluginProcessHost* PluginService::FindOrStartPpapiPluginProcess( |
| 298 const FilePath& plugin_path) { |
| 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 300 |
| 301 PpapiPluginProcessHost* plugin_host = FindPpapiPluginProcess(plugin_path); |
| 302 if (plugin_host) |
| 303 return plugin_host; |
| 304 |
| 305 // Validate that the plugin is actually registered. There should generally |
| 306 // be very few plugins so a brute-force search is fine. |
| 307 PepperPluginInfo* info = NULL; |
| 308 for (size_t i = 0; i < ppapi_plugins_.size(); i++) { |
| 309 if (ppapi_plugins_[i].path == plugin_path) { |
| 310 info = &ppapi_plugins_[i]; |
| 311 break; |
| 312 } |
| 313 } |
| 314 if (!info) |
| 315 return NULL; |
| 316 |
| 317 // This plugin isn't loaded by any plugin process, so create a new process. |
| 318 scoped_ptr<PpapiPluginProcessHost> new_host(new PpapiPluginProcessHost); |
| 319 if (!new_host->Init(plugin_path)) { |
| 320 NOTREACHED(); // Init is not expected to fail. |
| 321 return NULL; |
| 322 } |
| 323 return new_host.release(); |
| 324 } |
| 325 |
| 326 void PluginService::OpenChannelToNpapiPlugin( |
| 282 int render_process_id, | 327 int render_process_id, |
| 283 int render_view_id, | 328 int render_view_id, |
| 284 const GURL& url, | 329 const GURL& url, |
| 285 const std::string& mime_type, | 330 const std::string& mime_type, |
| 286 PluginProcessHost::Client* client) { | 331 PluginProcessHost::Client* client) { |
| 287 // The PluginList::GetFirstAllowedPluginInfo may need to load the | 332 // The PluginList::GetFirstAllowedPluginInfo may need to load the |
| 288 // plugins. Don't do it on the IO thread. | 333 // plugins. Don't do it on the IO thread. |
| 289 BrowserThread::PostTask( | 334 BrowserThread::PostTask( |
| 290 BrowserThread::FILE, FROM_HERE, | 335 BrowserThread::FILE, FROM_HERE, |
| 291 NewRunnableMethod( | 336 NewRunnableMethod( |
| 292 this, &PluginService::GetAllowedPluginForOpenChannelToPlugin, | 337 this, &PluginService::GetAllowedPluginForOpenChannelToPlugin, |
| 293 render_process_id, render_view_id, url, mime_type, client)); | 338 render_process_id, render_view_id, url, mime_type, client)); |
| 294 } | 339 } |
| 295 | 340 |
| 341 void PluginService::OpenChannelToPpapiPlugin( |
| 342 const FilePath& path, |
| 343 PpapiPluginProcessHost::Client* client) { |
| 344 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(path); |
| 345 if (plugin_host) |
| 346 plugin_host->OpenChannelToPlugin(client); |
| 347 else // Send error. |
| 348 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle()); |
| 349 } |
| 350 |
| 296 void PluginService::GetAllowedPluginForOpenChannelToPlugin( | 351 void PluginService::GetAllowedPluginForOpenChannelToPlugin( |
| 297 int render_process_id, | 352 int render_process_id, |
| 298 int render_view_id, | 353 int render_view_id, |
| 299 const GURL& url, | 354 const GURL& url, |
| 300 const std::string& mime_type, | 355 const std::string& mime_type, |
| 301 PluginProcessHost::Client* client) { | 356 PluginProcessHost::Client* client) { |
| 302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 303 webkit::npapi::WebPluginInfo info; | 358 webkit::npapi::WebPluginInfo info; |
| 304 bool found = GetFirstAllowedPluginInfo( | 359 bool found = GetFirstAllowedPluginInfo( |
| 305 render_process_id, render_view_id, url, mime_type, &info, NULL); | 360 render_process_id, render_view_id, url, mime_type, &info, NULL); |
| 306 FilePath plugin_path; | 361 FilePath plugin_path; |
| 307 if (found && webkit::npapi::IsPluginEnabled(info)) | 362 if (found && webkit::npapi::IsPluginEnabled(info)) |
| 308 plugin_path = FilePath(info.path); | 363 plugin_path = FilePath(info.path); |
| 309 | 364 |
| 310 // Now we jump back to the IO thread to finish opening the channel. | 365 // Now we jump back to the IO thread to finish opening the channel. |
| 311 BrowserThread::PostTask( | 366 BrowserThread::PostTask( |
| 312 BrowserThread::IO, FROM_HERE, | 367 BrowserThread::IO, FROM_HERE, |
| 313 NewRunnableMethod( | 368 NewRunnableMethod( |
| 314 this, &PluginService::FinishOpenChannelToPlugin, | 369 this, &PluginService::FinishOpenChannelToPlugin, |
| 315 plugin_path, client)); | 370 plugin_path, client)); |
| 316 } | 371 } |
| 317 | 372 |
| 318 void PluginService::FinishOpenChannelToPlugin( | 373 void PluginService::FinishOpenChannelToPlugin( |
| 319 const FilePath& plugin_path, | 374 const FilePath& plugin_path, |
| 320 PluginProcessHost::Client* client) { | 375 PluginProcessHost::Client* client) { |
| 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 322 | 377 |
| 323 PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path); | 378 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path); |
| 324 if (plugin_host) | 379 if (plugin_host) |
| 325 plugin_host->OpenChannelToPlugin(client); | 380 plugin_host->OpenChannelToPlugin(client); |
| 326 else | 381 else |
| 327 client->OnError(); | 382 client->OnError(); |
| 328 } | 383 } |
| 329 | 384 |
| 330 bool PluginService::GetFirstAllowedPluginInfo( | 385 bool PluginService::GetFirstAllowedPluginInfo( |
| 331 int render_process_id, | 386 int render_process_id, |
| 332 int render_view_id, | 387 int render_view_id, |
| 333 const GURL& url, | 388 const GURL& url, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); | 440 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); |
| 386 PurgePluginListCache(true); | 441 PurgePluginListCache(true); |
| 387 #else | 442 #else |
| 388 // This event should only get signaled on a Windows machine. | 443 // This event should only get signaled on a Windows machine. |
| 389 NOTREACHED(); | 444 NOTREACHED(); |
| 390 #endif // defined(OS_WIN) | 445 #endif // defined(OS_WIN) |
| 391 } | 446 } |
| 392 | 447 |
| 393 static void ForceShutdownPlugin(const FilePath& plugin_path) { | 448 static void ForceShutdownPlugin(const FilePath& plugin_path) { |
| 394 PluginProcessHost* plugin = | 449 PluginProcessHost* plugin = |
| 395 PluginService::GetInstance()->FindPluginProcess(plugin_path); | 450 PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path); |
| 396 if (plugin) | 451 if (plugin) |
| 397 plugin->ForceShutdown(); | 452 plugin->ForceShutdown(); |
| 398 } | 453 } |
| 399 | 454 |
| 400 void PluginService::Observe(NotificationType type, | 455 void PluginService::Observe(NotificationType type, |
| 401 const NotificationSource& source, | 456 const NotificationSource& source, |
| 402 const NotificationDetails& details) { | 457 const NotificationDetails& details) { |
| 403 switch (type.value) { | 458 switch (type.value) { |
| 404 case NotificationType::EXTENSION_LOADED: { | 459 case NotificationType::EXTENSION_LOADED: { |
| 405 const Extension* extension = Details<const Extension>(details).ptr(); | 460 const Extension* extension = Details<const Extension>(details).ptr(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 return (url.scheme() == required_url.scheme() && | 538 return (url.scheme() == required_url.scheme() && |
| 484 url.host() == required_url.host()); | 539 url.host() == required_url.host()); |
| 485 } | 540 } |
| 486 | 541 |
| 487 void PluginService::OverridePluginForTab(OverriddenPlugin plugin) { | 542 void PluginService::OverridePluginForTab(OverriddenPlugin plugin) { |
| 488 base::AutoLock auto_lock(overridden_plugins_lock_); | 543 base::AutoLock auto_lock(overridden_plugins_lock_); |
| 489 overridden_plugins_.push_back(plugin); | 544 overridden_plugins_.push_back(plugin); |
| 490 } | 545 } |
| 491 | 546 |
| 492 void PluginService::RegisterPepperPlugins() { | 547 void PluginService::RegisterPepperPlugins() { |
| 493 std::vector<PepperPluginInfo> plugins; | 548 PepperPluginRegistry::ComputeList(&ppapi_plugins_); |
| 494 PepperPluginRegistry::ComputeList(&plugins); | 549 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) { |
| 495 for (size_t i = 0; i < plugins.size(); ++i) { | |
| 496 webkit::npapi::WebPluginInfo info; | 550 webkit::npapi::WebPluginInfo info; |
| 497 info.path = plugins[i].path; | 551 info.path = ppapi_plugins_[i].path; |
| 498 info.name = plugins[i].name.empty() ? | 552 info.name = ppapi_plugins_[i].name.empty() ? |
| 499 plugins[i].path.BaseName().LossyDisplayName() : | 553 ppapi_plugins_[i].path.BaseName().LossyDisplayName() : |
| 500 ASCIIToUTF16(plugins[i].name); | 554 ASCIIToUTF16(ppapi_plugins_[i].name); |
| 501 info.desc = ASCIIToUTF16(plugins[i].description); | 555 info.desc = ASCIIToUTF16(ppapi_plugins_[i].description); |
| 502 info.enabled = webkit::npapi::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED; | 556 info.enabled = webkit::npapi::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED; |
| 503 | 557 |
| 504 // TODO(evan): Pepper shouldn't require us to parse strings to get | 558 // TODO(evan): Pepper shouldn't require us to parse strings to get |
| 505 // the list of mime types out. | 559 // the list of mime types out. |
| 506 if (!webkit::npapi::PluginList::ParseMimeTypes( | 560 if (!webkit::npapi::PluginList::ParseMimeTypes( |
| 507 JoinString(plugins[i].mime_types, '|'), | 561 JoinString(ppapi_plugins_[i].mime_types, '|'), |
| 508 plugins[i].file_extensions, | 562 ppapi_plugins_[i].file_extensions, |
| 509 ASCIIToUTF16(plugins[i].type_descriptions), | 563 ASCIIToUTF16(ppapi_plugins_[i].type_descriptions), |
| 510 &info.mime_types)) { | 564 &info.mime_types)) { |
| 511 LOG(ERROR) << "Error parsing mime types for " | 565 LOG(ERROR) << "Error parsing mime types for " |
| 512 << plugins[i].path.LossyDisplayName(); | 566 << ppapi_plugins_[i].path.LossyDisplayName(); |
| 513 return; | 567 return; |
| 514 } | 568 } |
| 515 | 569 |
| 516 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info); | 570 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info); |
| 517 } | 571 } |
| 518 } | 572 } |
| 519 | 573 |
| 520 #if defined(OS_LINUX) | 574 #if defined(OS_LINUX) |
| 521 // static | 575 // static |
| 522 void PluginService::RegisterFilePathWatcher( | 576 void PluginService::RegisterFilePathWatcher( |
| 523 FilePathWatcher *watcher, | 577 FilePathWatcher *watcher, |
| 524 const FilePath& path, | 578 const FilePath& path, |
| 525 FilePathWatcher::Delegate* delegate) { | 579 FilePathWatcher::Delegate* delegate) { |
| 526 bool result = watcher->Watch(path, delegate); | 580 bool result = watcher->Watch(path, delegate); |
| 527 DCHECK(result); | 581 DCHECK(result); |
| 528 } | 582 } |
| 529 #endif | 583 #endif |
| OLD | NEW |