// 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 PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ #define PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ #include <map> #include <string> #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/shared_memory.h" #include "ppapi/c/pp_stdint.h" #include "ppapi/c/pp_var.h" #include "ppapi/proxy/ppapi_proxy_export.h" #include "ppapi/shared_impl/var_tracker.h" template<typename T> struct DefaultSingletonTraits; struct PPP_Class_Deprecated; namespace ppapi { class ProxyObjectVar; namespace proxy { class PluginDispatcher; // Tracks live strings and objects in the plugin process. class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker { public: PluginVarTracker(); ~PluginVarTracker(); // Manages tracking for receiving a VARTYPE_OBJECT from the remote side // (either the plugin or the renderer) that has already had its reference // count incremented on behalf of the caller. PP_Var ReceiveObjectPassRef(const PP_Var& var, PluginDispatcher* dispatcher); // See the comment in var_tracker.h for more about what a tracked object is. // This adds and releases the "track_with_no_reference_count" for a given // object. PP_Var TrackObjectWithNoReference(const PP_Var& host_var, PluginDispatcher* dispatcher); void StopTrackingObjectWithNoReference(const PP_Var& plugin_var); // Returns the host var for the corresponding plugin object var. The object // should be a VARTYPE_OBJECT. The reference count is not affeceted. PP_Var GetHostObject(const PP_Var& plugin_object) const; PluginDispatcher* DispatcherForPluginObject( const PP_Var& plugin_object) const; // Like Release() but the var is identified by its host object ID (as // returned by GetHostObject). void ReleaseHostObject(PluginDispatcher* dispatcher, const PP_Var& host_object); // VarTracker public overrides. virtual PP_Var MakeResourcePPVarFromMessage( PP_Instance instance, const IPC::Message& creation_message, int pending_renderer_id, int pending_browser_id) OVERRIDE; virtual ResourceVar* MakeResourceVar(PP_Resource pp_resource) OVERRIDE; virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE; virtual int TrackSharedMemoryHandle(PP_Instance instance, base::SharedMemoryHandle file, uint32 size_in_bytes) OVERRIDE; virtual bool StopTrackingSharedMemoryHandle(int id, PP_Instance instance, base::SharedMemoryHandle* handle, uint32* size_in_bytes) OVERRIDE; // Notification that a plugin-implemented object (PPP_Class) was created by // the plugin or deallocated by WebKit over IPC. void PluginImplementedObjectCreated(PP_Instance instance, const PP_Var& created_var, const PPP_Class_Deprecated* ppp_class, void* ppp_class_data); void PluginImplementedObjectDestroyed(void* ppp_class_data); // Returns true if there is an object implemented by the plugin with the // given user_data that has not been deallocated yet. Call this when // receiving a scripting call to the plugin to validate that the object // receiving the call is still alive (see user_data_to_plugin_ below). bool IsPluginImplementedObjectAlive(void* user_data); // Validates that the given class/user_data pair corresponds to a currently // living plugin object. bool ValidatePluginObjectCall(const PPP_Class_Deprecated* ppp_class, void* user_data); void DidDeleteDispatcher(PluginDispatcher* dispatcher); private: // VarTracker protected overrides. virtual int32 AddVarInternal(Var* var, AddVarRefMode mode) OVERRIDE; virtual void TrackedObjectGettingOneRef(VarMap::const_iterator iter) OVERRIDE; virtual void ObjectGettingZeroRef(VarMap::iterator iter) OVERRIDE; virtual bool DeleteObjectInfoIfNecessary(VarMap::iterator iter) OVERRIDE; virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) OVERRIDE; virtual ArrayBufferVar* CreateShmArrayBuffer( uint32 size_in_bytes, base::SharedMemoryHandle handle) OVERRIDE; private: friend struct DefaultSingletonTraits<PluginVarTracker>; friend class PluginProxyTestHarness; // Represents a var as received from the host. struct HostVar { HostVar(PluginDispatcher* d, int32 i); bool operator<(const HostVar& other) const; // The dispatcher that sent us this object. This is used so we know how to // send back requests on this object. PluginDispatcher* dispatcher; // The object ID that the host generated to identify the object. This is // unique only within that host: different hosts could give us different // objects with the same ID. int32 host_object_id; }; struct PluginImplementedVar { const PPP_Class_Deprecated* ppp_class; // The instance that created this Var. This will be 0 if the instance has // been destroyed but the object is still alive. PP_Instance instance; // Represents the plugin var ID for the var corresponding to this object. // If the plugin does not have a ref to the object but it's still alive // (the DOM could be holding a ref keeping it alive) this will be 0. // // There is an obscure corner case. If the plugin returns an object to the // renderer and releases all of its refs, the object will still be alive // but there will be no plugin refs. It's possible for the plugin to get // this same object again through the DOM, and we'll lose the correlation // between plugin implemented object and car. This means we won't know when // the plugin releases its last refs and may call Deallocate when the // plugin is still holding a ref. // // However, for the plugin to be depending on holding a ref to an object // that it implements that it previously released but got again through // indirect means would be extremely rare, and we only allow var scripting // in limited cases anyway. int32 plugin_object_id; }; // Returns the existing var ID for the given object var, creating and // assigning an ID to it if necessary. This does not affect the reference // count, so in the creation case the refcount will be 0. It's assumed in // this case the caller will either adjust the refcount or the // track_with_no_reference_count. PP_Var GetOrCreateObjectVarID(ProxyObjectVar* object); // Sends an addref or release message to the browser for the given object ID. void SendAddRefObjectMsg(const ProxyObjectVar& proxy_object); void SendReleaseObjectMsg(const ProxyObjectVar& proxy_object); // Looks up the given host var. If we already know about it, returns a // reference to the already-tracked object. If it doesn't creates a new one // and returns it. If it's created, it's not added to the map. scoped_refptr<ProxyObjectVar> FindOrMakePluginVarFromHostVar( const PP_Var& var, PluginDispatcher* dispatcher); // Maps host vars in the host to IDs in the plugin process. typedef std::map<HostVar, int32> HostVarToPluginVarMap; HostVarToPluginVarMap host_var_to_plugin_var_; // Maps "user data" for plugin implemented objects (PPP_Class) that are // alive to various tracking info. // // This is tricky because there may not actually be any vars in the plugin // associated with a plugin-implemented object, so they won't all have // entries in our HostVarToPluginVarMap or the base class VarTracker's map. // // All objects that the plugin has created using CreateObject that have not // yet been Deallocate()-ed by WebKit will be in this map. When the instance // that created the object goes away, we know to call Deallocate on all // remaining objects for that instance so that the data backing the object // that the plugin owns is not leaked. We may not receive normal Deallocate // calls from WebKit because the object could be leaked (attached to the DOM // and outliving the plugin instance) or WebKit could send the deallocate // after the out-of-process routing for that instance was torn down. // // There is an additional complexity. In WebKit, objects created by the // plugin aren't actually bound to the plugin instance (for example, you // could attach it to the DOM or send it to another plugin instance). It's // possible that we could force deallocate an object when an instance id // destroyed, but then another instance could get to that object somehow // (like by reading it out of the DOM). We will then have deallocated the // object and can't complete the call. We do not care about this case, and // the calls will just fail. typedef std::map<void*, PluginImplementedVar> UserDataToPluginImplementedVarMap; UserDataToPluginImplementedVarMap user_data_to_plugin_; DISALLOW_COPY_AND_ASSIGN(PluginVarTracker); }; } // namespace proxy } // namespace ppapi #endif // PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_