Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(659)

Side by Side Diff: content/common/plugin_list_posix.cc

Issue 271753006: Linux: Remove some unused NPAPI code. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/common/plugin_list.h ('k') | content/common/plugin_list_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/plugin_list.h" 5 #include "content/common/plugin_list.h"
6 6
7 #include <algorithm>
8 #include <dlfcn.h>
9 #if defined(OS_OPENBSD)
10 #include <sys/exec_elf.h>
11 #else
12 #include <elf.h>
13 #endif
14 #include <fcntl.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #include "base/cpu.h"
20 #include "base/file_util.h"
21 #include "base/files/file_enumerator.h"
22 #include "base/native_library.h"
23 #include "base/path_service.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "base/sha1.h"
26 #include "base/strings/string_split.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/stringprintf.h"
29 #include "base/strings/sys_string_conversions.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "build/build_config.h"
32 #include "third_party/npapi/bindings/nphostapi.h"
33
34 namespace content { 7 namespace content {
35 8
36 namespace { 9 bool PluginList::ReadWebPluginInfo(const base::FilePath& filename,
37 10 WebPluginInfo* info) {
38 // We build up a list of files and mtimes so we can sort them.
39 typedef std::pair<base::FilePath, base::Time> FileAndTime;
40 typedef std::vector<FileAndTime> FileTimeList;
41
42 enum PluginQuirk {
43 // No quirks - plugin is outright banned.
44 PLUGIN_QUIRK_NONE = 0,
45 // Plugin is using SSE2 instructions without checking for SSE2 instruction
46 // support. Ban the plugin if the system has no SSE2 support.
47 PLUGIN_QUIRK_MISSING_SSE2_CHECK = 1 << 0,
48 };
49
50 // Copied from nsplugindefs.h instead of including the file since it has a bunch
51 // of dependencies.
52 enum nsPluginVariable {
53 nsPluginVariable_NameString = 1,
54 nsPluginVariable_DescriptionString = 2
55 };
56
57 // Comparator used to sort by descending mtime then ascending filename.
58 bool CompareTime(const FileAndTime& a, const FileAndTime& b) {
59 if (a.second == b.second) {
60 // Fall back on filename sorting, just to make the predicate valid.
61 return a.first < b.first;
62 }
63
64 // Sort by mtime, descending.
65 return a.second > b.second;
66 }
67
68 // Checks to see if the current environment meets any of the condtions set in
69 // |quirks|. Returns true if any of the conditions are met, or if |quirks| is
70 // PLUGIN_QUIRK_NONE.
71 bool CheckQuirks(PluginQuirk quirks) {
72 if (quirks == PLUGIN_QUIRK_NONE)
73 return true;
74
75 if ((quirks & PLUGIN_QUIRK_MISSING_SSE2_CHECK) != 0) {
76 base::CPU cpu;
77 if (!cpu.has_sse2())
78 return true;
79 }
80
81 return false; 11 return false;
82 } 12 }
83 13
84 // Return true if |path| matches a known (file size, sha1sum) pair. 14 void PluginList::GetPluginDirectories(
85 // Also check against any PluginQuirks the bad plugin may have. 15 std::vector<base::FilePath>* plugin_dirs) {
86 // The use of the file size is an optimization so we don't have to read in
87 // the entire file unless we have to.
88 bool IsBlacklistedBySha1sumAndQuirks(const base::FilePath& path) {
89 const struct BadEntry {
90 int64 size;
91 std::string sha1;
92 PluginQuirk quirks;
93 } bad_entries[] = {
94 // Flash 9 r31 - http://crbug.com/29237
95 { 7040080, "fa5803061125ca47846713b34a26a42f1f1e98bb", PLUGIN_QUIRK_NONE },
96 // Flash 9 r48 - http://crbug.com/29237
97 { 7040036, "0c4b3768a6d4bfba003088e4b9090d381de1af2b", PLUGIN_QUIRK_NONE },
98 // Flash 11.2.202.236, 32-bit - http://crbug.com/140086
99 { 17406436, "1e07eac912faf9426c52a288c76c3b6238f90b6b",
100 PLUGIN_QUIRK_MISSING_SSE2_CHECK },
101 // Flash 11.2.202.238, 32-bit - http://crbug.com/140086
102 { 17410532, "e9401097e97c8443a7d9156be62184ffe1addd5c",
103 PLUGIN_QUIRK_MISSING_SSE2_CHECK },
104 };
105
106 int64 size;
107 if (!base::GetFileSize(path, &size))
108 return false;
109 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(bad_entries); i++) {
110 if (bad_entries[i].size != size)
111 continue;
112
113 std::string file_content;
114 if (!base::ReadFileToString(path, &file_content))
115 continue;
116 std::string sha1 = base::SHA1HashString(file_content);
117 std::string sha1_readable;
118 for (size_t j = 0; j < sha1.size(); j++)
119 base::StringAppendF(&sha1_readable, "%02x", sha1[j] & 0xFF);
120 if (bad_entries[i].sha1 == sha1_readable)
121 return CheckQuirks(bad_entries[i].quirks);
122 }
123 return false;
124 } 16 }
125 17
126 // Some plugins are shells around other plugins; we prefer to use the 18 void PluginList::GetPluginsInDir(const base::FilePath& dir_path,
127 // real plugin directly, if it's available. This function returns 19 std::vector<base::FilePath>* plugins) {
128 // true if we should prefer other plugins over this one. We'll still
129 // use a "undesirable" plugin if no other option is available.
130 bool IsUndesirablePlugin(const WebPluginInfo& info) {
131 std::string filename = info.path.BaseName().value();
132 const char* kUndesiredPlugins[] = {
133 "npcxoffice", // Crossover
134 "npwrapper", // nspluginwrapper
135 };
136 for (size_t i = 0; i < arraysize(kUndesiredPlugins); i++) {
137 if (filename.find(kUndesiredPlugins[i]) != std::string::npos) {
138 return true;
139 }
140 }
141 return false;
142 } 20 }
143 21
144 // Return true if we shouldn't load a plugin at all. 22 bool PluginList::ShouldLoadPluginUsingPluginList(
145 // This is an ugly hack to blacklist Adobe Acrobat due to not supporting 23 const WebPluginInfo& info,
146 // its Xt-based mainloop. 24 std::vector<WebPluginInfo>* plugins) {
147 // http://code.google.com/p/chromium/issues/detail?id=38229 25 LOG_IF(ERROR, PluginList::DebugPluginLoading())
148 bool IsBlacklistedPlugin(const base::FilePath& path) { 26 << "Considering " << info.path.value() << " (" << info.name << ")";
149 const char* kBlackListedPlugins[] = {
150 "nppdf.so", // Adobe PDF
151 };
152 std::string filename = path.BaseName().value();
153 for (size_t i = 0; i < arraysize(kBlackListedPlugins); i++) {
154 if (filename.find(kBlackListedPlugins[i]) != std::string::npos) {
155 return true;
156 }
157 }
158 return IsBlacklistedBySha1sumAndQuirks(path);
159 }
160 27
161 // Read the ELF header and return true if it is usable on 28 if (info.type == WebPluginInfo::PLUGIN_TYPE_NPAPI) {
162 // the current architecture (e.g. 32-bit ELF on 32-bit build). 29 NOTREACHED() << "NPAPI plugins are not supported";
163 // Returns false on other errors as well.
164 bool ELFMatchesCurrentArchitecture(const base::FilePath& filename) {
165 // First make sure we can open the file and it is in fact, a regular file.
166 struct stat stat_buf;
167 // Open with O_NONBLOCK so we don't block on pipes.
168 int fd = open(filename.value().c_str(), O_RDONLY|O_NONBLOCK);
169 if (fd < 0)
170 return false;
171 bool ret = (fstat(fd, &stat_buf) >= 0 && S_ISREG(stat_buf.st_mode));
172 if (IGNORE_EINTR(close(fd)) < 0)
173 return false;
174 if (!ret)
175 return false;
176
177 const size_t kELFBufferSize = 5;
178 char buffer[kELFBufferSize];
179 if (!base::ReadFile(filename, buffer, kELFBufferSize))
180 return false;
181
182 if (buffer[0] != ELFMAG0 ||
183 buffer[1] != ELFMAG1 ||
184 buffer[2] != ELFMAG2 ||
185 buffer[3] != ELFMAG3) {
186 // Not an ELF file, perhaps?
187 return false; 30 return false;
188 } 31 }
189 32
190 int elf_class = buffer[EI_CLASS]; 33 VLOG_IF(1, PluginList::DebugPluginLoading()) << "Using " << info.path.value();
191 #if defined(ARCH_CPU_32_BITS)
192 if (elf_class == ELFCLASS32)
193 return true;
194 #elif defined(ARCH_CPU_64_BITS)
195 if (elf_class == ELFCLASS64)
196 return true;
197 #endif
198
199 return false;
200 }
201
202 // This structure matches enough of nspluginwrapper's NPW_PluginInfo
203 // for us to extract the real plugin path.
204 struct __attribute__((packed)) NSPluginWrapperInfo {
205 char ident[32]; // NSPluginWrapper magic identifier (includes version).
206 char path[PATH_MAX]; // Path to wrapped plugin.
207 };
208
209 // Test a plugin for whether it's been wrapped by NSPluginWrapper, and
210 // if so attempt to unwrap it. Pass in an opened plugin handle; on
211 // success, |dl| and |unwrapped_path| will be filled in with the newly
212 // opened plugin. On failure, params are left unmodified.
213 void UnwrapNSPluginWrapper(void **dl, base::FilePath* unwrapped_path) {
214 NSPluginWrapperInfo* info =
215 reinterpret_cast<NSPluginWrapperInfo*>(dlsym(*dl, "NPW_Plugin"));
216 if (!info)
217 return; // Not a NSPW plugin.
218
219 // Here we could check the NSPW ident field for the versioning
220 // information, but the path field is available in all versions
221 // anyway.
222
223 // Grab the path to the wrapped plugin. Just in case the structure
224 // format changes, protect against the path not being null-terminated.
225 char* path_end = static_cast<char*>(memchr(info->path, '\0',
226 sizeof(info->path)));
227 if (!path_end)
228 path_end = info->path + sizeof(info->path);
229 base::FilePath path = base::FilePath(
230 std::string(info->path, path_end - info->path));
231
232 if (!ELFMatchesCurrentArchitecture(path)) {
233 LOG(WARNING) << path.value() << " is nspluginwrapper wrapping a "
234 << "plugin for a different architecture; it will "
235 << "work better if you instead use a native plugin.";
236 return;
237 }
238
239 base::NativeLibraryLoadError error;
240 void* newdl = base::LoadNativeLibrary(path, &error);
241 if (!newdl) {
242 // We couldn't load the unwrapped plugin for some reason, despite
243 // being able to load the wrapped one. Just use the wrapped one.
244 LOG_IF(ERROR, PluginList::DebugPluginLoading())
245 << "Could not use unwrapped nspluginwrapper plugin "
246 << unwrapped_path->value() << " (" << error.ToString() << "), "
247 << "using the wrapped one.";
248 return;
249 }
250
251 // Unload the wrapped plugin, and use the wrapped plugin instead.
252 LOG_IF(ERROR, PluginList::DebugPluginLoading())
253 << "Using unwrapped version " << unwrapped_path->value()
254 << " of nspluginwrapper-wrapped plugin.";
255 base::UnloadNativeLibrary(*dl);
256 *dl = newdl;
257 *unwrapped_path = path;
258 }
259
260 } // namespace
261
262 bool PluginList::ReadWebPluginInfo(const base::FilePath& filename,
263 WebPluginInfo* info) {
264 // The file to reference is:
265 // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginsDirU nix.cpp
266
267 // Skip files that aren't appropriate for our architecture.
268 if (!ELFMatchesCurrentArchitecture(filename)) {
269 LOG_IF(ERROR, PluginList::DebugPluginLoading())
270 << "Skipping plugin " << filename.value()
271 << " because it doesn't match the current architecture.";
272 return false;
273 }
274
275 base::NativeLibraryLoadError error;
276 void* dl = base::LoadNativeLibrary(filename, &error);
277 if (!dl) {
278 LOG_IF(ERROR, PluginList::DebugPluginLoading())
279 << "While reading plugin info, unable to load library "
280 << filename.value() << " (" << error.ToString() << "), skipping.";
281 return false;
282 }
283
284 info->path = filename;
285
286 // Attempt to swap in the wrapped plugin if this is nspluginwrapper.
287 UnwrapNSPluginWrapper(&dl, &info->path);
288
289 // See comments in plugin_lib_mac regarding this symbol.
290 typedef const char* (*NP_GetMimeDescriptionType)();
291 NP_GetMimeDescriptionType NP_GetMIMEDescription =
292 reinterpret_cast<NP_GetMimeDescriptionType>(
293 dlsym(dl, "NP_GetMIMEDescription"));
294 const char* mime_description = NULL;
295 if (!NP_GetMIMEDescription) {
296 LOG_IF(ERROR, PluginList::DebugPluginLoading())
297 << "Plugin " << filename.value() << " doesn't have a "
298 << "NP_GetMIMEDescription symbol";
299 return false;
300 }
301 mime_description = NP_GetMIMEDescription();
302
303 if (!mime_description) {
304 LOG_IF(ERROR, PluginList::DebugPluginLoading())
305 << "MIME description for " << filename.value() << " is empty";
306 return false;
307 }
308 ParseMIMEDescription(mime_description, &info->mime_types);
309
310 // The plugin name and description live behind NP_GetValue calls.
311 typedef NPError (*NP_GetValueType)(void* unused,
312 nsPluginVariable variable,
313 void* value_out);
314 NP_GetValueType NP_GetValue =
315 reinterpret_cast<NP_GetValueType>(dlsym(dl, "NP_GetValue"));
316 if (NP_GetValue) {
317 const char* name = NULL;
318 NP_GetValue(NULL, nsPluginVariable_NameString, &name);
319 if (name) {
320 info->name = base::UTF8ToUTF16(name);
321 ExtractVersionString(name, info);
322 }
323
324 const char* description = NULL;
325 NP_GetValue(NULL, nsPluginVariable_DescriptionString, &description);
326 if (description) {
327 info->desc = base::UTF8ToUTF16(description);
328 if (info->version.empty())
329 ExtractVersionString(description, info);
330 }
331
332 LOG_IF(ERROR, PluginList::DebugPluginLoading())
333 << "Got info for plugin " << filename.value()
334 << " Name = \"" << base::UTF16ToUTF8(info->name)
335 << "\", Description = \"" << base::UTF16ToUTF8(info->desc)
336 << "\", Version = \"" << base::UTF16ToUTF8(info->version)
337 << "\".";
338 } else {
339 LOG_IF(ERROR, PluginList::DebugPluginLoading())
340 << "Plugin " << filename.value()
341 << " has no GetValue() and probably won't work.";
342 }
343
344 // Intentionally not unloading the plugin here, it can lead to crashes.
345
346 return true; 34 return true;
347 } 35 }
348 36
349 // static
350 void PluginList::ParseMIMEDescription(
351 const std::string& description,
352 std::vector<WebPluginMimeType>* mime_types) {
353 // We parse the description here into WebPluginMimeType structures.
354 // Naively from the NPAPI docs you'd think you could use
355 // string-splitting, but the Firefox parser turns out to do something
356 // different: find the first colon, then the second, then a semi.
357 //
358 // See ParsePluginMimeDescription near
359 // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginsDirU tils.h#53
360
361 std::string::size_type ofs = 0;
362 for (;;) {
363 WebPluginMimeType mime_type;
364
365 std::string::size_type end = description.find(':', ofs);
366 if (end == std::string::npos)
367 break;
368 mime_type.mime_type = description.substr(ofs, end - ofs);
369 ofs = end + 1;
370
371 end = description.find(':', ofs);
372 if (end == std::string::npos)
373 break;
374 const std::string extensions = description.substr(ofs, end - ofs);
375 base::SplitString(extensions, ',', &mime_type.file_extensions);
376 ofs = end + 1;
377
378 end = description.find(';', ofs);
379 // It's ok for end to run off the string here. If there's no
380 // trailing semicolon we consume the remainder of the string.
381 if (end != std::string::npos) {
382 mime_type.description =
383 base::UTF8ToUTF16(description.substr(ofs, end - ofs));
384 } else {
385 mime_type.description = base::UTF8ToUTF16(description.substr(ofs));
386 }
387 mime_types->push_back(mime_type);
388 if (end == std::string::npos)
389 break;
390 ofs = end + 1;
391 }
392 }
393
394 // static
395 void PluginList::ExtractVersionString(const std::string& desc,
396 WebPluginInfo* info) {
397 // This matching works by extracting a version substring, along the lines of:
398 // No postfix: second match in .*<prefix>.*$
399 // With postfix: second match .*<prefix>.*<postfix>
400 static const struct {
401 const char* kPrefix;
402 const char* kPostfix;
403 } kPrePostFixes[] = {
404 { "Shockwave Flash ", 0 },
405 { "Java(TM) Plug-in ", 0 },
406 { "(using IcedTea-Web ", " " },
407 { 0, 0 }
408 };
409 std::string version;
410 for (size_t i = 0; kPrePostFixes[i].kPrefix; ++i) {
411 size_t pos;
412 if ((pos = desc.find(kPrePostFixes[i].kPrefix)) != std::string::npos) {
413 version = desc.substr(pos + strlen(kPrePostFixes[i].kPrefix));
414 pos = std::string::npos;
415 if (kPrePostFixes[i].kPostfix)
416 pos = version.find(kPrePostFixes[i].kPostfix);
417 if (pos != std::string::npos)
418 version = version.substr(0, pos);
419 break;
420 }
421 }
422 if (!version.empty()) {
423 info->version = base::UTF8ToUTF16(version);
424 }
425 }
426
427 void PluginList::GetPluginDirectories(std::vector<base::FilePath>* plugin_dirs) {
428 // See http://groups.google.com/group/chromium-dev/browse_thread/thread/7a70e5 fcbac786a9
429 // for discussion.
430 // We first consult Chrome-specific dirs, then fall back on the logic
431 // Mozilla uses.
432
433 if (PluginList::plugins_discovery_disabled_)
434 return;
435
436 // Note: "extra" plugin dirs and paths are examined before these.
437 // "Extra" are those added by PluginList::AddExtraPluginDir() and
438 // PluginList::AddExtraPluginPath().
439
440 // The Chrome binary dir + "plugins/".
441 base::FilePath dir;
442 PathService::Get(base::DIR_EXE, &dir);
443 plugin_dirs->push_back(dir.Append("plugins"));
444
445 // Chrome OS only loads plugins from /opt/google/chrome/plugins.
446 #if !defined(OS_CHROMEOS)
447 // Mozilla code to reference:
448 // http://mxr.mozilla.org/firefox/ident?i=NS_APP_PLUGINS_DIR_LIST
449 // and tens of accompanying files (mxr is very helpful).
450 // This code carefully matches their behavior for compat reasons.
451
452 // 1) MOZ_PLUGIN_PATH env variable.
453 const char* moz_plugin_path = getenv("MOZ_PLUGIN_PATH");
454 if (moz_plugin_path) {
455 std::vector<std::string> paths;
456 base::SplitString(moz_plugin_path, ':', &paths);
457 for (size_t i = 0; i < paths.size(); ++i)
458 plugin_dirs->push_back(base::FilePath(paths[i]));
459 }
460
461 // 2) NS_USER_PLUGINS_DIR: ~/.mozilla/plugins.
462 // This is a de-facto standard, so even though we're not Mozilla, let's
463 // look in there too.
464 base::FilePath home = base::GetHomeDir();
465 if (!home.empty())
466 plugin_dirs->push_back(home.Append(".mozilla/plugins"));
467
468 // 3) NS_SYSTEM_PLUGINS_DIR:
469 // This varies across different browsers and versions, so check 'em all.
470 plugin_dirs->push_back(base::FilePath("/usr/lib/browser-plugins"));
471 plugin_dirs->push_back(base::FilePath("/usr/lib/mozilla/plugins"));
472 plugin_dirs->push_back(base::FilePath("/usr/lib/firefox/plugins"));
473 plugin_dirs->push_back(base::FilePath("/usr/lib/xulrunner-addons/plugins"));
474
475 #if defined(ARCH_CPU_64_BITS)
476 // On my Ubuntu system, /usr/lib64 is a symlink to /usr/lib.
477 // But a user reported on their Fedora system they are separate.
478 plugin_dirs->push_back(base::FilePath("/usr/lib64/browser-plugins"));
479 plugin_dirs->push_back(base::FilePath("/usr/lib64/mozilla/plugins"));
480 plugin_dirs->push_back(base::FilePath("/usr/lib64/firefox/plugins"));
481 plugin_dirs->push_back(base::FilePath("/usr/lib64/xulrunner-addons/plugins"));
482 #endif // defined(ARCH_CPU_64_BITS)
483 #endif // !defined(OS_CHROMEOS)
484 }
485
486 void PluginList::GetPluginsInDir(
487 const base::FilePath& dir_path, std::vector<base::FilePath>* plugins) {
488 // See ScanPluginsDirectory near
489 // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginHostI mpl.cpp#5052
490
491 // Construct and stat a list of all filenames under consideration, for
492 // later sorting by mtime.
493 FileTimeList files;
494 base::FileEnumerator enumerator(dir_path,
495 false, // not recursive
496 base::FileEnumerator::FILES);
497 for (base::FilePath path = enumerator.Next(); !path.value().empty();
498 path = enumerator.Next()) {
499 // Skip over Mozilla .xpt files.
500 if (path.MatchesExtension(FILE_PATH_LITERAL(".xpt")))
501 continue;
502
503 // Java doesn't like being loaded through a symlink, since it uses
504 // its path to find dependent data files.
505 // MakeAbsoluteFilePath calls through to realpath(), which resolves
506 // symlinks.
507 base::FilePath orig_path = path;
508 path = base::MakeAbsoluteFilePath(path);
509 if (path.empty())
510 path = orig_path;
511 LOG_IF(ERROR, PluginList::DebugPluginLoading())
512 << "Resolved " << orig_path.value() << " -> " << path.value();
513
514 if (std::find(plugins->begin(), plugins->end(), path) != plugins->end()) {
515 LOG_IF(ERROR, PluginList::DebugPluginLoading())
516 << "Skipping duplicate instance of " << path.value();
517 continue;
518 }
519
520 if (IsBlacklistedPlugin(path)) {
521 LOG_IF(ERROR, PluginList::DebugPluginLoading())
522 << "Skipping blacklisted plugin " << path.value();
523 continue;
524 }
525
526 // Flash stops working if the containing directory involves 'netscape'.
527 // No joke. So use the other path if it's better.
528 static const char kFlashPlayerFilename[] = "libflashplayer.so";
529 static const char kNetscapeInPath[] = "/netscape/";
530 if (path.BaseName().value() == kFlashPlayerFilename &&
531 path.value().find(kNetscapeInPath) != std::string::npos) {
532 if (orig_path.value().find(kNetscapeInPath) == std::string::npos) {
533 // Go back to the old path.
534 path = orig_path;
535 } else {
536 LOG_IF(ERROR, PluginList::DebugPluginLoading())
537 << "Flash misbehaves when used from a directory containing "
538 << kNetscapeInPath << ", so skipping " << orig_path.value();
539 continue;
540 }
541 }
542
543 // Get mtime.
544 base::File::Info info;
545 if (!base::GetFileInfo(path, &info))
546 continue;
547
548 files.push_back(std::make_pair(path, info.last_modified));
549 }
550
551 // Sort the file list by time (and filename).
552 std::sort(files.begin(), files.end(), CompareTime);
553
554 // Load the files in order.
555 for (FileTimeList::const_iterator i = files.begin(); i != files.end(); ++i) {
556 plugins->push_back(i->first);
557 }
558 }
559
560 bool PluginList::ShouldLoadPluginUsingPluginList(
561 const WebPluginInfo& info, std::vector<WebPluginInfo>* plugins) {
562 LOG_IF(ERROR, PluginList::DebugPluginLoading())
563 << "Considering " << info.path.value() << " (" << info.name << ")";
564
565 if (IsUndesirablePlugin(info)) {
566 LOG_IF(ERROR, PluginList::DebugPluginLoading())
567 << info.path.value() << " is undesirable.";
568
569 // See if we have a better version of this plugin.
570 for (size_t j = 0; j < plugins->size(); ++j) {
571 if ((*plugins)[j].name == info.name &&
572 !IsUndesirablePlugin((*plugins)[j])) {
573 // Skip the current undesirable one so we can use the better one
574 // we just found.
575 LOG_IF(ERROR, PluginList::DebugPluginLoading())
576 << "Skipping " << info.path.value() << ", preferring "
577 << (*plugins)[j].path.value();
578 return false;
579 }
580 }
581 }
582
583 // TODO(evanm): prefer the newest version of flash, etc. here?
584
585 VLOG_IF(1, PluginList::DebugPluginLoading()) << "Using " << info.path.value();
586
587 return true;
588 }
589
590 } // namespace content 37 } // namespace content
OLDNEW
« no previous file with comments | « content/common/plugin_list.h ('k') | content/common/plugin_list_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698