// 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 #include #include "base/memory/ref_counted.h" #include "ppapi/c/pp_stdint.h" #include "ppapi/c/pp_var.h" struct PPB_Var; template 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; friend class PluginProxyTestHarness; class RefCountedString : public base::RefCounted { 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::Release() const; virtual ~RefCountedString() {} }; typedef scoped_refptr 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 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 HostVarToPluginVarMap; HostVarToPluginVarMap host_var_to_plugin_var_; // Maps plugin var IDs to ref counted strings. typedef std::map 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_