• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/plugins/plugin_prefs.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/path_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "build/build_config.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/plugins/plugin_installer.h"
22 #include "chrome/browser/plugins/plugin_metadata.h"
23 #include "chrome/browser/plugins/plugin_prefs_factory.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/common/chrome_constants.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/keyed_service/core/keyed_service.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/plugin_service.h"
33 #include "content/public/common/webplugininfo.h"
34 
35 #if !defined(DISABLE_NACL)
36 #include "components/nacl/common/nacl_constants.h"
37 #endif
38 
39 using content::BrowserThread;
40 using content::PluginService;
41 
42 namespace {
43 
IsComponentUpdatedPepperFlash(const base::FilePath & plugin)44 bool IsComponentUpdatedPepperFlash(const base::FilePath& plugin) {
45   if (plugin.BaseName().value() == chrome::kPepperFlashPluginFilename) {
46     base::FilePath component_updated_pepper_flash_dir;
47     if (PathService::Get(chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN,
48                          &component_updated_pepper_flash_dir) &&
49         component_updated_pepper_flash_dir.IsParent(plugin)) {
50       return true;
51     }
52   }
53 
54   return false;
55 }
56 
57 }  // namespace
58 
PluginState()59 PluginPrefs::PluginState::PluginState() {
60 }
61 
~PluginState()62 PluginPrefs::PluginState::~PluginState() {
63 }
64 
Get(const base::FilePath & plugin,bool * enabled) const65 bool PluginPrefs::PluginState::Get(const base::FilePath& plugin,
66                                    bool* enabled) const {
67   base::FilePath key = ConvertMapKey(plugin);
68   std::map<base::FilePath, bool>::const_iterator iter = state_.find(key);
69   if (iter != state_.end()) {
70     *enabled = iter->second;
71     return true;
72   }
73   return false;
74 }
75 
Set(const base::FilePath & plugin,bool enabled)76 void PluginPrefs::PluginState::Set(const base::FilePath& plugin, bool enabled) {
77   state_[ConvertMapKey(plugin)] = enabled;
78 }
79 
ConvertMapKey(const base::FilePath & plugin) const80 base::FilePath PluginPrefs::PluginState::ConvertMapKey(
81     const base::FilePath& plugin) const {
82   // Keep the state of component-updated and bundled Pepper Flash in sync.
83   if (IsComponentUpdatedPepperFlash(plugin)) {
84     base::FilePath bundled_pepper_flash;
85     if (PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN,
86                          &bundled_pepper_flash)) {
87       return bundled_pepper_flash;
88     }
89   }
90 
91   return plugin;
92 }
93 
94 // static
GetForProfile(Profile * profile)95 scoped_refptr<PluginPrefs> PluginPrefs::GetForProfile(Profile* profile) {
96   return PluginPrefsFactory::GetPrefsForProfile(profile);
97 }
98 
99 // static
GetForTestingProfile(Profile * profile)100 scoped_refptr<PluginPrefs> PluginPrefs::GetForTestingProfile(
101     Profile* profile) {
102   return static_cast<PluginPrefs*>(
103       PluginPrefsFactory::GetInstance()->SetTestingFactoryAndUse(
104           profile, &PluginPrefsFactory::CreateForTestingProfile).get());
105 }
106 
EnablePluginGroup(bool enabled,const base::string16 & group_name)107 void PluginPrefs::EnablePluginGroup(bool enabled,
108                                     const base::string16& group_name) {
109   PluginService::GetInstance()->GetPlugins(
110       base::Bind(&PluginPrefs::EnablePluginGroupInternal,
111                  this, enabled, group_name));
112 }
113 
EnablePluginGroupInternal(bool enabled,const base::string16 & group_name,const std::vector<content::WebPluginInfo> & plugins)114 void PluginPrefs::EnablePluginGroupInternal(
115     bool enabled,
116     const base::string16& group_name,
117     const std::vector<content::WebPluginInfo>& plugins) {
118   base::AutoLock auto_lock(lock_);
119   PluginFinder* finder = PluginFinder::GetInstance();
120 
121   // Set the desired state for the group.
122   plugin_group_state_[group_name] = enabled;
123 
124   // Update the state for all plug-ins in the group.
125   for (size_t i = 0; i < plugins.size(); ++i) {
126     scoped_ptr<PluginMetadata> plugin(finder->GetPluginMetadata(plugins[i]));
127     if (group_name != plugin->name())
128       continue;
129     plugin_state_.Set(plugins[i].path, enabled);
130   }
131 
132   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
133       base::Bind(&PluginPrefs::OnUpdatePreferences, this, plugins));
134   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
135       base::Bind(&PluginPrefs::NotifyPluginStatusChanged, this));
136 }
137 
EnablePlugin(bool enabled,const base::FilePath & path,const base::Callback<void (bool)> & callback)138 void PluginPrefs::EnablePlugin(
139     bool enabled, const base::FilePath& path,
140     const base::Callback<void(bool)>& callback) {
141   PluginFinder* finder = PluginFinder::GetInstance();
142   content::WebPluginInfo plugin;
143   bool can_enable = true;
144   if (PluginService::GetInstance()->GetPluginInfoByPath(path, &plugin)) {
145     scoped_ptr<PluginMetadata> plugin_metadata(
146         finder->GetPluginMetadata(plugin));
147     PolicyStatus plugin_status = PolicyStatusForPlugin(plugin.name);
148     PolicyStatus group_status = PolicyStatusForPlugin(plugin_metadata->name());
149     if (enabled) {
150       if (plugin_status == POLICY_DISABLED || group_status == POLICY_DISABLED)
151         can_enable = false;
152     } else {
153       if (plugin_status == POLICY_ENABLED || group_status == POLICY_ENABLED)
154         can_enable = false;
155     }
156   } else {
157     NOTREACHED();
158   }
159 
160   if (!can_enable) {
161     base::MessageLoop::current()->PostTask(FROM_HERE,
162                                            base::Bind(callback, false));
163     return;
164   }
165 
166   PluginService::GetInstance()->GetPlugins(
167       base::Bind(&PluginPrefs::EnablePluginInternal, this,
168                  enabled, path, finder, callback));
169 }
170 
EnablePluginInternal(bool enabled,const base::FilePath & path,PluginFinder * plugin_finder,const base::Callback<void (bool)> & callback,const std::vector<content::WebPluginInfo> & plugins)171 void PluginPrefs::EnablePluginInternal(
172     bool enabled,
173     const base::FilePath& path,
174     PluginFinder* plugin_finder,
175     const base::Callback<void(bool)>& callback,
176     const std::vector<content::WebPluginInfo>& plugins) {
177   {
178     // Set the desired state for the plug-in.
179     base::AutoLock auto_lock(lock_);
180     plugin_state_.Set(path, enabled);
181   }
182 
183   base::string16 group_name;
184   for (size_t i = 0; i < plugins.size(); ++i) {
185     if (plugins[i].path == path) {
186       scoped_ptr<PluginMetadata> plugin_metadata(
187           plugin_finder->GetPluginMetadata(plugins[i]));
188       // set the group name for this plug-in.
189       group_name = plugin_metadata->name();
190       DCHECK_EQ(enabled, IsPluginEnabled(plugins[i]));
191       break;
192     }
193   }
194 
195   bool all_disabled = true;
196   for (size_t i = 0; i < plugins.size(); ++i) {
197     scoped_ptr<PluginMetadata> plugin_metadata(
198         plugin_finder->GetPluginMetadata(plugins[i]));
199     DCHECK(!plugin_metadata->name().empty());
200     if (group_name == plugin_metadata->name()) {
201       all_disabled = all_disabled && !IsPluginEnabled(plugins[i]);
202     }
203   }
204 
205   if (!group_name.empty()) {
206     // Update the state for the corresponding plug-in group.
207     base::AutoLock auto_lock(lock_);
208     plugin_group_state_[group_name] = !all_disabled;
209   }
210 
211   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
212       base::Bind(&PluginPrefs::OnUpdatePreferences, this, plugins));
213   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
214       base::Bind(&PluginPrefs::NotifyPluginStatusChanged, this));
215   callback.Run(true);
216 }
217 
PolicyStatusForPlugin(const base::string16 & name) const218 PluginPrefs::PolicyStatus PluginPrefs::PolicyStatusForPlugin(
219     const base::string16& name) const {
220   base::AutoLock auto_lock(lock_);
221   if (IsStringMatchedInSet(name, policy_enabled_plugin_patterns_)) {
222     return POLICY_ENABLED;
223   } else if (IsStringMatchedInSet(name, policy_disabled_plugin_patterns_) &&
224              !IsStringMatchedInSet(
225                  name, policy_disabled_plugin_exception_patterns_)) {
226     return POLICY_DISABLED;
227   } else {
228     return NO_POLICY;
229   }
230 }
231 
IsPluginEnabled(const content::WebPluginInfo & plugin) const232 bool PluginPrefs::IsPluginEnabled(const content::WebPluginInfo& plugin) const {
233   scoped_ptr<PluginMetadata> plugin_metadata(
234       PluginFinder::GetInstance()->GetPluginMetadata(plugin));
235   base::string16 group_name = plugin_metadata->name();
236 
237   // Check if the plug-in or its group is enabled by policy.
238   PolicyStatus plugin_status = PolicyStatusForPlugin(plugin.name);
239   PolicyStatus group_status = PolicyStatusForPlugin(group_name);
240   if (plugin_status == POLICY_ENABLED || group_status == POLICY_ENABLED)
241     return true;
242 
243   // Check if the plug-in or its group is disabled by policy.
244   if (plugin_status == POLICY_DISABLED || group_status == POLICY_DISABLED)
245     return false;
246 
247 #if !defined(DISABLE_NACL)
248   // If enabling NaCl, make sure the plugin is also enabled. See bug
249   // http://code.google.com/p/chromium/issues/detail?id=81010 for more
250   // information.
251   // TODO(dspringer): When NaCl is on by default, remove this code.
252   if ((plugin.name == base::ASCIIToUTF16(nacl::kNaClPluginName)) &&
253       CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableNaCl)) {
254     return true;
255   }
256 #endif
257 
258   base::AutoLock auto_lock(lock_);
259   // Check user preferences for the plug-in.
260   bool plugin_enabled = false;
261   if (plugin_state_.Get(plugin.path, &plugin_enabled))
262     return plugin_enabled;
263 
264   // Check user preferences for the plug-in group.
265   std::map<base::string16, bool>::const_iterator group_it(
266       plugin_group_state_.find(group_name));
267   if (group_it != plugin_group_state_.end())
268     return group_it->second;
269 
270   // Default to enabled.
271   return true;
272 }
273 
UpdatePatternsAndNotify(std::set<base::string16> * patterns,const std::string & pref_name)274 void PluginPrefs::UpdatePatternsAndNotify(std::set<base::string16>* patterns,
275                                           const std::string& pref_name) {
276   base::AutoLock auto_lock(lock_);
277   ListValueToStringSet(prefs_->GetList(pref_name.c_str()), patterns);
278 
279   NotifyPluginStatusChanged();
280 }
281 
282 /*static*/
IsStringMatchedInSet(const base::string16 & name,const std::set<base::string16> & pattern_set)283 bool PluginPrefs::IsStringMatchedInSet(
284     const base::string16& name,
285     const std::set<base::string16>& pattern_set) {
286   std::set<base::string16>::const_iterator pattern(pattern_set.begin());
287   while (pattern != pattern_set.end()) {
288     if (MatchPattern(name, *pattern))
289       return true;
290     ++pattern;
291   }
292 
293   return false;
294 }
295 
296 /* static */
ListValueToStringSet(const base::ListValue * src,std::set<base::string16> * dest)297 void PluginPrefs::ListValueToStringSet(const base::ListValue* src,
298                                        std::set<base::string16>* dest) {
299   DCHECK(src);
300   DCHECK(dest);
301   dest->clear();
302   base::ListValue::const_iterator end(src->end());
303   for (base::ListValue::const_iterator current(src->begin());
304        current != end; ++current) {
305     base::string16 plugin_name;
306     if ((*current)->GetAsString(&plugin_name)) {
307       dest->insert(plugin_name);
308     }
309   }
310 }
311 
SetPrefs(PrefService * prefs)312 void PluginPrefs::SetPrefs(PrefService* prefs) {
313   prefs_ = prefs;
314   bool update_internal_dir = false;
315   base::FilePath last_internal_dir =
316       prefs_->GetFilePath(prefs::kPluginsLastInternalDirectory);
317   base::FilePath cur_internal_dir;
318   if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
319       cur_internal_dir != last_internal_dir) {
320     update_internal_dir = true;
321     prefs_->SetFilePath(
322         prefs::kPluginsLastInternalDirectory, cur_internal_dir);
323   }
324 
325   bool migrate_to_pepper_flash = false;
326 #if defined(OS_WIN) || defined(OS_MACOSX)
327   // If bundled NPAPI Flash is enabled while Pepper Flash is disabled, we
328   // would like to turn Pepper Flash on. And we only want to do it once.
329   // TODO(yzshen): Remove all |migrate_to_pepper_flash|-related code after it
330   // has been run once by most users. (Maybe Chrome 24 or Chrome 25.)
331   // NOTE(shess): Keep in mind that Mac is on a different schedule.
332   if (!prefs_->GetBoolean(prefs::kPluginsMigratedToPepperFlash)) {
333     prefs_->SetBoolean(prefs::kPluginsMigratedToPepperFlash, true);
334     migrate_to_pepper_flash = true;
335   }
336 #endif
337 
338   bool remove_component_pepper_flash_settings = false;
339   // If component-updated Pepper Flash is disabled, we would like to remove that
340   // settings item. And we only want to do it once. (Please see the comments of
341   // kPluginsRemovedOldComponentPepperFlashSettings for why.)
342   // TODO(yzshen): Remove all |remove_component_pepper_flash_settings|-related
343   // code after it has been run once by most users.
344   if (!prefs_->GetBoolean(
345           prefs::kPluginsRemovedOldComponentPepperFlashSettings)) {
346     prefs_->SetBoolean(prefs::kPluginsRemovedOldComponentPepperFlashSettings,
347                        true);
348     remove_component_pepper_flash_settings = true;
349   }
350 
351   {  // Scoped update of prefs::kPluginsPluginsList.
352     ListPrefUpdate update(prefs_, prefs::kPluginsPluginsList);
353     base::ListValue* saved_plugins_list = update.Get();
354     if (saved_plugins_list && !saved_plugins_list->empty()) {
355       // The following four variables are only valid when
356       // |migrate_to_pepper_flash| is set to true.
357       base::FilePath npapi_flash;
358       base::FilePath pepper_flash;
359       base::DictionaryValue* pepper_flash_node = NULL;
360       bool npapi_flash_enabled = false;
361       if (migrate_to_pepper_flash) {
362         PathService::Get(chrome::FILE_FLASH_PLUGIN, &npapi_flash);
363         PathService::Get(chrome::FILE_PEPPER_FLASH_PLUGIN, &pepper_flash);
364       }
365 
366       // Used when |remove_component_pepper_flash_settings| is set to true.
367       base::ListValue::iterator component_pepper_flash_node =
368           saved_plugins_list->end();
369 
370       for (base::ListValue::iterator it = saved_plugins_list->begin();
371            it != saved_plugins_list->end();
372            ++it) {
373         if (!(*it)->IsType(base::Value::TYPE_DICTIONARY)) {
374           LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList;
375           continue;  // Oops, don't know what to do with this item.
376         }
377 
378         base::DictionaryValue* plugin =
379             static_cast<base::DictionaryValue*>(*it);
380         base::string16 group_name;
381         bool enabled;
382         if (!plugin->GetBoolean("enabled", &enabled))
383           enabled = true;
384 
385         base::FilePath::StringType path;
386         // The plugin list constains all the plugin files in addition to the
387         // plugin groups.
388         if (plugin->GetString("path", &path)) {
389           // Files have a path attribute, groups don't.
390           base::FilePath plugin_path(path);
391 
392           // The path to the intenral plugin directory changes everytime Chrome
393           // is auto-updated, since it contains the current version number. For
394           // example, it changes from foobar\Chrome\Application\21.0.1180.83 to
395           // foobar\Chrome\Application\21.0.1180.89.
396           // However, we would like the settings of internal plugins to persist
397           // across Chrome updates. Therefore, we need to recognize those paths
398           // that are within the previous internal plugin directory, and update
399           // them in the prefs accordingly.
400           if (update_internal_dir) {
401             base::FilePath relative_path;
402 
403             // Extract the part of |plugin_path| that is relative to
404             // |last_internal_dir|. For example, |relative_path| will be
405             // foo\bar.dll if |plugin_path| is <last_internal_dir>\foo\bar.dll.
406             //
407             // Every iteration the last path component from |plugin_path| is
408             // removed and prepended to |relative_path| until we get up to
409             // |last_internal_dir|.
410             while (last_internal_dir.IsParent(plugin_path)) {
411               relative_path = plugin_path.BaseName().Append(relative_path);
412 
413               base::FilePath old_path = plugin_path;
414               plugin_path = plugin_path.DirName();
415               // To be extra sure that we won't end up in an infinite loop.
416               if (old_path == plugin_path) {
417                 NOTREACHED();
418                 break;
419               }
420             }
421 
422             // If |relative_path| is empty, |plugin_path| is not within
423             // |last_internal_dir|. We don't need to update it.
424             if (!relative_path.empty()) {
425               plugin_path = cur_internal_dir.Append(relative_path);
426               path = plugin_path.value();
427               plugin->SetString("path", path);
428             }
429           }
430 
431           if (migrate_to_pepper_flash &&
432                      base::FilePath::CompareEqualIgnoreCase(
433                          path, npapi_flash.value())) {
434             npapi_flash_enabled = enabled;
435           } else if (migrate_to_pepper_flash &&
436                      base::FilePath::CompareEqualIgnoreCase(
437                          path, pepper_flash.value())) {
438             if (!enabled)
439               pepper_flash_node = plugin;
440           } else if (remove_component_pepper_flash_settings &&
441                      IsComponentUpdatedPepperFlash(plugin_path)) {
442             if (!enabled) {
443               component_pepper_flash_node = it;
444               // Skip setting |enabled| into |plugin_state_|.
445               continue;
446             }
447           }
448 
449           plugin_state_.Set(plugin_path, enabled);
450         } else if (!enabled && plugin->GetString("name", &group_name)) {
451           // Otherwise this is a list of groups.
452           plugin_group_state_[group_name] = false;
453         }
454       }
455 
456       if (npapi_flash_enabled && pepper_flash_node) {
457         DCHECK(migrate_to_pepper_flash);
458         pepper_flash_node->SetBoolean("enabled", true);
459         plugin_state_.Set(pepper_flash, true);
460       }
461 
462       if (component_pepper_flash_node != saved_plugins_list->end()) {
463         DCHECK(remove_component_pepper_flash_settings);
464         saved_plugins_list->Erase(component_pepper_flash_node, NULL);
465       }
466     } else {
467       // If the saved plugin list is empty, then the call to UpdatePreferences()
468       // below failed in an earlier run, possibly because the user closed the
469       // browser too quickly.
470 
471       // Only want one PDF plugin enabled at a time. See http://crbug.com/50105
472       // for background.
473       plugin_group_state_[base::ASCIIToUTF16(
474           PluginMetadata::kAdobeReaderGroupName)] = false;
475     }
476   }  // Scoped update of prefs::kPluginsPluginsList.
477 
478   // Build the set of policy enabled/disabled plugin patterns once and cache it.
479   // Don't do this in the constructor, there's no profile available there.
480   ListValueToStringSet(prefs_->GetList(prefs::kPluginsDisabledPlugins),
481                        &policy_disabled_plugin_patterns_);
482   ListValueToStringSet(
483       prefs_->GetList(prefs::kPluginsDisabledPluginsExceptions),
484       &policy_disabled_plugin_exception_patterns_);
485   ListValueToStringSet(prefs_->GetList(prefs::kPluginsEnabledPlugins),
486                        &policy_enabled_plugin_patterns_);
487 
488   registrar_.Init(prefs_);
489 
490   // Because pointers to our own members will remain unchanged for the
491   // lifetime of |registrar_| (which we also own), we can bind their
492   // pointer values directly in the callbacks to avoid string-based
493   // lookups at notification time.
494   registrar_.Add(prefs::kPluginsDisabledPlugins,
495                  base::Bind(&PluginPrefs::UpdatePatternsAndNotify,
496                             base::Unretained(this),
497                             &policy_disabled_plugin_patterns_));
498   registrar_.Add(prefs::kPluginsDisabledPluginsExceptions,
499                  base::Bind(&PluginPrefs::UpdatePatternsAndNotify,
500                             base::Unretained(this),
501                             &policy_disabled_plugin_exception_patterns_));
502   registrar_.Add(prefs::kPluginsEnabledPlugins,
503                  base::Bind(&PluginPrefs::UpdatePatternsAndNotify,
504                             base::Unretained(this),
505                             &policy_enabled_plugin_patterns_));
506 
507   NotifyPluginStatusChanged();
508 }
509 
ShutdownOnUIThread()510 void PluginPrefs::ShutdownOnUIThread() {
511   prefs_ = NULL;
512   registrar_.RemoveAll();
513 }
514 
PluginPrefs()515 PluginPrefs::PluginPrefs() : profile_(NULL),
516                              prefs_(NULL) {
517 }
518 
~PluginPrefs()519 PluginPrefs::~PluginPrefs() {
520 }
521 
SetPolicyEnforcedPluginPatterns(const std::set<base::string16> & disabled_patterns,const std::set<base::string16> & disabled_exception_patterns,const std::set<base::string16> & enabled_patterns)522 void PluginPrefs::SetPolicyEnforcedPluginPatterns(
523     const std::set<base::string16>& disabled_patterns,
524     const std::set<base::string16>& disabled_exception_patterns,
525     const std::set<base::string16>& enabled_patterns) {
526   policy_disabled_plugin_patterns_ = disabled_patterns;
527   policy_disabled_plugin_exception_patterns_ = disabled_exception_patterns;
528   policy_enabled_plugin_patterns_ = enabled_patterns;
529 }
530 
OnUpdatePreferences(const std::vector<content::WebPluginInfo> & plugins)531 void PluginPrefs::OnUpdatePreferences(
532     const std::vector<content::WebPluginInfo>& plugins) {
533   if (!prefs_)
534     return;
535 
536   PluginFinder* finder = PluginFinder::GetInstance();
537   ListPrefUpdate update(prefs_, prefs::kPluginsPluginsList);
538   base::ListValue* plugins_list = update.Get();
539   plugins_list->Clear();
540 
541   base::FilePath internal_dir;
542   if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
543     prefs_->SetFilePath(prefs::kPluginsLastInternalDirectory, internal_dir);
544 
545   base::AutoLock auto_lock(lock_);
546 
547   // Add the plugin files.
548   std::set<base::string16> group_names;
549   for (size_t i = 0; i < plugins.size(); ++i) {
550     base::DictionaryValue* summary = new base::DictionaryValue();
551     summary->SetString("path", plugins[i].path.value());
552     summary->SetString("name", plugins[i].name);
553     summary->SetString("version", plugins[i].version);
554     bool enabled = true;
555     plugin_state_.Get(plugins[i].path, &enabled);
556     summary->SetBoolean("enabled", enabled);
557     plugins_list->Append(summary);
558 
559     scoped_ptr<PluginMetadata> plugin_metadata(
560         finder->GetPluginMetadata(plugins[i]));
561     // Insert into a set of all group names.
562     group_names.insert(plugin_metadata->name());
563   }
564 
565   // Add the plug-in groups.
566   for (std::set<base::string16>::const_iterator it = group_names.begin();
567       it != group_names.end(); ++it) {
568     base::DictionaryValue* summary = new base::DictionaryValue();
569     summary->SetString("name", *it);
570     bool enabled = true;
571     std::map<base::string16, bool>::iterator gstate_it =
572         plugin_group_state_.find(*it);
573     if (gstate_it != plugin_group_state_.end())
574       enabled = gstate_it->second;
575     summary->SetBoolean("enabled", enabled);
576     plugins_list->Append(summary);
577   }
578 }
579 
NotifyPluginStatusChanged()580 void PluginPrefs::NotifyPluginStatusChanged() {
581   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
582   content::NotificationService::current()->Notify(
583       chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
584       content::Source<Profile>(profile_),
585       content::NotificationService::NoDetails());
586 }
587