OLD | NEW |
| (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/pepper_plugin_module.h" | |
6 | |
7 #include <set> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/message_loop_proxy.h" | |
12 #include "base/logging.h" | |
13 #include "base/scoped_ptr.h" | |
14 #include "base/time.h" | |
15 #include "ppapi/c/dev/ppb_buffer_dev.h" | |
16 #include "ppapi/c/dev/ppb_char_set_dev.h" | |
17 #include "ppapi/c/dev/ppb_cursor_control_dev.h" | |
18 #include "ppapi/c/dev/ppb_directory_reader_dev.h" | |
19 #include "ppapi/c/dev/ppb_file_io_dev.h" | |
20 #include "ppapi/c/dev/ppb_file_io_trusted_dev.h" | |
21 #include "ppapi/c/dev/ppb_file_system_dev.h" | |
22 #include "ppapi/c/dev/ppb_find_dev.h" | |
23 #include "ppapi/c/dev/ppb_font_dev.h" | |
24 #include "ppapi/c/dev/ppb_fullscreen_dev.h" | |
25 #include "ppapi/c/dev/ppb_graphics_3d_dev.h" | |
26 #include "ppapi/c/dev/ppb_opengles_dev.h" | |
27 #include "ppapi/c/dev/ppb_scrollbar_dev.h" | |
28 #include "ppapi/c/dev/ppb_testing_dev.h" | |
29 #include "ppapi/c/dev/ppb_transport_dev.h" | |
30 #include "ppapi/c/dev/ppb_url_util_dev.h" | |
31 #include "ppapi/c/dev/ppb_var_deprecated.h" | |
32 #include "ppapi/c/dev/ppb_video_decoder_dev.h" | |
33 #include "ppapi/c/dev/ppb_widget_dev.h" | |
34 #include "ppapi/c/dev/ppb_zoom_dev.h" | |
35 #include "ppapi/c/pp_module.h" | |
36 #include "ppapi/c/pp_resource.h" | |
37 #include "ppapi/c/pp_var.h" | |
38 #include "ppapi/c/ppb_class.h" | |
39 #include "ppapi/c/ppb_core.h" | |
40 #include "ppapi/c/ppb_graphics_2d.h" | |
41 #include "ppapi/c/ppb_image_data.h" | |
42 #include "ppapi/c/ppb_instance.h" | |
43 #include "ppapi/c/ppb_url_loader.h" | |
44 #include "ppapi/c/ppb_url_request_info.h" | |
45 #include "ppapi/c/ppb_url_response_info.h" | |
46 #include "ppapi/c/ppb_var.h" | |
47 #include "ppapi/c/ppp.h" | |
48 #include "ppapi/c/ppp_instance.h" | |
49 #include "ppapi/c/trusted/ppb_image_data_trusted.h" | |
50 #include "ppapi/c/trusted/ppb_url_loader_trusted.h" | |
51 #include "webkit/glue/plugins/pepper_audio.h" | |
52 #include "webkit/glue/plugins/pepper_buffer.h" | |
53 #include "webkit/glue/plugins/pepper_common.h" | |
54 #include "webkit/glue/plugins/pepper_char_set.h" | |
55 #include "webkit/glue/plugins/pepper_class.h" | |
56 #include "webkit/glue/plugins/pepper_cursor_control.h" | |
57 #include "webkit/glue/plugins/pepper_directory_reader.h" | |
58 #include "webkit/glue/plugins/pepper_file_chooser.h" | |
59 #include "webkit/glue/plugins/pepper_file_io.h" | |
60 #include "webkit/glue/plugins/pepper_file_ref.h" | |
61 #include "webkit/glue/plugins/pepper_file_system.h" | |
62 #include "webkit/glue/plugins/pepper_font.h" | |
63 #include "webkit/glue/plugins/pepper_graphics_2d.h" | |
64 #include "webkit/glue/plugins/pepper_image_data.h" | |
65 #include "webkit/glue/plugins/pepper_plugin_instance.h" | |
66 #include "webkit/glue/plugins/pepper_plugin_object.h" | |
67 #include "webkit/glue/plugins/pepper_private.h" | |
68 #include "webkit/glue/plugins/pepper_private2.h" | |
69 #include "webkit/glue/plugins/pepper_resource_tracker.h" | |
70 #include "webkit/glue/plugins/pepper_scrollbar.h" | |
71 #include "webkit/glue/plugins/pepper_transport.h" | |
72 #include "webkit/glue/plugins/pepper_url_loader.h" | |
73 #include "webkit/glue/plugins/pepper_url_request_info.h" | |
74 #include "webkit/glue/plugins/pepper_url_response_info.h" | |
75 #include "webkit/glue/plugins/pepper_url_util.h" | |
76 #include "webkit/glue/plugins/pepper_var.h" | |
77 #include "webkit/glue/plugins/pepper_video_decoder.h" | |
78 #include "webkit/glue/plugins/pepper_widget.h" | |
79 #include "webkit/glue/plugins/ppb_private.h" | |
80 #include "webkit/glue/plugins/ppb_private2.h" | |
81 | |
82 #ifdef ENABLE_GPU | |
83 #include "webkit/glue/plugins/pepper_graphics_3d.h" | |
84 #endif // ENABLE_GPU | |
85 | |
86 namespace pepper { | |
87 | |
88 namespace { | |
89 | |
90 // Maintains all currently loaded plugin libs for validating PP_Module | |
91 // identifiers. | |
92 typedef std::set<PluginModule*> PluginModuleSet; | |
93 | |
94 PluginModuleSet* GetLivePluginSet() { | |
95 static PluginModuleSet live_plugin_libs; | |
96 return &live_plugin_libs; | |
97 } | |
98 | |
99 base::MessageLoopProxy* GetMainThreadMessageLoop() { | |
100 static scoped_refptr<base::MessageLoopProxy> proxy( | |
101 base::MessageLoopProxy::CreateForCurrentThread()); | |
102 return proxy.get(); | |
103 } | |
104 | |
105 // PPB_Core -------------------------------------------------------------------- | |
106 | |
107 void AddRefResource(PP_Resource resource) { | |
108 if (!ResourceTracker::Get()->AddRefResource(resource)) { | |
109 DLOG(WARNING) << "AddRefResource()ing a nonexistent resource"; | |
110 } | |
111 } | |
112 | |
113 void ReleaseResource(PP_Resource resource) { | |
114 if (!ResourceTracker::Get()->UnrefResource(resource)) { | |
115 DLOG(WARNING) << "ReleaseResource()ing a nonexistent resource"; | |
116 } | |
117 } | |
118 | |
119 void* MemAlloc(size_t num_bytes) { | |
120 return malloc(num_bytes); | |
121 } | |
122 | |
123 void MemFree(void* ptr) { | |
124 free(ptr); | |
125 } | |
126 | |
127 double GetTime() { | |
128 return base::Time::Now().ToDoubleT(); | |
129 } | |
130 | |
131 double GetTickTime() { | |
132 // TODO(brettw) http://code.google.com/p/chromium/issues/detail?id=57448 | |
133 // This should be a tick timer rather than wall clock time, but needs to | |
134 // match message times, which also currently use wall clock time. | |
135 return GetTime(); | |
136 } | |
137 | |
138 void CallOnMainThread(int delay_in_msec, | |
139 PP_CompletionCallback callback, | |
140 int32_t result) { | |
141 GetMainThreadMessageLoop()->PostDelayedTask( | |
142 FROM_HERE, | |
143 NewRunnableFunction(callback.func, callback.user_data, result), | |
144 delay_in_msec); | |
145 } | |
146 | |
147 PP_Bool IsMainThread() { | |
148 return BoolToPPBool(GetMainThreadMessageLoop()->BelongsToCurrentThread()); | |
149 } | |
150 | |
151 const PPB_Core core_interface = { | |
152 &AddRefResource, | |
153 &ReleaseResource, | |
154 &MemAlloc, | |
155 &MemFree, | |
156 &GetTime, | |
157 &GetTickTime, | |
158 &CallOnMainThread, | |
159 &IsMainThread | |
160 }; | |
161 | |
162 // PPB_Testing ----------------------------------------------------------------- | |
163 | |
164 PP_Bool ReadImageData(PP_Resource device_context_2d, | |
165 PP_Resource image, | |
166 const PP_Point* top_left) { | |
167 scoped_refptr<Graphics2D> context( | |
168 Resource::GetAs<Graphics2D>(device_context_2d)); | |
169 if (!context.get()) | |
170 return PP_FALSE; | |
171 return BoolToPPBool(context->ReadImageData(image, top_left)); | |
172 } | |
173 | |
174 void RunMessageLoop() { | |
175 bool old_state = MessageLoop::current()->NestableTasksAllowed(); | |
176 MessageLoop::current()->SetNestableTasksAllowed(true); | |
177 MessageLoop::current()->Run(); | |
178 MessageLoop::current()->SetNestableTasksAllowed(old_state); | |
179 } | |
180 | |
181 void QuitMessageLoop() { | |
182 MessageLoop::current()->QuitNow(); | |
183 } | |
184 | |
185 uint32_t GetLiveObjectCount(PP_Module module_id) { | |
186 PluginModule* module = ResourceTracker::Get()->GetModule(module_id); | |
187 if (!module) | |
188 return static_cast<uint32_t>(-1); | |
189 return ResourceTracker::Get()->GetLiveObjectsForModule(module); | |
190 } | |
191 | |
192 const PPB_Testing_Dev testing_interface = { | |
193 &ReadImageData, | |
194 &RunMessageLoop, | |
195 &QuitMessageLoop, | |
196 &GetLiveObjectCount | |
197 }; | |
198 | |
199 // GetInterface ---------------------------------------------------------------- | |
200 | |
201 const void* GetInterface(const char* name) { | |
202 if (strcmp(name, PPB_CORE_INTERFACE) == 0) | |
203 return &core_interface; | |
204 if (strcmp(name, PPB_VAR_DEPRECATED_INTERFACE) == 0) | |
205 return Var::GetDeprecatedInterface(); | |
206 if (strcmp(name, PPB_VAR_INTERFACE) == 0) | |
207 return Var::GetInterface(); | |
208 if (strcmp(name, PPB_INSTANCE_INTERFACE) == 0) | |
209 return PluginInstance::GetInterface(); | |
210 if (strcmp(name, PPB_IMAGEDATA_INTERFACE) == 0) | |
211 return ImageData::GetInterface(); | |
212 if (strcmp(name, PPB_IMAGEDATA_TRUSTED_INTERFACE) == 0) | |
213 return ImageData::GetTrustedInterface(); | |
214 if (strcmp(name, PPB_AUDIO_CONFIG_DEV_INTERFACE) == 0) | |
215 return AudioConfig::GetInterface(); | |
216 if (strcmp(name, PPB_AUDIO_DEV_INTERFACE) == 0) | |
217 return Audio::GetInterface(); | |
218 if (strcmp(name, PPB_AUDIO_TRUSTED_DEV_INTERFACE) == 0) | |
219 return Audio::GetTrustedInterface(); | |
220 if (strcmp(name, PPB_GRAPHICS_2D_INTERFACE) == 0) | |
221 return Graphics2D::GetInterface(); | |
222 #ifdef ENABLE_GPU | |
223 if (strcmp(name, PPB_GRAPHICS_3D_DEV_INTERFACE) == 0) | |
224 return Graphics3D::GetInterface(); | |
225 if (strcmp(name, PPB_OPENGLES_DEV_INTERFACE) == 0) | |
226 return Graphics3D::GetOpenGLESInterface(); | |
227 #endif // ENABLE_GPU | |
228 if (strcmp(name, PPB_TRANSPORT_DEV_INTERFACE) == 0) | |
229 return Transport::GetInterface(); | |
230 if (strcmp(name, PPB_URLLOADER_INTERFACE) == 0) | |
231 return URLLoader::GetInterface(); | |
232 if (strcmp(name, PPB_URLLOADERTRUSTED_INTERFACE) == 0) | |
233 return URLLoader::GetTrustedInterface(); | |
234 if (strcmp(name, PPB_URLREQUESTINFO_INTERFACE) == 0) | |
235 return URLRequestInfo::GetInterface(); | |
236 if (strcmp(name, PPB_URLRESPONSEINFO_INTERFACE) == 0) | |
237 return URLResponseInfo::GetInterface(); | |
238 if (strcmp(name, PPB_BUFFER_DEV_INTERFACE) == 0) | |
239 return Buffer::GetInterface(); | |
240 if (strcmp(name, PPB_FILEREF_DEV_INTERFACE) == 0) | |
241 return FileRef::GetInterface(); | |
242 if (strcmp(name, PPB_FILEIO_DEV_INTERFACE) == 0) | |
243 return FileIO::GetInterface(); | |
244 if (strcmp(name, PPB_FILEIOTRUSTED_DEV_INTERFACE) == 0) | |
245 return FileIO::GetTrustedInterface(); | |
246 if (strcmp(name, PPB_FILESYSTEM_DEV_INTERFACE) == 0) | |
247 return FileSystem::GetInterface(); | |
248 if (strcmp(name, PPB_DIRECTORYREADER_DEV_INTERFACE) == 0) | |
249 return DirectoryReader::GetInterface(); | |
250 if (strcmp(name, PPB_WIDGET_DEV_INTERFACE) == 0) | |
251 return Widget::GetInterface(); | |
252 if (strcmp(name, PPB_SCROLLBAR_DEV_INTERFACE) == 0) | |
253 return Scrollbar::GetInterface(); | |
254 if (strcmp(name, PPB_FONT_DEV_INTERFACE) == 0) | |
255 return Font::GetInterface(); | |
256 if (strcmp(name, PPB_FIND_DEV_INTERFACE) == 0) | |
257 return PluginInstance::GetFindInterface(); | |
258 if (strcmp(name, PPB_FULLSCREEN_DEV_INTERFACE) == 0) | |
259 return PluginInstance::GetFullscreenInterface(); | |
260 if (strcmp(name, PPB_URLUTIL_DEV_INTERFACE) == 0) | |
261 return UrlUtil::GetInterface(); | |
262 if (strcmp(name, PPB_PRIVATE_INTERFACE) == 0) | |
263 return Private::GetInterface(); | |
264 if (strcmp(name, PPB_PRIVATE2_INTERFACE) == 0) | |
265 return Private2::GetInterface(); | |
266 if (strcmp(name, PPB_FILECHOOSER_DEV_INTERFACE) == 0) | |
267 return FileChooser::GetInterface(); | |
268 if (strcmp(name, PPB_VIDEODECODER_DEV_INTERFACE) == 0) | |
269 return VideoDecoder::GetInterface(); | |
270 if (strcmp(name, PPB_CHAR_SET_DEV_INTERFACE) == 0) | |
271 return CharSet::GetInterface(); | |
272 if (strcmp(name, PPB_CURSOR_CONTROL_DEV_INTERFACE) == 0) | |
273 return GetCursorControlInterface(); | |
274 if (strcmp(name, PPB_ZOOM_DEV_INTERFACE) == 0) | |
275 return PluginInstance::GetZoomInterface(); | |
276 if (strcmp(name, PPB_CLASS_INTERFACE) == 0) | |
277 return VarObjectClass::GetInterface(); | |
278 | |
279 // Only support the testing interface when the command line switch is | |
280 // specified. This allows us to prevent people from (ab)using this interface | |
281 // in production code. | |
282 if (strcmp(name, PPB_TESTING_DEV_INTERFACE) == 0) { | |
283 if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing")) | |
284 return &testing_interface; | |
285 } | |
286 return NULL; | |
287 } | |
288 | |
289 // Gets the PPAPI entry points from the given library and places them into the | |
290 // given structure. Returns true on success. | |
291 bool LoadEntryPointsFromLibrary(const base::NativeLibrary& library, | |
292 PluginModule::EntryPoints* entry_points) { | |
293 entry_points->get_interface = | |
294 reinterpret_cast<PluginModule::GetInterfaceFunc>( | |
295 base::GetFunctionPointerFromNativeLibrary(library, | |
296 "PPP_GetInterface")); | |
297 if (!entry_points->get_interface) { | |
298 LOG(WARNING) << "No PPP_GetInterface in plugin library"; | |
299 return false; | |
300 } | |
301 | |
302 entry_points->initialize_module = | |
303 reinterpret_cast<PluginModule::PPP_InitializeModuleFunc>( | |
304 base::GetFunctionPointerFromNativeLibrary(library, | |
305 "PPP_InitializeModule")); | |
306 if (!entry_points->initialize_module) { | |
307 LOG(WARNING) << "No PPP_InitializeModule in plugin library"; | |
308 return false; | |
309 } | |
310 | |
311 // It's okay for PPP_ShutdownModule to not be defined and shutdown_module to | |
312 // be NULL. | |
313 entry_points->shutdown_module = | |
314 reinterpret_cast<PluginModule::PPP_ShutdownModuleFunc>( | |
315 base::GetFunctionPointerFromNativeLibrary(library, | |
316 "PPP_ShutdownModule")); | |
317 | |
318 return true; | |
319 } | |
320 | |
321 } // namespace | |
322 | |
323 PluginModule::EntryPoints::EntryPoints() | |
324 : get_interface(NULL), | |
325 initialize_module(NULL), | |
326 shutdown_module(NULL) { | |
327 } | |
328 | |
329 // PluginModule ---------------------------------------------------------------- | |
330 | |
331 PluginModule::PluginModule() : library_(NULL) { | |
332 pp_module_ = ResourceTracker::Get()->AddModule(this); | |
333 GetMainThreadMessageLoop(); // Initialize the main thread message loop. | |
334 GetLivePluginSet()->insert(this); | |
335 } | |
336 | |
337 PluginModule::~PluginModule() { | |
338 // Free all the plugin objects. This will automatically clear the back- | |
339 // pointer from the NPObject so WebKit can't call into the plugin any more. | |
340 // | |
341 // Swap out the set so we can delete from it (the objects will try to | |
342 // unregister themselves inside the delete call). | |
343 PluginObjectSet plugin_object_copy; | |
344 live_plugin_objects_.swap(plugin_object_copy); | |
345 for (PluginObjectSet::iterator i = live_plugin_objects_.begin(); | |
346 i != live_plugin_objects_.end(); ++i) | |
347 delete *i; | |
348 | |
349 // When the module is being deleted, there should be no more instances still | |
350 // holding a reference to us. | |
351 DCHECK(instances_.empty()); | |
352 | |
353 GetLivePluginSet()->erase(this); | |
354 | |
355 if (entry_points_.shutdown_module) | |
356 entry_points_.shutdown_module(); | |
357 | |
358 if (library_) | |
359 base::UnloadNativeLibrary(library_); | |
360 | |
361 ResourceTracker::Get()->ModuleDeleted(pp_module_); | |
362 } | |
363 | |
364 bool PluginModule::InitAsInternalPlugin(const EntryPoints& entry_points) { | |
365 entry_points_ = entry_points; | |
366 return InitializeModule(); | |
367 } | |
368 | |
369 bool PluginModule::InitAsLibrary(const FilePath& path) { | |
370 base::NativeLibrary library = base::LoadNativeLibrary(path); | |
371 if (!library) | |
372 return false; | |
373 | |
374 if (!LoadEntryPointsFromLibrary(library, &entry_points_) || | |
375 !InitializeModule()) { | |
376 base::UnloadNativeLibrary(library); | |
377 return false; | |
378 } | |
379 | |
380 library_ = library; | |
381 return true; | |
382 } | |
383 | |
384 void PluginModule::InitAsProxied( | |
385 PluginDelegate::OutOfProcessProxy* out_of_process_proxy) { | |
386 DCHECK(!out_of_process_proxy_.get()); | |
387 out_of_process_proxy_.reset(out_of_process_proxy); | |
388 } | |
389 | |
390 // static | |
391 const PPB_Core* PluginModule::GetCore() { | |
392 return &core_interface; | |
393 } | |
394 | |
395 // static | |
396 PluginModule::GetInterfaceFunc PluginModule::GetLocalGetInterfaceFunc() { | |
397 return &GetInterface; | |
398 } | |
399 | |
400 PluginInstance* PluginModule::CreateInstance(PluginDelegate* delegate) { | |
401 const PPP_Instance* plugin_instance_interface = | |
402 reinterpret_cast<const PPP_Instance*>(GetPluginInterface( | |
403 PPP_INSTANCE_INTERFACE)); | |
404 if (!plugin_instance_interface) { | |
405 LOG(WARNING) << "Plugin doesn't support instance interface, failing."; | |
406 return NULL; | |
407 } | |
408 PluginInstance* instance = new PluginInstance(delegate, this, | |
409 plugin_instance_interface); | |
410 if (out_of_process_proxy_.get()) | |
411 out_of_process_proxy_->AddInstance(instance->pp_instance()); | |
412 return instance; | |
413 } | |
414 | |
415 PluginInstance* PluginModule::GetSomeInstance() const { | |
416 // This will generally crash later if there is not actually any instance to | |
417 // return, so we force a crash now to make bugs easier to track down. | |
418 CHECK(!instances_.empty()); | |
419 return *instances_.begin(); | |
420 } | |
421 | |
422 const void* PluginModule::GetPluginInterface(const char* name) const { | |
423 if (out_of_process_proxy_.get()) | |
424 return out_of_process_proxy_->GetProxiedInterface(name); | |
425 | |
426 // In-process plugins. | |
427 if (!entry_points_.get_interface) | |
428 return NULL; | |
429 return entry_points_.get_interface(name); | |
430 } | |
431 | |
432 void PluginModule::InstanceCreated(PluginInstance* instance) { | |
433 instances_.insert(instance); | |
434 } | |
435 | |
436 void PluginModule::InstanceDeleted(PluginInstance* instance) { | |
437 if (out_of_process_proxy_.get()) | |
438 out_of_process_proxy_->RemoveInstance(instance->pp_instance()); | |
439 instances_.erase(instance); | |
440 } | |
441 | |
442 void PluginModule::AddNPObjectVar(ObjectVar* object_var) { | |
443 DCHECK(np_object_to_object_var_.find(object_var->np_object()) == | |
444 np_object_to_object_var_.end()) << "ObjectVar already in map"; | |
445 np_object_to_object_var_[object_var->np_object()] = object_var; | |
446 } | |
447 | |
448 void PluginModule::RemoveNPObjectVar(ObjectVar* object_var) { | |
449 NPObjectToObjectVarMap::iterator found = | |
450 np_object_to_object_var_.find(object_var->np_object()); | |
451 if (found == np_object_to_object_var_.end()) { | |
452 NOTREACHED() << "ObjectVar not registered."; | |
453 return; | |
454 } | |
455 if (found->second != object_var) { | |
456 NOTREACHED() << "ObjectVar doesn't match."; | |
457 return; | |
458 } | |
459 np_object_to_object_var_.erase(found); | |
460 } | |
461 | |
462 ObjectVar* PluginModule::ObjectVarForNPObject(NPObject* np_object) const { | |
463 NPObjectToObjectVarMap::const_iterator found = | |
464 np_object_to_object_var_.find(np_object); | |
465 if (found == np_object_to_object_var_.end()) | |
466 return NULL; | |
467 return found->second; | |
468 } | |
469 | |
470 void PluginModule::AddPluginObject(PluginObject* plugin_object) { | |
471 DCHECK(live_plugin_objects_.find(plugin_object) == | |
472 live_plugin_objects_.end()); | |
473 live_plugin_objects_.insert(plugin_object); | |
474 } | |
475 | |
476 void PluginModule::RemovePluginObject(PluginObject* plugin_object) { | |
477 // Don't actually verify that the object is in the set since during module | |
478 // deletion we'll be in the process of freeing them. | |
479 live_plugin_objects_.erase(plugin_object); | |
480 } | |
481 | |
482 bool PluginModule::InitializeModule() { | |
483 DCHECK(!out_of_process_proxy_.get()) << "Don't call for proxied modules."; | |
484 int retval = entry_points_.initialize_module(pp_module(), &GetInterface); | |
485 if (retval != 0) { | |
486 LOG(WARNING) << "PPP_InitializeModule returned failure " << retval; | |
487 return false; | |
488 } | |
489 return true; | |
490 } | |
491 | |
492 } // namespace pepper | |
OLD | NEW |