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