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
147using ppapi::InputEventData;
148using ppapi::PpapiGlobals;
149using ppapi::TimeTicksToPPTimeTicks;
150using ppapi::TimeToPPTime;
151using ppapi::thunk::EnterResource;
152using ppapi::thunk::PPB_Graphics2D_API;
153using ppapi::thunk::PPB_InputEvent_API;
154
155namespace content {
156
157namespace {
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.
168HostGlobals* host_globals = NULL;
169
170// Maintains all currently loaded plugin libs for validating PP_Module
171// identifiers.
172typedef std::set<PluginModule*> PluginModuleSet;
173
174PluginModuleSet* GetLivePluginSet() {
175  CR_DEFINE_STATIC_LOCAL(PluginModuleSet, live_plugin_libs, ());
176  return &live_plugin_libs;
177}
178
179// PPB_Core --------------------------------------------------------------------
180
181void AddRefResource(PP_Resource resource) {
182  PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(resource);
183}
184
185void ReleaseResource(PP_Resource resource) {
186  PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(resource);
187}
188
189PP_Time GetTime() {
190  return TimeToPPTime(base::Time::Now());
191}
192
193PP_TimeTicks GetTickTime() {
194  return TimeTicksToPPTimeTicks(base::TimeTicks::Now());
195}
196
197void 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
208PP_Bool IsMainThread() {
209  return BoolToPPBool(PpapiGlobals::Get()->
210      GetMainThreadMessageLoop()->BelongsToCurrentThread());
211}
212
213const PPB_Core core_interface = {
214  &AddRefResource,
215  &ReleaseResource,
216  &GetTime,
217  &GetTickTime,
218  &CallOnMainThread,
219  &IsMainThread
220};
221
222// PPB_Testing -----------------------------------------------------------------
223
224PP_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
233void RunMessageLoop(PP_Instance instance) {
234  base::MessageLoop::ScopedNestableTaskAllower allow(
235      base::MessageLoop::current());
236  base::MessageLoop::current()->Run();
237}
238
239void QuitMessageLoop(PP_Instance instance) {
240  base::MessageLoop::current()->QuitNow();
241}
242
243uint32_t GetLiveObjectsForInstance(PP_Instance instance_id) {
244  return HostGlobals::Get()->GetResourceTracker()->GetLiveObjectsForInstance(
245      instance_id);
246}
247
248PP_Bool IsOutOfProcess() {
249  return PP_FALSE;
250}
251
252void 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
266PP_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
274uint32_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
284void SetMinimumArrayBufferSizeForShmem(PP_Instance /*instance*/,
285                                       uint32_t /*threshold*/) {
286  // Does nothing. Not needed in-process.
287}
288
289const 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
303const 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
345const 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.
354bool 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
385void 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
405PluginModule::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
426PluginModule::~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
464void PluginModule::SetRendererPpapiHost(
465    scoped_ptr<RendererPpapiHostImpl> host) {
466  renderer_ppapi_host_ = host.Pass();
467}
468
469bool 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
478bool 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
495void PluginModule::InitAsProxied(
496    HostDispatcherWrapper* host_dispatcher_wrapper) {
497  DCHECK(!host_dispatcher_wrapper_.get());
498  host_dispatcher_wrapper_.reset(host_dispatcher_wrapper);
499}
500
501scoped_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
512PP_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
526bool PluginModule::IsProxied() const {
527  return !!host_dispatcher_wrapper_;
528}
529
530base::ProcessId PluginModule::GetPeerProcessId() {
531  if (host_dispatcher_wrapper_)
532    return host_dispatcher_wrapper_->peer_pid();
533  return base::kNullProcessId;
534}
535
536int PluginModule::GetPluginChildId() {
537  if (host_dispatcher_wrapper_)
538    return host_dispatcher_wrapper_->plugin_child_id();
539  return 0;
540}
541
542// static
543const PPB_Core* PluginModule::GetCore() {
544  return &core_interface;
545}
546
547// static
548bool PluginModule::SupportsInterface(const char* name) {
549  return !!InternalGetInterface(name);
550}
551
552PepperPluginInstanceImpl* 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
567PepperPluginInstanceImpl* 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
574const 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
584void PluginModule::InstanceCreated(PepperPluginInstanceImpl* instance) {
585  instances_.insert(instance);
586}
587
588void PluginModule::InstanceDeleted(PepperPluginInstanceImpl* instance) {
589  if (host_dispatcher_wrapper_)
590    host_dispatcher_wrapper_->RemoveInstance(instance->pp_instance());
591  instances_.erase(instance);
592}
593
594scoped_refptr<ppapi::CallbackTracker> PluginModule::GetCallbackTracker() {
595  return callback_tracker_;
596}
597
598void 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
610void 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
616bool 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
622void PluginModule::SetBroker(PepperBroker* broker) {
623  DCHECK(!broker_ || !broker);
624  broker_ = broker;
625}
626
627PepperBroker* PluginModule::GetBroker() {
628  return broker_;
629}
630
631RendererPpapiHostImpl* 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
664void PluginModule::ResetHostGlobalsForTest() {
665  delete host_globals;
666  host_globals = NULL;
667}
668
669bool 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
681scoped_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