| // 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_ |