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

Side by Side Diff: chrome/browser/plugin_service.cc

Issue 6538111: Move the rest of the core files in chrome\browser to content\browser.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 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 | « chrome/browser/plugin_service.h ('k') | chrome/browser/plugin_service_browsertest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "chrome/browser/plugin_service.h"
6
7 #include <vector>
8
9 #include "base/command_line.h"
10 #include "base/path_service.h"
11 #include "base/string_util.h"
12 #include "base/threading/thread.h"
13 #include "base/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/browser_thread.h"
18 #include "chrome/browser/chrome_plugin_host.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/plugin_updater.h"
21 #include "chrome/browser/ppapi_plugin_process_host.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/renderer_host/render_process_host.h"
24 #include "chrome/browser/renderer_host/render_view_host.h"
25 #include "chrome/common/chrome_plugin_lib.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/default_plugin.h"
29 #include "chrome/common/extensions/extension.h"
30 #include "chrome/common/gpu_plugin.h"
31 #include "chrome/common/logging_chrome.h"
32 #include "chrome/common/notification_type.h"
33 #include "chrome/common/notification_service.h"
34 #include "chrome/common/pepper_plugin_registry.h"
35 #include "chrome/common/plugin_messages.h"
36 #include "chrome/common/render_messages.h"
37 #include "webkit/plugins/npapi/plugin_constants_win.h"
38 #include "webkit/plugins/npapi/plugin_list.h"
39 #include "webkit/plugins/npapi/webplugininfo.h"
40
41 #if defined(OS_CHROMEOS)
42 #include "chrome/browser/chromeos/plugin_selection_policy.h"
43 #endif
44
45 #if defined(OS_MACOSX)
46 static void NotifyPluginsOfActivation() {
47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
48
49 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
50 !iter.Done(); ++iter) {
51 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
52 plugin->OnAppActivation();
53 }
54 }
55 #endif
56
57 static void PurgePluginListCache(bool reload_pages) {
58 for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
59 !it.IsAtEnd(); it.Advance()) {
60 it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
61 }
62 }
63
64 #if defined(OS_LINUX)
65 // Delegate class for monitoring directories.
66 class PluginDirWatcherDelegate : public FilePathWatcher::Delegate {
67 virtual void OnFilePathChanged(const FilePath& path) {
68 VLOG(1) << "Watched path changed: " << path.value();
69 // Make the plugin list update itself
70 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
71 }
72 virtual void OnError() {
73 // TODO(pastarmovj): Add some sensible error handling. Maybe silently
74 // stopping the watcher would be enough. Or possibly restart it.
75 NOTREACHED();
76 }
77 };
78 #endif
79
80 // static
81 bool PluginService::enable_chrome_plugins_ = true;
82
83 // static
84 void PluginService::InitGlobalInstance(Profile* profile) {
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86
87 // We first group the plugins and then figure out which groups to disable.
88 PluginUpdater::GetInstance()->DisablePluginGroupsFromPrefs(profile);
89
90 // Have Chrome plugins write their data to the profile directory.
91 GetInstance()->SetChromePluginDataDir(profile->GetPath());
92 }
93
94 // static
95 PluginService* PluginService::GetInstance() {
96 return Singleton<PluginService>::get();
97 }
98
99 // static
100 void PluginService::EnableChromePlugins(bool enable) {
101 enable_chrome_plugins_ = enable;
102 }
103
104 PluginService::PluginService()
105 : main_message_loop_(MessageLoop::current()),
106 resource_dispatcher_host_(NULL),
107 ui_locale_(g_browser_process->GetApplicationLocale()) {
108 RegisterPepperPlugins();
109
110 // Have the NPAPI plugin list search for Chrome plugins as well.
111 ChromePluginLib::RegisterPluginsWithNPAPI();
112
113 // Load any specified on the command line as well.
114 const CommandLine* command_line = CommandLine::ForCurrentProcess();
115 FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
116 if (!path.empty())
117 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
118 path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
119 if (!path.empty())
120 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(path);
121
122 chrome::RegisterInternalDefaultPlugin();
123
124 // Register the internal Flash and PDF, if available.
125 if (!CommandLine::ForCurrentProcess()->HasSwitch(
126 switches::kDisableInternalFlash) &&
127 PathService::Get(chrome::FILE_FLASH_PLUGIN, &path)) {
128 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(path);
129 }
130
131 #if defined(OS_CHROMEOS)
132 plugin_selection_policy_ = new chromeos::PluginSelectionPolicy;
133 plugin_selection_policy_->StartInit();
134 #endif
135
136 chrome::RegisterInternalGPUPlugin();
137
138 // Start watching for changes in the plugin list. This means watching
139 // for changes in the Windows registry keys and on both Windows and POSIX
140 // watch for changes in the paths that are expected to contain plugins.
141 #if defined(OS_WIN)
142 hkcu_key_.Create(
143 HKEY_CURRENT_USER, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY);
144 hklm_key_.Create(
145 HKEY_LOCAL_MACHINE, webkit::npapi::kRegistryMozillaPlugins, KEY_NOTIFY);
146 if (hkcu_key_.StartWatching() == ERROR_SUCCESS) {
147 hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
148 hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
149 }
150
151 if (hklm_key_.StartWatching() == ERROR_SUCCESS) {
152 hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
153 hklm_watcher_.StartWatching(hklm_event_.get(), this);
154 }
155 #elif defined(OS_POSIX) && !defined(OS_MACOSX)
156 // Also find plugins in a user-specific plugins dir,
157 // e.g. ~/.config/chromium/Plugins.
158 FilePath user_data_dir;
159 if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
160 webkit::npapi::PluginList::Singleton()->AddExtraPluginDir(
161 user_data_dir.Append("Plugins"));
162 }
163 #endif
164 // The FilePathWatcher produces too many false positives on MacOS (access time
165 // updates?) which will lead to enforcing updates of the plugins way too often.
166 // On ChromeOS the user can't install plugins anyway and on Windows all
167 // important plugins register themselves in the registry so no need to do that.
168 #if defined(OS_LINUX)
169 file_watcher_delegate_ = new PluginDirWatcherDelegate();
170 // Get the list of all paths for registering the FilePathWatchers
171 // that will track and if needed reload the list of plugins on runtime.
172 std::vector<FilePath> plugin_dirs;
173 webkit::npapi::PluginList::Singleton()->GetPluginDirectories(
174 &plugin_dirs);
175
176 for (size_t i = 0; i < plugin_dirs.size(); ++i) {
177 FilePathWatcher* watcher = new FilePathWatcher();
178 // FilePathWatcher can not handle non-absolute paths under windows.
179 // We don't watch for file changes in windows now but if this should ever
180 // be extended to Windows these lines might save some time of debugging.
181 #if defined(OS_WIN)
182 if (!plugin_dirs[i].IsAbsolute())
183 continue;
184 #endif
185 VLOG(1) << "Watching for changes in: " << plugin_dirs[i].value();
186 BrowserThread::PostTask(
187 BrowserThread::FILE, FROM_HERE,
188 NewRunnableFunction(
189 &PluginService::RegisterFilePathWatcher,
190 watcher, plugin_dirs[i], file_watcher_delegate_));
191 file_watchers_.push_back(watcher);
192 }
193 #endif
194 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
195 NotificationService::AllSources());
196 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
197 NotificationService::AllSources());
198 #if defined(OS_MACOSX)
199 // We need to know when the browser comes forward so we can bring modal plugin
200 // windows forward too.
201 registrar_.Add(this, NotificationType::APP_ACTIVATED,
202 NotificationService::AllSources());
203 #endif
204 registrar_.Add(this, NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
205 NotificationService::AllSources());
206 registrar_.Add(this,
207 NotificationType::RENDERER_PROCESS_CLOSED,
208 NotificationService::AllSources());
209 }
210
211 PluginService::~PluginService() {
212 #if defined(OS_WIN)
213 // Release the events since they're owned by RegKey, not WaitableEvent.
214 hkcu_watcher_.StopWatching();
215 hklm_watcher_.StopWatching();
216 if (hkcu_event_.get())
217 hkcu_event_->Release();
218 if (hklm_event_.get())
219 hklm_event_->Release();
220 #endif
221 }
222
223 void PluginService::LoadChromePlugins(
224 ResourceDispatcherHost* resource_dispatcher_host) {
225 if (!enable_chrome_plugins_)
226 return;
227
228 resource_dispatcher_host_ = resource_dispatcher_host;
229 ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
230 }
231
232 void PluginService::SetChromePluginDataDir(const FilePath& data_dir) {
233 chrome_plugin_data_dir_ = data_dir;
234 }
235
236 const FilePath& PluginService::GetChromePluginDataDir() {
237 return chrome_plugin_data_dir_;
238 }
239
240 const std::string& PluginService::GetUILocale() {
241 return ui_locale_;
242 }
243
244 PluginProcessHost* PluginService::FindNpapiPluginProcess(
245 const FilePath& plugin_path) {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
247
248 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
249 !iter.Done(); ++iter) {
250 PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
251 if (plugin->info().path == plugin_path)
252 return plugin;
253 }
254
255 return NULL;
256 }
257
258 PpapiPluginProcessHost* PluginService::FindPpapiPluginProcess(
259 const FilePath& plugin_path) {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
261
262 for (BrowserChildProcessHost::Iterator iter(
263 ChildProcessInfo::PPAPI_PLUGIN_PROCESS);
264 !iter.Done(); ++iter) {
265 PpapiPluginProcessHost* plugin =
266 static_cast<PpapiPluginProcessHost*>(*iter);
267 if (plugin->plugin_path() == plugin_path)
268 return plugin;
269 }
270
271 return NULL;
272 }
273
274 PluginProcessHost* PluginService::FindOrStartNpapiPluginProcess(
275 const FilePath& plugin_path) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
277
278 PluginProcessHost* plugin_host = FindNpapiPluginProcess(plugin_path);
279 if (plugin_host)
280 return plugin_host;
281
282 webkit::npapi::WebPluginInfo info;
283 if (!webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
284 plugin_path, &info)) {
285 return NULL;
286 }
287
288 // This plugin isn't loaded by any plugin process, so create a new process.
289 scoped_ptr<PluginProcessHost> new_host(new PluginProcessHost());
290 if (!new_host->Init(info, ui_locale_)) {
291 NOTREACHED(); // Init is not expected to fail.
292 return NULL;
293 }
294 return new_host.release();
295 }
296
297 PpapiPluginProcessHost* PluginService::FindOrStartPpapiPluginProcess(
298 const FilePath& plugin_path) {
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
300
301 PpapiPluginProcessHost* plugin_host = FindPpapiPluginProcess(plugin_path);
302 if (plugin_host)
303 return plugin_host;
304
305 // Validate that the plugin is actually registered. There should generally
306 // be very few plugins so a brute-force search is fine.
307 PepperPluginInfo* info = NULL;
308 for (size_t i = 0; i < ppapi_plugins_.size(); i++) {
309 if (ppapi_plugins_[i].path == plugin_path) {
310 info = &ppapi_plugins_[i];
311 break;
312 }
313 }
314 if (!info)
315 return NULL;
316
317 // This plugin isn't loaded by any plugin process, so create a new process.
318 scoped_ptr<PpapiPluginProcessHost> new_host(new PpapiPluginProcessHost);
319 if (!new_host->Init(plugin_path)) {
320 NOTREACHED(); // Init is not expected to fail.
321 return NULL;
322 }
323 return new_host.release();
324 }
325
326 void PluginService::OpenChannelToNpapiPlugin(
327 int render_process_id,
328 int render_view_id,
329 const GURL& url,
330 const std::string& mime_type,
331 PluginProcessHost::Client* client) {
332 // The PluginList::GetFirstAllowedPluginInfo may need to load the
333 // plugins. Don't do it on the IO thread.
334 BrowserThread::PostTask(
335 BrowserThread::FILE, FROM_HERE,
336 NewRunnableMethod(
337 this, &PluginService::GetAllowedPluginForOpenChannelToPlugin,
338 render_process_id, render_view_id, url, mime_type, client));
339 }
340
341 void PluginService::OpenChannelToPpapiPlugin(
342 const FilePath& path,
343 PpapiPluginProcessHost::Client* client) {
344 PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(path);
345 if (plugin_host)
346 plugin_host->OpenChannelToPlugin(client);
347 else // Send error.
348 client->OnChannelOpened(base::kNullProcessHandle, IPC::ChannelHandle());
349 }
350
351 void PluginService::GetAllowedPluginForOpenChannelToPlugin(
352 int render_process_id,
353 int render_view_id,
354 const GURL& url,
355 const std::string& mime_type,
356 PluginProcessHost::Client* client) {
357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
358 webkit::npapi::WebPluginInfo info;
359 bool found = GetFirstAllowedPluginInfo(
360 render_process_id, render_view_id, url, mime_type, &info, NULL);
361 FilePath plugin_path;
362 if (found && webkit::npapi::IsPluginEnabled(info))
363 plugin_path = FilePath(info.path);
364
365 // Now we jump back to the IO thread to finish opening the channel.
366 BrowserThread::PostTask(
367 BrowserThread::IO, FROM_HERE,
368 NewRunnableMethod(
369 this, &PluginService::FinishOpenChannelToPlugin,
370 plugin_path, client));
371 }
372
373 void PluginService::FinishOpenChannelToPlugin(
374 const FilePath& plugin_path,
375 PluginProcessHost::Client* client) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
377
378 PluginProcessHost* plugin_host = FindOrStartNpapiPluginProcess(plugin_path);
379 if (plugin_host)
380 plugin_host->OpenChannelToPlugin(client);
381 else
382 client->OnError();
383 }
384
385 bool PluginService::GetFirstAllowedPluginInfo(
386 int render_process_id,
387 int render_view_id,
388 const GURL& url,
389 const std::string& mime_type,
390 webkit::npapi::WebPluginInfo* info,
391 std::string* actual_mime_type) {
392 // GetPluginInfoArray may need to load the plugins, so we need to be
393 // on the FILE thread.
394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
395 bool allow_wildcard = true;
396 #if defined(OS_CHROMEOS)
397 std::vector<webkit::npapi::WebPluginInfo> info_array;
398 std::vector<std::string> actual_mime_types;
399 webkit::npapi::PluginList::Singleton()->GetPluginInfoArray(
400 url, mime_type, allow_wildcard, &info_array, &actual_mime_types);
401
402 // Now we filter by the plugin selection policy.
403 int allowed_index = plugin_selection_policy_->FindFirstAllowed(url,
404 info_array);
405 if (!info_array.empty() && allowed_index >= 0) {
406 *info = info_array[allowed_index];
407 if (actual_mime_type)
408 *actual_mime_type = actual_mime_types[allowed_index];
409 return true;
410 }
411 return false;
412 #else
413 {
414 base::AutoLock auto_lock(overridden_plugins_lock_);
415 for (size_t i = 0; i < overridden_plugins_.size(); ++i) {
416 if (overridden_plugins_[i].render_process_id == render_process_id &&
417 overridden_plugins_[i].render_view_id == render_view_id &&
418 overridden_plugins_[i].url == url) {
419 if (actual_mime_type)
420 *actual_mime_type = mime_type;
421 *info = overridden_plugins_[i].plugin;
422 return true;
423 }
424 }
425 }
426 return webkit::npapi::PluginList::Singleton()->GetPluginInfo(
427 url, mime_type, allow_wildcard, info, actual_mime_type);
428 #endif
429 }
430
431 void PluginService::OnWaitableEventSignaled(
432 base::WaitableEvent* waitable_event) {
433 #if defined(OS_WIN)
434 if (waitable_event == hkcu_event_.get()) {
435 hkcu_key_.StartWatching();
436 } else {
437 hklm_key_.StartWatching();
438 }
439
440 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
441 PurgePluginListCache(true);
442 #else
443 // This event should only get signaled on a Windows machine.
444 NOTREACHED();
445 #endif // defined(OS_WIN)
446 }
447
448 static void ForceShutdownPlugin(const FilePath& plugin_path) {
449 PluginProcessHost* plugin =
450 PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path);
451 if (plugin)
452 plugin->ForceShutdown();
453 }
454
455 void PluginService::Observe(NotificationType type,
456 const NotificationSource& source,
457 const NotificationDetails& details) {
458 switch (type.value) {
459 case NotificationType::EXTENSION_LOADED: {
460 const Extension* extension = Details<const Extension>(details).ptr();
461 bool plugins_changed = false;
462 for (size_t i = 0; i < extension->plugins().size(); ++i) {
463 const Extension::PluginInfo& plugin = extension->plugins()[i];
464 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
465 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
466 plugins_changed = true;
467 if (!plugin.is_public)
468 private_plugins_[plugin.path] = extension->url();
469 }
470 if (plugins_changed)
471 PurgePluginListCache(false);
472 break;
473 }
474
475 case NotificationType::EXTENSION_UNLOADED: {
476 const Extension* extension =
477 Details<UnloadedExtensionInfo>(details)->extension;
478 bool plugins_changed = false;
479 for (size_t i = 0; i < extension->plugins().size(); ++i) {
480 const Extension::PluginInfo& plugin = extension->plugins()[i];
481 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
482 NewRunnableFunction(&ForceShutdownPlugin,
483 plugin.path));
484 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
485 webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath(
486 plugin.path);
487 plugins_changed = true;
488 if (!plugin.is_public)
489 private_plugins_.erase(plugin.path);
490 }
491 if (plugins_changed)
492 PurgePluginListCache(false);
493 break;
494 }
495
496 #if defined(OS_MACOSX)
497 case NotificationType::APP_ACTIVATED: {
498 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
499 NewRunnableFunction(&NotifyPluginsOfActivation));
500 break;
501 }
502 #endif
503
504 case NotificationType::PLUGIN_ENABLE_STATUS_CHANGED: {
505 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
506 PurgePluginListCache(false);
507 break;
508 }
509 case NotificationType::RENDERER_PROCESS_CLOSED: {
510 int render_process_id = Source<RenderProcessHost>(source).ptr()->id();
511
512 base::AutoLock auto_lock(overridden_plugins_lock_);
513 for (size_t i = 0; i < overridden_plugins_.size(); ++i) {
514 if (overridden_plugins_[i].render_process_id == render_process_id) {
515 overridden_plugins_.erase(overridden_plugins_.begin() + i);
516 break;
517 }
518 }
519 break;
520 }
521 default:
522 NOTREACHED();
523 }
524 }
525
526 bool PluginService::PrivatePluginAllowedForURL(const FilePath& plugin_path,
527 const GURL& url) {
528 if (url.is_empty())
529 return true; // Caller wants all plugins.
530
531 PrivatePluginMap::iterator it = private_plugins_.find(plugin_path);
532 if (it == private_plugins_.end())
533 return true; // This plugin is not private, so it's allowed everywhere.
534
535 // We do a dumb compare of scheme and host, rather than using the domain
536 // service, since we only care about this for extensions.
537 const GURL& required_url = it->second;
538 return (url.scheme() == required_url.scheme() &&
539 url.host() == required_url.host());
540 }
541
542 void PluginService::OverridePluginForTab(OverriddenPlugin plugin) {
543 base::AutoLock auto_lock(overridden_plugins_lock_);
544 overridden_plugins_.push_back(plugin);
545 }
546
547 void PluginService::RegisterPepperPlugins() {
548 PepperPluginRegistry::ComputeList(&ppapi_plugins_);
549 for (size_t i = 0; i < ppapi_plugins_.size(); ++i) {
550 webkit::npapi::WebPluginInfo info;
551 info.path = ppapi_plugins_[i].path;
552 info.name = ppapi_plugins_[i].name.empty() ?
553 ppapi_plugins_[i].path.BaseName().LossyDisplayName() :
554 ASCIIToUTF16(ppapi_plugins_[i].name);
555 info.desc = ASCIIToUTF16(ppapi_plugins_[i].description);
556 info.version = ASCIIToUTF16(ppapi_plugins_[i].version);
557 info.enabled = webkit::npapi::WebPluginInfo::USER_ENABLED_POLICY_UNMANAGED;
558
559 // TODO(evan): Pepper shouldn't require us to parse strings to get
560 // the list of mime types out.
561 if (!webkit::npapi::PluginList::ParseMimeTypes(
562 JoinString(ppapi_plugins_[i].mime_types, '|'),
563 ppapi_plugins_[i].file_extensions,
564 ASCIIToUTF16(ppapi_plugins_[i].type_descriptions),
565 &info.mime_types)) {
566 LOG(ERROR) << "Error parsing mime types for "
567 << ppapi_plugins_[i].path.LossyDisplayName();
568 return;
569 }
570
571 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info);
572 }
573 }
574
575 #if defined(OS_LINUX)
576 // static
577 void PluginService::RegisterFilePathWatcher(
578 FilePathWatcher *watcher,
579 const FilePath& path,
580 FilePathWatcher::Delegate* delegate) {
581 bool result = watcher->Watch(path, delegate);
582 DCHECK(result);
583 }
584 #endif
OLDNEW
« no previous file with comments | « chrome/browser/plugin_service.h ('k') | chrome/browser/plugin_service_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698