| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/singleton.h" | |
| 9 #include "base/thread.h" | 8 #include "base/thread.h" |
| 10 #include "chrome/browser/browser_process.h" | 9 #include "chrome/browser/browser_process.h" |
| 11 #include "chrome/browser/chrome_plugin_host.h" | 10 #include "chrome/browser/chrome_plugin_host.h" |
| 12 #include "chrome/browser/chrome_thread.h" | 11 #include "chrome/browser/chrome_thread.h" |
| 13 #include "chrome/browser/plugin_process_host.h" | 12 #include "chrome/browser/plugin_process_host.h" |
| 14 #include "chrome/browser/renderer_host/render_process_host.h" | 13 #include "chrome/browser/renderer_host/render_process_host.h" |
| 15 #include "chrome/browser/renderer_host/resource_message_filter.h" | 14 #include "chrome/browser/renderer_host/resource_message_filter.h" |
| 16 #include "chrome/common/chrome_plugin_lib.h" | 15 #include "chrome/common/chrome_plugin_lib.h" |
| 17 #include "chrome/common/chrome_switches.h" | 16 #include "chrome/common/chrome_switches.h" |
| 18 #include "chrome/common/logging_chrome.h" | 17 #include "chrome/common/logging_chrome.h" |
| 19 #include "webkit/glue/plugins/plugin_list.h" | 18 #include "webkit/glue/plugins/plugin_list.h" |
| 20 | 19 |
| 21 // static | 20 // static |
| 22 PluginService* PluginService::GetInstance() { | 21 PluginService* PluginService::GetInstance() { |
| 23 return Singleton<PluginService>::get(); | 22 return Singleton<PluginService>::get(); |
| 24 } | 23 } |
| 25 | 24 |
| 26 PluginService::PluginService() | 25 PluginService::PluginService() |
| 27 : main_message_loop_(MessageLoop::current()), | 26 : main_message_loop_(MessageLoop::current()), |
| 28 resource_dispatcher_host_(NULL), | 27 resource_dispatcher_host_(NULL), |
| 29 ui_locale_(g_browser_process->GetApplicationLocale()), | 28 ui_locale_(g_browser_process->GetApplicationLocale()), |
| 30 plugin_shutdown_handler_(new ShutdownHandler) { | 29 plugin_shutdown_handler_(new ShutdownHandler) { |
| 31 // Have the NPAPI plugin list search for Chrome plugins as well. | 30 // Have the NPAPI plugin list search for Chrome plugins as well. |
| 32 ChromePluginLib::RegisterPluginsWithNPAPI(); | 31 ChromePluginLib::RegisterPluginsWithNPAPI(); |
| 33 | |
| 34 // Load the one specified on the command line as well. | 32 // Load the one specified on the command line as well. |
| 35 const CommandLine* command_line = CommandLine::ForCurrentProcess(); | 33 const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 36 std::wstring path = command_line->GetSwitchValue(switches::kLoadPlugin); | 34 std::wstring path = command_line->GetSwitchValue(switches::kLoadPlugin); |
| 37 if (!path.empty()) | 35 if (!path.empty()) |
| 38 NPAPI::PluginList::AddExtraPluginPath(FilePath::FromWStringHack(path)); | 36 NPAPI::PluginList::AddExtraPluginPath(FilePath::FromWStringHack(path)); |
| 39 } | 37 } |
| 40 | 38 |
| 41 PluginService::~PluginService() { | 39 PluginService::~PluginService() { |
| 42 } | 40 } |
| 43 | 41 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 70 PluginProcessHost* PluginService::FindPluginProcess( | 68 PluginProcessHost* PluginService::FindPluginProcess( |
| 71 const FilePath& plugin_path) { | 69 const FilePath& plugin_path) { |
| 72 DCHECK(MessageLoop::current() == | 70 DCHECK(MessageLoop::current() == |
| 73 ChromeThread::GetMessageLoop(ChromeThread::IO)); | 71 ChromeThread::GetMessageLoop(ChromeThread::IO)); |
| 74 | 72 |
| 75 if (plugin_path.value().empty()) { | 73 if (plugin_path.value().empty()) { |
| 76 NOTREACHED() << "should only be called if we have a plugin to load"; | 74 NOTREACHED() << "should only be called if we have a plugin to load"; |
| 77 return NULL; | 75 return NULL; |
| 78 } | 76 } |
| 79 | 77 |
| 80 PluginMap::iterator found = plugin_hosts_.find(plugin_path); | 78 for (ChildProcessInfo::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); |
| 81 if (found != plugin_hosts_.end()) | 79 !iter.Done(); ++iter) { |
| 82 return found->second; | 80 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter); |
| 81 if (plugin->info().path == plugin_path) |
| 82 return plugin; |
| 83 } |
| 84 |
| 83 return NULL; | 85 return NULL; |
| 84 } | 86 } |
| 85 | 87 |
| 86 PluginProcessHost* PluginService::FindOrStartPluginProcess( | 88 PluginProcessHost* PluginService::FindOrStartPluginProcess( |
| 87 const FilePath& plugin_path, | 89 const FilePath& plugin_path, |
| 88 const std::string& clsid) { | 90 const std::string& clsid) { |
| 89 DCHECK(MessageLoop::current() == | 91 DCHECK(MessageLoop::current() == |
| 90 ChromeThread::GetMessageLoop(ChromeThread::IO)); | 92 ChromeThread::GetMessageLoop(ChromeThread::IO)); |
| 91 | 93 |
| 92 PluginProcessHost *plugin_host = FindPluginProcess(plugin_path); | 94 PluginProcessHost *plugin_host = FindPluginProcess(plugin_path); |
| 93 if (plugin_host) | 95 if (plugin_host) |
| 94 return plugin_host; | 96 return plugin_host; |
| 95 | 97 |
| 96 WebPluginInfo info; | 98 WebPluginInfo info; |
| 97 if (!GetPluginInfoByPath(plugin_path, &info)) { | 99 if (!GetPluginInfoByPath(plugin_path, &info)) { |
| 98 DCHECK(false); | 100 DCHECK(false); |
| 99 return NULL; | 101 return NULL; |
| 100 } | 102 } |
| 101 | 103 |
| 102 // This plugin isn't loaded by any plugin process, so create a new process. | 104 // This plugin isn't loaded by any plugin process, so create a new process. |
| 103 plugin_host = new PluginProcessHost(this); | 105 plugin_host = new PluginProcessHost(); |
| 104 if (!plugin_host->Init(info, clsid, ui_locale_)) { | 106 if (!plugin_host->Init(info, clsid, ui_locale_)) { |
| 105 DCHECK(false); // Init is not expected to fail | 107 DCHECK(false); // Init is not expected to fail |
| 106 delete plugin_host; | 108 delete plugin_host; |
| 107 return NULL; | 109 return NULL; |
| 108 } | 110 } |
| 109 plugin_hosts_[plugin_path] = plugin_host; | 111 |
| 110 return plugin_host; | 112 return plugin_host; |
| 111 | 113 |
| 112 // TODO(jabdelmalek): adding a new channel means we can have one less | 114 // TODO(jabdelmalek): adding a new channel means we can have one less |
| 113 // renderer process (since each child process uses one handle in the | 115 // renderer process (since each child process uses one handle in the |
| 114 // IPC thread and main thread's WaitForMultipleObjects call). Limit the | 116 // IPC thread and main thread's WaitForMultipleObjects call). Limit the |
| 115 // number of plugin processes. | 117 // number of plugin processes. |
| 116 } | 118 } |
| 117 | 119 |
| 118 void PluginService::OpenChannelToPlugin( | 120 void PluginService::OpenChannelToPlugin( |
| 119 ResourceMessageFilter* renderer_msg_filter, const GURL& url, | 121 ResourceMessageFilter* renderer_msg_filter, const GURL& url, |
| 120 const std::string& mime_type, const std::string& clsid, | 122 const std::string& mime_type, const std::string& clsid, |
| 121 const std::wstring& locale, IPC::Message* reply_msg) { | 123 const std::wstring& locale, IPC::Message* reply_msg) { |
| 122 DCHECK(MessageLoop::current() == | 124 DCHECK(MessageLoop::current() == |
| 123 ChromeThread::GetMessageLoop(ChromeThread::IO)); | 125 ChromeThread::GetMessageLoop(ChromeThread::IO)); |
| 124 FilePath plugin_path = GetPluginPath(url, mime_type, clsid, NULL); | 126 FilePath plugin_path = GetPluginPath(url, mime_type, clsid, NULL); |
| 125 PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path, clsid); | 127 PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path, clsid); |
| 126 if (plugin_host) { | 128 if (plugin_host) { |
| 127 plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg); | 129 plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg); |
| 128 } else { | 130 } else { |
| 129 PluginProcessHost::ReplyToRenderer(renderer_msg_filter, | 131 PluginProcessHost::ReplyToRenderer(renderer_msg_filter, |
| 130 std::wstring(), | 132 std::wstring(), |
| 131 FilePath(), | 133 FilePath(), |
| 132 reply_msg); | 134 reply_msg); |
| 133 } | 135 } |
| 134 } | 136 } |
| 135 | 137 |
| 136 void PluginService::OnPluginProcessIsShuttingDown(PluginProcessHost* host) { | |
| 137 RemoveHost(host); | |
| 138 } | |
| 139 | |
| 140 void PluginService::OnPluginProcessExited(PluginProcessHost* host) { | |
| 141 RemoveHost(host); // in case shutdown was not graceful | |
| 142 delete host; | |
| 143 } | |
| 144 | |
| 145 void PluginService::RemoveHost(PluginProcessHost* host) { | |
| 146 DCHECK(MessageLoop::current() == | |
| 147 ChromeThread::GetMessageLoop(ChromeThread::IO)); | |
| 148 // Search for the instance rather than lookup by plugin path, | |
| 149 // there is a small window where two instances for the same | |
| 150 // plugin path can co-exists. | |
| 151 PluginMap::iterator i = plugin_hosts_.begin(); | |
| 152 while (i != plugin_hosts_.end()) { | |
| 153 if (i->second == host) { | |
| 154 plugin_hosts_.erase(i); | |
| 155 return; | |
| 156 } | |
| 157 i++; | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 FilePath PluginService::GetPluginPath(const GURL& url, | 138 FilePath PluginService::GetPluginPath(const GURL& url, |
| 162 const std::string& mime_type, | 139 const std::string& mime_type, |
| 163 const std::string& clsid, | 140 const std::string& clsid, |
| 164 std::string* actual_mime_type) { | 141 std::string* actual_mime_type) { |
| 165 AutoLock lock(lock_); | 142 AutoLock lock(lock_); |
| 166 bool allow_wildcard = true; | 143 bool allow_wildcard = true; |
| 167 WebPluginInfo info; | 144 WebPluginInfo info; |
| 168 NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid, | 145 NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid, |
| 169 allow_wildcard, &info, | 146 allow_wildcard, &info, |
| 170 actual_mime_type); | 147 actual_mime_type); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 186 return NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, "", | 163 return NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, "", |
| 187 allow_wildcard, &info, | 164 allow_wildcard, &info, |
| 188 NULL); | 165 NULL); |
| 189 } | 166 } |
| 190 | 167 |
| 191 void PluginService::Shutdown() { | 168 void PluginService::Shutdown() { |
| 192 plugin_shutdown_handler_->InitiateShutdown(); | 169 plugin_shutdown_handler_->InitiateShutdown(); |
| 193 } | 170 } |
| 194 | 171 |
| 195 void PluginService::OnShutdown() { | 172 void PluginService::OnShutdown() { |
| 196 PluginMap::iterator host_index; | 173 for (ChildProcessInfo::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS); |
| 197 for (host_index = plugin_hosts_.begin(); host_index != plugin_hosts_.end(); | 174 !iter.Done(); ++iter) { |
| 198 ++host_index) { | 175 static_cast<PluginProcessHost*>(*iter)->Shutdown(); |
| 199 host_index->second->Shutdown(); | |
| 200 } | 176 } |
| 201 } | 177 } |
| 202 | 178 |
| 203 PluginProcessHostIterator::PluginProcessHostIterator() | |
| 204 : iterator_(PluginService::GetInstance()->plugin_hosts_.begin()), | |
| 205 end_(PluginService::GetInstance()->plugin_hosts_.end()) { | |
| 206 DCHECK(MessageLoop::current() == | |
| 207 ChromeThread::GetMessageLoop(ChromeThread::IO)) << | |
| 208 "PluginProcessHostIterator must be used on the IO thread."; | |
| 209 } | |
| 210 | |
| 211 PluginProcessHostIterator::PluginProcessHostIterator( | |
| 212 const PluginProcessHostIterator& instance) | |
| 213 : iterator_(instance.iterator_) { | |
| 214 DCHECK(MessageLoop::current() == | |
| 215 ChromeThread::GetMessageLoop(ChromeThread::IO)) << | |
| 216 "PluginProcessHostIterator must be used on the IO thread."; | |
| 217 } | |
| 218 | |
| 219 void PluginService::ShutdownHandler::InitiateShutdown() { | 179 void PluginService::ShutdownHandler::InitiateShutdown() { |
| 220 g_browser_process->io_thread()->message_loop()->PostTask( | 180 g_browser_process->io_thread()->message_loop()->PostTask( |
| 221 FROM_HERE, | 181 FROM_HERE, |
| 222 NewRunnableMethod(this, &ShutdownHandler::OnShutdown)); | 182 NewRunnableMethod(this, &ShutdownHandler::OnShutdown)); |
| 223 } | 183 } |
| 224 | 184 |
| 225 void PluginService::ShutdownHandler::OnShutdown() { | 185 void PluginService::ShutdownHandler::OnShutdown() { |
| 226 PluginService* plugin_service = PluginService::GetInstance(); | 186 PluginService* plugin_service = PluginService::GetInstance(); |
| 227 if (plugin_service) { | 187 if (plugin_service) { |
| 228 plugin_service->OnShutdown(); | 188 plugin_service->OnShutdown(); |
| 229 } | 189 } |
| 230 } | 190 } |
| 231 | 191 |
| OLD | NEW |