diff options
Diffstat (limited to 'ppapi/proxy/plugin_var_tracker.h')
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.h | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/ppapi/proxy/plugin_var_tracker.h b/ppapi/proxy/plugin_var_tracker.h new file mode 100644 index 0000000..748ec2d --- /dev/null +++ b/ppapi/proxy/plugin_var_tracker.h @@ -0,0 +1,196 @@ +// Copyright (c) 2011 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/memory/ref_counted.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/pp_var.h" + +struct PPB_Var; + +template<typename T> struct DefaultSingletonTraits; + +namespace pp { +namespace proxy { + +class PluginDispatcher; + +// Tracks live strings and objects in the plugin process. +// +// This object maintains its own object IDs that are used by the plugin. These +// IDs can be mapped to the renderer that created them, and that renderer's ID. +// This way, we can maintain multiple renderers each giving us objects, and the +// plugin can work with them using a uniform set of unique IDs. +// +// We maintain our own reference count for objects. a single ref in the +// renderer process whenever we have a nonzero refcount in the plugin process. +// This allows AddRef and Release to not initiate too much IPC chat. +// +// In addition to the local reference count, we also maintain "tracked objects" +// which are objects that the plugin is aware of, but doesn't hold a reference +// to. This will happen when the plugin is passed an object as an argument from +// the host (renderer) but where a reference is not passed. +class PluginVarTracker { + public: + typedef int64_t VarID; + + // Called by tests that want to specify a specific VarTracker. This allows + // them to use a unique one each time and avoids singletons sticking around + // across tests. + static void SetInstanceForTest(PluginVarTracker* tracker); + + // Returns the global var tracker for the plugin object. + static PluginVarTracker* GetInstance(); + + // Allocates a string and returns the ID of it. The refcount will be 1. + VarID MakeString(const std::string& str); + VarID MakeString(const char* str, uint32_t len); + + // Returns a pointer to the given string if it exists, or NULL if the var + // isn't a string var. + const std::string* GetExistingString(const PP_Var& plugin_var) const; + + void AddRef(const PP_Var& plugin_var); + void Release(const PP_Var& plugin_var); + + // 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); + + 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 + 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); + + // Retrieves the internal reference counts for testing. Returns 0 if we + // know about the object but the corresponding value is 0, or -1 if the + // given object ID isn't in our map. + int GetRefCountForObject(const PP_Var& plugin_object); + int GetTrackedWithNoReferenceCountForObject(const PP_Var& plugin_object); + + private: + friend struct DefaultSingletonTraits<PluginVarTracker>; + friend class PluginProxyTestHarness; + + class RefCountedString : public base::RefCounted<RefCountedString> { + public: + RefCountedString() { + } + RefCountedString(const std::string& str) : value_(str) { + } + RefCountedString(const char* data, size_t len) + : value_(data, len) { + } + + const std::string& value() const { return value_; } + + private: + std::string value_; + + // Ensure only base::RefCounted can delete a RefCountedString. + friend void base::RefCounted<RefCountedString>::Release() const; + virtual ~RefCountedString() {} + }; + typedef scoped_refptr<RefCountedString> RefCountedStringPtr; + + // Represents a var as received from the host. + struct HostVar { + HostVar(PluginDispatcher* d, int64_t 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. + VarID host_object_id; + }; + + // The information associated with a var object in the plugin. + struct PluginVarInfo { + PluginVarInfo(const HostVar& host_var); + + // Maps back to the original var in the host. + HostVar host_var; + + // Explicit reference count. This value is affected by the renderer calling + // AddRef and Release. A nonzero value here is represented by a single + // reference in the host on our behalf (this reduces IPC traffic). + int32_t ref_count; + + // Tracked object count (see class comment above). + // + // "TrackObjectWithNoReference" might be called recursively in rare cases. + // For example, say the host calls a plugin function with an object as an + // argument, and in response, the plugin calls a host function that then + // calls another (or the same) plugin function with the same object. + // + // This value tracks the number of calls to TrackObjectWithNoReference so + // we know when we can stop tracking this object. + int32_t track_with_no_reference_count; + }; + + typedef std::map<int64_t, PluginVarInfo> PluginVarInfoMap; + + PluginVarTracker(); + ~PluginVarTracker(); + + // Sends an addref or release message to the browser for the given object ID. + void SendAddRefObjectMsg(const HostVar& host_var); + void SendReleaseObjectMsg(const HostVar& host_var); + + PluginVarInfoMap::iterator FindOrMakePluginVarFromHostVar( + const PP_Var& var, + PluginDispatcher* dispatcher); + + // Checks the reference counds of the given plugin var info and removes the + // tracking information if necessary. We're done with the object when its + // explicit reference count and its "tracked with no reference" count both + // reach zero. + void DeletePluginVarInfoIfNecessary(PluginVarInfoMap::iterator iter); + + // Tracks all information about plugin vars. + PluginVarInfoMap plugin_var_info_; + + // Maps host vars to plugin vars. This allows us to know if we've previously + // seen a host var and re-use the information. + typedef std::map<HostVar, VarID> HostVarToPluginVarMap; + HostVarToPluginVarMap host_var_to_plugin_var_; + + // Maps plugin var IDs to ref counted strings. + typedef std::map<VarID, RefCountedStringPtr> VarIDStringMap; + VarIDStringMap var_id_to_string_; + + // The last plugin PP_Var ID we've handed out. This must be unique for the + // process. + VarID last_plugin_var_id_; + + // Get a new Var ID and increment last_plugin_var_id_. + VarID GetNewVarID(); +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_PLUGIN_VAR_TRACKER_H_ |