• 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/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.
AssertPluginEnabled(bool did_enable)63 void AssertPluginEnabled(bool did_enable) {
64   DCHECK(did_enable);
65 }
66 
CreatePluginsUIHTMLSource(Profile * profile)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 
PluginTypeToString(int type)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();
~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 
PluginsDOMHandler()192 PluginsDOMHandler::PluginsDOMHandler()
193     : weak_ptr_factory_(this) {
194 }
195 
RegisterMessages()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 
HandleRequestPluginsData(const base::ListValue * args)223 void PluginsDOMHandler::HandleRequestPluginsData(const base::ListValue* args) {
224   LoadPlugins();
225 }
226 
HandleEnablePluginMessage(const base::ListValue * args)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 
HandleSaveShowDetailsToPrefs(const base::ListValue * args)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 
HandleGetShowDetails(const base::ListValue * args)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 
HandleSetPluginAlwaysAllowed(const base::ListValue * args)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 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 
LoadPlugins()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 
PluginsLoaded(const std::vector<WebPluginInfo> & plugins)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 
PluginsUI(content::WebUI * web_ui)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
GetFaviconResourceBytes(ui::ScaleFactor scale_factor)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
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)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