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