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.
5 #include "chrome/browser/plugins/plugin_prefs.h"
10 #include "base/command_line.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop.h"
13 #include "base/path_service.h"
14 #include "base/string_util.h"
15 #include "base/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "build/build_config.h"
18 #include "chrome/browser/plugins/plugin_installer.h"
19 #include "chrome/browser/plugins/plugin_metadata.h"
20 #include "chrome/browser/plugins/plugin_prefs_factory.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/prefs/scoped_user_pref_update.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/profiles/profile_keyed_service.h"
25 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_content_client.h"
27 #include "chrome/common/chrome_notification_types.h"
28 #include "chrome/common/chrome_paths.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/browser/plugin_service.h"
34 #include "webkit/plugins/npapi/plugin_list.h"
35 #include "webkit/plugins/webplugininfo.h"
37 using content::BrowserThread
;
38 using content::PluginService
;
42 // How long to wait to save the plugin enabled information, which might need to
44 const int64 kPluginUpdateDelayMs
= 60 * 1000;
46 bool IsComponentUpdatedPepperFlash(const base::FilePath
& plugin
) {
47 if (plugin
.BaseName().value() == chrome::kPepperFlashPluginFilename
) {
48 base::FilePath component_updated_pepper_flash_dir
;
49 if (PathService::Get(chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN
,
50 &component_updated_pepper_flash_dir
) &&
51 component_updated_pepper_flash_dir
.IsParent(plugin
)) {
61 PluginPrefs::PluginState::PluginState() {
64 PluginPrefs::PluginState::~PluginState() {
67 bool PluginPrefs::PluginState::Get(const base::FilePath
& plugin
,
68 bool* enabled
) const {
69 base::FilePath key
= ConvertMapKey(plugin
);
70 std::map
<base::FilePath
, bool>::const_iterator iter
= state_
.find(key
);
71 if (iter
!= state_
.end()) {
72 *enabled
= iter
->second
;
78 void PluginPrefs::PluginState::Set(const base::FilePath
& plugin
, bool enabled
) {
79 state_
[ConvertMapKey(plugin
)] = enabled
;
82 base::FilePath
PluginPrefs::PluginState::ConvertMapKey(
83 const base::FilePath
& plugin
) const {
84 // Keep the state of component-updated and bundled Pepper Flash in sync.
85 if (IsComponentUpdatedPepperFlash(plugin
)) {
86 base::FilePath bundled_pepper_flash
;
87 if (PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN
,
88 &bundled_pepper_flash
)) {
89 return bundled_pepper_flash
;
97 scoped_refptr
<PluginPrefs
> PluginPrefs::GetForProfile(Profile
* profile
) {
98 return PluginPrefsFactory::GetPrefsForProfile(profile
);
102 scoped_refptr
<PluginPrefs
> PluginPrefs::GetForTestingProfile(
104 return static_cast<PluginPrefs
*>(
105 PluginPrefsFactory::GetInstance()->SetTestingFactoryAndUse(
106 profile
, &PluginPrefsFactory::CreateForTestingProfile
).get());
109 void PluginPrefs::SetPluginListForTesting(
110 webkit::npapi::PluginList
* plugin_list
) {
111 plugin_list_
= plugin_list
;
114 void PluginPrefs::EnablePluginGroup(bool enabled
, const string16
& group_name
) {
115 PluginService::GetInstance()->GetPlugins(
116 base::Bind(&PluginPrefs::EnablePluginGroupInternal
,
117 this, enabled
, group_name
));
120 void PluginPrefs::EnablePluginGroupInternal(
122 const string16
& group_name
,
123 const std::vector
<webkit::WebPluginInfo
>& plugins
) {
124 base::AutoLock
auto_lock(lock_
);
125 PluginFinder
* finder
= PluginFinder::GetInstance();
127 // Set the desired state for the group.
128 plugin_group_state_
[group_name
] = enabled
;
130 // Update the state for all plug-ins in the group.
131 for (size_t i
= 0; i
< plugins
.size(); ++i
) {
132 scoped_ptr
<PluginMetadata
> plugin(finder
->GetPluginMetadata(plugins
[i
]));
133 if (group_name
!= plugin
->name())
135 plugin_state_
.Set(plugins
[i
].path
, enabled
);
138 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
139 base::Bind(&PluginPrefs::OnUpdatePreferences
, this, plugins
));
140 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
141 base::Bind(&PluginPrefs::NotifyPluginStatusChanged
, this));
144 void PluginPrefs::EnablePlugin(
145 bool enabled
, const base::FilePath
& path
,
146 const base::Callback
<void(bool)>& callback
) {
147 PluginFinder
* finder
= PluginFinder::GetInstance();
148 webkit::WebPluginInfo plugin
;
149 bool can_enable
= true;
150 if (PluginService::GetInstance()->GetPluginInfoByPath(path
, &plugin
)) {
151 scoped_ptr
<PluginMetadata
> plugin_metadata(
152 finder
->GetPluginMetadata(plugin
));
153 PolicyStatus plugin_status
= PolicyStatusForPlugin(plugin
.name
);
154 PolicyStatus group_status
= PolicyStatusForPlugin(plugin_metadata
->name());
156 if (plugin_status
== POLICY_DISABLED
|| group_status
== POLICY_DISABLED
)
159 if (plugin_status
== POLICY_ENABLED
|| group_status
== POLICY_ENABLED
)
167 MessageLoop::current()->PostTask(FROM_HERE
,
168 base::Bind(callback
, false));
172 PluginService::GetInstance()->GetPlugins(
173 base::Bind(&PluginPrefs::EnablePluginInternal
, this,
174 enabled
, path
, finder
, callback
));
177 void PluginPrefs::EnablePluginInternal(
179 const base::FilePath
& path
,
180 PluginFinder
* plugin_finder
,
181 const base::Callback
<void(bool)>& callback
,
182 const std::vector
<webkit::WebPluginInfo
>& plugins
) {
184 // Set the desired state for the plug-in.
185 base::AutoLock
auto_lock(lock_
);
186 plugin_state_
.Set(path
, enabled
);
190 for (size_t i
= 0; i
< plugins
.size(); ++i
) {
191 if (plugins
[i
].path
== path
) {
192 scoped_ptr
<PluginMetadata
> plugin_metadata(
193 plugin_finder
->GetPluginMetadata(plugins
[i
]));
194 // set the group name for this plug-in.
195 group_name
= plugin_metadata
->name();
196 DCHECK_EQ(enabled
, IsPluginEnabled(plugins
[i
]));
201 bool all_disabled
= true;
202 for (size_t i
= 0; i
< plugins
.size(); ++i
) {
203 scoped_ptr
<PluginMetadata
> plugin_metadata(
204 plugin_finder
->GetPluginMetadata(plugins
[i
]));
205 DCHECK(!plugin_metadata
->name().empty());
206 if (group_name
== plugin_metadata
->name()) {
207 all_disabled
= all_disabled
&& !IsPluginEnabled(plugins
[i
]);
211 if (!group_name
.empty()) {
212 // Update the state for the corresponding plug-in group.
213 base::AutoLock
auto_lock(lock_
);
214 plugin_group_state_
[group_name
] = !all_disabled
;
217 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
218 base::Bind(&PluginPrefs::OnUpdatePreferences
, this, plugins
));
219 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
220 base::Bind(&PluginPrefs::NotifyPluginStatusChanged
, this));
224 PluginPrefs::PolicyStatus
PluginPrefs::PolicyStatusForPlugin(
225 const string16
& name
) const {
226 base::AutoLock
auto_lock(lock_
);
227 if (IsStringMatchedInSet(name
, policy_enabled_plugin_patterns_
)) {
228 return POLICY_ENABLED
;
229 } else if (IsStringMatchedInSet(name
, policy_disabled_plugin_patterns_
) &&
230 !IsStringMatchedInSet(
231 name
, policy_disabled_plugin_exception_patterns_
)) {
232 return POLICY_DISABLED
;
238 bool PluginPrefs::IsPluginEnabled(const webkit::WebPluginInfo
& plugin
) const {
239 scoped_ptr
<PluginMetadata
> plugin_metadata(
240 PluginFinder::GetInstance()->GetPluginMetadata(plugin
));
241 string16 group_name
= plugin_metadata
->name();
243 // Check if the plug-in or its group is enabled by policy.
244 PolicyStatus plugin_status
= PolicyStatusForPlugin(plugin
.name
);
245 PolicyStatus group_status
= PolicyStatusForPlugin(group_name
);
246 if (plugin_status
== POLICY_ENABLED
|| group_status
== POLICY_ENABLED
)
249 // Check if the plug-in or its group is disabled by policy.
250 if (plugin_status
== POLICY_DISABLED
|| group_status
== POLICY_DISABLED
)
253 // If enabling NaCl, make sure the plugin is also enabled. See bug
254 // http://code.google.com/p/chromium/issues/detail?id=81010 for more
256 // TODO(dspringer): When NaCl is on by default, remove this code.
258 ASCIIToUTF16(chrome::ChromeContentClient::kNaClPluginName
)) &&
259 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableNaCl
)) {
263 base::AutoLock
auto_lock(lock_
);
264 // Check user preferences for the plug-in.
265 bool plugin_enabled
= false;
266 if (plugin_state_
.Get(plugin
.path
, &plugin_enabled
))
267 return plugin_enabled
;
269 // Check user preferences for the plug-in group.
270 std::map
<string16
, bool>::const_iterator
group_it(
271 plugin_group_state_
.find(plugin
.name
));
272 if (group_it
!= plugin_group_state_
.end())
273 return group_it
->second
;
275 // Default to enabled.
279 void PluginPrefs::UpdatePatternsAndNotify(std::set
<string16
>* patterns
,
280 const std::string
& pref_name
) {
281 base::AutoLock
auto_lock(lock_
);
282 ListValueToStringSet(prefs_
->GetList(pref_name
.c_str()), patterns
);
284 NotifyPluginStatusChanged();
288 bool PluginPrefs::IsStringMatchedInSet(const string16
& name
,
289 const std::set
<string16
>& pattern_set
) {
290 std::set
<string16
>::const_iterator
pattern(pattern_set
.begin());
291 while (pattern
!= pattern_set
.end()) {
292 if (MatchPattern(name
, *pattern
))
301 void PluginPrefs::ListValueToStringSet(const ListValue
* src
,
302 std::set
<string16
>* dest
) {
306 ListValue::const_iterator
end(src
->end());
307 for (ListValue::const_iterator
current(src
->begin());
308 current
!= end
; ++current
) {
309 string16 plugin_name
;
310 if ((*current
)->GetAsString(&plugin_name
)) {
311 dest
->insert(plugin_name
);
316 void PluginPrefs::SetPrefs(PrefService
* prefs
) {
318 bool update_internal_dir
= false;
319 base::FilePath last_internal_dir
=
320 prefs_
->GetFilePath(prefs::kPluginsLastInternalDirectory
);
321 base::FilePath cur_internal_dir
;
322 if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS
, &cur_internal_dir
) &&
323 cur_internal_dir
!= last_internal_dir
) {
324 update_internal_dir
= true;
326 prefs::kPluginsLastInternalDirectory
, cur_internal_dir
);
329 bool force_enable_internal_pdf
= false;
330 bool internal_pdf_enabled
= false;
331 string16 pdf_group_name
=
332 ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName
);
333 base::FilePath pdf_path
;
334 PathService::Get(chrome::FILE_PDF_PLUGIN
, &pdf_path
);
335 base::FilePath::StringType pdf_path_str
= pdf_path
.value();
336 if (!prefs_
->GetBoolean(prefs::kPluginsEnabledInternalPDF
)) {
337 // We switched to the internal pdf plugin being on by default, and so we
338 // need to force it to be enabled. We only want to do it this once though,
339 // i.e. we don't want to enable it again if the user disables it afterwards.
340 prefs_
->SetBoolean(prefs::kPluginsEnabledInternalPDF
, true);
341 force_enable_internal_pdf
= true;
344 bool force_enable_nacl
= false;
345 string16 nacl_group_name
=
346 ASCIIToUTF16(chrome::ChromeContentClient::kNaClPluginName
);
347 // Since the NaCl Plugin changed names between Chrome 13 and 14, we need to
348 // check for both because either could be stored as the plugin group name.
349 string16 old_nacl_group_name
=
350 ASCIIToUTF16(chrome::ChromeContentClient::kNaClOldPluginName
);
351 base::FilePath nacl_path
;
352 PathService::Get(chrome::FILE_NACL_PLUGIN
, &nacl_path
);
353 base::FilePath::StringType nacl_path_str
= nacl_path
.value();
354 if (!prefs_
->GetBoolean(prefs::kPluginsEnabledNaCl
)) {
355 // We switched to the nacl plugin being on by default, and so we need to
356 // force it to be enabled. We only want to do it this once though, i.e.
357 // we don't want to enable it again if the user disables it afterwards.
358 prefs_
->SetBoolean(prefs::kPluginsEnabledNaCl
, true);
359 force_enable_nacl
= true;
362 bool migrate_to_pepper_flash
= false;
363 #if defined(OS_WIN) || defined(OS_MACOSX)
364 // If bundled NPAPI Flash is enabled while Pepper Flash is disabled, we
365 // would like to turn Pepper Flash on. And we only want to do it once.
366 // TODO(yzshen): Remove all |migrate_to_pepper_flash|-related code after it
367 // has been run once by most users. (Maybe Chrome 24 or Chrome 25.)
368 // NOTE(shess): Keep in mind that Mac is on a different schedule.
369 if (!prefs_
->GetBoolean(prefs::kPluginsMigratedToPepperFlash
)) {
370 prefs_
->SetBoolean(prefs::kPluginsMigratedToPepperFlash
, true);
371 migrate_to_pepper_flash
= true;
375 bool remove_component_pepper_flash_settings
= false;
376 // If component-updated Pepper Flash is disabled, we would like to remove that
377 // settings item. And we only want to do it once. (Please see the comments of
378 // kPluginsRemovedOldComponentPepperFlashSettings for why.)
379 // TODO(yzshen): Remove all |remove_component_pepper_flash_settings|-related
380 // code after it has been run once by most users.
381 if (!prefs_
->GetBoolean(
382 prefs::kPluginsRemovedOldComponentPepperFlashSettings
)) {
383 prefs_
->SetBoolean(prefs::kPluginsRemovedOldComponentPepperFlashSettings
,
385 remove_component_pepper_flash_settings
= true;
388 { // Scoped update of prefs::kPluginsPluginsList.
389 ListPrefUpdate
update(prefs_
, prefs::kPluginsPluginsList
);
390 ListValue
* saved_plugins_list
= update
.Get();
391 if (saved_plugins_list
&& !saved_plugins_list
->empty()) {
392 // The following four variables are only valid when
393 // |migrate_to_pepper_flash| is set to true.
394 base::FilePath npapi_flash
;
395 base::FilePath pepper_flash
;
396 DictionaryValue
* pepper_flash_node
= NULL
;
397 bool npapi_flash_enabled
= false;
398 if (migrate_to_pepper_flash
) {
399 PathService::Get(chrome::FILE_FLASH_PLUGIN
, &npapi_flash
);
400 PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN
, &pepper_flash
);
403 // Used when |remove_component_pepper_flash_settings| is set to true.
404 ListValue::iterator component_pepper_flash_node
=
405 saved_plugins_list
->end();
407 for (ListValue::iterator it
= saved_plugins_list
->begin();
408 it
!= saved_plugins_list
->end();
410 if (!(*it
)->IsType(Value::TYPE_DICTIONARY
)) {
411 LOG(WARNING
) << "Invalid entry in " << prefs::kPluginsPluginsList
;
412 continue; // Oops, don't know what to do with this item.
415 DictionaryValue
* plugin
= static_cast<DictionaryValue
*>(*it
);
418 if (!plugin
->GetBoolean("enabled", &enabled
))
421 base::FilePath::StringType path
;
422 // The plugin list constains all the plugin files in addition to the
424 if (plugin
->GetString("path", &path
)) {
425 // Files have a path attribute, groups don't.
426 base::FilePath
plugin_path(path
);
428 // The path to the intenral plugin directory changes everytime Chrome
429 // is auto-updated, since it contains the current version number. For
430 // example, it changes from foobar\Chrome\Application\21.0.1180.83 to
431 // foobar\Chrome\Application\21.0.1180.89.
432 // However, we would like the settings of internal plugins to persist
433 // across Chrome updates. Therefore, we need to recognize those paths
434 // that are within the previous internal plugin directory, and update
435 // them in the prefs accordingly.
436 if (update_internal_dir
) {
437 base::FilePath relative_path
;
439 // Extract the part of |plugin_path| that is relative to
440 // |last_internal_dir|. For example, |relative_path| will be
441 // foo\bar.dll if |plugin_path| is <last_internal_dir>\foo\bar.dll.
443 // Every iteration the last path component from |plugin_path| is
444 // removed and prepended to |relative_path| until we get up to
445 // |last_internal_dir|.
446 while (last_internal_dir
.IsParent(plugin_path
)) {
447 relative_path
= plugin_path
.BaseName().Append(relative_path
);
449 base::FilePath old_path
= plugin_path
;
450 plugin_path
= plugin_path
.DirName();
451 // To be extra sure that we won't end up in an infinite loop.
452 if (old_path
== plugin_path
) {
458 // If |relative_path| is empty, |plugin_path| is not within
459 // |last_internal_dir|. We don't need to update it.
460 if (!relative_path
.empty()) {
461 plugin_path
= cur_internal_dir
.Append(relative_path
);
462 path
= plugin_path
.value();
463 plugin
->SetString("path", path
);
467 if (base::FilePath::CompareIgnoreCase(path
, pdf_path_str
) == 0) {
468 if (!enabled
&& force_enable_internal_pdf
) {
470 plugin
->SetBoolean("enabled", true);
473 internal_pdf_enabled
= enabled
;
475 base::FilePath::CompareIgnoreCase(path
, nacl_path_str
) == 0) {
476 if (!enabled
&& force_enable_nacl
) {
478 plugin
->SetBoolean("enabled", true);
480 } else if (migrate_to_pepper_flash
&&
481 base::FilePath::CompareEqualIgnoreCase(
482 path
, npapi_flash
.value())) {
483 npapi_flash_enabled
= enabled
;
484 } else if (migrate_to_pepper_flash
&&
485 base::FilePath::CompareEqualIgnoreCase(
486 path
, pepper_flash
.value())) {
488 pepper_flash_node
= plugin
;
489 } else if (remove_component_pepper_flash_settings
&&
490 IsComponentUpdatedPepperFlash(plugin_path
)) {
492 component_pepper_flash_node
= it
;
493 // Skip setting |enabled| into |plugin_state_|.
498 plugin_state_
.Set(plugin_path
, enabled
);
499 } else if (!enabled
&& plugin
->GetString("name", &group_name
)) {
500 // Don't disable this group if it's for the pdf or nacl plugins and
501 // we just forced it on.
502 if (force_enable_internal_pdf
&& pdf_group_name
== group_name
)
504 if (force_enable_nacl
&& (nacl_group_name
== group_name
||
505 old_nacl_group_name
== group_name
))
508 // Otherwise this is a list of groups.
509 plugin_group_state_
[group_name
] = false;
513 if (npapi_flash_enabled
&& pepper_flash_node
) {
514 DCHECK(migrate_to_pepper_flash
);
515 pepper_flash_node
->SetBoolean("enabled", true);
516 plugin_state_
.Set(pepper_flash
, true);
519 if (component_pepper_flash_node
!= saved_plugins_list
->end()) {
520 DCHECK(remove_component_pepper_flash_settings
);
521 saved_plugins_list
->Erase(component_pepper_flash_node
, NULL
);
524 // If the saved plugin list is empty, then the call to UpdatePreferences()
525 // below failed in an earlier run, possibly because the user closed the
526 // browser too quickly. Try to force enable the internal PDF and nacl
528 force_enable_internal_pdf
= true;
529 force_enable_nacl
= true;
531 } // Scoped update of prefs::kPluginsPluginsList.
533 // Build the set of policy enabled/disabled plugin patterns once and cache it.
534 // Don't do this in the constructor, there's no profile available there.
535 ListValueToStringSet(prefs_
->GetList(prefs::kPluginsDisabledPlugins
),
536 &policy_disabled_plugin_patterns_
);
537 ListValueToStringSet(
538 prefs_
->GetList(prefs::kPluginsDisabledPluginsExceptions
),
539 &policy_disabled_plugin_exception_patterns_
);
540 ListValueToStringSet(prefs_
->GetList(prefs::kPluginsEnabledPlugins
),
541 &policy_enabled_plugin_patterns_
);
543 registrar_
.Init(prefs_
);
545 // Because pointers to our own members will remain unchanged for the
546 // lifetime of |registrar_| (which we also own), we can bind their
547 // pointer values directly in the callbacks to avoid string-based
548 // lookups at notification time.
549 registrar_
.Add(prefs::kPluginsDisabledPlugins
,
550 base::Bind(&PluginPrefs::UpdatePatternsAndNotify
,
551 base::Unretained(this),
552 &policy_disabled_plugin_patterns_
));
553 registrar_
.Add(prefs::kPluginsDisabledPluginsExceptions
,
554 base::Bind(&PluginPrefs::UpdatePatternsAndNotify
,
555 base::Unretained(this),
556 &policy_disabled_plugin_exception_patterns_
));
557 registrar_
.Add(prefs::kPluginsEnabledPlugins
,
558 base::Bind(&PluginPrefs::UpdatePatternsAndNotify
,
559 base::Unretained(this),
560 &policy_enabled_plugin_patterns_
));
562 if (force_enable_internal_pdf
|| internal_pdf_enabled
) {
563 // See http://crbug.com/50105 for background.
564 plugin_group_state_
[ASCIIToUTF16(
565 PluginMetadata::kAdobeReaderGroupName
)] = false;
568 if (force_enable_internal_pdf
|| force_enable_nacl
) {
569 // We want to save this, but doing so requires loading the list of plugins,
570 // so do it after a minute as to not impact startup performance. Note that
571 // plugins are loaded after 30s by the metrics service.
572 BrowserThread::PostDelayedTask(
575 base::Bind(&PluginPrefs::GetPreferencesDataOnFileThread
, this),
576 base::TimeDelta::FromMilliseconds(kPluginUpdateDelayMs
));
579 NotifyPluginStatusChanged();
582 void PluginPrefs::ShutdownOnUIThread() {
584 registrar_
.RemoveAll();
587 PluginPrefs::PluginPrefs() : profile_(NULL
),
592 PluginPrefs::~PluginPrefs() {
595 void PluginPrefs::SetPolicyEnforcedPluginPatterns(
596 const std::set
<string16
>& disabled_patterns
,
597 const std::set
<string16
>& disabled_exception_patterns
,
598 const std::set
<string16
>& enabled_patterns
) {
599 policy_disabled_plugin_patterns_
= disabled_patterns
;
600 policy_disabled_plugin_exception_patterns_
= disabled_exception_patterns
;
601 policy_enabled_plugin_patterns_
= enabled_patterns
;
604 webkit::npapi::PluginList
* PluginPrefs::GetPluginList() const {
607 return PluginService::GetInstance()->GetPluginList();
610 void PluginPrefs::GetPreferencesDataOnFileThread() {
611 std::vector
<webkit::WebPluginInfo
> plugins
;
612 webkit::npapi::PluginList
* plugin_list
= GetPluginList();
613 plugin_list
->GetPluginsNoRefresh(&plugins
);
615 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
616 base::Bind(&PluginPrefs::OnUpdatePreferences
, this, plugins
));
619 void PluginPrefs::OnUpdatePreferences(
620 const std::vector
<webkit::WebPluginInfo
>& plugins
) {
624 PluginFinder
* finder
= PluginFinder::GetInstance();
625 ListPrefUpdate
update(prefs_
, prefs::kPluginsPluginsList
);
626 ListValue
* plugins_list
= update
.Get();
627 plugins_list
->Clear();
629 base::FilePath internal_dir
;
630 if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS
, &internal_dir
))
631 prefs_
->SetFilePath(prefs::kPluginsLastInternalDirectory
, internal_dir
);
633 base::AutoLock
auto_lock(lock_
);
635 // Add the plugin files.
636 std::set
<string16
> group_names
;
637 for (size_t i
= 0; i
< plugins
.size(); ++i
) {
638 DictionaryValue
* summary
= new DictionaryValue();
639 summary
->SetString("path", plugins
[i
].path
.value());
640 summary
->SetString("name", plugins
[i
].name
);
641 summary
->SetString("version", plugins
[i
].version
);
643 plugin_state_
.Get(plugins
[i
].path
, &enabled
);
644 summary
->SetBoolean("enabled", enabled
);
645 plugins_list
->Append(summary
);
647 scoped_ptr
<PluginMetadata
> plugin_metadata(
648 finder
->GetPluginMetadata(plugins
[i
]));
649 // Insert into a set of all group names.
650 group_names
.insert(plugin_metadata
->name());
653 // Add the plug-in groups.
654 for (std::set
<string16
>::const_iterator it
= group_names
.begin();
655 it
!= group_names
.end(); ++it
) {
656 DictionaryValue
* summary
= new DictionaryValue();
657 summary
->SetString("name", *it
);
659 std::map
<string16
, bool>::iterator gstate_it
=
660 plugin_group_state_
.find(*it
);
661 if (gstate_it
!= plugin_group_state_
.end())
662 enabled
= gstate_it
->second
;
663 summary
->SetBoolean("enabled", enabled
);
664 plugins_list
->Append(summary
);
668 void PluginPrefs::NotifyPluginStatusChanged() {
669 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
670 content::NotificationService::current()->Notify(
671 chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED
,
672 content::Source
<Profile
>(profile_
),
673 content::NotificationService::NoDetails());