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