// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_RENDERER_PEPPER_PLUGIN_MODULE_H_ #define CONTENT_RENDERER_PEPPER_PLUGIN_MODULE_H_ #include <map> #include <set> #include <string> #include "base/basictypes.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/native_library.h" #include "base/process/process.h" #include "content/common/content_export.h" #include "content/public/common/pepper_plugin_info.h" #include "ppapi/c/pp_bool.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/ppb_core.h" #include "ppapi/c/private/ppb_instance_private.h" #include "ppapi/shared_impl/ppapi_permissions.h" typedef void* NPIdentifier; class GURL; namespace base { class FilePath; } namespace ppapi { class CallbackTracker; class WebKitForwarding; } // namespace ppapi namespace IPC { struct ChannelHandle; } namespace blink { class WebPluginContainer; } // namespace blink namespace content { class HostDispatcherWrapper; class PepperPluginInstanceImpl; class PepperBroker; class RendererPpapiHostImpl; class RenderFrameImpl; struct WebPluginInfo; // Represents one plugin library loaded into one renderer. This library may // have multiple instances. // // Note: to get from a PP_Instance to a PepperPluginInstance*, use the // ResourceTracker. class CONTENT_EXPORT PluginModule : public base::RefCounted<PluginModule>, public base::SupportsWeakPtr<PluginModule> { public: typedef std::set<PepperPluginInstanceImpl*> PluginInstanceSet; // You must call one of the Init functions after the constructor to create a // module of the type you desire. // // The module lifetime delegate is a non-owning pointer that must outlive // all plugin modules. In practice it will be a global singleton that // tracks which modules are alive. PluginModule(const std::string& name, const base::FilePath& path, const ppapi::PpapiPermissions& perms); // Sets the given class as being associated with this module. It will be // deleted when the module is destroyed. You can only set it once, subsequent // sets will assert. void SetRendererPpapiHost(scoped_ptr<RendererPpapiHostImpl> host); // Initializes this module as an internal plugin with the given entrypoints. // This is used for "plugins" compiled into Chrome. Returns true on success. // False means that the plugin can not be used. bool InitAsInternalPlugin(const PepperPluginInfo::EntryPoints& entry_points); // Initializes this module using the given library path as the plugin. // Returns true on success. False means that the plugin can not be used. bool InitAsLibrary(const base::FilePath& path); // Initializes this module for the given out of process proxy. This takes // ownership of the given pointer, even in the failure case. void InitAsProxied(HostDispatcherWrapper* host_dispatcher_wrapper); // Creates a new module for an external plugin instance that will be using the // IPC proxy. We can't use the existing module, or new instances of the plugin // can't be created. scoped_refptr<PluginModule> CreateModuleForExternalPluginInstance(); // Initializes the external plugin module for the out of process proxy. // InitAsProxied must be called before calling InitAsProxiedExternalPlugin. // Returns a result code indicating whether the proxy started successfully or // there was an error. PP_ExternalPluginResult InitAsProxiedExternalPlugin( PepperPluginInstanceImpl* instance); bool IsProxied() const; // Returns the peer process ID if the plugin is running out of process; // returns |base::kNullProcessId| otherwise. base::ProcessId GetPeerProcessId(); // Returns the plugin child process ID if the plugin is running out of // process. Returns 0 otherwise. This is the ID that the browser process uses // to idetify the child process for the plugin. This isn't directly useful // from our process (the renderer) except in messages to the browser to // disambiguate plugins. int GetPluginChildId(); static const PPB_Core* GetCore(); // Returns whether an interface is supported. This method can be called from // the browser process and used for interface matching before plugin // registration. // NOTE: those custom interfaces provided by ContentRendererClient will not be // considered when called on the browser process. static bool SupportsInterface(const char* name); RendererPpapiHostImpl* renderer_ppapi_host() { return renderer_ppapi_host_.get(); } // Returns the module handle. This may be used before Init() is called (the // proxy needs this information to set itself up properly). PP_Module pp_module() const { return pp_module_; } const std::string& name() const { return name_; } const base::FilePath& path() const { return path_; } const ppapi::PpapiPermissions& permissions() const { return permissions_; } PepperPluginInstanceImpl* CreateInstance(RenderFrameImpl* render_frame, blink::WebPluginContainer* container, const GURL& plugin_url); // Returns "some" plugin instance associated with this module. This is not // guaranteed to be any one in particular. This is normally used to execute // callbacks up to the browser layer that are not inherently per-instance, // but the helper lives only on the plugin instance so we need one of them. PepperPluginInstanceImpl* GetSomeInstance() const; const PluginInstanceSet& GetAllInstances() const { return instances_; } // Calls the plugin's GetInterface and returns the given interface pointer, // which could be NULL. const void* GetPluginInterface(const char* name) const; // This module is associated with a set of instances. The PluginInstance // object declares its association with this module in its destructor and // releases us in its destructor. void InstanceCreated(PepperPluginInstanceImpl* instance); void InstanceDeleted(PepperPluginInstanceImpl* instance); scoped_refptr<ppapi::CallbackTracker> GetCallbackTracker(); // Called when running out of process and the plugin crashed. This will // release relevant resources and update all affected instances. void PluginCrashed(); bool is_in_destructor() const { return is_in_destructor_; } bool is_crashed() const { return is_crashed_; } // Reserves the given instance is unique within the plugin, checking for // collisions. See PPB_Proxy_Private for more information. // // The setter will set the callback which is set up when the proxy // initializes. The Reserve function will call the previously set callback if // it exists to validate the ID. If the callback has not been set (such as // for in-process plugins), the Reserve function will assume that the ID is // usable and will return true. void SetReserveInstanceIDCallback(PP_Bool (*reserve)(PP_Module, PP_Instance)); bool ReserveInstanceID(PP_Instance instance); // These should only be called from the main thread. void SetBroker(PepperBroker* broker); PepperBroker* GetBroker(); // Create a new HostDispatcher for proxying, hook it to the PluginModule, // and perform other common initialization. RendererPpapiHostImpl* CreateOutOfProcessModule( RenderFrameImpl* render_frame, const base::FilePath& path, ppapi::PpapiPermissions permissions, const IPC::ChannelHandle& channel_handle, base::ProcessId plugin_pid, int plugin_child_id, bool is_external); // In production we purposely leak the HostGlobals object but in unittest // code, this can interfere with subsequent tests. This deletes the // existing HostGlobals. A new one will be constructed when a PluginModule is // instantiated. static void ResetHostGlobalsForTest(); // Attempts to create a PPAPI plugin for the given filepath. On success, it // will return the newly-created module. // // There are two reasons for failure. The first is that the plugin isn't // a PPAPI plugin. In this case, |*pepper_plugin_was_registered| will be set // to false and the caller may want to fall back on creating an NPAPI plugin. // the second is that the plugin failed to initialize. In this case, // |*pepper_plugin_was_registered| will be set to true and the caller should // not fall back on any other plugin types. static scoped_refptr<PluginModule> Create(RenderFrameImpl* render_frame, const WebPluginInfo& webplugin_info, bool* pepper_plugin_was_registered); private: friend class base::RefCounted<PluginModule>; ~PluginModule(); // Calls the InitializeModule entrypoint. The entrypoint must have been // set and the plugin must not be out of process (we don't maintain // entrypoints in that case). bool InitializeModule(const PepperPluginInfo::EntryPoints& entry_points); scoped_ptr<RendererPpapiHostImpl> renderer_ppapi_host_; // Tracker for completion callbacks, used mainly to ensure that all callbacks // are properly aborted on module shutdown. scoped_refptr<ppapi::CallbackTracker> callback_tracker_; PP_Module pp_module_; // True when we're running in the destructor. This allows us to write some // assertions. bool is_in_destructor_; // True if the plugin is running out-of-process and has crashed. bool is_crashed_; // Manages the out of process proxy interface. The presence of this // pointer indicates that the plugin is running out of process and that the // entry_points_ aren't valid. scoped_ptr<HostDispatcherWrapper> host_dispatcher_wrapper_; // Non-owning pointer to the broker for this plugin module, if one exists. // It is populated and cleared in the main thread. PepperBroker* broker_; // Holds a reference to the base::NativeLibrary handle if this PluginModule // instance wraps functions loaded from a library. Can be NULL. If // |library_| is non-NULL, PluginModule will attempt to unload the library // during destruction. base::NativeLibrary library_; // Contains pointers to the entry points of the actual plugin implementation. // These will be NULL for out-of-process plugins, which is indicated by the // presence of the host_dispatcher_wrapper_ value. PepperPluginInfo::EntryPoints entry_points_; // The name and file location of the module. const std::string name_; const base::FilePath path_; ppapi::PpapiPermissions permissions_; // Non-owning pointers to all instances associated with this module. When // there are no more instances, this object should be deleted. PluginInstanceSet instances_; PP_Bool (*reserve_instance_id_)(PP_Module, PP_Instance); DISALLOW_COPY_AND_ASSIGN(PluginModule); }; } // namespace content #endif // CONTENT_RENDERER_PEPPER_PLUGIN_MODULE_H_