Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / content_settings / content_settings_default_provider.cc
blob6ee9c2c116ebadd123de6a4127883a77f56b4d98
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.
5 #include "chrome/browser/content_settings/content_settings_default_provider.h"
7 #include <string>
8 #include <vector>
10 #include "base/auto_reset.h"
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/prefs/scoped_user_pref_update.h"
17 #include "chrome/browser/content_settings/content_settings_utils.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/content_settings/core/browser/content_settings_rule.h"
20 #include "components/content_settings/core/common/content_settings.h"
21 #include "components/content_settings/core/common/content_settings_pattern.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "url/gurl.h"
26 using content::BrowserThread;
28 namespace {
30 // The default setting for each content type.
31 const ContentSetting kDefaultSettings[] = {
32 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_COOKIES
33 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_IMAGES
34 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_JAVASCRIPT
35 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_PLUGINS
36 CONTENT_SETTING_BLOCK, // CONTENT_SETTINGS_TYPE_POPUPS
37 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_GEOLOCATION
38 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_NOTIFICATIONS
39 CONTENT_SETTING_DEFAULT, // CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
40 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_FULLSCREEN
41 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_MOUSELOCK
42 CONTENT_SETTING_DEFAULT, // CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
43 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_MEDIASTREAM
44 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
45 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA
46 CONTENT_SETTING_DEFAULT, // CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS
47 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_PPAPI_BROKER
48 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS
49 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_MIDI_SYSEX
50 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_PUSH_MESSAGING
51 CONTENT_SETTING_ALLOW, // CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS
52 #if defined(OS_WIN)
53 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP
54 #elif defined(OS_ANDROID) || defined(OS_CHROMEOS)
55 CONTENT_SETTING_ASK, // CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER
56 #endif
57 #if defined(OS_ANDROID)
58 CONTENT_SETTING_DEFAULT, // CONTENT_SETTINGS_TYPE_APP_BANNER
59 #endif
61 COMPILE_ASSERT(arraysize(kDefaultSettings) == CONTENT_SETTINGS_NUM_TYPES,
62 default_settings_incorrect_size);
64 } // namespace
66 namespace content_settings {
68 namespace {
70 class DefaultRuleIterator : public RuleIterator {
71 public:
72 explicit DefaultRuleIterator(const base::Value* value) {
73 if (value)
74 value_.reset(value->DeepCopy());
77 virtual bool HasNext() const override {
78 return value_.get() != NULL;
81 virtual Rule Next() override {
82 DCHECK(value_.get());
83 return Rule(ContentSettingsPattern::Wildcard(),
84 ContentSettingsPattern::Wildcard(),
85 value_.release());
88 private:
89 scoped_ptr<base::Value> value_;
92 } // namespace
94 // static
95 void DefaultProvider::RegisterProfilePrefs(
96 user_prefs::PrefRegistrySyncable* registry) {
97 // The registration of the preference prefs::kDefaultContentSettings should
98 // also include the default values for default content settings. This allows
99 // functional tests to get default content settings by reading the preference
100 // prefs::kDefaultContentSettings via pyauto.
101 // TODO(markusheintz): Write pyauto hooks for the content settings map as
102 // content settings should be read from the host content settings map.
103 base::DictionaryValue* default_content_settings = new base::DictionaryValue();
104 registry->RegisterDictionaryPref(
105 prefs::kDefaultContentSettings,
106 default_content_settings,
107 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
110 DefaultProvider::DefaultProvider(PrefService* prefs, bool incognito)
111 : prefs_(prefs),
112 is_incognito_(incognito),
113 updating_preferences_(false) {
114 DCHECK(prefs_);
116 // Read global defaults.
117 ReadDefaultSettings(true);
119 UMA_HISTOGRAM_ENUMERATION(
120 "ContentSettings.DefaultCookiesSetting",
121 ValueToContentSetting(
122 default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()),
123 CONTENT_SETTING_NUM_SETTINGS);
124 UMA_HISTOGRAM_ENUMERATION(
125 "ContentSettings.DefaultImagesSetting",
126 ValueToContentSetting(
127 default_settings_[CONTENT_SETTINGS_TYPE_IMAGES].get()),
128 CONTENT_SETTING_NUM_SETTINGS);
129 UMA_HISTOGRAM_ENUMERATION(
130 "ContentSettings.DefaultJavaScriptSetting",
131 ValueToContentSetting(
132 default_settings_[CONTENT_SETTINGS_TYPE_JAVASCRIPT].get()),
133 CONTENT_SETTING_NUM_SETTINGS);
134 UMA_HISTOGRAM_ENUMERATION(
135 "ContentSettings.DefaultPluginsSetting",
136 ValueToContentSetting(
137 default_settings_[CONTENT_SETTINGS_TYPE_PLUGINS].get()),
138 CONTENT_SETTING_NUM_SETTINGS);
139 UMA_HISTOGRAM_ENUMERATION(
140 "ContentSettings.DefaultPopupsSetting",
141 ValueToContentSetting(
142 default_settings_[CONTENT_SETTINGS_TYPE_POPUPS].get()),
143 CONTENT_SETTING_NUM_SETTINGS);
144 UMA_HISTOGRAM_ENUMERATION(
145 "ContentSettings.DefaultLocationSetting",
146 ValueToContentSetting(
147 default_settings_[CONTENT_SETTINGS_TYPE_GEOLOCATION].get()),
148 CONTENT_SETTING_NUM_SETTINGS);
149 UMA_HISTOGRAM_ENUMERATION(
150 "ContentSettings.DefaultNotificationsSetting",
151 ValueToContentSetting(
152 default_settings_[CONTENT_SETTINGS_TYPE_NOTIFICATIONS].get()),
153 CONTENT_SETTING_NUM_SETTINGS);
154 UMA_HISTOGRAM_ENUMERATION(
155 "ContentSettings.DefaultMouseCursorSetting",
156 ValueToContentSetting(
157 default_settings_[CONTENT_SETTINGS_TYPE_MOUSELOCK].get()),
158 CONTENT_SETTING_NUM_SETTINGS);
159 UMA_HISTOGRAM_ENUMERATION(
160 "ContentSettings.DefaultMediaStreamSetting",
161 ValueToContentSetting(
162 default_settings_[CONTENT_SETTINGS_TYPE_MEDIASTREAM].get()),
163 CONTENT_SETTING_NUM_SETTINGS);
164 UMA_HISTOGRAM_ENUMERATION(
165 "ContentSettings.DefaultMIDISysExSetting",
166 ValueToContentSetting(
167 default_settings_[CONTENT_SETTINGS_TYPE_MIDI_SYSEX].get()),
168 CONTENT_SETTING_NUM_SETTINGS);
169 UMA_HISTOGRAM_ENUMERATION(
170 "ContentSettings.DefaultPushMessagingSetting",
171 ValueToContentSetting(
172 default_settings_[CONTENT_SETTINGS_TYPE_PUSH_MESSAGING].get()),
173 CONTENT_SETTING_NUM_SETTINGS);
175 pref_change_registrar_.Init(prefs_);
176 PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
177 &DefaultProvider::OnPreferenceChanged, base::Unretained(this));
178 pref_change_registrar_.Add(prefs::kDefaultContentSettings, callback);
181 DefaultProvider::~DefaultProvider() {
184 bool DefaultProvider::SetWebsiteSetting(
185 const ContentSettingsPattern& primary_pattern,
186 const ContentSettingsPattern& secondary_pattern,
187 ContentSettingsType content_type,
188 const ResourceIdentifier& resource_identifier,
189 base::Value* in_value) {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
191 DCHECK(prefs_);
193 // Ignore non default settings
194 if (primary_pattern != ContentSettingsPattern::Wildcard() ||
195 secondary_pattern != ContentSettingsPattern::Wildcard()) {
196 return false;
199 // The default settings may not be directly modified for OTR sessions.
200 // Instead, they are synced to the main profile's setting.
201 if (is_incognito_)
202 return false;
204 // Put |in_value| in a scoped pointer to ensure that it gets cleaned up
205 // properly if we don't pass on the ownership.
206 scoped_ptr<base::Value> value(in_value);
208 base::AutoReset<bool> auto_reset(&updating_preferences_, true);
210 // |DefaultProvider| should not send any notifications when holding
211 // |lock_|. |DictionaryPrefUpdate| destructor and
212 // |PrefService::SetInteger()| send out notifications. As a response, the
213 // upper layers may call |GetAllContentSettingRules| which acquires |lock_|
214 // again.
215 DictionaryPrefUpdate update(prefs_, prefs::kDefaultContentSettings);
216 base::DictionaryValue* default_settings_dictionary = update.Get();
217 base::AutoLock lock(lock_);
218 if (value.get() == NULL ||
219 ValueToContentSetting(value.get()) == kDefaultSettings[content_type]) {
220 // If |value| is NULL we need to reset the default setting the the
221 // hardcoded default.
222 default_settings_[content_type].reset(
223 new base::FundamentalValue(kDefaultSettings[content_type]));
225 // Remove the corresponding pref entry since the hardcoded default value
226 // is used.
227 default_settings_dictionary->RemoveWithoutPathExpansion(
228 GetTypeName(content_type), NULL);
229 } else {
230 default_settings_[content_type].reset(value->DeepCopy());
231 // Transfer ownership of |value| to the |default_settings_dictionary|.
232 default_settings_dictionary->SetWithoutPathExpansion(
233 GetTypeName(content_type), value.release());
237 NotifyObservers(ContentSettingsPattern(),
238 ContentSettingsPattern(),
239 content_type,
240 std::string());
242 return true;
245 RuleIterator* DefaultProvider::GetRuleIterator(
246 ContentSettingsType content_type,
247 const ResourceIdentifier& resource_identifier,
248 bool incognito) const {
249 base::AutoLock lock(lock_);
250 if (resource_identifier.empty()) {
251 ValueMap::const_iterator it(default_settings_.find(content_type));
252 if (it != default_settings_.end()) {
253 return new DefaultRuleIterator(it->second.get());
255 NOTREACHED();
257 return new EmptyRuleIterator();
260 void DefaultProvider::ClearAllContentSettingsRules(
261 ContentSettingsType content_type) {
262 // TODO(markusheintz): This method is only called when the
263 // |DesktopNotificationService| calls |ClearAllSettingsForType| method on the
264 // |HostContentSettingsMap|. Don't implement this method yet, otherwise the
265 // default notification settings will be cleared as well.
268 void DefaultProvider::ShutdownOnUIThread() {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270 DCHECK(prefs_);
271 RemoveAllObservers();
272 pref_change_registrar_.RemoveAll();
273 prefs_ = NULL;
276 void DefaultProvider::OnPreferenceChanged(const std::string& name) {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
278 if (updating_preferences_)
279 return;
281 if (name == prefs::kDefaultContentSettings) {
282 ReadDefaultSettings(true);
283 } else {
284 NOTREACHED() << "Unexpected preference observed";
285 return;
288 NotifyObservers(ContentSettingsPattern(),
289 ContentSettingsPattern(),
290 CONTENT_SETTINGS_TYPE_DEFAULT,
291 std::string());
294 void DefaultProvider::ReadDefaultSettings(bool overwrite) {
295 base::AutoLock lock(lock_);
296 const base::DictionaryValue* default_settings_dictionary =
297 prefs_->GetDictionary(prefs::kDefaultContentSettings);
299 if (overwrite)
300 default_settings_.clear();
302 // Careful: The returned value could be NULL if the pref has never been set.
303 if (default_settings_dictionary)
304 GetSettingsFromDictionary(default_settings_dictionary);
306 ForceDefaultsToBeExplicit();
309 void DefaultProvider::ForceDefaultsToBeExplicit() {
310 for (int i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) {
311 ContentSettingsType type = ContentSettingsType(i);
312 if (!default_settings_[type].get() &&
313 kDefaultSettings[i] != CONTENT_SETTING_DEFAULT) {
314 default_settings_[type].reset(
315 new base::FundamentalValue(kDefaultSettings[i]));
320 void DefaultProvider::GetSettingsFromDictionary(
321 const base::DictionaryValue* dictionary) {
322 for (base::DictionaryValue::Iterator i(*dictionary);
323 !i.IsAtEnd(); i.Advance()) {
324 const std::string& content_type(i.key());
325 for (size_t type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
326 if (content_type == GetTypeName(ContentSettingsType(type))) {
327 int int_value = CONTENT_SETTING_DEFAULT;
328 bool is_integer = i.value().GetAsInteger(&int_value);
329 DCHECK(is_integer);
330 default_settings_[ContentSettingsType(type)].reset(
331 new base::FundamentalValue(int_value));
332 break;
336 // Migrate obsolete cookie prompt mode.
337 if (ValueToContentSetting(
338 default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].get()) ==
339 CONTENT_SETTING_ASK) {
340 default_settings_[CONTENT_SETTINGS_TYPE_COOKIES].reset(
341 new base::FundamentalValue(CONTENT_SETTING_BLOCK));
345 } // namespace content_settings