Home | History | Annotate | Download | only in proxy
      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 #ifndef PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_
      6 #define PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_
      7 
      8 #include <map>
      9 #include <string>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/shared_memory.h"
     15 #include "ppapi/c/pp_stdint.h"
     16 #include "ppapi/c/pp_var.h"
     17 #include "ppapi/proxy/ppapi_proxy_export.h"
     18 #include "ppapi/shared_impl/var_tracker.h"
     19 
     20 template<typename T> struct DefaultSingletonTraits;
     21 struct PPP_Class_Deprecated;
     22 
     23 namespace ppapi {
     24 
     25 class ProxyObjectVar;
     26 
     27 namespace proxy {
     28 
     29 class PluginDispatcher;
     30 
     31 // Tracks live strings and objects in the plugin process.
     32 class PPAPI_PROXY_EXPORT PluginVarTracker : public VarTracker {
     33  public:
     34   PluginVarTracker();
     35   ~PluginVarTracker();
     36 
     37   // Manages tracking for receiving a VARTYPE_OBJECT from the remote side
     38   // (either the plugin or the renderer) that has already had its reference
     39   // count incremented on behalf of the caller.
     40   PP_Var ReceiveObjectPassRef(const PP_Var& var, PluginDispatcher* dispatcher);
     41 
     42   // See the comment in var_tracker.h for more about what a tracked object is.
     43   // This adds and releases the "track_with_no_reference_count" for a given
     44   // object.
     45   PP_Var TrackObjectWithNoReference(const PP_Var& host_var,
     46                                     PluginDispatcher* dispatcher);
     47   void StopTrackingObjectWithNoReference(const PP_Var& plugin_var);
     48 
     49   // Returns the host var for the corresponding plugin object var. The object
     50   // should be a VARTYPE_OBJECT. The reference count is not affeceted.
     51   PP_Var GetHostObject(const PP_Var& plugin_object) const;
     52 
     53   PluginDispatcher* DispatcherForPluginObject(
     54       const PP_Var& plugin_object) const;
     55 
     56   // Like Release() but the var is identified by its host object ID (as
     57   // returned by GetHostObject).
     58   void ReleaseHostObject(PluginDispatcher* dispatcher,
     59                          const PP_Var& host_object);
     60 
     61   // VarTracker public overrides.
     62   virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE;
     63   virtual int TrackSharedMemoryHandle(PP_Instance instance,
     64                                       base::SharedMemoryHandle file,
     65                                       uint32 size_in_bytes) OVERRIDE;
     66   virtual bool StopTrackingSharedMemoryHandle(int id,
     67                                               PP_Instance instance,
     68                                               base::SharedMemoryHandle* handle,
     69                                               uint32* size_in_bytes) OVERRIDE;
     70 
     71   // Notification that a plugin-implemented object (PPP_Class) was created by
     72   // the plugin or deallocated by WebKit over IPC.
     73   void PluginImplementedObjectCreated(PP_Instance instance,
     74                                       const PP_Var& created_var,
     75                                       const PPP_Class_Deprecated* ppp_class,
     76                                       void* ppp_class_data);
     77   void PluginImplementedObjectDestroyed(void* ppp_class_data);
     78 
     79   // Returns true if there is an object implemented by the plugin with the
     80   // given user_data that has not been deallocated yet. Call this when
     81   // receiving a scripting call to the plugin to validate that the object
     82   // receiving the call is still alive (see user_data_to_plugin_ below).
     83   bool IsPluginImplementedObjectAlive(void* user_data);
     84 
     85   // Validates that the given class/user_data pair corresponds to a currently
     86   // living plugin object.
     87   bool ValidatePluginObjectCall(const PPP_Class_Deprecated* ppp_class,
     88                                 void* user_data);
     89 
     90   void DidDeleteDispatcher(PluginDispatcher* dispatcher);
     91 
     92  private:
     93   // VarTracker protected overrides.
     94   virtual int32 AddVarInternal(Var* var, AddVarRefMode mode) OVERRIDE;
     95   virtual void TrackedObjectGettingOneRef(VarMap::const_iterator iter) OVERRIDE;
     96   virtual void ObjectGettingZeroRef(VarMap::iterator iter) OVERRIDE;
     97   virtual bool DeleteObjectInfoIfNecessary(VarMap::iterator iter) OVERRIDE;
     98   virtual ArrayBufferVar* CreateArrayBuffer(uint32 size_in_bytes) OVERRIDE;
     99   virtual ArrayBufferVar* CreateShmArrayBuffer(
    100       uint32 size_in_bytes,
    101       base::SharedMemoryHandle handle) OVERRIDE;
    102 
    103  private:
    104   friend struct DefaultSingletonTraits<PluginVarTracker>;
    105   friend class PluginProxyTestHarness;
    106 
    107   // Represents a var as received from the host.
    108   struct HostVar {
    109     HostVar(PluginDispatcher* d, int32 i);
    110 
    111     bool operator<(const HostVar& other) const;
    112 
    113     // The dispatcher that sent us this object. This is used so we know how to
    114     // send back requests on this object.
    115     PluginDispatcher* dispatcher;
    116 
    117     // The object ID that the host generated to identify the object. This is
    118     // unique only within that host: different hosts could give us different
    119     // objects with the same ID.
    120     int32 host_object_id;
    121   };
    122 
    123   struct PluginImplementedVar {
    124     const PPP_Class_Deprecated* ppp_class;
    125 
    126     // The instance that created this Var. This will be 0 if the instance has
    127     // been destroyed but the object is still alive.
    128     PP_Instance instance;
    129 
    130     // Represents the plugin var ID for the var corresponding to this object.
    131     // If the plugin does not have a ref to the object but it's still alive
    132     // (the DOM could be holding a ref keeping it alive) this will be 0.
    133     //
    134     // There is an obscure corner case. If the plugin returns an object to the
    135     // renderer and releases all of its refs, the object will still be alive
    136     // but there will be no plugin refs. It's possible for the plugin to get
    137     // this same object again through the DOM, and we'll lose the correlation
    138     // between plugin implemented object and car. This means we won't know when
    139     // the plugin releases its last refs and may call Deallocate when the
    140     // plugin is still holding a ref.
    141     //
    142     // However, for the plugin to be depending on holding a ref to an object
    143     // that it implements that it previously released but got again through
    144     // indirect means would be extremely rare, and we only allow var scripting
    145     // in limited cases anyway.
    146     int32 plugin_object_id;
    147   };
    148 
    149   // Returns the existing var ID for the given object var, creating and
    150   // assigning an ID to it if necessary. This does not affect the reference
    151   // count, so in the creation case the refcount will be 0. It's assumed in
    152   // this case the caller will either adjust the refcount or the
    153   // track_with_no_reference_count.
    154   PP_Var GetOrCreateObjectVarID(ProxyObjectVar* object);
    155 
    156   // Sends an addref or release message to the browser for the given object ID.
    157   void SendAddRefObjectMsg(const ProxyObjectVar& proxy_object);
    158   void SendReleaseObjectMsg(const ProxyObjectVar& proxy_object);
    159 
    160   // Looks up the given host var. If we already know about it, returns a
    161   // reference to the already-tracked object. If it doesn't creates a new one
    162   // and returns it. If it's created, it's not added to the map.
    163   scoped_refptr<ProxyObjectVar> FindOrMakePluginVarFromHostVar(
    164       const PP_Var& var,
    165       PluginDispatcher* dispatcher);
    166 
    167   // Maps host vars in the host to IDs in the plugin process.
    168   typedef std::map<HostVar, int32> HostVarToPluginVarMap;
    169   HostVarToPluginVarMap host_var_to_plugin_var_;
    170 
    171   // Maps "user data" for plugin implemented objects (PPP_Class) that are
    172   // alive to various tracking info.
    173   //
    174   // This is tricky because there may not actually be any vars in the plugin
    175   // associated with a plugin-implemented object, so they won't all have
    176   // entries in our HostVarToPluginVarMap or the base class VarTracker's map.
    177   //
    178   // All objects that the plugin has created using CreateObject that have not
    179   // yet been Deallocate()-ed by WebKit will be in this map. When the instance
    180   // that created the object goes away, we know to call Deallocate on all
    181   // remaining objects for that instance so that the data backing the object
    182   // that the plugin owns is not leaked. We may not receive normal Deallocate
    183   // calls from WebKit because the object could be leaked (attached to the DOM
    184   // and outliving the plugin instance) or WebKit could send the deallocate
    185   // after the out-of-process routing for that instance was torn down.
    186   //
    187   // There is an additional complexity. In WebKit, objects created by the
    188   // plugin aren't actually bound to the plugin instance (for example, you
    189   // could attach it to the DOM or send it to another plugin instance). It's
    190   // possible that we could force deallocate an object when an instance id
    191   // destroyed, but then another instance could get to that object somehow
    192   // (like by reading it out of the DOM). We will then have deallocated the
    193   // object and can't complete the call. We do not care about this case, and
    194   // the calls will just fail.
    195   typedef std::map<void*, PluginImplementedVar>
    196       UserDataToPluginImplementedVarMap;
    197   UserDataToPluginImplementedVarMap user_data_to_plugin_;
    198 
    199   DISALLOW_COPY_AND_ASSIGN(PluginVarTracker);
    200 };
    201 
    202 }  // namespace proxy
    203 }  // namespace ppapi
    204 
    205 #endif  // PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_
    206