| 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 "content/common/pepper_plugin_registry.h" | 5 #include "content/common/pepper_plugin_registry.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | |
| 8 #include "base/file_util.h" | |
| 9 #include "base/native_library.h" | |
| 10 #include "base/string_split.h" | |
| 11 #include "base/string_util.h" | |
| 12 #include "base/utf_string_conversions.h" | |
| 13 #include "content/common/content_client.h" | |
| 14 #include "content/common/content_switches.h" | |
| 15 #include "webkit/plugins/npapi/plugin_list.h" | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 // Appends any plugins from the command line to the given vector. | |
| 20 void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) { | |
| 21 bool out_of_process = | |
| 22 CommandLine::ForCurrentProcess()->HasSwitch(switches::kPpapiOutOfProcess); | |
| 23 const std::string value = | |
| 24 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 25 switches::kRegisterPepperPlugins); | |
| 26 if (value.empty()) | |
| 27 return; | |
| 28 | |
| 29 // FORMAT: | |
| 30 // command-line = <plugin-entry> + *( LWS + "," + LWS + <plugin-entry> ) | |
| 31 // plugin-entry = | |
| 32 // <file-path> + | |
| 33 // ["#" + <name> + ["#" + <description> + ["#" + <version>]]] + | |
| 34 // *1( LWS + ";" + LWS + <mime-type> ) | |
| 35 std::vector<std::string> modules; | |
| 36 base::SplitString(value, ',', &modules); | |
| 37 for (size_t i = 0; i < modules.size(); ++i) { | |
| 38 std::vector<std::string> parts; | |
| 39 base::SplitString(modules[i], ';', &parts); | |
| 40 if (parts.size() < 2) { | |
| 41 DLOG(ERROR) << "Required mime-type not found"; | |
| 42 continue; | |
| 43 } | |
| 44 | |
| 45 std::vector<std::string> name_parts; | |
| 46 base::SplitString(parts[0], '#', &name_parts); | |
| 47 | |
| 48 PepperPluginInfo plugin; | |
| 49 plugin.is_out_of_process = out_of_process; | |
| 50 #if defined(OS_WIN) | |
| 51 // This means we can't provide plugins from non-ASCII paths, but | |
| 52 // since this switch is only for development I don't think that's | |
| 53 // too awful. | |
| 54 plugin.path = FilePath(ASCIIToUTF16(name_parts[0])); | |
| 55 #else | |
| 56 plugin.path = FilePath(name_parts[0]); | |
| 57 #endif | |
| 58 if (name_parts.size() > 1) | |
| 59 plugin.name = name_parts[1]; | |
| 60 if (name_parts.size() > 2) | |
| 61 plugin.description = name_parts[2]; | |
| 62 if (name_parts.size() > 3) | |
| 63 plugin.version = name_parts[3]; | |
| 64 for (size_t j = 1; j < parts.size(); ++j) { | |
| 65 webkit::WebPluginMimeType mime_type(parts[j], | |
| 66 std::string(), | |
| 67 plugin.description); | |
| 68 plugin.mime_types.push_back(mime_type); | |
| 69 } | |
| 70 | |
| 71 plugins->push_back(plugin); | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 } // namespace | |
| 76 | |
| 77 webkit::WebPluginInfo PepperPluginInfo::ToWebPluginInfo() const { | |
| 78 webkit::WebPluginInfo info; | |
| 79 | |
| 80 info.type = is_out_of_process ? | |
| 81 webkit::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS : | |
| 82 webkit::WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS; | |
| 83 | |
| 84 info.name = name.empty() ? | |
| 85 path.BaseName().LossyDisplayName() : UTF8ToUTF16(name); | |
| 86 info.path = path; | |
| 87 info.version = ASCIIToUTF16(version); | |
| 88 info.desc = ASCIIToUTF16(description); | |
| 89 info.mime_types = mime_types; | |
| 90 | |
| 91 return info; | |
| 92 } | |
| 93 | |
| 94 PepperPluginInfo::PepperPluginInfo() | |
| 95 : is_internal(false), | |
| 96 is_out_of_process(false) { | |
| 97 } | |
| 98 | |
| 99 PepperPluginInfo::~PepperPluginInfo() { | |
| 100 } | |
| 101 | |
| 102 bool MakePepperPluginInfo(const webkit::WebPluginInfo& webplugin_info, | |
| 103 PepperPluginInfo* pepper_info) { | |
| 104 if (!webkit::IsPepperPlugin(webplugin_info)) | |
| 105 return false; | |
| 106 | |
| 107 pepper_info->is_out_of_process = | |
| 108 webplugin_info.type == | |
| 109 webkit::WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS; | |
| 110 | |
| 111 pepper_info->path = FilePath(webplugin_info.path); | |
| 112 pepper_info->name = UTF16ToASCII(webplugin_info.name); | |
| 113 pepper_info->description = UTF16ToASCII(webplugin_info.desc); | |
| 114 pepper_info->version = UTF16ToASCII(webplugin_info.version); | |
| 115 pepper_info->mime_types = webplugin_info.mime_types; | |
| 116 return true; | |
| 117 } | |
| 118 | |
| 119 // static | 7 // static |
| 120 PepperPluginRegistry* PepperPluginRegistry::GetInstance() { | 8 PepperPluginRegistry* PepperPluginRegistry::GetInstance() { |
| 121 static PepperPluginRegistry* registry = NULL; | 9 return Singleton<PepperPluginRegistry>::get(); |
| 122 // This object leaks. It is a temporary hack to work around a crash. | |
| 123 // http://code.google.com/p/chromium/issues/detail?id=63234 | |
| 124 if (!registry) | |
| 125 registry = new PepperPluginRegistry; | |
| 126 return registry; | |
| 127 } | 10 } |
| 128 | |
| 129 // static | |
| 130 void PepperPluginRegistry::ComputeList(std::vector<PepperPluginInfo>* plugins) { | |
| 131 content::GetContentClient()->AddPepperPlugins(plugins); | |
| 132 ComputePluginsFromCommandLine(plugins); | |
| 133 } | |
| 134 | |
| 135 // static | |
| 136 void PepperPluginRegistry::PreloadModules() { | |
| 137 std::vector<PepperPluginInfo> plugins; | |
| 138 ComputeList(&plugins); | |
| 139 for (size_t i = 0; i < plugins.size(); ++i) { | |
| 140 if (!plugins[i].is_internal) { | |
| 141 std::string error; | |
| 142 base::NativeLibrary library = base::LoadNativeLibrary(plugins[i].path, | |
| 143 &error); | |
| 144 LOG_IF(WARNING, !library) << "Unable to load plugin " | |
| 145 << plugins[i].path.value() << " " | |
| 146 << error; | |
| 147 } | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 const PepperPluginInfo* PepperPluginRegistry::GetInfoForPlugin( | |
| 152 const webkit::WebPluginInfo& info) { | |
| 153 for (size_t i = 0; i < plugin_list_.size(); ++i) { | |
| 154 if (info.path == plugin_list_[i].path) | |
| 155 return &plugin_list_[i]; | |
| 156 } | |
| 157 // We did not find the plugin in our list. But wait! the plugin can also | |
| 158 // be a latecomer, as it happens with pepper flash. This information | |
| 159 // is actually in |info| and we can use it to construct it and add it to | |
| 160 // the list. This same deal needs to be done in the browser side in | |
| 161 // PluginService. | |
| 162 PepperPluginInfo plugin; | |
| 163 if (!MakePepperPluginInfo(info, &plugin)) | |
| 164 return NULL; | |
| 165 | |
| 166 plugin_list_.push_back(plugin); | |
| 167 return &plugin_list_[plugin_list_.size() - 1]; | |
| 168 } | |
| 169 | |
| 170 webkit::ppapi::PluginModule* PepperPluginRegistry::GetLiveModule( | |
| 171 const FilePath& path) { | |
| 172 NonOwningModuleMap::iterator it = live_modules_.find(path); | |
| 173 if (it == live_modules_.end()) | |
| 174 return NULL; | |
| 175 return it->second; | |
| 176 } | |
| 177 | |
| 178 void PepperPluginRegistry::AddLiveModule(const FilePath& path, | |
| 179 webkit::ppapi::PluginModule* module) { | |
| 180 DCHECK(live_modules_.find(path) == live_modules_.end()); | |
| 181 live_modules_[path] = module; | |
| 182 } | |
| 183 | |
| 184 void PepperPluginRegistry::PluginModuleDead( | |
| 185 webkit::ppapi::PluginModule* dead_module) { | |
| 186 // DANGER: Don't dereference the dead_module pointer! It may be in the | |
| 187 // process of being deleted. | |
| 188 | |
| 189 // Modules aren't destroyed very often and there are normally at most a | |
| 190 // couple of them. So for now we just do a brute-force search. | |
| 191 for (NonOwningModuleMap::iterator i = live_modules_.begin(); | |
| 192 i != live_modules_.end(); ++i) { | |
| 193 if (i->second == dead_module) { | |
| 194 live_modules_.erase(i); | |
| 195 return; | |
| 196 } | |
| 197 } | |
| 198 NOTREACHED(); // Should have always found the module above. | |
| 199 } | |
| 200 | |
| 201 PepperPluginRegistry::~PepperPluginRegistry() { | |
| 202 // Explicitly clear all preloaded modules first. This will cause callbacks | |
| 203 // to erase these modules from the live_modules_ list, and we don't want | |
| 204 // that to happen implicitly out-of-order. | |
| 205 preloaded_modules_.clear(); | |
| 206 | |
| 207 DCHECK(live_modules_.empty()); | |
| 208 } | |
| 209 | |
| 210 PepperPluginRegistry::PepperPluginRegistry() { | |
| 211 ComputeList(&plugin_list_); | |
| 212 | |
| 213 // Note that in each case, AddLiveModule must be called before completing | |
| 214 // initialization. If we bail out (in the continue clauses) before saving | |
| 215 // the initialized module, it will still try to unregister itself in its | |
| 216 // destructor. | |
| 217 for (size_t i = 0; i < plugin_list_.size(); i++) { | |
| 218 const PepperPluginInfo& current = plugin_list_[i]; | |
| 219 if (current.is_out_of_process) | |
| 220 continue; // Out of process plugins need no special pre-initialization. | |
| 221 | |
| 222 scoped_refptr<webkit::ppapi::PluginModule> module = | |
| 223 new webkit::ppapi::PluginModule(current.name, current.path, this); | |
| 224 AddLiveModule(current.path, module); | |
| 225 if (current.is_internal) { | |
| 226 if (!module->InitAsInternalPlugin(current.internal_entry_points)) { | |
| 227 DLOG(ERROR) << "Failed to load pepper module: " << current.path.value(); | |
| 228 continue; | |
| 229 } | |
| 230 } else { | |
| 231 // Preload all external plugins we're not running out of process. | |
| 232 if (!module->InitAsLibrary(current.path)) { | |
| 233 DLOG(ERROR) << "Failed to load pepper module: " << current.path.value(); | |
| 234 continue; | |
| 235 } | |
| 236 } | |
| 237 preloaded_modules_[current.path] = module; | |
| 238 } | |
| 239 } | |
| 240 | |
| OLD | NEW |