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

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

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

Powered by Google App Engine
This is Rietveld 408576698