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