Home | History | Annotate | Download | only in webui
      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/ui/webui/plugins_ui.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/bind_helpers.h"
     13 #include "base/files/file_path.h"
     14 #include "base/memory/ref_counted_memory.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "base/memory/singleton.h"
     17 #include "base/memory/weak_ptr.h"
     18 #include "base/message_loop/message_loop.h"
     19 #include "base/path_service.h"
     20 #include "base/prefs/pref_member.h"
     21 #include "base/prefs/pref_service.h"
     22 #include "base/prefs/scoped_user_pref_update.h"
     23 #include "base/strings/utf_string_conversions.h"
     24 #include "base/values.h"
     25 #include "chrome/browser/chrome_notification_types.h"
     26 #include "chrome/browser/content_settings/host_content_settings_map.h"
     27 #include "chrome/browser/plugins/plugin_finder.h"
     28 #include "chrome/browser/plugins/plugin_metadata.h"
     29 #include "chrome/browser/plugins/plugin_prefs.h"
     30 #include "chrome/browser/profiles/profile.h"
     31 #include "chrome/browser/ui/browser.h"
     32 #include "chrome/browser/ui/browser_window.h"
     33 #include "chrome/common/chrome_content_client.h"
     34 #include "chrome/common/chrome_paths.h"
     35 #include "chrome/common/pref_names.h"
     36 #include "chrome/common/url_constants.h"
     37 #include "chrome/grit/generated_resources.h"
     38 #include "components/pref_registry/pref_registry_syncable.h"
     39 #include "content/public/browser/notification_source.h"
     40 #include "content/public/browser/plugin_service.h"
     41 #include "content/public/browser/web_contents.h"
     42 #include "content/public/browser/web_ui.h"
     43 #include "content/public/browser/web_ui_data_source.h"
     44 #include "content/public/browser/web_ui_message_handler.h"
     45 #include "content/public/common/content_constants.h"
     46 #include "grit/browser_resources.h"
     47 #include "grit/theme_resources.h"
     48 #include "ui/base/l10n/l10n_util.h"
     49 #include "ui/base/resource/resource_bundle.h"
     50 
     51 #if defined(OS_CHROMEOS)
     52 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
     53 #endif
     54 
     55 using content::PluginService;
     56 using content::WebContents;
     57 using content::WebPluginInfo;
     58 using content::WebUIMessageHandler;
     59 
     60 namespace {
     61 
     62 // Callback function to process result of EnablePlugin method.
     63 void AssertPluginEnabled(bool did_enable) {
     64   DCHECK(did_enable);
     65 }
     66 
     67 content::WebUIDataSource* CreatePluginsUIHTMLSource(Profile* profile) {
     68   content::WebUIDataSource* source =
     69       content::WebUIDataSource::Create(chrome::kChromeUIPluginsHost);
     70   source->SetUseJsonJSFormatV2();
     71 
     72   source->AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE);
     73   source->AddLocalizedString("pluginsDetailsModeLink",
     74                              IDS_PLUGINS_DETAILS_MODE_LINK);
     75   source->AddLocalizedString("pluginsNoneInstalled",
     76                              IDS_PLUGINS_NONE_INSTALLED);
     77   source->AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN);
     78   source->AddLocalizedString("pluginDisabledByPolicy",
     79                              IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN);
     80   source->AddLocalizedString("pluginEnabledByPolicy",
     81                              IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN);
     82   source->AddLocalizedString("pluginGroupManagedByPolicy",
     83                              IDS_PLUGINS_GROUP_MANAGED_BY_POLICY);
     84   source->AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD);
     85   source->AddLocalizedString("pluginName", IDS_PLUGINS_NAME);
     86   source->AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION);
     87   source->AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION);
     88   source->AddLocalizedString("pluginPath", IDS_PLUGINS_PATH);
     89   source->AddLocalizedString("pluginType", IDS_PLUGINS_TYPE);
     90   source->AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES);
     91   source->AddLocalizedString("pluginMimeTypesMimeType",
     92                              IDS_PLUGINS_MIME_TYPES_MIME_TYPE);
     93   source->AddLocalizedString("pluginMimeTypesDescription",
     94                              IDS_PLUGINS_MIME_TYPES_DESCRIPTION);
     95   source->AddLocalizedString("pluginMimeTypesFileExtensions",
     96                              IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS);
     97   source->AddLocalizedString("disable", IDS_PLUGINS_DISABLE);
     98   source->AddLocalizedString("enable", IDS_PLUGINS_ENABLE);
     99   source->AddLocalizedString("alwaysAllowed", IDS_PLUGINS_ALWAYS_ALLOWED);
    100   source->AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS);
    101 
    102   source->SetJsonPath("strings.js");
    103   source->AddResourcePath("plugins.js", IDR_PLUGINS_JS);
    104   source->SetDefaultResource(IDR_PLUGINS_HTML);
    105 #if defined(OS_CHROMEOS)
    106   chromeos::AddAccountUITweaksLocalizedValues(source, profile);
    107 #endif
    108   return source;
    109 }
    110 
    111 base::string16 PluginTypeToString(int type) {
    112   // The type is stored as an |int|, but doing the switch on the right
    113   // enumeration type gives us better build-time error checking (if someone adds
    114   // a new type).
    115   switch (static_cast<WebPluginInfo::PluginType>(type)) {
    116     case WebPluginInfo::PLUGIN_TYPE_NPAPI:
    117       return l10n_util::GetStringUTF16(IDS_PLUGINS_NPAPI);
    118     case WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS:
    119       return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_IN_PROCESS);
    120     case WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS:
    121       return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_OUT_OF_PROCESS);
    122     case WebPluginInfo::PLUGIN_TYPE_PEPPER_UNSANDBOXED:
    123       return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_UNSANDBOXED);
    124     case WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN:
    125       return l10n_util::GetStringUTF16(IDS_PLUGINS_BROWSER_PLUGIN);
    126   }
    127   NOTREACHED();
    128   return base::string16();
    129 }
    130 
    131 ////////////////////////////////////////////////////////////////////////////////
    132 //
    133 // PluginsDOMHandler
    134 //
    135 ////////////////////////////////////////////////////////////////////////////////
    136 
    137 // The handler for Javascript messages for the chrome://plugins/ page.
    138 // TODO(viettrungluu): Make plugin list updates notify, and then observe
    139 // changes; maybe replumb plugin list through plugin service?
    140 // <http://crbug.com/39101>
    141 class PluginsDOMHandler : public WebUIMessageHandler,
    142                           public content::NotificationObserver {
    143  public:
    144   PluginsDOMHandler();
    145   virtual ~PluginsDOMHandler() {}
    146 
    147   // WebUIMessageHandler implementation.
    148   virtual void RegisterMessages() OVERRIDE;
    149 
    150   // Callback for the "requestPluginsData" message.
    151   void HandleRequestPluginsData(const base::ListValue* args);
    152 
    153   // Callback for the "enablePlugin" message.
    154   void HandleEnablePluginMessage(const base::ListValue* args);
    155 
    156   // Callback for the "saveShowDetailsToPrefs" message.
    157   void HandleSaveShowDetailsToPrefs(const base::ListValue* args);
    158 
    159   // Calback for the "getShowDetails" message.
    160   void HandleGetShowDetails(const base::ListValue* args);
    161 
    162   // Callback for the "setPluginAlwaysAllowed" message.
    163   void HandleSetPluginAlwaysAllowed(const base::ListValue* args);
    164 
    165   // content::NotificationObserver method overrides
    166   virtual void Observe(int type,
    167                        const content::NotificationSource& source,
    168                        const content::NotificationDetails& details) OVERRIDE;
    169 
    170  private:
    171   void LoadPlugins();
    172 
    173   // Called on the UI thread when the plugin information is ready.
    174   void PluginsLoaded(const std::vector<WebPluginInfo>& plugins);
    175 
    176   content::NotificationRegistrar registrar_;
    177 
    178   // Holds grouped plug-ins. The key is the group identifier and
    179   // the value is the list of plug-ins belonging to the group.
    180   typedef base::hash_map<std::string, std::vector<const WebPluginInfo*> >
    181       PluginGroups;
    182 
    183   // This pref guards the value whether about:plugins is in the details mode or
    184   // not.
    185   BooleanPrefMember show_details_;
    186 
    187   base::WeakPtrFactory<PluginsDOMHandler> weak_ptr_factory_;
    188 
    189   DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
    190 };
    191 
    192 PluginsDOMHandler::PluginsDOMHandler()
    193     : weak_ptr_factory_(this) {
    194 }
    195 
    196 void PluginsDOMHandler::RegisterMessages() {
    197   Profile* profile = Profile::FromWebUI(web_ui());
    198 
    199   PrefService* prefs = profile->GetPrefs();
    200   show_details_.Init(prefs::kPluginsShowDetails, prefs);
    201 
    202   registrar_.Add(this,
    203                  chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
    204                  content::Source<Profile>(profile));
    205 
    206   web_ui()->RegisterMessageCallback("requestPluginsData",
    207       base::Bind(&PluginsDOMHandler::HandleRequestPluginsData,
    208                  base::Unretained(this)));
    209   web_ui()->RegisterMessageCallback("enablePlugin",
    210       base::Bind(&PluginsDOMHandler::HandleEnablePluginMessage,
    211                  base::Unretained(this)));
    212   web_ui()->RegisterMessageCallback("setPluginAlwaysAllowed",
    213       base::Bind(&PluginsDOMHandler::HandleSetPluginAlwaysAllowed,
    214                  base::Unretained(this)));
    215   web_ui()->RegisterMessageCallback("saveShowDetailsToPrefs",
    216       base::Bind(&PluginsDOMHandler::HandleSaveShowDetailsToPrefs,
    217                  base::Unretained(this)));
    218   web_ui()->RegisterMessageCallback("getShowDetails",
    219       base::Bind(&PluginsDOMHandler::HandleGetShowDetails,
    220                  base::Unretained(this)));
    221 }
    222 
    223 void PluginsDOMHandler::HandleRequestPluginsData(const base::ListValue* args) {
    224   LoadPlugins();
    225 }
    226 
    227 void PluginsDOMHandler::HandleEnablePluginMessage(const base::ListValue* args) {
    228   Profile* profile = Profile::FromWebUI(web_ui());
    229 
    230   // Be robust in accepting badness since plug-ins display HTML (hence
    231   // JavaScript).
    232   if (args->GetSize() != 3) {
    233     NOTREACHED();
    234     return;
    235   }
    236 
    237   std::string enable_str;
    238   std::string is_group_str;
    239   if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str)) {
    240     NOTREACHED();
    241     return;
    242   }
    243   bool enable = enable_str == "true";
    244 
    245   PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
    246   if (is_group_str == "true") {
    247     base::string16 group_name;
    248     if (!args->GetString(0, &group_name)) {
    249       NOTREACHED();
    250       return;
    251     }
    252 
    253     plugin_prefs->EnablePluginGroup(enable, group_name);
    254     if (enable) {
    255       // See http://crbug.com/50105 for background.
    256       base::string16 adobereader = base::ASCIIToUTF16(
    257           PluginMetadata::kAdobeReaderGroupName);
    258       base::string16 internalpdf =
    259           base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName);
    260       if (group_name == adobereader)
    261         plugin_prefs->EnablePluginGroup(false, internalpdf);
    262       else if (group_name == internalpdf)
    263         plugin_prefs->EnablePluginGroup(false, adobereader);
    264     }
    265   } else {
    266     base::FilePath::StringType file_path;
    267     if (!args->GetString(0, &file_path)) {
    268       NOTREACHED();
    269       return;
    270     }
    271 
    272     plugin_prefs->EnablePlugin(enable, base::FilePath(file_path),
    273                                base::Bind(&AssertPluginEnabled));
    274   }
    275 }
    276 
    277 void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(
    278     const base::ListValue* args) {
    279   std::string details_mode;
    280   if (!args->GetString(0, &details_mode)) {
    281     NOTREACHED();
    282     return;
    283   }
    284   show_details_.SetValue(details_mode == "true");
    285 }
    286 
    287 void PluginsDOMHandler::HandleGetShowDetails(const base::ListValue* args) {
    288   base::FundamentalValue show_details(show_details_.GetValue());
    289   web_ui()->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details);
    290 }
    291 
    292 void PluginsDOMHandler::HandleSetPluginAlwaysAllowed(
    293     const base::ListValue* args) {
    294   // Be robust in the input parameters, but crash in a Debug build.
    295   if (args->GetSize() != 2) {
    296     NOTREACHED();
    297     return;
    298   }
    299 
    300   std::string plugin;
    301   bool allowed = false;
    302   if (!args->GetString(0, &plugin) || !args->GetBoolean(1, &allowed)) {
    303     NOTREACHED();
    304     return;
    305   }
    306   Profile* profile = Profile::FromWebUI(web_ui());
    307   profile->GetHostContentSettingsMap()->SetContentSetting(
    308       ContentSettingsPattern::Wildcard(),
    309       ContentSettingsPattern::Wildcard(),
    310       CONTENT_SETTINGS_TYPE_PLUGINS,
    311       plugin,
    312       allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_DEFAULT);
    313 
    314   // Keep track of the whitelist separately, so that we can distinguish plug-ins
    315   // whitelisted by the user from automatically whitelisted ones.
    316   DictionaryPrefUpdate update(profile->GetPrefs(),
    317                               prefs::kContentSettingsPluginWhitelist);
    318   update->SetBoolean(plugin, allowed);
    319 }
    320 
    321 void PluginsDOMHandler::Observe(int type,
    322                                 const content::NotificationSource& source,
    323                                 const content::NotificationDetails& details) {
    324   DCHECK_EQ(chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type);
    325   LoadPlugins();
    326 }
    327 
    328 void PluginsDOMHandler::LoadPlugins() {
    329   if (weak_ptr_factory_.HasWeakPtrs())
    330     return;
    331 
    332   PluginService::GetInstance()->GetPlugins(
    333       base::Bind(&PluginsDOMHandler::PluginsLoaded,
    334                  weak_ptr_factory_.GetWeakPtr()));
    335 }
    336 
    337 void PluginsDOMHandler::PluginsLoaded(
    338     const std::vector<WebPluginInfo>& plugins) {
    339   Profile* profile = Profile::FromWebUI(web_ui());
    340   PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
    341 
    342   ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
    343 
    344   PluginFinder* plugin_finder = PluginFinder::GetInstance();
    345   // Group plug-ins by identifier. This is done to be able to display
    346   // the plug-ins in UI in a grouped fashion.
    347   PluginGroups groups;
    348   for (size_t i = 0; i < plugins.size(); ++i) {
    349     scoped_ptr<PluginMetadata> plugin(
    350         plugin_finder->GetPluginMetadata(plugins[i]));
    351     groups[plugin->identifier()].push_back(&plugins[i]);
    352   }
    353 
    354   // Construct DictionaryValues to return to UI.
    355   base::ListValue* plugin_groups_data = new base::ListValue();
    356   for (PluginGroups::const_iterator it = groups.begin();
    357       it != groups.end(); ++it) {
    358     const std::vector<const WebPluginInfo*>& group_plugins = it->second;
    359     base::ListValue* plugin_files = new base::ListValue();
    360     scoped_ptr<PluginMetadata> plugin_metadata(
    361         plugin_finder->GetPluginMetadata(*group_plugins[0]));
    362     base::string16 group_name = plugin_metadata->name();
    363     std::string group_identifier = plugin_metadata->identifier();
    364     bool group_enabled = false;
    365     bool all_plugins_enabled_by_policy = true;
    366     bool all_plugins_disabled_by_policy = true;
    367     bool all_plugins_managed_by_policy = true;
    368     const WebPluginInfo* active_plugin = NULL;
    369     for (size_t j = 0; j < group_plugins.size(); ++j) {
    370       const WebPluginInfo& group_plugin = *group_plugins[j];
    371 
    372       base::DictionaryValue* plugin_file = new base::DictionaryValue();
    373       plugin_file->SetString("name", group_plugin.name);
    374 
    375       // If this plugin is Pepper Flash, and the plugin path is the same as the
    376       // path for the Pepper Flash Debugger plugin, then mark this plugin
    377       // description as the debugger plugin to help the user disambiguate the
    378       // two plugins.
    379       base::string16 desc = group_plugin.desc;
    380       if (group_plugin.is_pepper_plugin() &&
    381           group_plugin.name == base::ASCIIToUTF16(content::kFlashPluginName)) {
    382         base::FilePath debug_path;
    383         PathService::Get(chrome::DIR_PEPPER_FLASH_DEBUGGER_PLUGIN, &debug_path);
    384         if (group_plugin.path.DirName() == debug_path)
    385           desc += base::ASCIIToUTF16(" Debug");
    386       }
    387       plugin_file->SetString("description", desc);
    388 
    389       plugin_file->SetString("path", group_plugin.path.value());
    390       plugin_file->SetString("version", group_plugin.version);
    391       plugin_file->SetString("type", PluginTypeToString(group_plugin.type));
    392 
    393       base::ListValue* mime_types = new base::ListValue();
    394       const std::vector<content::WebPluginMimeType>& plugin_mime_types =
    395           group_plugin.mime_types;
    396       for (size_t k = 0; k < plugin_mime_types.size(); ++k) {
    397         base::DictionaryValue* mime_type = new base::DictionaryValue();
    398         mime_type->SetString("mimeType", plugin_mime_types[k].mime_type);
    399         mime_type->SetString("description", plugin_mime_types[k].description);
    400 
    401         base::ListValue* file_extensions = new base::ListValue();
    402         const std::vector<std::string>& mime_file_extensions =
    403             plugin_mime_types[k].file_extensions;
    404         for (size_t l = 0; l < mime_file_extensions.size(); ++l) {
    405           file_extensions->Append(
    406               new base::StringValue(mime_file_extensions[l]));
    407         }
    408         mime_type->Set("fileExtensions", file_extensions);
    409 
    410         mime_types->Append(mime_type);
    411       }
    412       plugin_file->Set("mimeTypes", mime_types);
    413 
    414       bool plugin_enabled = plugin_prefs->IsPluginEnabled(group_plugin);
    415 
    416       if (!active_plugin || (plugin_enabled && !group_enabled))
    417         active_plugin = &group_plugin;
    418       group_enabled = plugin_enabled || group_enabled;
    419 
    420       std::string enabled_mode;
    421       PluginPrefs::PolicyStatus plugin_status =
    422           plugin_prefs->PolicyStatusForPlugin(group_plugin.name);
    423       PluginPrefs::PolicyStatus group_status =
    424           plugin_prefs->PolicyStatusForPlugin(group_name);
    425       if (plugin_status == PluginPrefs::POLICY_ENABLED ||
    426           group_status == PluginPrefs::POLICY_ENABLED) {
    427         enabled_mode = "enabledByPolicy";
    428         all_plugins_disabled_by_policy = false;
    429       } else {
    430         all_plugins_enabled_by_policy = false;
    431         if (plugin_status == PluginPrefs::POLICY_DISABLED ||
    432             group_status == PluginPrefs::POLICY_DISABLED) {
    433           enabled_mode = "disabledByPolicy";
    434         } else {
    435           all_plugins_disabled_by_policy = false;
    436           all_plugins_managed_by_policy = false;
    437           if (plugin_enabled) {
    438             enabled_mode = "enabledByUser";
    439           } else {
    440             enabled_mode = "disabledByUser";
    441           }
    442         }
    443       }
    444       plugin_file->SetString("enabledMode", enabled_mode);
    445 
    446       plugin_files->Append(plugin_file);
    447     }
    448     base::DictionaryValue* group_data = new base::DictionaryValue();
    449 
    450     group_data->Set("plugin_files", plugin_files);
    451     group_data->SetString("name", group_name);
    452     group_data->SetString("id", group_identifier);
    453     group_data->SetString("description", active_plugin->desc);
    454     group_data->SetString("version", active_plugin->version);
    455 
    456 #if defined(ENABLE_PLUGIN_INSTALLATION)
    457     bool out_of_date = plugin_metadata->GetSecurityStatus(*active_plugin) ==
    458         PluginMetadata::SECURITY_STATUS_OUT_OF_DATE;
    459     group_data->SetBoolean("critical", out_of_date);
    460     group_data->SetString("update_url", plugin_metadata->plugin_url().spec());
    461 #endif
    462 
    463     std::string enabled_mode;
    464     if (all_plugins_enabled_by_policy) {
    465       enabled_mode = "enabledByPolicy";
    466     } else if (all_plugins_disabled_by_policy) {
    467       enabled_mode = "disabledByPolicy";
    468     } else if (all_plugins_managed_by_policy) {
    469       enabled_mode = "managedByPolicy";
    470     } else if (group_enabled) {
    471       enabled_mode = "enabledByUser";
    472     } else {
    473       enabled_mode = "disabledByUser";
    474     }
    475     group_data->SetString("enabledMode", enabled_mode);
    476 
    477     bool always_allowed = false;
    478     if (group_enabled) {
    479       const base::DictionaryValue* whitelist =
    480           profile->GetPrefs()->GetDictionary(
    481               prefs::kContentSettingsPluginWhitelist);
    482       whitelist->GetBoolean(group_identifier, &always_allowed);
    483     }
    484     group_data->SetBoolean("alwaysAllowed", always_allowed);
    485 
    486     plugin_groups_data->Append(group_data);
    487   }
    488   base::DictionaryValue results;
    489   results.Set("plugins", plugin_groups_data);
    490   web_ui()->CallJavascriptFunction("returnPluginsData", results);
    491 }
    492 
    493 }  // namespace
    494 
    495 ///////////////////////////////////////////////////////////////////////////////
    496 //
    497 // PluginsUI
    498 //
    499 ///////////////////////////////////////////////////////////////////////////////
    500 
    501 PluginsUI::PluginsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
    502   web_ui->AddMessageHandler(new PluginsDOMHandler());
    503 
    504   // Set up the chrome://plugins/ source.
    505   Profile* profile = Profile::FromWebUI(web_ui);
    506   content::WebUIDataSource::Add(profile, CreatePluginsUIHTMLSource(profile));
    507 }
    508 
    509 // static
    510 base::RefCountedMemory* PluginsUI::GetFaviconResourceBytes(
    511       ui::ScaleFactor scale_factor) {
    512   return ResourceBundle::GetSharedInstance().
    513       LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor);
    514 }
    515 
    516 // static
    517 void PluginsUI::RegisterProfilePrefs(
    518     user_prefs::PrefRegistrySyncable* registry) {
    519   registry->RegisterBooleanPref(
    520       prefs::kPluginsShowDetails,
    521       false,
    522       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    523   registry->RegisterDictionaryPref(
    524       prefs::kContentSettingsPluginWhitelist,
    525       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
    526 }
    527