1 // Copyright (c) 2012 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 "content/renderer/pepper/plugin_module.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <string.h>
10
11 #include <memory>
12 #include <set>
13 #include <utility>
14
15 #include "base/bind.h"
16 #include "base/command_line.h"
17 #include "base/logging.h"
18 #include "base/no_destructor.h"
19 #include "base/run_loop.h"
20 #include "base/time/time.h"
21 #include "build/build_config.h"
22 #include "components/nacl/common/buildflags.h"
23 #include "content/common/frame_messages.h"
24 #include "content/public/renderer/content_renderer_client.h"
25 #include "content/renderer/pepper/host_dispatcher_wrapper.h"
26 #include "content/renderer/pepper/host_globals.h"
27 #include "content/renderer/pepper/pepper_hung_plugin_filter.h"
28 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
29 #include "content/renderer/pepper/pepper_plugin_registry.h"
30 #include "content/renderer/pepper/ppapi_preferences_builder.h"
31 #include "content/renderer/pepper/ppb_image_data_impl.h"
32 #include "content/renderer/pepper/ppb_proxy_impl.h"
33 #include "content/renderer/pepper/ppb_var_deprecated_impl.h"
34 #include "content/renderer/pepper/ppb_video_decoder_impl.h"
35 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
36 #include "content/renderer/render_frame_impl.h"
37 #include "content/renderer/render_thread_impl.h"
38 #include "content/renderer/render_view_impl.h"
39 #include "ppapi/c/dev/ppb_audio_input_dev.h"
40 #include "ppapi/c/dev/ppb_audio_output_dev.h"
41 #include "ppapi/c/dev/ppb_buffer_dev.h"
42 #include "ppapi/c/dev/ppb_char_set_dev.h"
43 #include "ppapi/c/dev/ppb_crypto_dev.h"
44 #include "ppapi/c/dev/ppb_cursor_control_dev.h"
45 #include "ppapi/c/dev/ppb_device_ref_dev.h"
46 #include "ppapi/c/dev/ppb_file_chooser_dev.h"
47 #include "ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h"
48 #include "ppapi/c/dev/ppb_memory_dev.h"
49 #include "ppapi/c/dev/ppb_opengles2ext_dev.h"
50 #include "ppapi/c/dev/ppb_printing_dev.h"
51 #include "ppapi/c/dev/ppb_text_input_dev.h"
52 #include "ppapi/c/dev/ppb_trace_event_dev.h"
53 #include "ppapi/c/dev/ppb_url_util_dev.h"
54 #include "ppapi/c/dev/ppb_var_deprecated.h"
55 #include "ppapi/c/dev/ppb_video_capture_dev.h"
56 #include "ppapi/c/dev/ppb_video_decoder_dev.h"
57 #include "ppapi/c/dev/ppb_view_dev.h"
58 #include "ppapi/c/pp_module.h"
59 #include "ppapi/c/pp_resource.h"
60 #include "ppapi/c/pp_var.h"
61 #include "ppapi/c/ppb_audio.h"
62 #include "ppapi/c/ppb_audio_buffer.h"
63 #include "ppapi/c/ppb_audio_config.h"
64 #include "ppapi/c/ppb_console.h"
65 #include "ppapi/c/ppb_core.h"
66 #include "ppapi/c/ppb_file_io.h"
67 #include "ppapi/c/ppb_file_ref.h"
68 #include "ppapi/c/ppb_file_system.h"
69 #include "ppapi/c/ppb_fullscreen.h"
70 #include "ppapi/c/ppb_graphics_2d.h"
71 #include "ppapi/c/ppb_graphics_3d.h"
72 #include "ppapi/c/ppb_host_resolver.h"
73 #include "ppapi/c/ppb_image_data.h"
74 #include "ppapi/c/ppb_instance.h"
75 #include "ppapi/c/ppb_media_stream_audio_track.h"
76 #include "ppapi/c/ppb_media_stream_video_track.h"
77 #include "ppapi/c/ppb_messaging.h"
78 #include "ppapi/c/ppb_mouse_cursor.h"
79 #include "ppapi/c/ppb_mouse_lock.h"
80 #include "ppapi/c/ppb_net_address.h"
81 #include "ppapi/c/ppb_network_list.h"
82 #include "ppapi/c/ppb_network_monitor.h"
83 #include "ppapi/c/ppb_network_proxy.h"
84 #include "ppapi/c/ppb_opengles2.h"
85 #include "ppapi/c/ppb_tcp_socket.h"
86 #include "ppapi/c/ppb_text_input_controller.h"
87 #include "ppapi/c/ppb_udp_socket.h"
88 #include "ppapi/c/ppb_url_loader.h"
89 #include "ppapi/c/ppb_url_request_info.h"
90 #include "ppapi/c/ppb_url_response_info.h"
91 #include "ppapi/c/ppb_var.h"
92 #include "ppapi/c/ppb_var_array.h"
93 #include "ppapi/c/ppb_var_array_buffer.h"
94 #include "ppapi/c/ppb_var_dictionary.h"
95 #include "ppapi/c/ppb_video_decoder.h"
96 #include "ppapi/c/ppb_video_encoder.h"
97 #include "ppapi/c/ppb_video_frame.h"
98 #include "ppapi/c/ppb_view.h"
99 #include "ppapi/c/ppb_vpn_provider.h"
100 #include "ppapi/c/ppp.h"
101 #include "ppapi/c/ppp_instance.h"
102 #include "ppapi/c/private/ppb_camera_capabilities_private.h"
103 #include "ppapi/c/private/ppb_camera_device_private.h"
104 #include "ppapi/c/private/ppb_ext_crx_file_system_private.h"
105 #include "ppapi/c/private/ppb_file_io_private.h"
106 #include "ppapi/c/private/ppb_file_ref_private.h"
107 #include "ppapi/c/private/ppb_find_private.h"
108 #include "ppapi/c/private/ppb_flash_font_file.h"
109 #include "ppapi/c/private/ppb_host_resolver_private.h"
110 #include "ppapi/c/private/ppb_instance_private.h"
111 #include "ppapi/c/private/ppb_isolated_file_system_private.h"
112 #include "ppapi/c/private/ppb_pdf.h"
113 #include "ppapi/c/private/ppb_proxy_private.h"
114 #include "ppapi/c/private/ppb_tcp_server_socket_private.h"
115 #include "ppapi/c/private/ppb_tcp_socket_private.h"
116 #include "ppapi/c/private/ppb_testing_private.h"
117 #include "ppapi/c/private/ppb_udp_socket_private.h"
118 #include "ppapi/c/private/ppb_uma_private.h"
119 #include "ppapi/c/private/ppb_x509_certificate_private.h"
120 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
121 #include "ppapi/c/trusted/ppb_char_set_trusted.h"
122 #include "ppapi/c/trusted/ppb_file_chooser_trusted.h"
123 #include "ppapi/c/trusted/ppb_url_loader_trusted.h"
124 #include "ppapi/shared_impl/callback_tracker.h"
125 #include "ppapi/shared_impl/dictionary_var.h"
126 #include "ppapi/shared_impl/ppapi_preferences.h"
127 #include "ppapi/shared_impl/ppapi_switches.h"
128 #include "ppapi/shared_impl/ppb_input_event_shared.h"
129 #include "ppapi/shared_impl/ppb_opengles2_shared.h"
130 #include "ppapi/shared_impl/ppb_var_shared.h"
131 #include "ppapi/shared_impl/time_conversion.h"
132 #include "ppapi/thunk/enter.h"
133 #include "ppapi/thunk/ppb_graphics_2d_api.h"
134 #include "ppapi/thunk/thunk.h"
135 #include "third_party/blink/public/platform/web_security_origin.h"
136 #include "third_party/blink/public/web/web_local_frame.h"
137
138 using ppapi::InputEventData;
139 using ppapi::PpapiGlobals;
140 using ppapi::TimeTicksToPPTimeTicks;
141 using ppapi::TimeToPPTime;
142 using ppapi::thunk::EnterResource;
143 using ppapi::thunk::PPB_Graphics2D_API;
144 using ppapi::thunk::PPB_InputEvent_API;
145
146 namespace content {
147
148 namespace {
149
150 // Global tracking info for PPAPI plugins. This is lazily created before the
151 // first plugin is allocated, and leaked on shutdown.
152 //
153 // Note that we don't want a Singleton here since destroying this object will
154 // try to free some stuff that requires WebKit, and Singletons are destroyed
155 // after WebKit.
156 // TODO(raymes): I'm not sure if it is completely necessary to leak the
157 // HostGlobals. Figure out the shutdown sequence and find a way to do this
158 // more elegantly.
159 HostGlobals* host_globals = nullptr;
160
161 // Maintains all currently loaded plugin libs for validating PP_Module
162 // identifiers.
163 typedef std::set<PluginModule*> PluginModuleSet;
164
GetLivePluginSet()165 PluginModuleSet* GetLivePluginSet() {
166 static base::NoDestructor<PluginModuleSet> live_plugin_libs;
167 return live_plugin_libs.get();
168 }
169
170 // PPB_Core --------------------------------------------------------------------
171
AddRefResource(PP_Resource resource)172 void AddRefResource(PP_Resource resource) {
173 PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(resource);
174 }
175
ReleaseResource(PP_Resource resource)176 void ReleaseResource(PP_Resource resource) {
177 PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(resource);
178 }
179
GetTime()180 PP_Time GetTime() { return TimeToPPTime(base::Time::Now()); }
181
GetTickTime()182 PP_TimeTicks GetTickTime() {
183 return TimeTicksToPPTimeTicks(base::TimeTicks::Now());
184 }
185
CallOnMainThread(int delay_in_msec,PP_CompletionCallback callback,int32_t result)186 void CallOnMainThread(int delay_in_msec,
187 PP_CompletionCallback callback,
188 int32_t result) {
189 if (callback.func) {
190 PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostDelayedTask(
191 FROM_HERE, base::BindOnce(callback.func, callback.user_data, result),
192 base::TimeDelta::FromMilliseconds(delay_in_msec));
193 }
194 }
195
IsMainThread()196 PP_Bool IsMainThread() {
197 return PP_FromBool(PpapiGlobals::Get()
198 ->GetMainThreadMessageLoop()
199 ->BelongsToCurrentThread());
200 }
201
202 const PPB_Core core_interface = {&AddRefResource, &ReleaseResource,
203 &GetTime, &GetTickTime,
204 &CallOnMainThread, &IsMainThread};
205
206 // PPB_Testing -----------------------------------------------------------------
207
ReadImageData(PP_Resource device_context_2d,PP_Resource image,const PP_Point * top_left)208 PP_Bool ReadImageData(PP_Resource device_context_2d,
209 PP_Resource image,
210 const PP_Point* top_left) {
211 EnterResource<PPB_Graphics2D_API> enter(device_context_2d, true);
212 if (enter.failed())
213 return PP_FALSE;
214 return PP_FromBool(enter.object()->ReadImageData(image, top_left));
215 }
216
RunMessageLoop(PP_Instance instance)217 void RunMessageLoop(PP_Instance instance) {
218 base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).Run();
219 }
220
QuitMessageLoop(PP_Instance instance)221 void QuitMessageLoop(PP_Instance instance) {
222 base::RunLoop::QuitCurrentDeprecated();
223 }
224
GetLiveObjectsForInstance(PP_Instance instance_id)225 uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) {
226 return HostGlobals::Get()->GetResourceTracker()->GetLiveObjectsForInstance(
227 instance_id);
228 }
229
IsOutOfProcess()230 PP_Bool IsOutOfProcess() { return PP_FALSE; }
231
SimulateInputEvent(PP_Instance instance,PP_Resource input_event)232 void SimulateInputEvent(PP_Instance instance, PP_Resource input_event) {
233 PepperPluginInstanceImpl* plugin_instance =
234 host_globals->GetInstance(instance);
235 if (!plugin_instance)
236 return;
237
238 EnterResource<PPB_InputEvent_API> enter(input_event, false);
239 if (enter.failed())
240 return;
241
242 const InputEventData& input_event_data = enter.object()->GetInputEventData();
243 plugin_instance->SimulateInputEvent(input_event_data);
244 }
245
GetDocumentURL(PP_Instance instance,PP_URLComponents_Dev * components)246 PP_Var GetDocumentURL(PP_Instance instance, PP_URLComponents_Dev* components) {
247 PepperPluginInstanceImpl* plugin_instance =
248 host_globals->GetInstance(instance);
249 if (!plugin_instance)
250 return PP_MakeUndefined();
251 return plugin_instance->GetDocumentURL(instance, components);
252 }
253
GetLiveVars(PP_Var live_vars[],uint32_t array_size)254 uint32_t GetLiveVars(PP_Var live_vars[], uint32_t array_size) {
255 std::vector<PP_Var> vars =
256 PpapiGlobals::Get()->GetVarTracker()->GetLiveVars();
257 for (size_t i = 0u;
258 i < std::min(static_cast<size_t>(array_size), vars.size());
259 ++i)
260 live_vars[i] = vars[i];
261 return vars.size();
262 }
263
SetMinimumArrayBufferSizeForShmem(PP_Instance,uint32_t)264 void SetMinimumArrayBufferSizeForShmem(PP_Instance /*instance*/,
265 uint32_t /*threshold*/) {
266 // Does nothing. Not needed in-process.
267 }
268
RunV8GC(PP_Instance pp_instance)269 void RunV8GC(PP_Instance pp_instance) {
270 PepperPluginInstanceImpl* instance =
271 content::PepperPluginInstanceImpl::GetForTesting(pp_instance);
272 instance->GetIsolate()->RequestGarbageCollectionForTesting(
273 v8::Isolate::kFullGarbageCollection);
274 }
275
276 const PPB_Testing_Private testing_interface = {
277 &ReadImageData,
278 &RunMessageLoop,
279 &QuitMessageLoop,
280 &GetLiveObjectsForInstance,
281 &IsOutOfProcess,
282 &SimulateInputEvent,
283 &GetDocumentURL,
284 &GetLiveVars,
285 &SetMinimumArrayBufferSizeForShmem,
286 &RunV8GC};
287
288 // GetInterface ----------------------------------------------------------------
289
InternalGetInterface(const char * name)290 const void* InternalGetInterface(const char* name) {
291 // TODO(brettw) put these in a hash map for better performance.
292 #define PROXIED_IFACE(iface_str, iface_struct) \
293 if (strcmp(name, iface_str) == 0) \
294 return ppapi::thunk::Get##iface_struct##_Thunk();
295
296 #include "ppapi/thunk/interfaces_ppb_private.h"
297 #include "ppapi/thunk/interfaces_ppb_private_flash.h"
298 #include "ppapi/thunk/interfaces_ppb_private_no_permissions.h"
299 #include "ppapi/thunk/interfaces_ppb_private_pdf.h"
300 #include "ppapi/thunk/interfaces_ppb_public_dev.h"
301 #include "ppapi/thunk/interfaces_ppb_public_dev_channel.h"
302 #include "ppapi/thunk/interfaces_ppb_public_socket.h"
303 #include "ppapi/thunk/interfaces_ppb_public_stable.h"
304
305 #undef PROXIED_IFACE
306
307 #define LEGACY_IFACE(iface_str, function_name) \
308 if (strcmp(name, iface_str) == 0) \
309 return function_name;
310
311 #include "ppapi/thunk/interfaces_legacy.h"
312
313 #undef LEGACY_IFACE
314
315 // Only support the testing interface when the command line switch is
316 // specified. This allows us to prevent people from (ab)using this interface
317 // in production code.
318 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
319 switches::kEnablePepperTesting)) {
320 if (strcmp(name, PPB_TESTING_PRIVATE_INTERFACE) == 0)
321 return &testing_interface;
322 }
323 return nullptr;
324 }
325
GetInterface(const char * name)326 const void* GetInterface(const char* name) {
327 // All interfaces should be used on the main thread.
328 CHECK(IsMainThread());
329
330 return InternalGetInterface(name);
331 }
332
333 // Gets the PPAPI entry points from the given library and places them into the
334 // given structure. Returns true on success.
LoadEntryPointsFromLibrary(const base::NativeLibrary & library,PepperPluginInfo::EntryPoints * entry_points)335 bool LoadEntryPointsFromLibrary(const base::NativeLibrary& library,
336 PepperPluginInfo::EntryPoints* entry_points) {
337 entry_points->get_interface =
338 reinterpret_cast<PepperPluginInfo::GetInterfaceFunc>(
339 base::GetFunctionPointerFromNativeLibrary(library,
340 "PPP_GetInterface"));
341 if (!entry_points->get_interface) {
342 LOG(WARNING) << "No PPP_GetInterface in plugin library";
343 return false;
344 }
345
346 entry_points->initialize_module =
347 reinterpret_cast<PepperPluginInfo::PPP_InitializeModuleFunc>(
348 base::GetFunctionPointerFromNativeLibrary(library,
349 "PPP_InitializeModule"));
350 if (!entry_points->initialize_module) {
351 LOG(WARNING) << "No PPP_InitializeModule in plugin library";
352 return false;
353 }
354
355 // It's okay for PPP_ShutdownModule to not be defined and shutdown_module to
356 // be NULL.
357 entry_points->shutdown_module =
358 reinterpret_cast<PepperPluginInfo::PPP_ShutdownModuleFunc>(
359 base::GetFunctionPointerFromNativeLibrary(library,
360 "PPP_ShutdownModule"));
361
362 return true;
363 }
364
CreateHostForInProcessModule(RenderFrameImpl * render_frame,PluginModule * module,const WebPluginInfo & webplugin_info)365 void CreateHostForInProcessModule(RenderFrameImpl* render_frame,
366 PluginModule* module,
367 const WebPluginInfo& webplugin_info) {
368 // First time an in-process plugin was used, make a host for it.
369 const PepperPluginInfo* info =
370 PepperPluginRegistry::GetInstance()->GetInfoForPlugin(webplugin_info);
371 DCHECK(!info->is_out_of_process);
372
373 ppapi::PpapiPermissions perms(PepperPluginRegistry::GetInstance()
374 ->GetInfoForPlugin(webplugin_info)
375 ->permissions);
376 RendererPpapiHostImpl* host_impl =
377 RendererPpapiHostImpl::CreateOnModuleForInProcess(module, perms);
378 render_frame->PepperPluginCreated(host_impl);
379 }
380
381 } // namespace
382
383 // PluginModule ----------------------------------------------------------------
384
PluginModule(const std::string & name,const std::string & version,const base::FilePath & path,const ppapi::PpapiPermissions & perms)385 PluginModule::PluginModule(const std::string& name,
386 const std::string& version,
387 const base::FilePath& path,
388 const ppapi::PpapiPermissions& perms)
389 : callback_tracker_(new ppapi::CallbackTracker),
390 is_in_destructor_(false),
391 is_crashed_(false),
392 library_(nullptr),
393 name_(name),
394 version_(version),
395 path_(path),
396 permissions_(ppapi::PpapiPermissions::GetForCommandLine(perms.GetBits())),
397 reserve_instance_id_(nullptr) {
398 // Ensure the globals object is created.
399 if (!host_globals)
400 host_globals = new HostGlobals;
401
402 memset(&entry_points_, 0, sizeof(entry_points_));
403 pp_module_ = HostGlobals::Get()->AddModule(this);
404 GetLivePluginSet()->insert(this);
405 }
406
~PluginModule()407 PluginModule::~PluginModule() {
408 // In the past there have been crashes reentering the plugin module
409 // destructor. Catch if that happens again earlier.
410 CHECK(!is_in_destructor_);
411 is_in_destructor_ = true;
412
413 // When the module is being deleted, there should be no more instances still
414 // holding a reference to us.
415 DCHECK(instances_.empty());
416
417 // Some resources and other stuff are hung off of the embedder state, which
418 // should be torn down before the routing stuff below.
419 renderer_ppapi_host_.reset();
420
421 GetLivePluginSet()->erase(this);
422
423 callback_tracker_->AbortAll();
424
425 if (entry_points_.shutdown_module)
426 entry_points_.shutdown_module();
427
428 if (library_)
429 base::UnloadNativeLibrary(library_);
430
431 // Notifications that we've been deleted should be last.
432 HostGlobals::Get()->ModuleDeleted(pp_module_);
433 if (!is_crashed_) {
434 // When the plugin crashes, we immediately tell the lifetime delegate that
435 // we're gone, so we don't want to tell it again.
436 PepperPluginRegistry::GetInstance()->PluginModuleDead(this);
437 }
438
439 // Don't add stuff here, the two notifications that the module object has
440 // been deleted should be last. This allows, for example,
441 // PPB_Proxy.IsInModuleDestructor to map PP_Module to this class during the
442 // previous parts of the destructor.
443 }
444
SetRendererPpapiHost(std::unique_ptr<RendererPpapiHostImpl> host)445 void PluginModule::SetRendererPpapiHost(
446 std::unique_ptr<RendererPpapiHostImpl> host) {
447 renderer_ppapi_host_ = std::move(host);
448 }
449
InitAsInternalPlugin(const PepperPluginInfo::EntryPoints & entry_points)450 bool PluginModule::InitAsInternalPlugin(
451 const PepperPluginInfo::EntryPoints& entry_points) {
452 if (InitializeModule(entry_points)) {
453 entry_points_ = entry_points;
454 return true;
455 }
456 return false;
457 }
458
InitAsLibrary(const base::FilePath & path)459 bool PluginModule::InitAsLibrary(const base::FilePath& path) {
460 base::NativeLibrary library = base::LoadNativeLibrary(path, nullptr);
461 if (!library)
462 return false;
463
464 PepperPluginInfo::EntryPoints entry_points;
465
466 if (!LoadEntryPointsFromLibrary(library, &entry_points) ||
467 !InitializeModule(entry_points)) {
468 base::UnloadNativeLibrary(library);
469 return false;
470 }
471 entry_points_ = entry_points;
472 library_ = library;
473 return true;
474 }
475
InitAsProxied(HostDispatcherWrapper * host_dispatcher_wrapper)476 void PluginModule::InitAsProxied(
477 HostDispatcherWrapper* host_dispatcher_wrapper) {
478 DCHECK(!host_dispatcher_wrapper_.get());
479 host_dispatcher_wrapper_.reset(host_dispatcher_wrapper);
480 }
481
482 scoped_refptr<PluginModule>
CreateModuleForExternalPluginInstance()483 PluginModule::CreateModuleForExternalPluginInstance() {
484 // Create a new module, but don't set the lifetime delegate. This isn't a
485 // plugin in the usual sense, so it isn't tracked by the browser.
486 scoped_refptr<PluginModule> external_plugin_module(
487 new PluginModule(name_, version_, path_, permissions_));
488 return external_plugin_module;
489 }
490
InitAsProxiedExternalPlugin(PepperPluginInstanceImpl * instance)491 PP_ExternalPluginResult PluginModule::InitAsProxiedExternalPlugin(
492 PepperPluginInstanceImpl* instance) {
493 DCHECK(host_dispatcher_wrapper_.get());
494 // InitAsProxied (for the trusted/out-of-process case) initializes only the
495 // module, and one or more instances are added later. In this case, the
496 // PluginInstance was already created as in-process, so we missed the proxy
497 // AddInstance step and must do it now.
498 host_dispatcher_wrapper_->AddInstance(instance->pp_instance());
499 // For external plugins, we need to tell the instance to reset itself as
500 // proxied. This will clear cached interface pointers and send DidCreate (etc)
501 // to the plugin side of the proxy.
502 return instance->ResetAsProxied(this);
503 }
504
IsProxied() const505 bool PluginModule::IsProxied() const { return !!host_dispatcher_wrapper_; }
506
GetPeerProcessId()507 base::ProcessId PluginModule::GetPeerProcessId() {
508 if (host_dispatcher_wrapper_)
509 return host_dispatcher_wrapper_->peer_pid();
510 return base::kNullProcessId;
511 }
512
GetPluginChildId()513 int PluginModule::GetPluginChildId() {
514 if (host_dispatcher_wrapper_)
515 return host_dispatcher_wrapper_->plugin_child_id();
516 return 0;
517 }
518
519 // static
GetCore()520 const PPB_Core* PluginModule::GetCore() { return &core_interface; }
521
522 // static
SupportsInterface(const char * name)523 bool PluginModule::SupportsInterface(const char* name) {
524 return !!InternalGetInterface(name);
525 }
526
CreateInstance(RenderFrameImpl * render_frame,blink::WebPluginContainer * container,const GURL & plugin_url)527 PepperPluginInstanceImpl* PluginModule::CreateInstance(
528 RenderFrameImpl* render_frame,
529 blink::WebPluginContainer* container,
530 const GURL& plugin_url) {
531 PepperPluginInstanceImpl* instance = PepperPluginInstanceImpl::Create(
532 render_frame, this, container, plugin_url);
533 if (!instance) {
534 LOG(WARNING) << "Plugin doesn't support instance interface, failing.";
535 return nullptr;
536 }
537 if (host_dispatcher_wrapper_)
538 host_dispatcher_wrapper_->AddInstance(instance->pp_instance());
539 return instance;
540 }
541
GetSomeInstance() const542 PepperPluginInstanceImpl* PluginModule::GetSomeInstance() const {
543 // This will generally crash later if there is not actually any instance to
544 // return, so we force a crash now to make bugs easier to track down.
545 CHECK(!instances_.empty());
546 return *instances_.begin();
547 }
548
GetPluginInterface(const char * name) const549 const void* PluginModule::GetPluginInterface(const char* name) const {
550 if (host_dispatcher_wrapper_)
551 return host_dispatcher_wrapper_->GetProxiedInterface(name);
552
553 // In-process plugins.
554 if (!entry_points_.get_interface)
555 return nullptr;
556 return entry_points_.get_interface(name);
557 }
558
InstanceCreated(PepperPluginInstanceImpl * instance)559 void PluginModule::InstanceCreated(PepperPluginInstanceImpl* instance) {
560 instances_.insert(instance);
561 }
562
InstanceDeleted(PepperPluginInstanceImpl * instance)563 void PluginModule::InstanceDeleted(PepperPluginInstanceImpl* instance) {
564 if (host_dispatcher_wrapper_)
565 host_dispatcher_wrapper_->RemoveInstance(instance->pp_instance());
566 instances_.erase(instance);
567 }
568
GetCallbackTracker()569 scoped_refptr<ppapi::CallbackTracker> PluginModule::GetCallbackTracker() {
570 return callback_tracker_;
571 }
572
PluginCrashed()573 void PluginModule::PluginCrashed() {
574 DCHECK(!is_crashed_); // Should only get one notification.
575 is_crashed_ = true;
576
577 // Notify all instances that they crashed.
578 for (auto i = instances_.begin(); i != instances_.end(); ++i)
579 (*i)->InstanceCrashed();
580
581 PepperPluginRegistry::GetInstance()->PluginModuleDead(this);
582 }
583
SetReserveInstanceIDCallback(PP_Bool (* reserve)(PP_Module,PP_Instance))584 void PluginModule::SetReserveInstanceIDCallback(
585 PP_Bool (*reserve)(PP_Module, PP_Instance)) {
586 DCHECK(!reserve_instance_id_) << "Only expect one set.";
587 reserve_instance_id_ = reserve;
588 }
589
ReserveInstanceID(PP_Instance instance)590 bool PluginModule::ReserveInstanceID(PP_Instance instance) {
591 if (reserve_instance_id_)
592 return PP_ToBool(reserve_instance_id_(pp_module_, instance));
593 return true; // Instance ID is usable.
594 }
595
CreateOutOfProcessModule(RenderFrameImpl * render_frame,const base::FilePath & path,ppapi::PpapiPermissions permissions,const IPC::ChannelHandle & channel_handle,base::ProcessId peer_pid,int plugin_child_id,bool is_external,scoped_refptr<base::SingleThreadTaskRunner> task_runner)596 RendererPpapiHostImpl* PluginModule::CreateOutOfProcessModule(
597 RenderFrameImpl* render_frame,
598 const base::FilePath& path,
599 ppapi::PpapiPermissions permissions,
600 const IPC::ChannelHandle& channel_handle,
601 base::ProcessId peer_pid,
602 int plugin_child_id,
603 bool is_external,
604 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
605 scoped_refptr<PepperHungPluginFilter> hung_filter(new PepperHungPluginFilter(
606 path, render_frame->GetRoutingID(), plugin_child_id));
607 std::unique_ptr<HostDispatcherWrapper> dispatcher(new HostDispatcherWrapper(
608 this, peer_pid, plugin_child_id, permissions, is_external));
609
610 RenderThreadImpl* render_thread = RenderThreadImpl::current();
611 if (!render_thread)
612 return nullptr;
613 scoped_refptr<gpu::GpuChannelHost> channel =
614 render_thread->EstablishGpuChannelSync();
615 // If no channel is established, feature statuses are unknown and disabled.
616 const gpu::GpuFeatureInfo default_gpu_feature_info;
617 const gpu::GpuFeatureInfo& gpu_feature_info =
618 channel ? channel->gpu_feature_info() : default_gpu_feature_info;
619
620 if (!dispatcher->Init(channel_handle, &GetInterface,
621 ppapi::Preferences(PpapiPreferencesBuilder::Build(
622 render_frame->render_view()->GetBlinkPreferences(),
623 gpu_feature_info)),
624 hung_filter.get(), task_runner)) {
625 return nullptr;
626 }
627
628 RendererPpapiHostImpl* host_impl =
629 RendererPpapiHostImpl::CreateOnModuleForOutOfProcess(
630 this, dispatcher->dispatcher(), permissions);
631 render_frame->PepperPluginCreated(host_impl);
632
633 InitAsProxied(dispatcher.release());
634 return host_impl;
635 }
636
637 // static
ResetHostGlobalsForTest()638 void PluginModule::ResetHostGlobalsForTest() {
639 delete host_globals;
640 host_globals = nullptr;
641 }
642
InitializeModule(const PepperPluginInfo::EntryPoints & entry_points)643 bool PluginModule::InitializeModule(
644 const PepperPluginInfo::EntryPoints& entry_points) {
645 DCHECK(!host_dispatcher_wrapper_.get()) << "Don't call for proxied modules.";
646 DCHECK(entry_points.initialize_module != nullptr);
647 int retval = entry_points.initialize_module(pp_module(), &GetInterface);
648 if (retval != 0) {
649 #if BUILDFLAG(ENABLE_NACL)
650 LOG(WARNING) << "PPP_InitializeModule returned failure " << retval;
651 #endif // BUILDFLAG(ENABLE_NACL)
652 return false;
653 }
654 return true;
655 }
656
Create(RenderFrameImpl * render_frame,const WebPluginInfo & webplugin_info,const base::Optional<url::Origin> & origin_lock,bool * pepper_plugin_was_registered,scoped_refptr<base::SingleThreadTaskRunner> task_runner)657 scoped_refptr<PluginModule> PluginModule::Create(
658 RenderFrameImpl* render_frame,
659 const WebPluginInfo& webplugin_info,
660 const base::Optional<url::Origin>& origin_lock,
661 bool* pepper_plugin_was_registered,
662 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
663 *pepper_plugin_was_registered = true;
664
665 // See if a module has already been loaded for this plugin.
666 base::FilePath path(webplugin_info.path);
667 scoped_refptr<PluginModule> module =
668 PepperPluginRegistry::GetInstance()->GetLiveModule(path, origin_lock);
669 if (module.get()) {
670 if (!module->renderer_ppapi_host()) {
671 // If the module exists and no embedder state was associated with it,
672 // then the module was one of the ones preloaded and is an in-process
673 // plugin. We need to associate our host state with it.
674 CreateHostForInProcessModule(render_frame, module.get(), webplugin_info);
675 }
676 return module;
677 }
678
679 // In-process plugins will have always been created up-front to avoid the
680 // sandbox restrictions. So getting here implies it doesn't exist or should
681 // be out of process.
682 const PepperPluginInfo* info =
683 PepperPluginRegistry::GetInstance()->GetInfoForPlugin(webplugin_info);
684 if (!info) {
685 *pepper_plugin_was_registered = false;
686 return scoped_refptr<PluginModule>();
687 } else if (!info->is_out_of_process) {
688 // In-process plugin not preloaded, it probably couldn't be initialized.
689 return scoped_refptr<PluginModule>();
690 }
691
692 // Out of process: have the browser start the plugin process for us.
693 IPC::ChannelHandle channel_handle;
694 base::ProcessId peer_pid = 0;
695 int plugin_child_id = 0;
696 render_frame->Send(new FrameHostMsg_OpenChannelToPepperPlugin(
697 render_frame->GetWebFrame()->GetSecurityOrigin(), path, origin_lock,
698 &channel_handle, &peer_pid, &plugin_child_id));
699 if (!channel_handle.is_mojo_channel_handle()) {
700 // Couldn't be initialized.
701 return scoped_refptr<PluginModule>();
702 }
703
704 ppapi::PpapiPermissions permissions(info->permissions);
705
706 // AddLiveModule must be called before any early returns since the
707 // module's destructor will remove itself.
708 module = new PluginModule(info->name, info->version, path, permissions);
709 PepperPluginRegistry::GetInstance()->AddLiveModule(path, origin_lock,
710 module.get());
711
712 if (!module->CreateOutOfProcessModule(render_frame, path, permissions,
713 channel_handle, peer_pid,
714 plugin_child_id, false,
715 task_runner)) // is_external = false
716 return scoped_refptr<PluginModule>();
717
718 return module;
719 }
720
721 } // namespace content
722