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