1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/pepper/pepper_plugin_registry.h" 6 7 #include "base/logging.h" 8 #include "content/common/pepper_plugin_list.h" 9 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 10 #include "content/renderer/pepper/plugin_module.h" 11 #include "ppapi/shared_impl/ppapi_permissions.h" 12 13 namespace content { 14 15 // static 16 PepperPluginRegistry* PepperPluginRegistry::GetInstance() { 17 static PepperPluginRegistry* registry = NULL; 18 // This object leaks. It is a temporary hack to work around a crash. 19 // http://code.google.com/p/chromium/issues/detail?id=63234 20 if (!registry) { 21 registry = new PepperPluginRegistry; 22 registry->Initialize(); 23 } 24 return registry; 25 } 26 27 const PepperPluginInfo* PepperPluginRegistry::GetInfoForPlugin( 28 const WebPluginInfo& info) { 29 for (size_t i = 0; i < plugin_list_.size(); ++i) { 30 if (info.path == plugin_list_[i].path) 31 return &plugin_list_[i]; 32 } 33 // We did not find the plugin in our list. But wait! the plugin can also 34 // be a latecomer, as it happens with pepper flash. This information 35 // is actually in |info| and we can use it to construct it and add it to 36 // the list. This same deal needs to be done in the browser side in 37 // PluginService. 38 PepperPluginInfo plugin; 39 if (!MakePepperPluginInfo(info, &plugin)) 40 return NULL; 41 42 plugin_list_.push_back(plugin); 43 return &plugin_list_[plugin_list_.size() - 1]; 44 } 45 46 PluginModule* PepperPluginRegistry::GetLiveModule(const base::FilePath& path) { 47 NonOwningModuleMap::iterator module_iter = live_modules_.find(path); 48 if (module_iter == live_modules_.end()) 49 return NULL; 50 51 // Check the instances for the module to see if they've all been Delete()d. 52 // We don't want to return a PluginModule in that case, since the plugin may 53 // have exited already. 54 const PluginModule::PluginInstanceSet& instance_set = 55 module_iter->second->GetAllInstances(); 56 57 // If instance_set is empty, InstanceCreated() hasn't been called yet, so 58 // it's safe to return the PluginModule. 59 if (instance_set.empty()) 60 return module_iter->second; 61 62 PluginModule::PluginInstanceSet::const_iterator instance_iter = 63 instance_set.begin(); 64 while (instance_iter != instance_set.end()) { 65 if (!(*instance_iter)->is_deleted()) 66 return module_iter->second; 67 ++instance_iter; 68 } 69 return NULL; 70 } 71 72 void PepperPluginRegistry::AddLiveModule(const base::FilePath& path, 73 PluginModule* module) { 74 DCHECK(live_modules_.find(path) == live_modules_.end()); 75 live_modules_[path] = module; 76 } 77 78 void PepperPluginRegistry::PluginModuleDead(PluginModule* dead_module) { 79 // DANGER: Don't dereference the dead_module pointer! It may be in the 80 // process of being deleted. 81 82 // Modules aren't destroyed very often and there are normally at most a 83 // couple of them. So for now we just do a brute-force search. 84 for (NonOwningModuleMap::iterator i = live_modules_.begin(); 85 i != live_modules_.end(); 86 ++i) { 87 if (i->second == dead_module) { 88 live_modules_.erase(i); 89 return; 90 } 91 } 92 // Can occur in tests. 93 } 94 95 PepperPluginRegistry::~PepperPluginRegistry() { 96 // Explicitly clear all preloaded modules first. This will cause callbacks 97 // to erase these modules from the live_modules_ list, and we don't want 98 // that to happen implicitly out-of-order. 99 preloaded_modules_.clear(); 100 101 DCHECK(live_modules_.empty()); 102 } 103 104 PepperPluginRegistry::PepperPluginRegistry() {} 105 106 void PepperPluginRegistry::Initialize() { 107 ComputePepperPluginList(&plugin_list_); 108 109 // Note that in each case, AddLiveModule must be called before completing 110 // initialization. If we bail out (in the continue clauses) before saving 111 // the initialized module, it will still try to unregister itself in its 112 // destructor. 113 for (size_t i = 0; i < plugin_list_.size(); i++) { 114 const PepperPluginInfo& current = plugin_list_[i]; 115 if (current.is_out_of_process) 116 continue; // Out of process plugins need no special pre-initialization. 117 118 scoped_refptr<PluginModule> module = 119 new PluginModule(current.name, 120 current.path, 121 ppapi::PpapiPermissions(current.permissions)); 122 AddLiveModule(current.path, module.get()); 123 if (current.is_internal) { 124 if (!module->InitAsInternalPlugin(current.internal_entry_points)) { 125 DVLOG(1) << "Failed to load pepper module: " << current.path.value(); 126 continue; 127 } 128 } else { 129 // Preload all external plugins we're not running out of process. 130 if (!module->InitAsLibrary(current.path)) { 131 DVLOG(1) << "Failed to load pepper module: " << current.path.value(); 132 continue; 133 } 134 } 135 preloaded_modules_[current.path] = module; 136 } 137 } 138 139 } // namespace content 140