Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Side by Side Diff: webkit/plugins/npapi/plugin_lib.cc

Issue 19761007: Move NPAPI implementation out of webkit/plugins/npapi and into content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix mac Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "webkit/plugins/npapi/plugin_lib.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/stats_counters.h"
11 #include "base/strings/string_util.h"
12 #include "webkit/plugins/npapi/plugin_host.h"
13 #include "webkit/plugins/npapi/plugin_instance.h"
14 #include "webkit/plugins/npapi/plugin_list.h"
15
16 namespace webkit {
17 namespace npapi {
18
19 const char kPluginLibrariesLoadedCounter[] = "PluginLibrariesLoaded";
20 const char kPluginInstancesActiveCounter[] = "PluginInstancesActive";
21
22 // A list of all the instantiated plugins.
23 static std::vector<scoped_refptr<PluginLib> >* g_loaded_libs;
24
25 PluginLib* PluginLib::CreatePluginLib(const base::FilePath& filename) {
26 // We can only have one PluginLib object per plugin as it controls the per
27 // instance function calls (i.e. NP_Initialize and NP_Shutdown). So we keep
28 // a map of PluginLib objects.
29 if (!g_loaded_libs)
30 g_loaded_libs = new std::vector<scoped_refptr<PluginLib> >;
31
32 for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
33 if ((*g_loaded_libs)[i]->plugin_info().path == filename)
34 return (*g_loaded_libs)[i].get();
35 }
36
37 webkit::WebPluginInfo info;
38 if (!PluginList::Singleton()->ReadPluginInfo(filename, &info))
39 return NULL;
40
41 return new PluginLib(info);
42 }
43
44 void PluginLib::UnloadAllPlugins() {
45 if (g_loaded_libs) {
46 // PluginLib::Unload() can remove items from the list and even delete
47 // the list when it removes the last item, so we must work with a copy
48 // of the list so that we don't get the carpet removed under our feet.
49 std::vector<scoped_refptr<PluginLib> > loaded_libs(*g_loaded_libs);
50 for (size_t i = 0; i < loaded_libs.size(); ++i)
51 loaded_libs[i]->Unload();
52
53 if (g_loaded_libs && g_loaded_libs->empty()) {
54 delete g_loaded_libs;
55 g_loaded_libs = NULL;
56 }
57 }
58 }
59
60 void PluginLib::ShutdownAllPlugins() {
61 if (g_loaded_libs) {
62 for (size_t i = 0; i < g_loaded_libs->size(); ++i)
63 (*g_loaded_libs)[i]->Shutdown();
64 }
65 }
66
67 PluginLib::PluginLib(const webkit::WebPluginInfo& info)
68 : web_plugin_info_(info),
69 library_(NULL),
70 initialized_(false),
71 saved_data_(0),
72 instance_count_(0),
73 skip_unload_(false),
74 defer_unload_(false) {
75 base::StatsCounter(kPluginLibrariesLoadedCounter).Increment();
76 memset(static_cast<void*>(&plugin_funcs_), 0, sizeof(plugin_funcs_));
77 g_loaded_libs->push_back(make_scoped_refptr(this));
78
79 memset(&entry_points_, 0, sizeof(entry_points_));
80 }
81
82 PluginLib::~PluginLib() {
83 base::StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
84 if (saved_data_ != 0) {
85 // TODO - delete the savedData object here
86 }
87 }
88
89 NPPluginFuncs* PluginLib::functions() {
90 return &plugin_funcs_;
91 }
92
93 NPError PluginLib::NP_Initialize() {
94 LOG_IF(ERROR, PluginList::DebugPluginLoading())
95 << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
96 << "): initialized=" << initialized_;
97 if (initialized_)
98 return NPERR_NO_ERROR;
99
100 if (!Load())
101 return NPERR_MODULE_LOAD_FAILED_ERROR;
102
103 PluginHost* host = PluginHost::Singleton();
104 if (host == 0)
105 return NPERR_GENERIC_ERROR;
106
107 #if defined(OS_POSIX) && !defined(OS_MACOSX)
108 NPError rv = entry_points_.np_initialize(host->host_functions(),
109 &plugin_funcs_);
110 #else
111 NPError rv = entry_points_.np_initialize(host->host_functions());
112 #if defined(OS_MACOSX)
113 // On the Mac, we need to get entry points after calling np_initialize to
114 // match the behavior of other browsers.
115 if (rv == NPERR_NO_ERROR) {
116 rv = entry_points_.np_getentrypoints(&plugin_funcs_);
117 }
118 #endif // OS_MACOSX
119 #endif
120 LOG_IF(ERROR, PluginList::DebugPluginLoading())
121 << "PluginLib::NP_Initialize(" << web_plugin_info_.path.value()
122 << "): result=" << rv;
123 initialized_ = (rv == NPERR_NO_ERROR);
124 return rv;
125 }
126
127 void PluginLib::NP_Shutdown(void) {
128 DCHECK(initialized_);
129 entry_points_.np_shutdown();
130 }
131
132 NPError PluginLib::NP_ClearSiteData(const char* site,
133 uint64 flags,
134 uint64 max_age) {
135 DCHECK(initialized_);
136 if (plugin_funcs_.clearsitedata)
137 return plugin_funcs_.clearsitedata(site, flags, max_age);
138 return NPERR_INVALID_FUNCTABLE_ERROR;
139 }
140
141 char** PluginLib::NP_GetSitesWithData() {
142 DCHECK(initialized_);
143 if (plugin_funcs_.getsiteswithdata)
144 return plugin_funcs_.getsiteswithdata();
145 return NULL;
146 }
147
148 void PluginLib::PreventLibraryUnload() {
149 skip_unload_ = true;
150 }
151
152 PluginInstance* PluginLib::CreateInstance(const std::string& mime_type) {
153 PluginInstance* new_instance = new PluginInstance(this, mime_type);
154 instance_count_++;
155 base::StatsCounter(kPluginInstancesActiveCounter).Increment();
156 DCHECK_NE(static_cast<PluginInstance*>(NULL), new_instance);
157 return new_instance;
158 }
159
160 void PluginLib::CloseInstance() {
161 base::StatsCounter(kPluginInstancesActiveCounter).Decrement();
162 instance_count_--;
163 // If a plugin is running in its own process it will get unloaded on process
164 // shutdown.
165 if ((instance_count_ == 0) && !defer_unload_)
166 Unload();
167 }
168
169 bool PluginLib::Load() {
170 if (library_)
171 return true;
172
173 bool rv = false;
174 base::NativeLibrary library = 0;
175 std::string error;
176
177 #if defined(OS_WIN)
178 // This is to work around a bug in the Real player recorder plugin which
179 // intercepts LoadLibrary calls from chrome.dll and wraps NPAPI functions
180 // provided by the plugin. It crashes if the media player plugin is being
181 // loaded. Workaround is to load the dll dynamically by getting the
182 // LoadLibrary API address from kernel32.dll which bypasses the recorder
183 // plugin.
184 if (web_plugin_info_.name.find(L"Windows Media Player") !=
185 std::wstring::npos) {
186 library = base::LoadNativeLibraryDynamically(web_plugin_info_.path);
187 } else {
188 library = base::LoadNativeLibrary(web_plugin_info_.path, &error);
189 }
190 #else
191 library = base::LoadNativeLibrary(web_plugin_info_.path, &error);
192 #endif
193
194 if (!library) {
195 LOG_IF(ERROR, PluginList::DebugPluginLoading())
196 << "Couldn't load plugin " << web_plugin_info_.path.value() << " "
197 << error;
198 return rv;
199 }
200
201 #if defined(OS_MACOSX)
202 // According to the WebKit source, QuickTime at least requires us to call
203 // UseResFile on the plugin resources before loading.
204 if (library->bundle_resource_ref != -1)
205 UseResFile(library->bundle_resource_ref);
206 #endif
207
208 rv = true; // assume success now
209
210 entry_points_.np_initialize =
211 (NP_InitializeFunc)base::GetFunctionPointerFromNativeLibrary(library,
212 "NP_Initialize");
213 if (entry_points_.np_initialize == 0)
214 rv = false;
215
216 #if defined(OS_WIN) || defined(OS_MACOSX)
217 entry_points_.np_getentrypoints =
218 (NP_GetEntryPointsFunc)base::GetFunctionPointerFromNativeLibrary(
219 library, "NP_GetEntryPoints");
220 if (entry_points_.np_getentrypoints == 0)
221 rv = false;
222 #endif
223
224 entry_points_.np_shutdown =
225 (NP_ShutdownFunc)base::GetFunctionPointerFromNativeLibrary(library,
226 "NP_Shutdown");
227 if (entry_points_.np_shutdown == 0)
228 rv = false;
229
230 if (rv) {
231 plugin_funcs_.size = sizeof(plugin_funcs_);
232 plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
233 #if !defined(OS_POSIX)
234 if (entry_points_.np_getentrypoints(&plugin_funcs_) != NPERR_NO_ERROR)
235 rv = false;
236 #else
237 // On Linux and Mac, we get the plugin entry points during NP_Initialize.
238 #endif
239 }
240
241 if (rv) {
242 LOG_IF(ERROR, PluginList::DebugPluginLoading())
243 << "Plugin " << web_plugin_info_.path.value()
244 << " loaded successfully.";
245 library_ = library;
246 } else {
247 LOG_IF(ERROR, PluginList::DebugPluginLoading())
248 << "Plugin " << web_plugin_info_.path.value()
249 << " failed to load, unloading.";
250 base::UnloadNativeLibrary(library);
251 }
252
253 return rv;
254 }
255
256 // This is a helper to help perform a delayed NP_Shutdown and FreeLibrary on the
257 // plugin dll.
258 void FreePluginLibraryHelper(const base::FilePath& path,
259 base::NativeLibrary library,
260 NP_ShutdownFunc shutdown_func) {
261 if (shutdown_func) {
262 // Don't call NP_Shutdown if the library has been reloaded since this task
263 // was posted.
264 bool reloaded = false;
265 if (g_loaded_libs) {
266 for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
267 if ((*g_loaded_libs)[i]->plugin_info().path == path)
268 reloaded = true;
269 }
270 }
271 if (!reloaded)
272 shutdown_func();
273 }
274
275 if (library) {
276 // Always call base::UnloadNativeLibrary so that the system reference
277 // count is decremented.
278 base::UnloadNativeLibrary(library);
279 }
280 }
281
282 void PluginLib::Unload() {
283 if (library_) {
284 // In case of single process mode, a plugin can delete itself
285 // by executing a script. So delay the unloading of the library
286 // so that the plugin will have a chance to unwind.
287 /* TODO(dglazkov): Revisit when re-enabling the JSC build.
288 #if USE(JSC)
289 // The plugin NPAPI instances may still be around. Delay the
290 // NP_Shutdown and FreeLibrary calls at least till the next
291 // peek message.
292 defer_unload = true;
293 #endif
294 */
295 if (!defer_unload_) {
296 LOG_IF(ERROR, PluginList::DebugPluginLoading())
297 << "Scheduling delayed unload for plugin "
298 << web_plugin_info_.path.value();
299 base::MessageLoop::current()->PostTask(
300 FROM_HERE,
301 base::Bind(&FreePluginLibraryHelper,
302 web_plugin_info_.path,
303 skip_unload_ ? NULL : library_,
304 entry_points_.np_shutdown));
305 } else {
306 Shutdown();
307 if (!skip_unload_) {
308 LOG_IF(ERROR, PluginList::DebugPluginLoading())
309 << "Unloading plugin " << web_plugin_info_.path.value();
310 base::UnloadNativeLibrary(library_);
311 }
312 }
313
314 library_ = NULL;
315 }
316
317 for (size_t i = 0; i < g_loaded_libs->size(); ++i) {
318 if ((*g_loaded_libs)[i].get() == this) {
319 g_loaded_libs->erase(g_loaded_libs->begin() + i);
320 break;
321 }
322 }
323 if (g_loaded_libs->empty()) {
324 delete g_loaded_libs;
325 g_loaded_libs = NULL;
326 }
327 }
328
329 void PluginLib::Shutdown() {
330 if (initialized_) {
331 NP_Shutdown();
332 initialized_ = false;
333 }
334 }
335
336 } // namespace npapi
337 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698