OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/proxy/plugin_var_tracker.h" | 5 #include "ppapi/proxy/plugin_var_tracker.h" |
6 | 6 |
7 #include "base/ref_counted.h" | 7 #include "base/ref_counted.h" |
| 8 #include "base/singleton.h" |
8 #include "ppapi/c/ppb_var.h" | 9 #include "ppapi/c/ppb_var.h" |
9 #include "ppapi/proxy/plugin_dispatcher.h" | |
10 #include "ppapi/proxy/ppapi_messages.h" | 10 #include "ppapi/proxy/ppapi_messages.h" |
| 11 #include "ppapi/proxy/interface_id.h" |
11 | 12 |
12 namespace pp { | 13 namespace pp { |
13 namespace proxy { | 14 namespace proxy { |
14 | 15 |
15 namespace { | 16 namespace { |
16 | 17 |
17 class RefCountedString : public base::RefCounted<RefCountedString> { | 18 class RefCountedString : public base::RefCounted<RefCountedString> { |
18 public: | 19 public: |
19 RefCountedString() { | 20 RefCountedString() { |
20 } | 21 } |
21 RefCountedString(const std::string& str) : value_(str) { | 22 RefCountedString(const std::string& str) : value_(str) { |
22 } | 23 } |
23 RefCountedString(const char* data, size_t len) | 24 RefCountedString(const char* data, size_t len) |
24 : value_(data, len) { | 25 : value_(data, len) { |
25 } | 26 } |
26 | 27 |
27 const std::string& value() const { return value_; } | 28 const std::string& value() const { return value_; } |
28 | 29 |
29 private: | 30 private: |
30 std::string value_; | 31 std::string value_; |
31 }; | 32 }; |
32 | 33 |
33 // When running in the plugin, this will convert the string ID to the object | 34 // When running in the plugin, this will convert the string ID to the object |
34 // using casting. No validity checking is done. | 35 // using casting. No validity checking is done. |
35 RefCountedString* PluginStringFromID(int64 id) { | 36 RefCountedString* PluginStringFromID(PluginVarTracker::VarID id) { |
36 return reinterpret_cast<RefCountedString*>(static_cast<intptr_t>(id)); | 37 return reinterpret_cast<RefCountedString*>(static_cast<intptr_t>(id)); |
37 } | 38 } |
38 | 39 |
39 } // namespace | 40 } // namespace |
40 | 41 |
41 PluginVarTracker::PluginVarTracker(PluginDispatcher* dispatcher) | 42 PluginVarTracker::HostVar::HostVar(Sender* d, VarID i) |
42 : dispatcher_(dispatcher) { | 43 : channel(d), |
| 44 host_object_id(i) { |
43 } | 45 } |
44 | 46 |
45 PluginVarTracker::~PluginVarTracker() {} | 47 bool PluginVarTracker::HostVar::operator<(const HostVar& other) const { |
| 48 if (channel < other.channel) |
| 49 return true; |
| 50 if (other.channel < channel) |
| 51 return false; |
| 52 return host_object_id < other.host_object_id; |
| 53 } |
46 | 54 |
47 int64 PluginVarTracker::MakeString(const std::string& str) { | 55 PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var) |
| 56 : host_var(host_var), |
| 57 ref_count(0), |
| 58 track_with_no_reference_count(0) { |
| 59 } |
| 60 |
| 61 PluginVarTracker::PluginVarTracker() : last_plugin_object_id_(0) { |
| 62 } |
| 63 |
| 64 PluginVarTracker::~PluginVarTracker() { |
| 65 } |
| 66 |
| 67 PluginVarTracker* PluginVarTracker::GetInstance() { |
| 68 return Singleton<PluginVarTracker>::get(); |
| 69 } |
| 70 |
| 71 PluginVarTracker::VarID PluginVarTracker::MakeString(const std::string& str) { |
48 RefCountedString* out = new RefCountedString(str); | 72 RefCountedString* out = new RefCountedString(str); |
49 out->AddRef(); | 73 out->AddRef(); |
50 return static_cast<int64>(reinterpret_cast<intptr_t>(out)); | 74 return static_cast<VarID>(reinterpret_cast<intptr_t>(out)); |
51 } | 75 } |
52 | 76 |
53 int64 PluginVarTracker::MakeString(const char* str, uint32_t len) { | 77 PluginVarTracker::VarID PluginVarTracker::MakeString(const char* str, |
| 78 uint32_t len) { |
54 RefCountedString* out = new RefCountedString(str, len); | 79 RefCountedString* out = new RefCountedString(str, len); |
55 out->AddRef(); | 80 out->AddRef(); |
56 return static_cast<int64>(reinterpret_cast<intptr_t>(out)); | 81 return static_cast<VarID>(reinterpret_cast<intptr_t>(out)); |
57 } | 82 } |
58 | 83 |
59 std::string PluginVarTracker::GetString(const PP_Var& var) const { | 84 std::string PluginVarTracker::GetString(const PP_Var& var) const { |
60 return PluginStringFromID(var.value.as_id)->value(); | 85 return PluginStringFromID(var.value.as_id)->value(); |
61 } | 86 } |
62 | 87 |
63 const std::string* PluginVarTracker::GetExistingString( | 88 const std::string* PluginVarTracker::GetExistingString( |
64 const PP_Var& var) const { | 89 const PP_Var& var) const { |
65 if (var.type != PP_VARTYPE_STRING) | 90 if (var.type != PP_VARTYPE_STRING) |
66 return NULL; | 91 return NULL; |
67 RefCountedString* str = PluginStringFromID(var.value.as_id); | 92 RefCountedString* str = PluginStringFromID(var.value.as_id); |
68 return &str->value(); | 93 return &str->value(); |
69 } | 94 } |
70 | 95 |
71 void PluginVarTracker::AddRef(const PP_Var& var) { | 96 void PluginVarTracker::AddRef(const PP_Var& var) { |
72 if (var.type == PP_VARTYPE_STRING) { | 97 if (var.type == PP_VARTYPE_STRING) { |
73 PluginStringFromID(var.value.as_id)->AddRef(); | 98 PluginStringFromID(var.value.as_id)->AddRef(); |
74 } else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) { | 99 } else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) { |
75 int& ref_count = object_ref_count_[var.value.as_id]; | 100 PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); |
76 ref_count++; | 101 if (found == plugin_var_info_.end()) { |
77 if (ref_count == 1) { | 102 NOTREACHED() << "Requesting to addref an unknown object."; |
78 // We must handle the case where we got requested to AddRef an object | 103 return; |
79 // that we've never seen before. This should tell the browser we've | |
80 // taken a ref. This comes up when the browser passes an object as an | |
81 // input param and holds a ref for us. We may not have seen that object | |
82 // and the plugin handler may want to AddRef and release it internally. | |
83 SendAddRefObjectMsg(var.value.as_id); | |
84 } | 104 } |
| 105 |
| 106 PluginVarInfo& info = found->second; |
| 107 if (info.ref_count == 0) { |
| 108 // Got an AddRef for an object we have no existing reference for. |
| 109 // We need to tell the browser we've taken a ref. This comes up when the |
| 110 // browser passes an object as an input param and holds a ref for us. |
| 111 SendAddRefObjectMsg(info.host_var); |
| 112 } |
| 113 info.ref_count++; |
85 } | 114 } |
86 } | 115 } |
87 | 116 |
88 void PluginVarTracker::Release(const PP_Var& var) { | 117 void PluginVarTracker::Release(const PP_Var& var) { |
89 if (var.type == PP_VARTYPE_STRING) { | 118 if (var.type == PP_VARTYPE_STRING) { |
90 PluginStringFromID(var.value.as_id)->Release(); | 119 PluginStringFromID(var.value.as_id)->Release(); |
91 } else if (var.type == PP_VARTYPE_OBJECT) { | 120 } else if (var.type == PP_VARTYPE_OBJECT) { |
92 ObjectRefCount::iterator found = object_ref_count_.find(var.value.as_id); | 121 PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); |
93 if (found == object_ref_count_.end()) | 122 if (found == plugin_var_info_.end()) { |
94 return; // Invalid object. | 123 NOTREACHED() << "Requesting to release an unknown object."; |
95 found->second--; | 124 return; |
| 125 } |
96 | 126 |
97 if (found->second == 0) { | 127 PluginVarInfo& info = found->second; |
98 // Plugin has released all of its refs, tell the browser. | 128 if (info.ref_count == 0) { |
99 object_ref_count_.erase(found); | 129 NOTREACHED() << "Releasing an object with zero ref."; |
100 SendReleaseObjectMsg(var.value.as_id); | 130 return; |
101 } | 131 } |
| 132 |
| 133 info.ref_count--; |
| 134 if (info.ref_count == 0) |
| 135 SendReleaseObjectMsg(info.host_var); |
| 136 DeletePluginVarInfoIfNecessary(found); |
102 } | 137 } |
103 } | 138 } |
104 | 139 |
105 void PluginVarTracker::ReceiveObjectPassRef(const PP_Var& var) { | 140 PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& var, |
106 // We're the plugin and the renderer just sent us a ref. The renderer has | 141 Sender* channel) { |
107 // addrefed the var in its tracker for us since it's returning it. | 142 DCHECK(var.type == PP_VARTYPE_OBJECT); |
108 // | 143 |
109 // - If We don't have a reference to this already, then we just add it to | 144 // Find the plugin info. |
110 // our tracker and use that one ref. | 145 PluginVarInfoMap::iterator found = |
111 // | 146 FindOrMakePluginVarFromHostVar(var, channel); |
112 // - If we do already have a reference to it, that means the renderer now | 147 if (found == plugin_var_info_.end()) { |
113 // has two references on our behalf. We want to transfer that extra | 148 // The above code should have always made an entry in the map. |
114 // reference to our list. This means we addref in the plugin, and release | 149 NOTREACHED(); |
115 // the extra one in the renderer. | 150 return PP_MakeUndefined(); |
116 ObjectRefCount::iterator found = object_ref_count_.find(var.value.as_id); | 151 } |
117 if (found == object_ref_count_.end()) { | 152 |
118 object_ref_count_[var.value.as_id] = 1; | 153 // Fix up the references. The host (renderer) just sent us a ref. The |
| 154 // renderer has addrefed the var in its tracker for us since it's returning |
| 155 // it. |
| 156 PluginVarInfo& info = found->second; |
| 157 if (info.ref_count == 0) { |
| 158 // We don't have a reference to this already, then we just add it to our |
| 159 // tracker and use that one ref. |
| 160 info.ref_count = 1; |
119 } else { | 161 } else { |
120 SendReleaseObjectMsg(var.value.as_id); | 162 // We already have a reference to it, that means the renderer now has two |
121 found->second++; | 163 // references on our behalf. We want to transfer that extra reference to |
| 164 // our list. This means we addref in the plugin, and release the extra one |
| 165 // in the renderer. |
| 166 SendReleaseObjectMsg(info.host_var); |
| 167 info.ref_count++; |
122 } | 168 } |
| 169 |
| 170 PP_Var ret; |
| 171 ret.type = PP_VARTYPE_OBJECT; |
| 172 ret.value.as_id = found->first; |
| 173 return ret; |
123 } | 174 } |
124 | 175 |
125 void PluginVarTracker::SendAddRefObjectMsg(int64_t id) { | 176 PP_Var PluginVarTracker::TrackObjectWithNoReference(const PP_Var& host_var, |
126 dispatcher_->Send(new PpapiHostMsg_PPBVar_AddRefObject( | 177 Sender* channel) { |
127 INTERFACE_ID_PPB_VAR_DEPRECATED, id)); | 178 DCHECK(host_var.type == PP_VARTYPE_OBJECT); |
| 179 |
| 180 PluginVarInfoMap::iterator found = |
| 181 FindOrMakePluginVarFromHostVar(host_var, channel); |
| 182 if (found == plugin_var_info_.end()) { |
| 183 // The above code should have always made an entry in the map. |
| 184 NOTREACHED(); |
| 185 return PP_MakeUndefined(); |
| 186 } |
| 187 |
| 188 found->second.track_with_no_reference_count++; |
| 189 |
| 190 PP_Var ret; |
| 191 ret.type = PP_VARTYPE_OBJECT; |
| 192 ret.value.as_id = found->first; |
| 193 return ret; |
128 } | 194 } |
129 | 195 |
130 void PluginVarTracker::SendReleaseObjectMsg(int64_t id) { | 196 void PluginVarTracker::StopTrackingObjectWithNoReference( |
131 dispatcher_->Send(new PpapiHostMsg_PPBVar_ReleaseObject( | 197 const PP_Var& plugin_var) { |
132 INTERFACE_ID_PPB_VAR_DEPRECATED, id)); | 198 DCHECK(plugin_var.type == PP_VARTYPE_OBJECT); |
| 199 PluginVarInfoMap::iterator found = plugin_var_info_.find( |
| 200 plugin_var.value.as_id); |
| 201 if (found == plugin_var_info_.end()) { |
| 202 NOTREACHED(); |
| 203 return; |
| 204 } |
| 205 |
| 206 found->second.track_with_no_reference_count--; |
| 207 DeletePluginVarInfoIfNecessary(found); |
| 208 } |
| 209 |
| 210 PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const { |
| 211 DCHECK(plugin_object.type == PP_VARTYPE_OBJECT); |
| 212 PluginVarInfoMap::const_iterator found = plugin_var_info_.find( |
| 213 plugin_object.value.as_id); |
| 214 if (found == plugin_var_info_.end()) { |
| 215 NOTREACHED(); |
| 216 return PP_MakeUndefined(); |
| 217 } |
| 218 PP_Var ret; |
| 219 ret.type = PP_VARTYPE_OBJECT; |
| 220 ret.value.as_id = found->second.host_var.host_object_id; |
| 221 return ret; |
| 222 } |
| 223 |
| 224 int PluginVarTracker::GetRefCountForObject(const PP_Var& plugin_object) { |
| 225 PluginVarInfoMap::iterator found = plugin_var_info_.find( |
| 226 plugin_object.value.as_id); |
| 227 if (found == plugin_var_info_.end()) |
| 228 return -1; |
| 229 return found->second.ref_count; |
| 230 } |
| 231 |
| 232 int PluginVarTracker::GetTrackedWithNoReferenceCountForObject( |
| 233 const PP_Var& plugin_object) { |
| 234 PluginVarInfoMap::iterator found = plugin_var_info_.find( |
| 235 plugin_object.value.as_id); |
| 236 if (found == plugin_var_info_.end()) |
| 237 return -1; |
| 238 return found->second.track_with_no_reference_count; |
| 239 } |
| 240 |
| 241 void PluginVarTracker::SendAddRefObjectMsg(const HostVar& host_var) { |
| 242 host_var.channel->Send(new PpapiHostMsg_PPBVar_AddRefObject( |
| 243 INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id)); |
| 244 } |
| 245 |
| 246 void PluginVarTracker::SendReleaseObjectMsg(const HostVar& host_var) { |
| 247 host_var.channel->Send(new PpapiHostMsg_PPBVar_ReleaseObject( |
| 248 INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id)); |
| 249 } |
| 250 |
| 251 PluginVarTracker::PluginVarInfoMap::iterator |
| 252 PluginVarTracker::FindOrMakePluginVarFromHostVar(const PP_Var& var, |
| 253 Sender* channel) { |
| 254 DCHECK(var.type == PP_VARTYPE_OBJECT); |
| 255 HostVar host_var(channel, var.value.as_id); |
| 256 |
| 257 HostVarToPluginVarMap::iterator found = |
| 258 host_var_to_plugin_var_.find(host_var); |
| 259 if (found != host_var_to_plugin_var_.end()) { |
| 260 PluginVarInfoMap::iterator ret = plugin_var_info_.find(found->second); |
| 261 DCHECK(ret != plugin_var_info_.end()); |
| 262 return ret; // Already know about this var return the ID. |
| 263 } |
| 264 |
| 265 // Make a new var, adding references to both maps. |
| 266 VarID new_plugin_var_id = ++last_plugin_object_id_; |
| 267 host_var_to_plugin_var_[host_var] = new_plugin_var_id; |
| 268 return plugin_var_info_.insert( |
| 269 std::make_pair(new_plugin_var_id, PluginVarInfo(host_var))).first; |
| 270 } |
| 271 |
| 272 void PluginVarTracker::DeletePluginVarInfoIfNecessary( |
| 273 PluginVarInfoMap::iterator iter) { |
| 274 if (iter->second.ref_count != 0 || |
| 275 iter->second.track_with_no_reference_count != 0) |
| 276 return; // Object still alive. |
| 277 |
| 278 // Object ref counts are all zero, delete from both maps. |
| 279 DCHECK(host_var_to_plugin_var_.find(iter->second.host_var) != |
| 280 host_var_to_plugin_var_.end()); |
| 281 host_var_to_plugin_var_.erase(iter->second.host_var); |
| 282 plugin_var_info_.erase(iter); |
133 } | 283 } |
134 | 284 |
135 } // namesace proxy | 285 } // namesace proxy |
136 } // namespace pp | 286 } // namespace pp |
OLD | NEW |