blob: 8b5c979db67bf53a394be7c503a2d3a9d15f6d7d [file] [log] [blame]
initial.commit09911bf2008-07-26 23:55:291// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "chrome/browser/plugin_service.h"
31
32#include "base/singleton.h"
33#include "base/thread.h"
34#include "chrome/browser/browser_process.h"
35#include "chrome/browser/chrome_plugin_host.h"
36#include "chrome/browser/chrome_thread.h"
37#include "chrome/browser/plugin_process_host.h"
38#include "chrome/browser/render_process_host.h"
39#include "chrome/browser/resource_message_filter.h"
40#include "chrome/common/chrome_plugin_lib.h"
41#include "chrome/common/logging_chrome.h"
42#include "webkit/glue/plugins/plugin_list.h"
43
44// static
45PluginService* PluginService::GetInstance() {
46 return Singleton<PluginService>::get();
47}
48
49PluginService::PluginService()
50 : main_message_loop_(MessageLoop::current()),
51 ui_locale_(g_browser_process->GetApplicationLocale()),
52 resource_dispatcher_host_(NULL),
53 plugin_shutdown_handler_(new ShutdownHandler) {
54 // Have the NPAPI plugin list search for Chrome plugins as well.
55 ChromePluginLib::RegisterPluginsWithNPAPI();
56}
57
58PluginService::~PluginService() {
59}
60
61void PluginService::GetPlugins(bool refresh,
62 std::vector<WebPluginInfo>* plugins) {
63 AutoLock lock(lock_);
64 NPAPI::PluginList::Singleton()->GetPlugins(refresh, plugins);
65}
66
67void PluginService::LoadChromePlugins(
68 ResourceDispatcherHost* resource_dispatcher_host) {
69 resource_dispatcher_host_ = resource_dispatcher_host;
70 ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
71}
72
73void PluginService::SetChromePluginDataDir(const std::wstring& data_dir) {
74 AutoLock lock(lock_);
75 chrome_plugin_data_dir_ = data_dir;
76}
77
78const std::wstring& PluginService::GetChromePluginDataDir() {
79 AutoLock lock(lock_);
80 return chrome_plugin_data_dir_;
81}
82
83const std::wstring& PluginService::GetUILocale() {
84 return ui_locale_;
85}
86
87PluginProcessHost* PluginService::FindPluginProcess(const std::wstring& dll) {
88 DCHECK(MessageLoop::current() ==
89 ChromeThread::GetMessageLoop(ChromeThread::IO));
90
91 if (dll.empty()) {
92 NOTREACHED() << "should only be called if we have a plugin dll to load";
93 return NULL;
94 }
95
96 PluginMap::iterator found = plugin_hosts_.find(dll);
97 if (found != plugin_hosts_.end())
98 return found->second;
99 return NULL;
100}
101
102PluginProcessHost* PluginService::FindOrStartPluginProcess(
103 const std::wstring& dll,
104 const std::string& clsid) {
105 DCHECK(MessageLoop::current() ==
106 ChromeThread::GetMessageLoop(ChromeThread::IO));
107
108 PluginProcessHost *plugin_host = FindPluginProcess(dll);
109 if (plugin_host)
110 return plugin_host;
111
112 // This plugin isn't loaded by any plugin process, so create a new process.
113 plugin_host = new PluginProcessHost(this);
114 if (!plugin_host->Init(dll, clsid, ui_locale_)) {
115 DCHECK(false); // Init is not expected to fail
116 delete plugin_host;
117 return NULL;
118 }
119 plugin_hosts_[dll] = plugin_host;
120 return plugin_host;
121
122 // TODO(jabdelmalek): adding a new channel means we can have one less
123 // renderer process (since each child process uses one handle in the
124 // IPC thread and main thread's WaitForMultipleObjects call). Limit the
125 // number of plugin processes.
126}
127
128void PluginService::OpenChannelToPlugin(
129 ResourceMessageFilter* renderer_msg_filter, const GURL& url,
130 const std::string& mime_type, const std::string& clsid,
131 const std::wstring& locale, IPC::Message* reply_msg) {
132 DCHECK(MessageLoop::current() ==
133 ChromeThread::GetMessageLoop(ChromeThread::IO));
134 std::wstring dll = GetPluginPath(url, mime_type, clsid, NULL);
135 PluginProcessHost* plugin_host = FindOrStartPluginProcess(dll, clsid);
136 if (plugin_host) {
137 plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg);
138 } else {
139 PluginProcessHost::ReplyToRenderer(renderer_msg_filter,
140 std::wstring(),
141 std::wstring(),
142 reply_msg);
143 }
144}
145
146void PluginService::OnPluginProcessIsShuttingDown(PluginProcessHost* host) {
147 RemoveHost(host);
148}
149
150void PluginService::OnPluginProcessExited(PluginProcessHost* host) {
151 RemoveHost(host); // in case shutdown was not graceful
152 delete host;
153}
154
155void PluginService::RemoveHost(PluginProcessHost* host) {
156 DCHECK(MessageLoop::current() ==
157 ChromeThread::GetMessageLoop(ChromeThread::IO));
158 // Search for the instance rather than lookup by dll path,
159 // there is a small window where two instances for the same
160 // dll path can co-exists.
161 PluginMap::iterator i = plugin_hosts_.begin();
162 while (i != plugin_hosts_.end()) {
163 if (i->second == host) {
164 plugin_hosts_.erase(i);
165 return;
166 }
167 i++;
168 }
169}
170
171std::wstring PluginService::GetPluginPath(const GURL& url,
172 const std::string& mime_type,
173 const std::string& clsid,
174 std::string* actual_mime_type) {
175 AutoLock lock(lock_);
176 bool allow_wildcard = true;
177 WebPluginInfo info;
178 NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, clsid,
179 allow_wildcard, &info,
180 actual_mime_type);
181 return info.file;
182}
183
184bool PluginService::GetPluginInfoByDllPath(const std::wstring& dll_path,
185 WebPluginInfo* info) {
186 AutoLock lock(lock_);
187 return NPAPI::PluginList::Singleton()->GetPluginInfoByDllPath(dll_path, info);
188}
189
190bool PluginService::HavePluginFor(const std::string& mime_type,
191 bool allow_wildcard) {
192 AutoLock lock(lock_);
193
194 GURL url;
195 WebPluginInfo info;
196 return NPAPI::PluginList::Singleton()->GetPluginInfo(url, mime_type, "",
197 allow_wildcard, &info,
198 NULL);
199}
200
201void PluginService::Shutdown() {
202 plugin_shutdown_handler_->InitiateShutdown();
203}
204
205void PluginService::OnShutdown() {
206 PluginMap::iterator host_index;
207 for (host_index = plugin_hosts_.begin(); host_index != plugin_hosts_.end();
208 ++host_index) {
209 host_index->second->Shutdown();
210 }
211}
212
213PluginProcessHostIterator::PluginProcessHostIterator()
214 : iterator_(PluginService::GetInstance()->plugin_hosts_.begin()),
215 end_(PluginService::GetInstance()->plugin_hosts_.end()) {
216 DCHECK(MessageLoop::current() ==
217 ChromeThread::GetMessageLoop(ChromeThread::IO)) <<
218 "PluginProcessHostIterator must be used on the IO thread.";
219}
220
221PluginProcessHostIterator::PluginProcessHostIterator(
222 const PluginProcessHostIterator& instance)
223 : iterator_(instance.iterator_) {
224 DCHECK(MessageLoop::current() ==
225 ChromeThread::GetMessageLoop(ChromeThread::IO)) <<
226 "PluginProcessHostIterator must be used on the IO thread.";
227}
228
229void PluginService::ShutdownHandler::InitiateShutdown() {
230 g_browser_process->io_thread()->message_loop()->PostTask(
231 FROM_HERE,
232 NewRunnableMethod(this, &ShutdownHandler::OnShutdown));
233}
234
235void PluginService::ShutdownHandler::OnShutdown() {
236 PluginService* plugin_service = PluginService::GetInstance();
237 if (plugin_service) {
238 plugin_service->OnShutdown();
239 }
240}