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