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