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