Reland r96364: Rename PluginUpdater to PluginPrefs and make it per-profile.

BUG=80794
TEST=none

Review URL: http://codereview.chromium.org/7639017

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97452 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 1f2e0c1d..7f1efa0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -14,7 +14,6 @@
 #include "base/string_number_conversions.h"
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/plugin_updater.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_content_client.h"
@@ -738,21 +737,10 @@
   DCHECK(e);
 
   if (e->type == Experiment::SINGLE_VALUE) {
-    if (enable) {
+    if (enable)
       enabled_experiments.insert(internal_name);
-      // If enabling NaCl, make sure the plugin is also enabled. See bug
-      // http://code.google.com/p/chromium/issues/detail?id=81010 for more
-      // information.
-      // TODO(dspringer): When NaCl is on by default, remove this code.
-      if (internal_name == switches::kEnableNaCl) {
-        PluginUpdater* plugin_updater = PluginUpdater::GetInstance();
-        string16 nacl_plugin_name =
-            ASCIIToUTF16(chrome::ChromeContentClient::kNaClPluginName);
-        plugin_updater->EnablePluginGroup(true, nacl_plugin_name);
-      }
-    } else {
+    else
       enabled_experiments.erase(internal_name);
-    }
   } else {
     if (enable) {
       // Enable the first choice.
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index a4753ae..e41a701 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -59,6 +59,7 @@
 #include "chrome/browser/password_manager/password_store.h"
 #include "chrome/browser/password_manager/password_store_change.h"
 #include "chrome/browser/platform_util.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -3406,6 +3407,7 @@
   }
   std::vector<webkit::WebPluginInfo> plugins;
   webkit::npapi::PluginList::Singleton()->GetPlugins(&plugins);
+  PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(browser->profile());
   ListValue* items = new ListValue;
   for (std::vector<webkit::WebPluginInfo>::const_iterator it =
            plugins.begin();
@@ -3416,7 +3418,7 @@
     item->SetString("path", it->path.value());
     item->SetString("version", it->version);
     item->SetString("desc", it->desc);
-    item->SetBoolean("enabled", webkit::IsPluginEnabled(*it));
+    item->SetBoolean("enabled", plugin_prefs->IsPluginEnabled(*it));
     // Add info about mime types.
     ListValue* mime_types = new ListValue();
     for (std::vector<webkit::WebPluginMimeType>::const_iterator type_it =
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index dcc286d097..340c604 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -32,6 +32,7 @@
 #include "chrome/browser/metrics/histogram_synchronizer.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/net/url_fixer_upper.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -1115,8 +1116,9 @@
       GURL(), "application/x-shockwave-flash", false, NULL, &info_array, NULL);
   string16 flash_version =
       l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN);
+  PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
   for (size_t i = 0; i < info_array.size(); ++i) {
-    if (webkit::IsPluginEnabled(info_array[i])) {
+    if (plugin_prefs->IsPluginEnabled(info_array[i])) {
       flash_version = info_array[i].version;
       break;
     }
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index d2d9c40..a9063cf 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -57,7 +57,7 @@
 #include "chrome/browser/net/chrome_net_log.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/net/sdch_dictionary_fetcher.h"
-#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/prefs/pref_value_store.h"
@@ -1970,9 +1970,6 @@
   browser_process->google_url_tracker();
   browser_process->intranet_redirect_detector();
 
-  // Do initialize the plug-in service (and related preferences).
-  PluginUpdater::GetInstance()->SetProfile(profile);
-
   // Prepare for memory caching of SDCH dictionaries.
   // Perform A/B test to measure global impact of SDCH support.
   // Set up a field trial to see what disabling SDCH does to latency of page
diff --git a/chrome/browser/browser_shutdown.cc b/chrome/browser/browser_shutdown.cc
index 830f825..c18d22f5 100644
--- a/chrome/browser/browser_shutdown.cc
+++ b/chrome/browser/browser_shutdown.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/first_run/upgrade_util.h"
 #include "chrome/browser/jankometer.h"
 #include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/plugin_updater.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/service/service_process_control.h"
@@ -141,8 +140,6 @@
   // consider putting it in BrowserProcessImpl::EndSession.
   PrefService* prefs = g_browser_process->local_state();
 
-  PluginUpdater::GetInstance()->Shutdown();
-
   MetricsService* metrics = g_browser_process->metrics_service();
   if (metrics)
     metrics->RecordCompletedSessionEnd();
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index 18904b0e..e1f412c 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/net/gaia/gaia_oauth_fetcher.h"
 #include "chrome/browser/net/gaia/token_service.h"
 #include "chrome/browser/net/preconnect.h"
-#include "chrome/browser/plugin_updater.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/prefs/pref_member.h"
 #include "chrome/browser/profiles/profile.h"
@@ -562,9 +561,6 @@
     btl->AddLoginTimeMarker("TPMOwn-End", false);
   }
 
-  // Enable/disable plugins based on user preferences.
-  PluginUpdater::GetInstance()->SetProfile(user_profile);
-
   // We suck. This is a hack since we do not have the enterprise feature
   // done yet to pull down policies from the domain admin. We'll take this
   // out when we get that done properly.
diff --git a/chrome/browser/metrics/metrics_log.cc b/chrome/browser/metrics/metrics_log.cc
index ce82634..8200f44 100644
--- a/chrome/browser/metrics/metrics_log.cc
+++ b/chrome/browser/metrics/metrics_log.cc
@@ -291,6 +291,7 @@
 #endif
     WriteAttribute("filename", CreateBase64Hash(filename_bytes));
     WriteAttribute("version", UTF16ToUTF8(iter->version));
+    // TODO(bauerb): Plug-in state is per-profile.
     WriteIntAttribute("disabled", !webkit::IsPluginEnabled(*iter));
   }
 }
diff --git a/chrome/browser/pdf_unsupported_feature.cc b/chrome/browser/pdf_unsupported_feature.cc
index 9190ffc..860ceec1 100644
--- a/chrome/browser/pdf_unsupported_feature.cc
+++ b/chrome/browser/pdf_unsupported_feature.cc
@@ -7,7 +7,7 @@
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
 #include "base/version.h"
-#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tab_contents/chrome_interstitial_page.h"
@@ -114,12 +114,12 @@
   UserMetrics::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarOK"));
   webkit::npapi::PluginList::Singleton()->EnableGroup(false,
       ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName));
-  PluginUpdater* plugin_updater = PluginUpdater::GetInstance();
-  plugin_updater->EnablePluginGroup(true,
-      ASCIIToUTF16(webkit::npapi::PluginGroup::kAdobeReaderGroupName));
   Profile* profile =
       Profile::FromBrowserContext(tab_contents_->browser_context());
-  plugin_updater->UpdatePreferences(profile, 0);
+  PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
+  plugin_prefs->EnablePluginGroup(
+      true, ASCIIToUTF16(webkit::npapi::PluginGroup::kAdobeReaderGroupName));
+  plugin_prefs->UpdatePreferences(0);
 }
 
 void PDFEnableAdobeReaderInfoBarDelegate::OnNo() {
diff --git a/chrome/browser/plugin_updater.cc b/chrome/browser/plugin_prefs.cc
similarity index 64%
rename from chrome/browser/plugin_updater.cc
rename to chrome/browser/plugin_prefs.cc
index 0fa0420b..2a1e3d0 100644
--- a/chrome/browser/plugin_updater.cc
+++ b/chrome/browser/plugin_prefs.cc
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/plugin_prefs.h"
 
 #include <string>
 
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
 #include "base/message_loop.h"
 #include "base/path_service.h"
 #include "base/utf_string_conversions.h"
@@ -15,63 +17,115 @@
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+#include "chrome/browser/profiles/profile_keyed_service.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/browser/browser_thread.h"
 #include "content/common/notification_service.h"
 #include "webkit/plugins/npapi/plugin_list.h"
 #include "webkit/plugins/webplugininfo.h"
 
+namespace {
+
+class PluginPrefsWrapper : public ProfileKeyedService {
+ public:
+  explicit PluginPrefsWrapper(scoped_refptr<PluginPrefs> plugin_prefs)
+      : plugin_prefs_(plugin_prefs) {}
+  virtual ~PluginPrefsWrapper() {}
+
+  PluginPrefs* plugin_prefs() { return plugin_prefs_.get(); }
+
+ private:
+  // ProfileKeyedService methods:
+  virtual void Shutdown() OVERRIDE {
+    plugin_prefs_->ShutdownOnUIThread();
+  }
+
+  scoped_refptr<PluginPrefs> plugin_prefs_;
+};
+
+}
+
 // How long to wait to save the plugin enabled information, which might need to
 // go to disk.
 #define kPluginUpdateDelayMs (60 * 1000)
 
-PluginUpdater::PluginUpdater()
-    : notify_pending_(false) {
+class PluginPrefs::Factory : public ProfileKeyedServiceFactory {
+ public:
+  static Factory* GetInstance();
+
+  PluginPrefsWrapper* GetWrapperForProfile(Profile* profile);
+
+ private:
+  friend struct DefaultSingletonTraits<Factory>;
+
+  Factory();
+  virtual ~Factory() {}
+
+  // ProfileKeyedServiceFactory methods:
+  virtual ProfileKeyedService* BuildServiceInstanceFor(
+      Profile* profile) const OVERRIDE;
+  virtual bool ServiceRedirectedInIncognito() OVERRIDE { return true; }
+  virtual bool ServiceIsNULLWhileTesting() OVERRIDE { return true; }
+  virtual bool ServiceIsCreatedWithProfile() OVERRIDE { return true; }
+};
+
+// static
+void PluginPrefs::Initialize() {
+  Factory::GetInstance();
 }
 
-DictionaryValue* PluginUpdater::CreatePluginFileSummary(
+// static
+PluginPrefs* PluginPrefs::GetForProfile(Profile* profile) {
+  PluginPrefs* plugin_prefs =
+      Factory::GetInstance()->GetWrapperForProfile(profile)->plugin_prefs();
+  DCHECK(plugin_prefs);
+  return plugin_prefs;
+}
+
+DictionaryValue* PluginPrefs::CreatePluginFileSummary(
     const webkit::WebPluginInfo& plugin) {
   DictionaryValue* data = new DictionaryValue();
   data->SetString("path", plugin.path.value());
   data->SetString("name", plugin.name);
   data->SetString("version", plugin.version);
-  data->SetBoolean("enabled", webkit::IsPluginEnabled(plugin));
+  data->SetBoolean("enabled", IsPluginEnabled(plugin));
   return data;
 }
 
-// static
-ListValue* PluginUpdater::GetPluginGroupsData() {
-  std::vector<webkit::npapi::PluginGroup> plugin_groups;
-  webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups);
-
-  // Construct DictionaryValues to return to the UI
-  ListValue* plugin_groups_data = new ListValue();
-  for (size_t i = 0; i < plugin_groups.size(); ++i) {
-    plugin_groups_data->Append(plugin_groups[i].GetDataForUI());
-  }
-  return plugin_groups_data;
-}
-
-void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) {
+void PluginPrefs::EnablePluginGroup(bool enable, const string16& group_name) {
   webkit::npapi::PluginList::Singleton()->EnableGroup(enable, group_name);
   NotifyPluginStatusChanged();
 }
 
-void PluginUpdater::EnablePlugin(bool enable,
-                                 const FilePath::StringType& path) {
-  FilePath file_path(path);
+void PluginPrefs::EnablePlugin(bool enable, const FilePath& path) {
   if (enable)
-    webkit::npapi::PluginList::Singleton()->EnablePlugin(file_path);
+    webkit::npapi::PluginList::Singleton()->EnablePlugin(path);
   else
-    webkit::npapi::PluginList::Singleton()->DisablePlugin(file_path);
+    webkit::npapi::PluginList::Singleton()->DisablePlugin(path);
 
   NotifyPluginStatusChanged();
 }
 
-void PluginUpdater::Observe(int type,
+bool PluginPrefs::IsPluginEnabled(const webkit::WebPluginInfo& plugin) {
+  // If enabling NaCl, make sure the plugin is also enabled. See bug
+  // http://code.google.com/p/chromium/issues/detail?id=81010 for more
+  // information.
+  // TODO(dspringer): When NaCl is on by default, remove this code.
+  if ((plugin.name ==
+       ASCIIToUTF16(chrome::ChromeContentClient::kNaClPluginName)) &&
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableNaCl)) {
+    return true;
+  }
+  return webkit::IsPluginEnabled(plugin);
+}
+
+void PluginPrefs::Observe(int type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
   DCHECK_EQ(chrome::NOTIFICATION_PREF_CHANGED, type);
@@ -80,21 +134,21 @@
     NOTREACHED();
     return;
   }
+  DCHECK_EQ(prefs_, Source<PrefService>(source).ptr());
   if (*pref_name == prefs::kPluginsDisabledPlugins ||
       *pref_name == prefs::kPluginsDisabledPluginsExceptions ||
       *pref_name == prefs::kPluginsEnabledPlugins) {
-    PrefService* pref_service = Source<PrefService>(source).ptr();
     const ListValue* disabled_list =
-        pref_service->GetList(prefs::kPluginsDisabledPlugins);
+        prefs_->GetList(prefs::kPluginsDisabledPlugins);
     const ListValue* exceptions_list =
-        pref_service->GetList(prefs::kPluginsDisabledPluginsExceptions);
+        prefs_->GetList(prefs::kPluginsDisabledPluginsExceptions);
     const ListValue* enabled_list =
-        pref_service->GetList(prefs::kPluginsEnabledPlugins);
+        prefs_->GetList(prefs::kPluginsEnabledPlugins);
     UpdatePluginsStateFromPolicy(disabled_list, exceptions_list, enabled_list);
   }
 }
 
-void PluginUpdater::UpdatePluginsStateFromPolicy(
+void PluginPrefs::UpdatePluginsStateFromPolicy(
     const ListValue* disabled_list,
     const ListValue* exceptions_list,
     const ListValue* enabled_list) {
@@ -114,8 +168,8 @@
   NotifyPluginStatusChanged();
 }
 
-void PluginUpdater::ListValueToStringSet(const ListValue* src,
-                                         std::set<string16>* dest) {
+void PluginPrefs::ListValueToStringSet(const ListValue* src,
+                                       std::set<string16>* dest) {
   DCHECK(src);
   DCHECK(dest);
   ListValue::const_iterator end(src->end());
@@ -128,15 +182,16 @@
   }
 }
 
-void PluginUpdater::SetProfile(Profile* profile) {
+void PluginPrefs::SetProfile(Profile* profile) {
+  prefs_ = profile->GetPrefs();
   bool update_internal_dir = false;
   FilePath last_internal_dir =
-  profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory);
+      prefs_->GetFilePath(prefs::kPluginsLastInternalDirectory);
   FilePath cur_internal_dir;
   if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) &&
       cur_internal_dir != last_internal_dir) {
     update_internal_dir = true;
-    profile->GetPrefs()->SetFilePath(
+    prefs_->SetFilePath(
         prefs::kPluginsLastInternalDirectory, cur_internal_dir);
   }
 
@@ -147,16 +202,16 @@
   FilePath pdf_path;
   PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path);
   FilePath::StringType pdf_path_str = pdf_path.value();
-  if (!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
+  if (!prefs_->GetBoolean(prefs::kPluginsEnabledInternalPDF)) {
     // We switched to the internal pdf plugin being on by default, and so we
     // need to force it to be enabled.  We only want to do it this once though,
     // i.e. we don't want to enable it again if the user disables it afterwards.
-    profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
+    prefs_->SetBoolean(prefs::kPluginsEnabledInternalPDF, true);
     force_enable_internal_pdf = true;
   }
 
   {  // Scoped update of prefs::kPluginsPluginsList.
-    ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList);
+    ListPrefUpdate update(prefs_, prefs::kPluginsPluginsList);
     ListValue* saved_plugins_list = update.Get();
     if (saved_plugins_list && !saved_plugins_list->empty()) {
       for (ListValue::const_iterator it = saved_plugins_list->begin();
@@ -221,17 +276,17 @@
   // Build the set of policy enabled/disabled plugin patterns once and cache it.
   // Don't do this in the constructor, there's no profile available there.
   const ListValue* disabled_plugins =
-      profile->GetPrefs()->GetList(prefs::kPluginsDisabledPlugins);
+      prefs_->GetList(prefs::kPluginsDisabledPlugins);
   const ListValue* disabled_exception_plugins =
-      profile->GetPrefs()->GetList(prefs::kPluginsDisabledPluginsExceptions);
+      prefs_->GetList(prefs::kPluginsDisabledPluginsExceptions);
   const ListValue* enabled_plugins =
-      profile->GetPrefs()->GetList(prefs::kPluginsEnabledPlugins);
+      prefs_->GetList(prefs::kPluginsEnabledPlugins);
   UpdatePluginsStateFromPolicy(disabled_plugins,
                                disabled_exception_plugins,
                                enabled_plugins);
 
   registrar_.RemoveAll();
-  registrar_.Init(profile->GetPrefs());
+  registrar_.Init(prefs_);
   registrar_.Add(prefs::kPluginsDisabledPlugins, this);
   registrar_.Add(prefs::kPluginsDisabledPluginsExceptions, this);
   registrar_.Add(prefs::kPluginsEnabledPlugins, this);
@@ -246,49 +301,77 @@
     // We want to save this, but doing so requires loading the list of plugins,
     // so do it after a minute as to not impact startup performance.  Note that
     // plugins are loaded after 30s by the metrics service.
-    UpdatePreferences(profile, kPluginUpdateDelayMs);
+    UpdatePreferences(kPluginUpdateDelayMs);
   }
 }
 
-void PluginUpdater::Shutdown() {
+void PluginPrefs::ShutdownOnUIThread() {
+  prefs_ = NULL;
   registrar_.RemoveAll();
 }
 
-void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) {
-  BrowserThread::PostDelayedTask(
-    BrowserThread::FILE,
-    FROM_HERE,
-    NewRunnableFunction(
-        &PluginUpdater::GetPreferencesDataOnFileThread, profile), delay_ms);
+// static
+PluginPrefs::Factory* PluginPrefs::Factory::GetInstance() {
+  return Singleton<PluginPrefs::Factory>::get();
 }
 
-void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) {
+PluginPrefsWrapper* PluginPrefs::Factory::GetWrapperForProfile(
+    Profile* profile) {
+  return static_cast<PluginPrefsWrapper*>(GetServiceForProfile(profile, true));
+}
+
+PluginPrefs::Factory::Factory()
+    : ProfileKeyedServiceFactory(ProfileDependencyManager::GetInstance()) {
+}
+
+ProfileKeyedService* PluginPrefs::Factory::BuildServiceInstanceFor(
+      Profile* profile) const {
+  scoped_refptr<PluginPrefs> plugin_prefs(new PluginPrefs());
+  plugin_prefs->SetProfile(profile);
+  return new PluginPrefsWrapper(plugin_prefs);
+}
+
+PluginPrefs::PluginPrefs() : notify_pending_(false) {
+}
+
+PluginPrefs::~PluginPrefs() {
+}
+
+void PluginPrefs::UpdatePreferences(int delay_ms) {
+  BrowserThread::PostDelayedTask(
+      BrowserThread::FILE,
+      FROM_HERE,
+      NewRunnableMethod(this, &PluginPrefs::GetPreferencesDataOnFileThread),
+      delay_ms);
+}
+
+void PluginPrefs::GetPreferencesDataOnFileThread() {
   std::vector<webkit::WebPluginInfo> plugins;
-  webkit::npapi::PluginList::Singleton()->GetPlugins(&plugins);
-
   std::vector<webkit::npapi::PluginGroup> groups;
-  webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, &groups);
 
-  BrowserThread::PostTask(
-    BrowserThread::UI,
-    FROM_HERE,
-    NewRunnableFunction(&PluginUpdater::OnUpdatePreferences,
-                        static_cast<Profile*>(profile),
+  webkit::npapi::PluginList* plugin_list =
+      webkit::npapi::PluginList::Singleton();
+  plugin_list->GetPlugins(&plugins);
+  plugin_list->GetPluginGroups(false, &groups);
+
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+      NewRunnableMethod(this, &PluginPrefs::OnUpdatePreferences,
                         plugins, groups));
 }
 
-void PluginUpdater::OnUpdatePreferences(
-    Profile* profile,
-    const std::vector<webkit::WebPluginInfo>& plugins,
-    const std::vector<webkit::npapi::PluginGroup>& groups) {
-  ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList);
+void PluginPrefs::OnUpdatePreferences(
+    std::vector<webkit::WebPluginInfo> plugins,
+    std::vector<webkit::npapi::PluginGroup> groups) {
+  if (!prefs_)
+    return;
+
+  ListPrefUpdate update(prefs_, prefs::kPluginsPluginsList);
   ListValue* plugins_list = update.Get();
   plugins_list->Clear();
 
   FilePath internal_dir;
   if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir))
-    profile->GetPrefs()->SetFilePath(prefs::kPluginsLastInternalDirectory,
-                                     internal_dir);
+    prefs_->SetFilePath(prefs::kPluginsLastInternalDirectory, internal_dir);
 
   // Add the plugin files.
   for (size_t i = 0; i < plugins.size(); ++i) {
@@ -317,30 +400,25 @@
   }
 }
 
-void PluginUpdater::NotifyPluginStatusChanged() {
+void PluginPrefs::NotifyPluginStatusChanged() {
   if (notify_pending_)
     return;
   notify_pending_ = true;
   MessageLoop::current()->PostTask(
       FROM_HERE,
-      NewRunnableFunction(&PluginUpdater::OnNotifyPluginStatusChanged));
+      NewRunnableMethod(this, &PluginPrefs::OnNotifyPluginStatusChanged));
 }
 
-void PluginUpdater::OnNotifyPluginStatusChanged() {
-  GetInstance()->notify_pending_ = false;
+void PluginPrefs::OnNotifyPluginStatusChanged() {
+  notify_pending_ = false;
   NotificationService::current()->Notify(
       content::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
-      Source<PluginUpdater>(GetInstance()),
+      Source<PluginPrefs>(this),
       NotificationService::NoDetails());
 }
 
 /*static*/
-PluginUpdater* PluginUpdater::GetInstance() {
-  return Singleton<PluginUpdater>::get();
-}
-
-/*static*/
-void PluginUpdater::RegisterPrefs(PrefService* prefs) {
+void PluginPrefs::RegisterPrefs(PrefService* prefs) {
   FilePath internal_dir;
   PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir);
   prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory,
diff --git a/chrome/browser/plugin_prefs.h b/chrome/browser/plugin_prefs.h
new file mode 100644
index 0000000..ae19ad4e
--- /dev/null
+++ b/chrome/browser/plugin_prefs.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PLUGIN_PREFS_H_
+#define CHROME_BROWSER_PLUGIN_PREFS_H_
+#pragma once
+
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/prefs/pref_change_registrar.h"
+#include "content/common/notification_observer.h"
+
+class NotificationDetails;
+class NotificationSource;
+class Profile;
+
+namespace content {
+class ResourceContext;
+}
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace webkit {
+struct WebPluginInfo;
+namespace npapi {
+class PluginGroup;
+}
+}
+
+// This class stores information about whether a plug-in or a plug-in group is
+// enabled or disabled.
+// Except for the |IsPluginEnabled| method, it should only be used on the UI
+// thread.
+class PluginPrefs : public base::RefCountedThreadSafe<PluginPrefs>,
+                    public NotificationObserver {
+ public:
+  // Initializes the factory for this class for dependency tracking.
+  // This should be called before the first profile is created.
+  static void Initialize();
+
+  static PluginPrefs* GetForProfile(Profile* profile);
+
+  // Enable or disable a plugin group.
+  void EnablePluginGroup(bool enable, const string16& group_name);
+
+  // Enable or disable a specific plugin file.
+  void EnablePlugin(bool enable, const FilePath& file_path);
+
+  // Returns whether the plugin is enabled or not.
+  bool IsPluginEnabled(const webkit::WebPluginInfo& plugin);
+
+  // Write the enable/disable status to the user's preference file.
+  void UpdatePreferences(int delay_ms);
+
+  // NotificationObserver method overrides
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details);
+
+  static void RegisterPrefs(PrefService* prefs);
+
+  void ShutdownOnUIThread();
+
+ private:
+  friend class base::RefCountedThreadSafe<PluginPrefs>;
+
+  class Factory;
+
+  PluginPrefs();
+  virtual ~PluginPrefs();
+
+  // Associates the PluginPrefs with |profile|. This enables or disables
+  // plugin groups as defined by the user's preferences.
+  void SetProfile(Profile* profile);
+
+  // Called on the file thread to get the data necessary to update the saved
+  // preferences.
+  void GetPreferencesDataOnFileThread();
+
+  // Called on the UI thread with the plugin data to save the preferences.
+  void OnUpdatePreferences(std::vector<webkit::WebPluginInfo> plugins,
+                           std::vector<webkit::npapi::PluginGroup> groups);
+
+  // Queues sending the notification that plugin data has changed.  This is done
+  // so that if a bunch of changes happen, we only send one notification.
+  void NotifyPluginStatusChanged();
+
+  // Used for the post task to notify that plugin enabled status changed.
+  void OnNotifyPluginStatusChanged();
+
+  base::DictionaryValue* CreatePluginFileSummary(
+      const webkit::WebPluginInfo& plugin);
+
+  // Force plugins to be enabled or disabled due to policy.
+  // |disabled_list| contains the list of StringValues of the names of the
+  // policy-disabled plugins, |exceptions_list| the policy-allowed plugins,
+  // and |enabled_list| the policy-enabled plugins.
+  void UpdatePluginsStateFromPolicy(const base::ListValue* disabled_list,
+                                    const base::ListValue* exceptions_list,
+                                    const base::ListValue* enabled_list);
+
+  void ListValueToStringSet(const base::ListValue* src,
+                            std::set<string16>* dest);
+
+  // Weak pointer, owned by the profile.
+  PrefService* prefs_;
+
+  PrefChangeRegistrar registrar_;
+
+  bool notify_pending_;
+
+  DISALLOW_COPY_AND_ASSIGN(PluginPrefs);
+};
+
+#endif  // CHROME_BROWSER_PLUGIN_PREFS_H_
diff --git a/chrome/browser/plugin_updater.h b/chrome/browser/plugin_updater.h
deleted file mode 100644
index cbc885d..0000000
--- a/chrome/browser/plugin_updater.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PLUGIN_UPDATER_H_
-#define CHROME_BROWSER_PLUGIN_UPDATER_H_
-#pragma once
-
-#include <set>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/file_path.h"
-#include "base/memory/singleton.h"
-#include "chrome/browser/prefs/pref_change_registrar.h"
-#include "content/common/notification_observer.h"
-
-class NotificationDetails;
-class NotificationSource;
-class Profile;
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
-namespace webkit {
-struct WebPluginInfo;
-namespace npapi {
-class PluginGroup;
-}
-}
-
-class PluginUpdater : public NotificationObserver {
- public:
-  // Get a list of all the plugin groups. The caller should take ownership
-  // of the returned ListValue.
-  static base::ListValue* GetPluginGroupsData();
-
-  // Enable or disable a plugin group.
-  void EnablePluginGroup(bool enable, const string16& group_name);
-
-  // Enable or disable a specific plugin file.
-  void EnablePlugin(bool enable, const FilePath::StringType& file_path);
-
-  // Associates the PluginUpdater with |profile|. This enables or disables
-  // plugin groups as defined by the user's preferences.
-  void SetProfile(Profile* profile);
-
-  // Called at shutdown before the profile is destroyed.
-  void Shutdown();
-
-  // Write the enable/disable status to the user's preference file.
-  void UpdatePreferences(Profile* profile, int delay_ms);
-
-  // NotificationObserver method overrides
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details);
-
-  static PluginUpdater* GetInstance();
-
-  static void RegisterPrefs(PrefService* prefs);
-
- private:
-  PluginUpdater();
-  virtual ~PluginUpdater() {}
-
-  // Called on the file thread to get the data necessary to update the saved
-  // preferences.  The profile pointer is only to be passed to the UI thread.
-  static void GetPreferencesDataOnFileThread(void* profile);
-
-  // Called on the UI thread with the plugin data to save the preferences.
-  static void OnUpdatePreferences(
-      Profile* profile,
-      const std::vector<webkit::WebPluginInfo>& plugins,
-      const std::vector<webkit::npapi::PluginGroup>& groups);
-
-  // Queues sending the notification that plugin data has changed.  This is done
-  // so that if a bunch of changes happen, we only send one notification.
-  void NotifyPluginStatusChanged();
-
-  // Used for the post task to notify that plugin enabled status changed.
-  static void OnNotifyPluginStatusChanged();
-
-  static base::DictionaryValue* CreatePluginFileSummary(
-      const webkit::WebPluginInfo& plugin);
-
-  // Force plugins to be enabled or disabled due to policy.
-  // |disabled_list| contains the list of StringValues of the names of the
-  // policy-disabled plugins, |exceptions_list| the policy-allowed plugins,
-  // and |enabled_list| the policy-enabled plugins.
-  void UpdatePluginsStateFromPolicy(const base::ListValue* disabled_list,
-                                    const base::ListValue* exceptions_list,
-                                    const base::ListValue* enabled_list);
-
-  void ListValueToStringSet(const base::ListValue* src,
-                            std::set<string16>* dest);
-
-  // Needed to allow singleton instantiation using private constructor.
-  friend struct DefaultSingletonTraits<PluginUpdater>;
-
-  PrefChangeRegistrar registrar_;
-
-  bool notify_pending_;
-
-  DISALLOW_COPY_AND_ASSIGN(PluginUpdater);
-};
-
-#endif  // CHROME_BROWSER_PLUGIN_UPDATER_H_
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index f94f68a..fc9343e 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -34,7 +34,7 @@
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/page_info_model.h"
 #include "chrome/browser/password_manager/password_manager.h"
-#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/policy/cloud_policy_subsystem.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
@@ -154,8 +154,8 @@
   ExtensionsUI::RegisterUserPrefs(user_prefs);
   IncognitoModePrefs::RegisterUserPrefs(user_prefs);
   NewTabUI::RegisterUserPrefs(user_prefs);
+  PluginPrefs::RegisterPrefs(user_prefs);
   PluginsUI::RegisterUserPrefs(user_prefs);
-  PluginUpdater::RegisterPrefs(user_prefs);
   ProfileImpl::RegisterUserPrefs(user_prefs);
   PromoResourceService::RegisterUserPrefs(user_prefs);
   HostContentSettingsMap::RegisterUserPrefs(user_prefs);
diff --git a/chrome/browser/profiles/profile_dependency_manager.cc b/chrome/browser/profiles/profile_dependency_manager.cc
index cdfbe2f..db551a2 100644
--- a/chrome/browser/profiles/profile_dependency_manager.cc
+++ b/chrome/browser/profiles/profile_dependency_manager.cc
@@ -9,6 +9,7 @@
 #include <iterator>
 
 #include "chrome/browser/background/background_contents_service_factory.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
 #include "chrome/browser/profiles/profile_keyed_service.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
@@ -36,6 +37,7 @@
   if (!g_initialized) {
     BackgroundContentsServiceFactory::GetInstance();
     CloudPrintProxyServiceFactory::GetInstance();
+    PluginPrefs::Initialize();
     SessionServiceFactory::GetInstance();
     TabRestoreServiceFactory::GetInstance();
     TemplateURLServiceFactory::GetInstance();
diff --git a/chrome/browser/ui/webui/flash_ui.cc b/chrome/browser/ui/webui/flash_ui.cc
index ad5f469..a973bfa 100644
--- a/chrome/browser/ui/webui/flash_ui.cc
+++ b/chrome/browser/ui/webui/flash_ui.cc
@@ -12,6 +12,7 @@
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/crash_upload_list.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
 #include "chrome/browser/ui/webui/crashes_ui.h"
@@ -229,8 +230,10 @@
   if (info_array.empty()) {
     AddPair(list, ASCIIToUTF16("Flash plugin"), "Disabled");
   } else {
+    PluginPrefs* plugin_prefs =
+        PluginPrefs::GetForProfile(Profile::FromWebUI(web_ui_));
     for (size_t i = 0; i < info_array.size(); ++i) {
-      if (webkit::IsPluginEnabled(info_array[i])) {
+      if (plugin_prefs->IsPluginEnabled(info_array[i])) {
         flash_version = info_array[i].version + ASCIIToUTF16(" ") +
                         info_array[i].path.LossyDisplayName();
         if (i != 0)
diff --git a/chrome/browser/ui/webui/plugins_ui.cc b/chrome/browser/ui/webui/plugins_ui.cc
index b830969f..55304c3a 100644
--- a/chrome/browser/ui/webui/plugins_ui.cc
+++ b/chrome/browser/ui/webui/plugins_ui.cc
@@ -13,7 +13,7 @@
 #include "base/path_service.h"
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/plugin_updater.h"
+#include "chrome/browser/plugin_prefs.h"
 #include "chrome/browser/prefs/pref_member.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -122,23 +122,19 @@
                        const NotificationDetails& details) OVERRIDE;
 
  private:
-  // This extra wrapper is used to ensure we don't leak the ListValue* pointer
-  // if the PluginsDOMHandler object goes away before the task on the UI thread
-  // to give it the plugin list runs.
-  struct ListWrapper {
-    ListValue* list;
-  };
   // Loads the plugins on the FILE thread.
-  static void LoadPluginsOnFileThread(ListWrapper* wrapper, Task* task);
+  static void LoadPluginsOnFileThread(
+      std::vector<webkit::npapi::PluginGroup>* groups, Task* task);
 
   // Used in conjunction with ListWrapper to avoid any memory leaks.
-  static void EnsureListDeleted(ListWrapper* wrapper);
+  static void EnsurePluginGroupsDeleted(
+      std::vector<webkit::npapi::PluginGroup>* groups);
 
   // Call this to start getting the plugins on the UI thread.
   void LoadPlugins();
 
   // Called on the UI thread when the plugin information is ready.
-  void PluginsLoaded(ListWrapper* wrapper);
+  void PluginsLoaded(const std::vector<webkit::npapi::PluginGroup>* groups);
 
   NotificationRegistrar registrar_;
 
@@ -161,7 +157,7 @@
 WebUIMessageHandler* PluginsDOMHandler::Attach(WebUI* web_ui) {
   PrefService* prefs = Profile::FromWebUI(web_ui)->GetPrefs();
 
-  show_details_.Init(prefs::kPluginsShowDetails, prefs, this);
+  show_details_.Init(prefs::kPluginsShowDetails, prefs, NULL);
 
   return WebUIMessageHandler::Attach(web_ui);
 }
@@ -202,13 +198,13 @@
     return;
   bool enable = enable_str == "true";
 
-  PluginUpdater* plugin_updater = PluginUpdater::GetInstance();
+  PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
   if (is_group_str == "true") {
     string16 group_name;
     if (!args->GetString(0, &group_name))
       return;
 
-    plugin_updater->EnablePluginGroup(enable, group_name);
+    plugin_prefs->EnablePluginGroup(enable, group_name);
     if (enable) {
       // See http://crbug.com/50105 for background.
       string16 adobereader = ASCIIToUTF16(
@@ -216,9 +212,9 @@
       string16 internalpdf =
           ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName);
       if (group_name == adobereader) {
-        plugin_updater->EnablePluginGroup(false, internalpdf);
+        plugin_prefs->EnablePluginGroup(false, internalpdf);
       } else if (group_name == internalpdf) {
-        plugin_updater->EnablePluginGroup(false, adobereader);
+        plugin_prefs->EnablePluginGroup(false, adobereader);
       }
     }
   } else {
@@ -226,13 +222,13 @@
     if (!args->GetString(0, &file_path))
       return;
 
-    plugin_updater->EnablePlugin(enable, file_path);
+    plugin_prefs->EnablePlugin(enable, FilePath(file_path));
   }
 
   // TODO(viettrungluu): We might also want to ensure that the plugins
   // list is always written to prefs even when the user hasn't disabled a
   // plugin. <http://crbug.com/39101>
-  plugin_updater->UpdatePreferences(profile, 0);
+  plugin_prefs->UpdatePreferences(0);
 }
 
 void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(const ListValue* args) {
@@ -256,41 +252,50 @@
   LoadPlugins();
 }
 
-void PluginsDOMHandler::LoadPluginsOnFileThread(ListWrapper* wrapper,
-                                                Task* task) {
-  wrapper->list = PluginUpdater::GetInstance()->GetPluginGroupsData();
+void PluginsDOMHandler::LoadPluginsOnFileThread(
+    std::vector<webkit::npapi::PluginGroup>* groups,
+    Task* task) {
+  webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, groups);
+
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
   BrowserThread::PostTask(
       BrowserThread::UI,
       FROM_HERE,
-      NewRunnableFunction(&PluginsDOMHandler::EnsureListDeleted, wrapper));
+      NewRunnableFunction(&PluginsDOMHandler::EnsurePluginGroupsDeleted,
+                          groups));
 }
 
-void PluginsDOMHandler::EnsureListDeleted(ListWrapper* wrapper) {
-  delete wrapper->list;
-  delete wrapper;
+void PluginsDOMHandler::EnsurePluginGroupsDeleted(
+    std::vector<webkit::npapi::PluginGroup>* groups) {
+  delete groups;
 }
 
 void PluginsDOMHandler::LoadPlugins() {
   if (!get_plugins_factory_.empty())
     return;
 
-  ListWrapper* wrapper = new ListWrapper;
-  wrapper->list = NULL;
+  std::vector<webkit::npapi::PluginGroup>* groups =
+      new std::vector<webkit::npapi::PluginGroup>;
   Task* task = get_plugins_factory_.NewRunnableMethod(
-          &PluginsDOMHandler::PluginsLoaded, wrapper);
+          &PluginsDOMHandler::PluginsLoaded, groups);
 
   BrowserThread::PostTask(
       BrowserThread::FILE,
       FROM_HERE,
       NewRunnableFunction(
-          &PluginsDOMHandler::LoadPluginsOnFileThread, wrapper, task));
+          &PluginsDOMHandler::LoadPluginsOnFileThread, groups, task));
 }
 
-void PluginsDOMHandler::PluginsLoaded(ListWrapper* wrapper) {
+void PluginsDOMHandler::PluginsLoaded(
+    const std::vector<webkit::npapi::PluginGroup>* groups) {
+  // Construct DictionaryValues to return to the UI
+  ListValue* plugin_groups_data = new ListValue();
+  for (size_t i = 0; i < groups->size(); ++i) {
+    plugin_groups_data->Append((*groups)[i].GetDataForUI());
+    // TODO(bauerb): Fetch plugin enabled state from PluginPrefs.
+  }
   DictionaryValue results;
-  results.Set("plugins", wrapper->list);
-  wrapper->list = NULL;  // So it doesn't get deleted.
+  results.Set("plugins", plugin_groups_data);
   web_ui_->CallJavascriptFunction("returnPluginsData", results);
 }
 
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index b9ec4dab..2f9764d 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1641,8 +1641,8 @@
         'browser/plugin_installer_infobar_delegate.h',
         'browser/plugin_observer.cc',
         'browser/plugin_observer.h',
-        'browser/plugin_updater.cc',
-        'browser/plugin_updater.h',
+        'browser/plugin_prefs.cc',
+        'browser/plugin_prefs.h',
         'browser/policy/asynchronous_policy_loader.cc',
         'browser/policy/asynchronous_policy_loader.h',
         'browser/policy/asynchronous_policy_provider.cc',