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