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 |