Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 13 #include "ppapi/c/pp_resource.h" | 13 #include "ppapi/c/pp_resource.h" |
| 14 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" | 14 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" |
| 15 #include "webkit/plugins/ppapi/resource.h" | 15 #include "webkit/plugins/ppapi/resource.h" |
| 16 #include "webkit/plugins/ppapi/var.h" | 16 #include "webkit/plugins/ppapi/var.h" |
| 17 | 17 |
| 18 enum PPIdType { | |
| 19 PP_ID_TYPE_MODULE, | |
| 20 PP_ID_TYPE_INSTANCE, | |
| 21 PP_ID_TYPE_RESOURCE, | |
| 22 PP_ID_TYPE_VAR, | |
| 23 PP_ID_TYPE_COUNT | |
| 24 }; | |
| 25 | |
| 26 static const unsigned int kPPIdTypeBits = 2; | |
| 27 COMPILE_ASSERT(PP_ID_TYPE_COUNT <= (1<<kPPIdTypeBits), | |
| 28 kPPIdTypeBits_is_too_small_for_all_id_types); | |
| 29 | |
| 30 template <typename T> static inline T MakeTypedId(T value, PPIdType type) { | |
| 31 return (value << kPPIdTypeBits) | static_cast<T>(type); | |
| 32 } | |
| 33 | |
| 34 template <typename T> static inline bool CheckIdType(T id, PPIdType type) { | |
| 35 // 0 is a valid resource. | |
| 36 if (!id) | |
| 37 return true; | |
| 38 const T mask = (static_cast<T>(1) << kPPIdTypeBits) - 1; | |
| 39 return (id & mask) == type; | |
| 40 } | |
| 41 | |
| 18 namespace webkit { | 42 namespace webkit { |
| 19 namespace ppapi { | 43 namespace ppapi { |
| 20 | 44 |
| 21 static base::LazyInstance<ResourceTracker> g_resource_tracker( | 45 static base::LazyInstance<ResourceTracker> g_resource_tracker( |
| 22 base::LINKER_INITIALIZED); | 46 base::LINKER_INITIALIZED); |
| 23 | 47 |
| 24 scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const { | 48 scoped_refptr<Resource> ResourceTracker::GetResource(PP_Resource res) const { |
| 49 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE)) | |
| 50 << res << " is not a PP_Resource."; | |
| 25 ResourceMap::const_iterator result = live_resources_.find(res); | 51 ResourceMap::const_iterator result = live_resources_.find(res); |
| 26 if (result == live_resources_.end()) { | 52 if (result == live_resources_.end()) { |
| 27 return scoped_refptr<Resource>(); | 53 return scoped_refptr<Resource>(); |
| 28 } | 54 } |
| 29 return result->second.first; | 55 return result->second.first; |
| 30 } | 56 } |
| 31 | 57 |
| 32 // static | 58 // static |
| 33 ResourceTracker* ResourceTracker::singleton_override_ = NULL; | 59 ResourceTracker* ResourceTracker::singleton_override_ = NULL; |
| 34 | 60 |
| 35 ResourceTracker::ResourceTracker() | 61 ResourceTracker::ResourceTracker() |
| 36 : last_resource_id_(0), | 62 : last_resource_id_(0), |
| 37 last_var_id_(0) { | 63 last_var_id_(0) { |
| 38 } | 64 } |
| 39 | 65 |
| 40 ResourceTracker::~ResourceTracker() { | 66 ResourceTracker::~ResourceTracker() { |
| 41 } | 67 } |
| 42 | 68 |
| 43 // static | 69 // static |
| 44 ResourceTracker* ResourceTracker::Get() { | 70 ResourceTracker* ResourceTracker::Get() { |
| 45 if (singleton_override_) | 71 if (singleton_override_) |
| 46 return singleton_override_; | 72 return singleton_override_; |
| 47 return g_resource_tracker.Pointer(); | 73 return g_resource_tracker.Pointer(); |
| 48 } | 74 } |
| 49 | 75 |
| 50 PP_Resource ResourceTracker::AddResource(Resource* resource) { | 76 PP_Resource ResourceTracker::AddResource(Resource* resource) { |
| 51 // If the plugin manages to create 4 billion resources, don't do crazy stuff. | 77 // If the plugin manages to create 1 billion resources, don't do crazy stuff. |
| 52 if (last_resource_id_ == std::numeric_limits<PP_Resource>::max()) | 78 if (last_resource_id_ == |
| 79 std::numeric_limits<PP_Resource>::max() >> kPPIdTypeBits) | |
|
brettw
2011/01/20 05:45:09
Can you add parens here to clarify the order of op
| |
| 53 return 0; | 80 return 0; |
| 54 | 81 |
| 55 // Add the resource with plugin use-count 1. | 82 // Add the resource with plugin use-count 1. |
| 56 PP_Resource new_id = ++last_resource_id_; | 83 PP_Resource new_id = MakeTypedId(++last_resource_id_, PP_ID_TYPE_RESOURCE); |
| 57 live_resources_.insert(std::make_pair(new_id, std::make_pair(resource, 1))); | 84 live_resources_.insert(std::make_pair(new_id, std::make_pair(resource, 1))); |
| 58 instance_to_resources_[resource->instance()->pp_instance()].insert(new_id); | 85 instance_to_resources_[resource->instance()->pp_instance()].insert(new_id); |
| 59 return new_id; | 86 return new_id; |
| 60 } | 87 } |
| 61 | 88 |
| 62 int32 ResourceTracker::AddVar(Var* var) { | 89 int32 ResourceTracker::AddVar(Var* var) { |
| 63 // If the plugin manages to create 4B strings... | 90 // If the plugin manages to create 1B strings... |
| 64 if (last_var_id_ == std::numeric_limits<int32>::max()) { | 91 if (last_var_id_ == std::numeric_limits<int32>::max() >> kPPIdTypeBits) { |
| 65 return 0; | 92 return 0; |
| 66 } | 93 } |
| 67 // Add the resource with plugin use-count 1. | 94 // Add the resource with plugin use-count 1. |
| 68 ++last_var_id_; | 95 int32 new_id = MakeTypedId(++last_var_id_, PP_ID_TYPE_VAR); |
| 69 live_vars_.insert(std::make_pair(last_var_id_, | 96 live_vars_.insert(std::make_pair(new_id, std::make_pair(var, 1))); |
| 70 std::make_pair(var, 1))); | 97 return new_id; |
| 71 return last_var_id_; | |
| 72 } | 98 } |
| 73 | 99 |
| 74 bool ResourceTracker::AddRefResource(PP_Resource res) { | 100 bool ResourceTracker::AddRefResource(PP_Resource res) { |
| 101 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE)) | |
| 102 << res << " is not a PP_Resource."; | |
| 75 ResourceMap::iterator i = live_resources_.find(res); | 103 ResourceMap::iterator i = live_resources_.find(res); |
| 76 if (i != live_resources_.end()) { | 104 if (i != live_resources_.end()) { |
| 77 // We don't protect against overflow, since a plugin as malicious as to ref | 105 // We don't protect against overflow, since a plugin as malicious as to ref |
| 78 // once per every byte in the address space could have just as well unrefed | 106 // once per every byte in the address space could have just as well unrefed |
| 79 // one time too many. | 107 // one time too many. |
| 80 ++i->second.second; | 108 ++i->second.second; |
| 81 return true; | 109 return true; |
| 82 } else { | 110 } else { |
| 83 return false; | 111 return false; |
| 84 } | 112 } |
| 85 } | 113 } |
| 86 | 114 |
| 87 bool ResourceTracker::UnrefResource(PP_Resource res) { | 115 bool ResourceTracker::UnrefResource(PP_Resource res) { |
| 116 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE)) | |
| 117 << res << " is not a PP_Resource."; | |
| 88 ResourceMap::iterator i = live_resources_.find(res); | 118 ResourceMap::iterator i = live_resources_.find(res); |
| 89 if (i != live_resources_.end()) { | 119 if (i != live_resources_.end()) { |
| 90 if (!--i->second.second) { | 120 if (!--i->second.second) { |
| 91 Resource* to_release = i->second.first; | 121 Resource* to_release = i->second.first; |
| 92 to_release->LastPluginRefWasDeleted(false); | 122 to_release->LastPluginRefWasDeleted(false); |
| 93 | 123 |
| 94 ResourceSet& instance_resource_set = | 124 ResourceSet& instance_resource_set = |
| 95 instance_to_resources_[to_release->instance()->pp_instance()]; | 125 instance_to_resources_[to_release->instance()->pp_instance()]; |
| 96 DCHECK(instance_resource_set.find(res) != instance_resource_set.end()); | 126 DCHECK(instance_resource_set.find(res) != instance_resource_set.end()); |
| 97 instance_resource_set.erase(res); | 127 instance_resource_set.erase(res); |
| 98 | 128 |
| 99 live_resources_.erase(i); | 129 live_resources_.erase(i); |
| 100 } | 130 } |
| 101 return true; | 131 return true; |
| 102 } else { | 132 } else { |
| 103 return false; | 133 return false; |
| 104 } | 134 } |
| 105 } | 135 } |
| 106 | 136 |
| 107 void ResourceTracker::ForceDeletePluginResourceRefs(PP_Resource res) { | 137 void ResourceTracker::ForceDeletePluginResourceRefs(PP_Resource res) { |
| 138 DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE)) | |
| 139 << res << " is not a PP_Resource."; | |
| 108 ResourceMap::iterator i = live_resources_.find(res); | 140 ResourceMap::iterator i = live_resources_.find(res); |
| 109 if (i == live_resources_.end()) | 141 if (i == live_resources_.end()) |
| 110 return; // Nothing to do. | 142 return; // Nothing to do. |
| 111 | 143 |
| 112 i->second.second = 0; | 144 i->second.second = 0; |
| 113 Resource* resource = i->second.first; | 145 Resource* resource = i->second.first; |
| 114 | 146 |
| 115 // Must delete from the resource set first since the resource's instance | 147 // Must delete from the resource set first since the resource's instance |
| 116 // pointer will get zeroed out in LastPluginRefWasDeleted. | 148 // pointer will get zeroed out in LastPluginRefWasDeleted. |
| 117 ResourceSet& resource_set = instance_to_resources_[ | 149 ResourceSet& resource_set = instance_to_resources_[ |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 131 // module->resource lookup to free resources when a module is unloaded. In | 163 // module->resource lookup to free resources when a module is unloaded. In |
| 132 // this case, this function can be implemented using that system. | 164 // this case, this function can be implemented using that system. |
| 133 uint32 count = 0; | 165 uint32 count = 0; |
| 134 for (ResourceMap::const_iterator i = live_resources_.begin(); | 166 for (ResourceMap::const_iterator i = live_resources_.begin(); |
| 135 i != live_resources_.end(); ++i) | 167 i != live_resources_.end(); ++i) |
| 136 count++; | 168 count++; |
| 137 return count; | 169 return count; |
| 138 } | 170 } |
| 139 | 171 |
| 140 scoped_refptr<Var> ResourceTracker::GetVar(int32 var_id) const { | 172 scoped_refptr<Var> ResourceTracker::GetVar(int32 var_id) const { |
| 173 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR)) | |
| 174 << var_id << " is not a PP_Var ID."; | |
| 141 VarMap::const_iterator result = live_vars_.find(var_id); | 175 VarMap::const_iterator result = live_vars_.find(var_id); |
| 142 if (result == live_vars_.end()) { | 176 if (result == live_vars_.end()) { |
| 143 return scoped_refptr<Var>(); | 177 return scoped_refptr<Var>(); |
| 144 } | 178 } |
| 145 return result->second.first; | 179 return result->second.first; |
| 146 } | 180 } |
| 147 | 181 |
| 148 bool ResourceTracker::AddRefVar(int32 var_id) { | 182 bool ResourceTracker::AddRefVar(int32 var_id) { |
| 183 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR)) | |
| 184 << var_id << " is not a PP_Var ID."; | |
| 149 VarMap::iterator i = live_vars_.find(var_id); | 185 VarMap::iterator i = live_vars_.find(var_id); |
| 150 if (i != live_vars_.end()) { | 186 if (i != live_vars_.end()) { |
| 151 // We don't protect against overflow, since a plugin as malicious as to ref | 187 // We don't protect against overflow, since a plugin as malicious as to ref |
| 152 // once per every byte in the address space could have just as well unrefed | 188 // once per every byte in the address space could have just as well unrefed |
| 153 // one time too many. | 189 // one time too many. |
| 154 ++i->second.second; | 190 ++i->second.second; |
| 155 return true; | 191 return true; |
| 156 } | 192 } |
| 157 return false; | 193 return false; |
| 158 } | 194 } |
| 159 | 195 |
| 160 bool ResourceTracker::UnrefVar(int32 var_id) { | 196 bool ResourceTracker::UnrefVar(int32 var_id) { |
| 197 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR)) | |
| 198 << var_id << " is not a PP_Var ID."; | |
| 161 VarMap::iterator i = live_vars_.find(var_id); | 199 VarMap::iterator i = live_vars_.find(var_id); |
| 162 if (i != live_vars_.end()) { | 200 if (i != live_vars_.end()) { |
| 163 if (!--i->second.second) | 201 if (!--i->second.second) |
| 164 live_vars_.erase(i); | 202 live_vars_.erase(i); |
| 165 return true; | 203 return true; |
| 166 } | 204 } |
| 167 return false; | 205 return false; |
| 168 } | 206 } |
| 169 | 207 |
| 170 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { | 208 PP_Instance ResourceTracker::AddInstance(PluginInstance* instance) { |
| 171 #ifndef NDEBUG | 209 #ifndef NDEBUG |
| 172 // Make sure we're not adding one more than once. | 210 // Make sure we're not adding one more than once. |
| 173 for (InstanceMap::const_iterator i = instance_map_.begin(); | 211 for (InstanceMap::const_iterator i = instance_map_.begin(); |
| 174 i != instance_map_.end(); ++i) | 212 i != instance_map_.end(); ++i) |
| 175 DCHECK(i->second != instance); | 213 DCHECK(i->second != instance); |
| 176 #endif | 214 #endif |
| 177 | 215 |
| 178 // Use a random 64-bit number for the instance ID. This helps prevent some | 216 // Use a random 64-bit number for the instance ID. This helps prevent some |
| 179 // mischeif where you could misallocate resources if you gave a different | 217 // mischeif where you could misallocate resources if you gave a different |
| 180 // instance ID. | 218 // instance ID. |
| 181 // | 219 // |
| 182 // See also AddModule below. | 220 // See also AddModule below. |
| 183 // | 221 // |
| 184 // Need to make sure the random number isn't a duplicate or 0. | 222 // Need to make sure the random number isn't a duplicate or 0. |
| 185 PP_Instance new_instance; | 223 PP_Instance new_instance; |
| 186 do { | 224 do { |
| 187 new_instance = static_cast<PP_Instance>(base::RandUint64()); | 225 new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()), |
| 226 PP_ID_TYPE_INSTANCE); | |
| 188 } while (!new_instance || | 227 } while (!new_instance || |
| 189 instance_map_.find(new_instance) != instance_map_.end()); | 228 instance_map_.find(new_instance) != instance_map_.end()); |
| 190 instance_map_[new_instance] = instance; | 229 instance_map_[new_instance] = instance; |
| 191 return new_instance; | 230 return new_instance; |
| 192 } | 231 } |
| 193 | 232 |
| 194 void ResourceTracker::InstanceDeleted(PP_Instance instance) { | 233 void ResourceTracker::InstanceDeleted(PP_Instance instance) { |
| 234 DLOG_IF(ERROR, !CheckIdType(instance, PP_ID_TYPE_INSTANCE)) | |
| 235 << instance << " is not a PP_Instance."; | |
| 195 // Force release all plugin references to resources associated with the | 236 // Force release all plugin references to resources associated with the |
| 196 // deleted instance. | 237 // deleted instance. |
| 197 ResourceSet& resource_set = instance_to_resources_[instance]; | 238 ResourceSet& resource_set = instance_to_resources_[instance]; |
| 198 ResourceSet::iterator i = resource_set.begin(); | 239 ResourceSet::iterator i = resource_set.begin(); |
| 199 while (i != resource_set.end()) { | 240 while (i != resource_set.end()) { |
| 200 // Iterators to a set are stable so we can iterate the set while the items | 241 // Iterators to a set are stable so we can iterate the set while the items |
| 201 // are being deleted as long as we're careful not to delete the item we're | 242 // are being deleted as long as we're careful not to delete the item we're |
| 202 // holding an iterator to. | 243 // holding an iterator to. |
| 203 ResourceSet::iterator current = i++; | 244 ResourceSet::iterator current = i++; |
| 204 ForceDeletePluginResourceRefs(*current); | 245 ForceDeletePluginResourceRefs(*current); |
| 205 } | 246 } |
| 206 DCHECK(resource_set.empty()); | 247 DCHECK(resource_set.empty()); |
| 207 instance_to_resources_.erase(instance); | 248 instance_to_resources_.erase(instance); |
| 208 | 249 |
| 209 InstanceMap::iterator found = instance_map_.find(instance); | 250 InstanceMap::iterator found = instance_map_.find(instance); |
| 210 if (found == instance_map_.end()) { | 251 if (found == instance_map_.end()) { |
| 211 NOTREACHED(); | 252 NOTREACHED(); |
| 212 return; | 253 return; |
| 213 } | 254 } |
| 214 instance_map_.erase(found); | 255 instance_map_.erase(found); |
| 215 } | 256 } |
| 216 | 257 |
| 217 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { | 258 PluginInstance* ResourceTracker::GetInstance(PP_Instance instance) { |
| 259 DLOG_IF(ERROR, !CheckIdType(instance, PP_ID_TYPE_INSTANCE)) | |
| 260 << instance << " is not a PP_Instance."; | |
| 218 InstanceMap::iterator found = instance_map_.find(instance); | 261 InstanceMap::iterator found = instance_map_.find(instance); |
| 219 if (found == instance_map_.end()) | 262 if (found == instance_map_.end()) |
| 220 return NULL; | 263 return NULL; |
| 221 return found->second; | 264 return found->second; |
| 222 } | 265 } |
| 223 | 266 |
| 224 PP_Module ResourceTracker::AddModule(PluginModule* module) { | 267 PP_Module ResourceTracker::AddModule(PluginModule* module) { |
| 225 #ifndef NDEBUG | 268 #ifndef NDEBUG |
| 226 // Make sure we're not adding one more than once. | 269 // Make sure we're not adding one more than once. |
| 227 for (ModuleMap::const_iterator i = module_map_.begin(); | 270 for (ModuleMap::const_iterator i = module_map_.begin(); |
| 228 i != module_map_.end(); ++i) | 271 i != module_map_.end(); ++i) |
| 229 DCHECK(i->second != module); | 272 DCHECK(i->second != module); |
| 230 #endif | 273 #endif |
| 231 | 274 |
| 232 // See AddInstance above. | 275 // See AddInstance above. |
| 233 PP_Module new_module; | 276 PP_Module new_module; |
| 234 do { | 277 do { |
| 235 new_module = static_cast<PP_Module>(base::RandUint64()); | 278 new_module = MakeTypedId(static_cast<PP_Module>(base::RandUint64()), |
| 279 PP_ID_TYPE_MODULE); | |
| 236 } while (!new_module || | 280 } while (!new_module || |
| 237 module_map_.find(new_module) != module_map_.end()); | 281 module_map_.find(new_module) != module_map_.end()); |
| 238 module_map_[new_module] = module; | 282 module_map_[new_module] = module; |
| 239 return new_module; | 283 return new_module; |
| 240 } | 284 } |
| 241 | 285 |
| 242 void ResourceTracker::ModuleDeleted(PP_Module module) { | 286 void ResourceTracker::ModuleDeleted(PP_Module module) { |
| 287 DLOG_IF(ERROR, !CheckIdType(module, PP_ID_TYPE_MODULE)) | |
| 288 << module << " is not a PP_Module."; | |
| 243 ModuleMap::iterator found = module_map_.find(module); | 289 ModuleMap::iterator found = module_map_.find(module); |
| 244 if (found == module_map_.end()) { | 290 if (found == module_map_.end()) { |
| 245 NOTREACHED(); | 291 NOTREACHED(); |
| 246 return; | 292 return; |
| 247 } | 293 } |
| 248 module_map_.erase(found); | 294 module_map_.erase(found); |
| 249 } | 295 } |
| 250 | 296 |
| 251 PluginModule* ResourceTracker::GetModule(PP_Module module) { | 297 PluginModule* ResourceTracker::GetModule(PP_Module module) { |
| 298 DLOG_IF(ERROR, !CheckIdType(module, PP_ID_TYPE_MODULE)) | |
| 299 << module << " is not a PP_Module."; | |
| 252 ModuleMap::iterator found = module_map_.find(module); | 300 ModuleMap::iterator found = module_map_.find(module); |
| 253 if (found == module_map_.end()) | 301 if (found == module_map_.end()) |
| 254 return NULL; | 302 return NULL; |
| 255 return found->second; | 303 return found->second; |
| 256 } | 304 } |
| 257 | 305 |
| 258 // static | 306 // static |
| 259 void ResourceTracker::SetSingletonOverride(ResourceTracker* tracker) { | 307 void ResourceTracker::SetSingletonOverride(ResourceTracker* tracker) { |
| 260 DCHECK(!singleton_override_); | 308 DCHECK(!singleton_override_); |
| 261 singleton_override_ = tracker; | 309 singleton_override_ = tracker; |
| 262 } | 310 } |
| 263 | 311 |
| 264 // static | 312 // static |
| 265 void ResourceTracker::ClearSingletonOverride() { | 313 void ResourceTracker::ClearSingletonOverride() { |
| 266 DCHECK(singleton_override_); | 314 DCHECK(singleton_override_); |
| 267 singleton_override_ = NULL; | 315 singleton_override_ = NULL; |
| 268 } | 316 } |
| 269 | 317 |
| 270 } // namespace ppapi | 318 } // namespace ppapi |
| 271 } // namespace webkit | 319 } // namespace webkit |
| 272 | 320 |
| OLD | NEW |