Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "build/build_config.h" | 5 #include "build/build_config.h" |
| 6 | 6 |
| 7 #include "chrome/browser/plugin_service.h" | 7 #include "chrome/browser/plugin_service.h" |
| 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/stl_util-inl.h" | |
| 11 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 12 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
| 13 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
| 14 #include "base/values.h" | 15 #include "base/values.h" |
| 15 #include "base/synchronization/waitable_event.h" | 16 #include "base/synchronization/waitable_event.h" |
| 16 #include "chrome/browser/browser_process.h" | 17 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/browser_thread.h" | 18 #include "chrome/browser/browser_thread.h" |
| 18 #include "chrome/browser/chrome_plugin_host.h" | 19 #include "chrome/browser/chrome_plugin_host.h" |
| 19 #include "chrome/browser/extensions/extension_service.h" | 20 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/plugin_updater.h" | 21 #include "chrome/browser/plugin_updater.h" |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 52 | 53 |
| 53 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); | 54 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); |
| 54 !iter.Done(); ++iter) { | 55 !iter.Done(); ++iter) { |
| 55 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); | 56 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); |
| 56 plugin->OnAppActivation(); | 57 plugin->OnAppActivation(); |
| 57 } | 58 } |
| 58 } | 59 } |
| 59 #endif | 60 #endif |
| 60 | 61 |
| 62 static void PurgePluginListCache(bool reload_pages) { | |
| 63 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); | |
| 64 !it.IsAtEnd(); it.Advance()) { | |
| 65 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages)); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 // Delegate class for monitoring directories. | |
| 70 class PluginDirWatcherDelegate : public FilePathWatcher::Delegate { | |
| 71 virtual void OnFilePathChanged(const FilePath& path) { | |
| 72 VLOG(1) << "Watched path changed: " << path.value(); | |
| 73 | |
| 74 // Make the plugin list update itself | |
| 75 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); | |
|
pastarmovj
2011/01/12 16:51:09
Problem here was that PurgePluginCache can be exec
| |
| 76 } | |
| 77 virtual void OnError() { | |
| 78 // TODO(pastarmovj): Add some sensible error handling. Maybe silently | |
| 79 // stopping the watcher would be enough. Or possibly restart it. | |
| 80 NOTREACHED(); | |
| 81 } | |
| 82 }; | |
| 83 | |
| 61 // static | 84 // static |
| 62 bool PluginService::enable_chrome_plugins_ = true; | 85 bool PluginService::enable_chrome_plugins_ = true; |
| 63 | 86 |
| 64 // static | 87 // static |
| 65 void PluginService::InitGlobalInstance(Profile* profile) { | 88 void PluginService::InitGlobalInstance(Profile* profile) { |
| 66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 67 | 90 |
| 68 // We first group the plugins and then figure out which groups to disable. | 91 // We first group the plugins and then figure out which groups to disable. |
| 69 PluginUpdater::GetInstance()->DisablePluginGroupsFromPrefs(profile); | 92 PluginUpdater::GetInstance()->DisablePluginGroupsFromPrefs(profile); |
| 70 | 93 |
| 71 // Have Chrome plugins write their data to the profile directory. | 94 // Have Chrome plugins write their data to the profile directory. |
| 72 GetInstance()->SetChromePluginDataDir(profile->GetPath()); | 95 GetInstance()->SetChromePluginDataDir(profile->GetPath()); |
| 73 } | 96 } |
| 74 | 97 |
| 75 // static | 98 // static |
| 76 PluginService* PluginService::GetInstance() { | 99 PluginService* PluginService::GetInstance() { |
| 77 return Singleton<PluginService>::get(); | 100 return Singleton<PluginService>::get(); |
| 78 } | 101 } |
| 79 | 102 |
| 80 // static | 103 // static |
| 81 void PluginService::EnableChromePlugins(bool enable) { | 104 void PluginService::EnableChromePlugins(bool enable) { |
| 82 enable_chrome_plugins_ = enable; | 105 enable_chrome_plugins_ = enable; |
| 83 } | 106 } |
| 84 | 107 |
| 85 PluginService::PluginService() | 108 PluginService::PluginService() |
| 86 : main_message_loop_(MessageLoop::current()), | 109 : main_message_loop_(MessageLoop::current()), |
| 87 resource_dispatcher_host_(NULL), | 110 resource_dispatcher_host_(NULL), |
| 88 ui_locale_(g_browser_process->GetApplicationLocale()) { | 111 ui_locale_(g_browser_process->GetApplicationLocale()), |
| 112 file_watcher_delegate_(new PluginDirWatcherDelegate()) { | |
| 89 RegisterPepperPlugins(); | 113 RegisterPepperPlugins(); |
| 90 | 114 |
| 91 // Have the NPAPI plugin list search for Chrome plugins as well. | 115 // Have the NPAPI plugin list search for Chrome plugins as well. |
| 92 ChromePluginLib::RegisterPluginsWithNPAPI(); | 116 ChromePluginLib::RegisterPluginsWithNPAPI(); |
| 93 | 117 |
| 94 // Load any specified on the command line as well. | 118 // Load any specified on the command line as well. |
| 95 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | 119 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 96 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin); | 120 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin); |
| 97 if (!path.empty()) | 121 if (!path.empty()) |
| 98 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path); | 122 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 115 } | 139 } |
| 116 #endif | 140 #endif |
| 117 | 141 |
| 118 #if defined(OS_CHROMEOS) | 142 #if defined(OS_CHROMEOS) |
| 119 plugin_selection_policy_ = new chromeos::PluginSelectionPolicy; | 143 plugin_selection_policy_ = new chromeos::PluginSelectionPolicy; |
| 120 plugin_selection_policy_->StartInit(); | 144 plugin_selection_policy_->StartInit(); |
| 121 #endif | 145 #endif |
| 122 | 146 |
| 123 chrome::RegisterInternalGPUPlugin(); | 147 chrome::RegisterInternalGPUPlugin(); |
| 124 | 148 |
| 149 // Start watching for changes in the plugin list. This means watching | |
| 150 // for changes in the Windows registry keys and on both Windows and POSIX | |
| 151 // watch for changes in the paths that are expected to contain plugins. | |
| 125 #if defined(OS_WIN) | 152 #if defined(OS_WIN) |
| 126 hkcu_key_.Create( | 153 hkcu_key_.Create( |
| 127 HKEY_CURRENT_USER, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY); | 154 HKEY_CURRENT_USER, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY); |
| 128 hklm_key_.Create( | 155 hklm_key_.Create( |
| 129 HKEY_LOCAL_MACHINE, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY); | 156 HKEY_LOCAL_MACHINE, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY); |
| 130 if (hkcu_key_.StartWatching()) { | 157 if (hkcu_key_.StartWatching()) { |
| 131 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event())); | 158 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event())); |
| 132 hkcu_watcher_.StartWatching(hkcu_event_.get(), this); | 159 hkcu_watcher_.StartWatching(hkcu_event_.get(), this); |
| 133 } | 160 } |
| 134 | 161 |
| 135 if (hklm_key_.StartWatching()) { | 162 if (hklm_key_.StartWatching()) { |
| 136 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event())); | 163 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event())); |
| 137 hklm_watcher_.StartWatching(hklm_event_.get(), this); | 164 hklm_watcher_.StartWatching(hklm_event_.get(), this); |
| 138 } | 165 } |
| 139 #elif defined(OS_POSIX) && !defined(OS_MACOSX) | 166 #elif defined(OS_POSIX) && !defined(OS_MACOSX) |
| 140 // Also find plugins in a user-specific plugins dir, | 167 // Also find plugins in a user-specific plugins dir, |
| 141 // e.g. ~/.config/chromium/Plugins. | 168 // e.g. ~/.config/chromium/Plugins. |
| 142 FilePath user_data_dir; | 169 FilePath user_data_dir; |
| 143 if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) { | 170 if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) { |
| 144 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir( | 171 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir( |
| 145 user_data_dir.Append("Plugins")); | 172 user_data_dir.Append("Plugins")); |
| 146 } | 173 } |
| 147 #endif | 174 #endif |
| 175 // Get the list of all paths for registering the FilePathWatchers | |
| 176 // that will track and if needed reload the list of plugins on runtime. | |
| 177 std::vector<FilePath> plugin_dirs; | |
| 178 webkit::npapi::PluginList::Singleton()->GetPluginDirectories( | |
| 179 &plugin_dirs); | |
| 180 | |
| 181 for (size_t i = 0; i < plugin_dirs.size(); ++i) { | |
| 182 FilePathWatcher* watcher = new FilePathWatcher(); | |
| 183 // FilePathWatcher can not handle non-absolute paths under windows. | |
| 184 #if defined(OS_WIN) | |
| 185 if(!plugin_dirs[i].IsAbsolute()) | |
| 186 continue; | |
| 187 #endif | |
| 188 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value(); | |
| 189 BrowserThread::PostTask( | |
| 190 BrowserThread::FILE, FROM_HERE, | |
| 191 NewRunnableFunction( | |
| 192 &PluginService::RegisterFilePathWatcher, | |
| 193 watcher, plugin_dirs[i], file_watcher_delegate_)); | |
| 194 file_watchers_.push_back(watcher); | |
| 195 } | |
| 148 | 196 |
| 149 registrar_.Add(this, NotificationType::EXTENSION_LOADED, | 197 registrar_.Add(this, NotificationType::EXTENSION_LOADED, |
| 150 NotificationService::AllSources()); | 198 NotificationService::AllSources()); |
| 151 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, | 199 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, |
| 152 NotificationService::AllSources()); | 200 NotificationService::AllSources()); |
| 153 #if defined(OS_MACOSX) | 201 #if defined(OS_MACOSX) |
| 154 // We need to know when the browser comes forward so we can bring modal plugin | 202 // We need to know when the browser comes forward so we can bring modal plugin |
| 155 // windows forward too. | 203 // windows forward too. |
| 156 registrar_.Add(this, NotificationType::APP_ACTIVATED, | 204 registrar_.Add(this, NotificationType::APP_ACTIVATED, |
| 157 NotificationService::AllSources()); | 205 NotificationService::AllSources()); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 297 *actual_mime_type = actual_mime_types[allowed_index]; | 345 *actual_mime_type = actual_mime_types[allowed_index]; |
| 298 return true; | 346 return true; |
| 299 } | 347 } |
| 300 return false; | 348 return false; |
| 301 #else | 349 #else |
| 302 return webkit::npapi::PluginList::Singleton()->GetPluginInfo( | 350 return webkit::npapi::PluginList::Singleton()->GetPluginInfo( |
| 303 url, mime_type, allow_wildcard, info, actual_mime_type); | 351 url, mime_type, allow_wildcard, info, actual_mime_type); |
| 304 #endif | 352 #endif |
| 305 } | 353 } |
| 306 | 354 |
| 307 static void PurgePluginListCache(bool reload_pages) { | |
| 308 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator(); | |
| 309 !it.IsAtEnd(); it.Advance()) { | |
| 310 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages)); | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 void PluginService::OnWaitableEventSignaled( | 355 void PluginService::OnWaitableEventSignaled( |
| 315 base::WaitableEvent* waitable_event) { | 356 base::WaitableEvent* waitable_event) { |
| 316 #if defined(OS_WIN) | 357 #if defined(OS_WIN) |
| 317 if (waitable_event == hkcu_event_.get()) { | 358 if (waitable_event == hkcu_event_.get()) { |
| 318 hkcu_key_.StartWatching(); | 359 hkcu_key_.StartWatching(); |
| 319 } else { | 360 } else { |
| 320 hklm_key_.StartWatching(); | 361 hklm_key_.StartWatching(); |
| 321 } | 362 } |
| 322 | 363 |
| 323 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); | 364 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); |
| 324 PurgePluginListCache(true); | 365 PurgePluginListCache(true); |
|
pastarmovj
2011/01/12 16:51:09
I can imagine this will lead to the same problem (
| |
| 366 #else | |
| 367 // This event should only get signaled on a Windows machine. | |
| 368 NOTREACHED(); | |
| 325 #endif // defined(OS_WIN) | 369 #endif // defined(OS_WIN) |
| 326 } | 370 } |
| 327 | 371 |
| 328 static void ForceShutdownPlugin(const FilePath& plugin_path) { | 372 static void ForceShutdownPlugin(const FilePath& plugin_path) { |
| 329 PluginProcessHost* plugin = | 373 PluginProcessHost* plugin = |
| 330 PluginService::GetInstance()->FindPluginProcess(plugin_path); | 374 PluginService::GetInstance()->FindPluginProcess(plugin_path); |
| 331 if (plugin) | 375 if (plugin) |
| 332 plugin->ForceShutdown(); | 376 plugin->ForceShutdown(); |
| 333 } | 377 } |
| 334 | 378 |
| 335 void PluginService::Observe(NotificationType type, | 379 void PluginService::Observe(NotificationType type, |
| 336 const NotificationSource& source, | 380 const NotificationSource& source, |
| 337 const NotificationDetails& details) { | 381 const NotificationDetails& details) { |
| 338 switch (type.value) { | 382 switch (type.value) { |
| 339 case NotificationType::EXTENSION_LOADED: { | 383 case NotificationType::EXTENSION_LOADED: { |
| 340 const Extension* extension = Details<const Extension>(details).ptr(); | 384 const Extension* extension = Details<const Extension>(details).ptr(); |
| 341 bool plugins_changed = false; | 385 bool plugins_changed = false; |
| 342 for (size_t i = 0; i < extension->plugins().size(); ++i) { | 386 for (size_t i = 0; i < extension->plugins().size(); ++i) { |
| 343 const Extension::PluginInfo& plugin = extension->plugins()[i]; | 387 const Extension::PluginInfo& plugin = extension->plugins()[i]; |
| 344 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); | 388 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); |
| 345 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path); | 389 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path); |
| 346 plugins_changed = true; | 390 plugins_changed = true; |
| 347 if (!plugin.is_public) | 391 if (!plugin.is_public) |
| 348 private_plugins_[plugin.path] = extension->url(); | 392 private_plugins_[plugin.path] = extension->url(); |
| 349 } | 393 } |
| 350 if (plugins_changed) | 394 if (plugins_changed) |
| 351 PurgePluginListCache(false); | 395 PurgePluginListCache(false); |
|
pastarmovj
2011/01/12 16:51:09
Dito.
| |
| 352 break; | 396 break; |
| 353 } | 397 } |
| 354 | 398 |
| 355 case NotificationType::EXTENSION_UNLOADED: { | 399 case NotificationType::EXTENSION_UNLOADED: { |
| 356 const Extension* extension = | 400 const Extension* extension = |
| 357 Details<UnloadedExtensionInfo>(details)->extension; | 401 Details<UnloadedExtensionInfo>(details)->extension; |
| 358 bool plugins_changed = false; | 402 bool plugins_changed = false; |
| 359 for (size_t i = 0; i < extension->plugins().size(); ++i) { | 403 for (size_t i = 0; i < extension->plugins().size(); ++i) { |
| 360 const Extension::PluginInfo& plugin = extension->plugins()[i]; | 404 const Extension::PluginInfo& plugin = extension->plugins()[i]; |
| 361 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 405 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 362 NewRunnableFunction(&ForceShutdownPlugin, | 406 NewRunnableFunction(&ForceShutdownPlugin, |
| 363 plugin.path)); | 407 plugin.path)); |
| 364 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); | 408 webkit::npapi::PluginList::Singleton()->RefreshPlugins(); |
| 365 webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath( | 409 webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath( |
| 366 plugin.path); | 410 plugin.path); |
| 367 plugins_changed = true; | 411 plugins_changed = true; |
| 368 if (!plugin.is_public) | 412 if (!plugin.is_public) |
| 369 private_plugins_.erase(plugin.path); | 413 private_plugins_.erase(plugin.path); |
| 370 } | 414 } |
| 371 if (plugins_changed) | 415 if (plugins_changed) |
| 372 PurgePluginListCache(false); | 416 PurgePluginListCache(false); |
|
pastarmovj
2011/01/12 16:51:09
Dito.
| |
| 373 break; | 417 break; |
| 374 } | 418 } |
| 375 | 419 |
| 376 #if defined(OS_MACOSX) | 420 #if defined(OS_MACOSX) |
| 377 case NotificationType::APP_ACTIVATED: { | 421 case NotificationType::APP_ACTIVATED: { |
| 378 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 422 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 379 NewRunnableFunction(&NotifyPluginsOfActivation)); | 423 NewRunnableFunction(&NotifyPluginsOfActivation)); |
| 380 break; | 424 break; |
| 381 } | 425 } |
| 382 #endif | 426 #endif |
| 383 | 427 |
| 384 case NotificationType::PLUGIN_ENABLE_STATUS_CHANGED: { | 428 case NotificationType::PLUGIN_ENABLE_STATUS_CHANGED: { |
| 385 PurgePluginListCache(false); | 429 PurgePluginListCache(false); |
|
pastarmovj
2011/01/12 16:51:09
Dito. Here we need additional RefreshPlugins call
| |
| 386 break; | 430 break; |
| 387 } | 431 } |
| 388 default: | 432 default: |
| 389 DCHECK(false); | 433 NOTREACHED(); |
| 390 } | 434 } |
| 391 } | 435 } |
| 392 | 436 |
| 393 bool PluginService::PrivatePluginAllowedForURL(const FilePath& plugin_path, | 437 bool PluginService::PrivatePluginAllowedForURL(const FilePath& plugin_path, |
| 394 const GURL& url) { | 438 const GURL& url) { |
| 395 if (url.is_empty()) | 439 if (url.is_empty()) |
| 396 return true; // Caller wants all plugins. | 440 return true; // Caller wants all plugins. |
| 397 | 441 |
| 398 PrivatePluginMap::iterator it = private_plugins_.find(plugin_path); | 442 PrivatePluginMap::iterator it = private_plugins_.find(plugin_path); |
| 399 if (it == private_plugins_.end()) | 443 if (it == private_plugins_.end()) |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 421 info.mime_types = ASCIIToWide(JoinString(plugins[i].mime_types, '|')); | 465 info.mime_types = ASCIIToWide(JoinString(plugins[i].mime_types, '|')); |
| 422 | 466 |
| 423 // These NPAPI entry points will never be called. TODO(darin): Come up | 467 // These NPAPI entry points will never be called. TODO(darin): Come up |
| 424 // with a cleaner way to register pepper plugins with the NPAPI PluginList, | 468 // with a cleaner way to register pepper plugins with the NPAPI PluginList, |
| 425 // or perhaps refactor the PluginList to be less specific to NPAPI. | 469 // or perhaps refactor the PluginList to be less specific to NPAPI. |
| 426 memset(&info.entry_points, 0, sizeof(info.entry_points)); | 470 memset(&info.entry_points, 0, sizeof(info.entry_points)); |
| 427 | 471 |
| 428 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info); | 472 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info); |
| 429 } | 473 } |
| 430 } | 474 } |
| 475 | |
| 476 // static | |
| 477 void PluginService::RegisterFilePathWatcher( | |
| 478 FilePathWatcher *watcher, | |
| 479 const FilePath& path, | |
| 480 FilePathWatcher::Delegate* delegate) { | |
| 481 bool result = watcher->Watch(path, delegate); | |
| 482 DCHECK(result); | |
| 483 } | |
| OLD | NEW |