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