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(); ++i) { 86 if (i->second == dead_module) { 87 live_modules_.erase(i); 88 return; 89 } 90 } 91 // Can occur in tests. 92 } 93 94 PepperPluginRegistry::~PepperPluginRegistry() { 95 // Explicitly clear all preloaded modules first. This will cause callbacks 96 // to erase these modules from the live_modules_ list, and we don't want 97 // that to happen implicitly out-of-order. 98 preloaded_modules_.clear(); 99 100 DCHECK(live_modules_.empty()); 101 } 102 103 PepperPluginRegistry::PepperPluginRegistry() { 104 } 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 = new PluginModule( 119 current.name, current.path, 120 ppapi::PpapiPermissions(current.permissions)); 121 AddLiveModule(current.path, module.get()); 122 if (current.is_internal) { 123 if (!module->InitAsInternalPlugin(current.internal_entry_points)) { 124 DLOG(ERROR) << "Failed to load pepper module: " << current.path.value(); 125 continue; 126 } 127 } else { 128 // Preload all external plugins we're not running out of process. 129 if (!module->InitAsLibrary(current.path)) { 130 DLOG(ERROR) << "Failed to load pepper module: " << current.path.value(); 131 continue; 132 } 133 } 134 preloaded_modules_[current.path] = module; 135 } 136 } 137 138 } // namespace content 139