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