OLD | NEW |
1 // Copyright (c) 2011 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 "webkit/plugins/ppapi/resource_tracker.h" | 5 #include "webkit/plugins/ppapi/resource_tracker.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 | 43 |
44 typedef std::map<NPObject*, NPObjectVar*> NPObjectToNPObjectVarMap; | 44 typedef std::map<NPObject*, NPObjectVar*> NPObjectToNPObjectVarMap; |
45 | 45 |
46 struct ResourceTracker::InstanceData { | 46 struct ResourceTracker::InstanceData { |
47 InstanceData() : instance(0) {} | 47 InstanceData() : instance(0) {} |
48 | 48 |
49 // Non-owning pointer to the instance object. When a PluginInstance is | 49 // Non-owning pointer to the instance object. When a PluginInstance is |
50 // destroyed, it will notify us and we'll delete all associated data. | 50 // destroyed, it will notify us and we'll delete all associated data. |
51 PluginInstance* instance; | 51 PluginInstance* instance; |
52 | 52 |
53 // Resources associated with the instance. | |
54 ResourceSet ref_resources; | |
55 std::set<Resource*> assoc_resources; | |
56 | |
57 // Tracks all live NPObjectVars used by this module so we can map NPObjects | 53 // Tracks all live NPObjectVars used by this module so we can map NPObjects |
58 // to the corresponding object, and also release these properly if the | 54 // to the corresponding object, and also release these properly if the |
59 // instance goes away when there are still refs. These are non-owning | 55 // instance goes away when there are still refs. These are non-owning |
60 // references. | 56 // references. |
61 NPObjectToNPObjectVarMap np_object_to_object_var; | 57 NPObjectToNPObjectVarMap np_object_to_object_var; |
62 | 58 |
63 // Lazily allocated function proxies for the different interfaces. | 59 // Lazily allocated function proxies for the different interfaces. |
64 scoped_ptr< ::ppapi::FunctionGroupBase > | 60 scoped_ptr< ::ppapi::FunctionGroupBase > |
65 function_proxies[::pp::proxy::INTERFACE_ID_COUNT]; | 61 function_proxies[::pp::proxy::INTERFACE_ID_COUNT]; |
66 }; | 62 }; |
67 | 63 |
68 scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const { | |
69 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE)) | |
70 << res << " is not a PP_Resource."; | |
71 ResourceMap::const_iterator result = live_resources_.find(res); | |
72 if (result == live_resources_.end()) { | |
73 return scoped_refptr<Resource>(); | |
74 } | |
75 return result->second.first; | |
76 } | |
77 | |
78 // static | 64 // static |
79 ResourceTracker* ResourceTracker::global_tracker_ = NULL; | 65 ResourceTracker* ResourceTracker::global_tracker_ = NULL; |
80 ResourceTracker* ResourceTracker::singleton_override_ = NULL; | 66 ResourceTracker* ResourceTracker::singleton_override_ = NULL; |
81 | 67 |
82 ResourceTracker::ResourceTracker() | 68 ResourceTracker::ResourceTracker() |
83 : last_resource_id_(0) { | 69 : last_resource_id_(0) { |
84 // Wire up the new shared resource tracker base to use our implementation. | 70 // Wire up the new shared resource tracker base to use our implementation. |
85 ::ppapi::TrackerBase::Init(&GetTrackerBase); | 71 ::ppapi::TrackerBase::Init(&GetTrackerBase); |
86 } | 72 } |
87 | 73 |
88 ResourceTracker::~ResourceTracker() { | 74 ResourceTracker::~ResourceTracker() { |
89 } | 75 } |
90 | 76 |
91 // static | 77 // static |
92 ResourceTracker* ResourceTracker::Get() { | 78 ResourceTracker* ResourceTracker::Get() { |
93 if (singleton_override_) | 79 if (singleton_override_) |
94 return singleton_override_; | 80 return singleton_override_; |
95 if (!global_tracker_) | 81 if (!global_tracker_) |
96 global_tracker_ = new ResourceTracker; | 82 global_tracker_ = new ResourceTracker; |
97 return global_tracker_; | 83 return global_tracker_; |
98 } | 84 } |
99 | 85 |
100 void ResourceTracker::ResourceCreated(Resource* resource, | |
101 PluginInstance* instance) { | |
102 if (!instance) | |
103 return; | |
104 PP_Instance pp_instance = instance->pp_instance(); | |
105 DCHECK(pp_instance); | |
106 DCHECK(instance_map_.find(pp_instance) != instance_map_.end()); | |
107 instance_map_[pp_instance]->assoc_resources.insert(resource); | |
108 } | |
109 | |
110 void ResourceTracker::ResourceDestroyed(Resource* resource) { | |
111 if (!resource->instance()) | |
112 return; | |
113 | |
114 PP_Instance pp_instance = resource->instance()->pp_instance(); | |
115 DCHECK(pp_instance); | |
116 DCHECK(instance_map_.find(pp_instance) != instance_map_.end()); | |
117 | |
118 instance_map_[pp_instance]->assoc_resources.erase(resource); | |
119 } | |
120 | |
121 PP_Resource ResourceTracker::AddResource(Resource* resource) { | |
122 // If the plugin manages to create 1 billion resources, don't do crazy stuff. | |
123 if (last_resource_id_ == | |
124 (std::numeric_limits<PP_Resource>::max() >> ::ppapi::kPPIdTypeBits)) | |
125 return 0; | |
126 | |
127 // Add the resource with plugin use-count 1. | |
128 PP_Resource new_id = MakeTypedId(++last_resource_id_, | |
129 ::ppapi::PP_ID_TYPE_RESOURCE); | |
130 live_resources_.insert(std::make_pair(new_id, std::make_pair(resource, 1))); | |
131 | |
132 // Track associated with the instance. | |
133 PP_Instance pp_instance = resource->instance()->pp_instance(); | |
134 DCHECK(instance_map_.find(pp_instance) != instance_map_.end()); | |
135 instance_map_[pp_instance]->ref_resources.insert(new_id); | |
136 return new_id; | |
137 } | |
138 | |
139 bool ResourceTracker::AddRefResource(PP_Resource res) { | |
140 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE)) | |
141 << res << " is not a PP_Resource."; | |
142 ResourceMap::iterator i = live_resources_.find(res); | |
143 if (i != live_resources_.end()) { | |
144 // We don't protect against overflow, since a plugin as malicious as to ref | |
145 // once per every byte in the address space could have just as well unrefed | |
146 // one time too many. | |
147 ++i->second.second; | |
148 return true; | |
149 } else { | |
150 return false; | |
151 } | |
152 } | |
153 | |
154 bool ResourceTracker::UnrefResource(PP_Resource res) { | |
155 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE)) | |
156 << res << " is not a PP_Resource."; | |
157 ResourceMap::iterator i = live_resources_.find(res); | |
158 if (i != live_resources_.end()) { | |
159 if (!--i->second.second) { | |
160 Resource* to_release = i->second.first; | |
161 // LastPluginRefWasDeleted will clear the instance pointer, so save it | |
162 // first. | |
163 PP_Instance instance = to_release->instance()->pp_instance(); | |
164 to_release->LastPluginRefWasDeleted(); | |
165 | |
166 instance_map_[instance]->ref_resources.erase(res); | |
167 live_resources_.erase(i); | |
168 } | |
169 return true; | |
170 } else { | |
171 return false; | |
172 } | |
173 } | |
174 | |
175 void ResourceTracker::CleanupInstanceData(PP_Instance instance, | 86 void ResourceTracker::CleanupInstanceData(PP_Instance instance, |
176 bool delete_instance) { | 87 bool delete_instance) { |
177 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE)) | 88 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE)) |
178 << instance << " is not a PP_Instance."; | 89 << instance << " is not a PP_Instance."; |
179 InstanceMap::iterator found = instance_map_.find(instance); | 90 InstanceMap::iterator found = instance_map_.find(instance); |
180 if (found == instance_map_.end()) { | 91 if (found == instance_map_.end()) { |
181 NOTREACHED(); | 92 NOTREACHED(); |
182 return; | 93 return; |
183 } | 94 } |
184 InstanceData& data = *found->second; | 95 InstanceData& data = *found->second; |
185 | 96 |
186 // Force release all plugin references to resources associated with the | |
187 // deleted instance. | |
188 ResourceSet::iterator cur_res = data.ref_resources.begin(); | |
189 while (cur_res != data.ref_resources.end()) { | |
190 ResourceMap::iterator found_resource = live_resources_.find(*cur_res); | |
191 if (found_resource == live_resources_.end()) { | |
192 NOTREACHED(); | |
193 } else { | |
194 Resource* resource = found_resource->second.first; | |
195 | |
196 // Must delete from the resource set first since the resource's instance | |
197 // pointer will get zeroed out in LastPluginRefWasDeleted. | |
198 resource->LastPluginRefWasDeleted(); | |
199 live_resources_.erase(*cur_res); | |
200 } | |
201 | |
202 // Iterators to a set are stable so we can iterate the set while the items | |
203 // are being deleted as long as we're careful not to delete the item we're | |
204 // holding an iterator to. | |
205 ResourceSet::iterator current = cur_res++; | |
206 data.ref_resources.erase(current); | |
207 } | |
208 DCHECK(data.ref_resources.empty()); | |
209 | |
210 // Force delete all var references. Need to make a copy so we can iterate over | 97 // Force delete all var references. Need to make a copy so we can iterate over |
211 // the map while deleting stuff from it. | 98 // the map while deleting stuff from it. |
212 NPObjectToNPObjectVarMap np_object_map_copy = data.np_object_to_object_var; | 99 NPObjectToNPObjectVarMap np_object_map_copy = data.np_object_to_object_var; |
213 NPObjectToNPObjectVarMap::iterator cur_var = | 100 NPObjectToNPObjectVarMap::iterator cur_var = |
214 np_object_map_copy.begin(); | 101 np_object_map_copy.begin(); |
215 while (cur_var != np_object_map_copy.end()) { | 102 while (cur_var != np_object_map_copy.end()) { |
216 NPObjectToNPObjectVarMap::iterator current = cur_var++; | 103 NPObjectToNPObjectVarMap::iterator current = cur_var++; |
217 | 104 |
218 // Clear the object from the var mapping and the live instance object list. | 105 // Clear the object from the var mapping and the live instance object list. |
219 int32 var_id = current->second->GetExistingVarID(); | 106 int32 var_id = current->second->GetExistingVarID(); |
220 if (var_id) | 107 if (var_id) |
221 live_vars_.erase(var_id); | 108 live_vars_.erase(var_id); |
222 | 109 |
223 current->second->InstanceDeleted(); | 110 current->second->InstanceDeleted(); |
224 data.np_object_to_object_var.erase(current->first); | 111 data.np_object_to_object_var.erase(current->first); |
225 } | 112 } |
226 DCHECK(data.np_object_to_object_var.empty()); | 113 DCHECK(data.np_object_to_object_var.empty()); |
227 | 114 |
228 // Clear any resources that still reference this instance. | |
229 for (std::set<Resource*>::iterator res = data.assoc_resources.begin(); | |
230 res != data.assoc_resources.end(); | |
231 ++res) | |
232 (*res)->ClearInstance(); | |
233 data.assoc_resources.clear(); | |
234 | |
235 if (delete_instance) | 115 if (delete_instance) |
236 instance_map_.erase(found); | 116 instance_map_.erase(found); |
237 } | 117 } |
238 | 118 |
239 uint32 ResourceTracker::GetLiveObjectsForInstance( | |
240 PP_Instance instance) const { | |
241 InstanceMap::const_iterator found = instance_map_.find(instance); | |
242 if (found == instance_map_.end()) | |
243 return 0; | |
244 return static_cast<uint32>(found->second->ref_resources.size() + | |
245 found->second->np_object_to_object_var.size()); | |
246 } | |
247 | |
248 ::ppapi::ResourceObjectBase* ResourceTracker::GetResourceAPI( | |
249 PP_Resource res) { | |
250 DLOG_IF(ERROR, !CheckIdType(res, ::ppapi::PP_ID_TYPE_RESOURCE)) | |
251 << res << " is not a PP_Resource."; | |
252 ResourceMap::const_iterator result = live_resources_.find(res); | |
253 if (result == live_resources_.end()) | |
254 return NULL; | |
255 return result->second.first.get(); | |
256 } | |
257 | |
258 ::ppapi::FunctionGroupBase* ResourceTracker::GetFunctionAPI( | 119 ::ppapi::FunctionGroupBase* ResourceTracker::GetFunctionAPI( |
259 PP_Instance pp_instance, | 120 PP_Instance pp_instance, |
260 pp::proxy::InterfaceID id) { | 121 pp::proxy::InterfaceID id) { |
261 // Get the instance object. This also ensures that the instance data is in | 122 // Get the instance object. This also ensures that the instance data is in |
262 // the map, since we need it below. | 123 // the map, since we need it below. |
263 PluginInstance* instance = GetInstance(pp_instance); | 124 PluginInstance* instance = GetInstance(pp_instance); |
264 if (!instance) | 125 if (!instance) |
265 return NULL; | 126 return NULL; |
266 | 127 |
267 // The instance one is special, since it's just implemented by the instance | 128 // The instance one is special, since it's just implemented by the instance |
(...skipping 22 matching lines...) Expand all Loading... |
290 case pp::proxy::INTERFACE_ID_RESOURCE_CREATION: | 151 case pp::proxy::INTERFACE_ID_RESOURCE_CREATION: |
291 proxy.reset(new ResourceCreationImpl(instance)); | 152 proxy.reset(new ResourceCreationImpl(instance)); |
292 break; | 153 break; |
293 default: | 154 default: |
294 NOTREACHED(); | 155 NOTREACHED(); |
295 } | 156 } |
296 | 157 |
297 return proxy.get(); | 158 return proxy.get(); |
298 } | 159 } |
299 | 160 |
300 PP_Instance ResourceTracker::GetInstanceForResource(PP_Resource pp_resource) { | |
301 scoped_refptr<Resource> resource(GetResource(pp_resource)); | |
302 if (!resource.get()) | |
303 return 0; | |
304 return resource->instance()->pp_instance(); | |
305 } | |
306 | |
307 ::ppapi::VarTracker* ResourceTracker::GetVarTracker() { | 161 ::ppapi::VarTracker* ResourceTracker::GetVarTracker() { |
308 return &var_tracker_; | 162 return &var_tracker_; |
309 } | 163 } |
310 | 164 |
| 165 ::ppapi::ResourceTracker* ResourceTracker::GetResourceTracker() { |
| 166 return this; |
| 167 } |
| 168 |
311 void ResourceTracker::AddNPObjectVar(NPObjectVar* object_var) { | 169 void ResourceTracker::AddNPObjectVar(NPObjectVar* object_var) { |
312 DCHECK(instance_map_.find(object_var->pp_instance()) != instance_map_.end()); | 170 DCHECK(instance_map_.find(object_var->pp_instance()) != instance_map_.end()); |
313 InstanceData& data = *instance_map_[object_var->pp_instance()].get(); | 171 InstanceData& data = *instance_map_[object_var->pp_instance()].get(); |
314 | 172 |
315 DCHECK(data.np_object_to_object_var.find(object_var->np_object()) == | 173 DCHECK(data.np_object_to_object_var.find(object_var->np_object()) == |
316 data.np_object_to_object_var.end()) << "NPObjectVar already in map"; | 174 data.np_object_to_object_var.end()) << "NPObjectVar already in map"; |
317 data.np_object_to_object_var[object_var->np_object()] = object_var; | 175 data.np_object_to_object_var[object_var->np_object()] = object_var; |
318 } | 176 } |
319 | 177 |
320 void ResourceTracker::RemoveNPObjectVar(NPObjectVar* object_var) { | 178 void ResourceTracker::RemoveNPObjectVar(NPObjectVar* object_var) { |
(...skipping 18 matching lines...) Expand all Loading... |
339 DCHECK(instance_map_.find(instance) != instance_map_.end()); | 197 DCHECK(instance_map_.find(instance) != instance_map_.end()); |
340 InstanceData& data = *instance_map_[instance].get(); | 198 InstanceData& data = *instance_map_[instance].get(); |
341 | 199 |
342 NPObjectToNPObjectVarMap::iterator found = | 200 NPObjectToNPObjectVarMap::iterator found = |
343 data.np_object_to_object_var.find(np_object); | 201 data.np_object_to_object_var.find(np_object); |
344 if (found == data.np_object_to_object_var.end()) | 202 if (found == data.np_object_to_object_var.end()) |
345 return NULL; | 203 return NULL; |
346 return found->second; | 204 return found->second; |
347 } | 205 } |
348 | 206 |
| 207 int ResourceTracker::GetLiveNPObjectVarsForInstance( |
| 208 PP_Instance instance) const { |
| 209 InstanceMap::const_iterator found = instance_map_.find(instance); |
| 210 if (found == instance_map_.end()) |
| 211 return 0; |
| 212 return static_cast<int>(found->second->np_object_to_object_var.size()); |
| 213 } |
| 214 |
349 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { | 215 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { |
350 DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end()); | 216 DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end()); |
351 | 217 |
352 // Use a random number for the instance ID. This helps prevent some | 218 // Use a random number for the instance ID. This helps prevent some |
353 // accidents. See also AddModule below. | 219 // accidents. See also AddModule below. |
354 // | 220 // |
355 // Need to make sure the random number isn't a duplicate or 0. | 221 // Need to make sure the random number isn't a duplicate or 0. |
356 PP_Instance new_instance; | 222 PP_Instance new_instance; |
357 do { | 223 do { |
358 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()), | 224 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()), |
359 ::ppapi::PP_ID_TYPE_INSTANCE); | 225 ::ppapi::PP_ID_TYPE_INSTANCE); |
360 } while (!new_instance || | 226 } while (!new_instance || |
361 instance_map_.find(new_instance) != instance_map_.end() || | 227 instance_map_.find(new_instance) != instance_map_.end() || |
362 !instance->module()->ReserveInstanceID(new_instance)); | 228 !instance->module()->ReserveInstanceID(new_instance)); |
363 | 229 |
364 instance_map_[new_instance] = linked_ptr<InstanceData>(new InstanceData); | 230 instance_map_[new_instance] = linked_ptr<InstanceData>(new InstanceData); |
365 instance_map_[new_instance]->instance = instance; | 231 instance_map_[new_instance]->instance = instance; |
| 232 |
| 233 DidCreateInstance(new_instance); |
366 return new_instance; | 234 return new_instance; |
367 } | 235 } |
368 | 236 |
369 void ResourceTracker::InstanceDeleted(PP_Instance instance) { | 237 void ResourceTracker::InstanceDeleted(PP_Instance instance) { |
| 238 DidDeleteInstance(instance); |
370 CleanupInstanceData(instance, true); | 239 CleanupInstanceData(instance, true); |
371 } | 240 } |
372 | 241 |
373 void ResourceTracker::InstanceCrashed(PP_Instance instance) { | 242 void ResourceTracker::InstanceCrashed(PP_Instance instance) { |
| 243 DidDeleteInstance(instance); |
374 CleanupInstanceData(instance, false); | 244 CleanupInstanceData(instance, false); |
375 } | 245 } |
376 | 246 |
377 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { | 247 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { |
378 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE)) | 248 DLOG_IF(ERROR, !CheckIdType(instance, ::ppapi::PP_ID_TYPE_INSTANCE)) |
379 << instance << " is not a PP_Instance."; | 249 << instance << " is not a PP_Instance."; |
380 InstanceMap::iterator found = instance_map_.find(instance); | 250 InstanceMap::iterator found = instance_map_.find(instance); |
381 if (found == instance_map_.end()) | 251 if (found == instance_map_.end()) |
382 return NULL; | 252 return NULL; |
383 return found->second->instance; | 253 return found->second->instance; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 | 300 |
431 // static | 301 // static |
432 void ResourceTracker::ClearSingletonOverride() { | 302 void ResourceTracker::ClearSingletonOverride() { |
433 DCHECK(singleton_override_); | 303 DCHECK(singleton_override_); |
434 singleton_override_ = NULL; | 304 singleton_override_ = NULL; |
435 } | 305 } |
436 | 306 |
437 } // namespace ppapi | 307 } // namespace ppapi |
438 } // namespace webkit | 308 } // namespace webkit |
439 | 309 |
OLD | NEW |