OLD | NEW |
| (Empty) |
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/content_settings/content_settings_pref_provider.h" | |
6 | |
7 #include <map> | |
8 #include <string> | |
9 #include <utility> | |
10 | |
11 #include "base/auto_reset.h" | |
12 #include "base/bind.h" | |
13 #include "base/command_line.h" | |
14 #include "base/memory/scoped_ptr.h" | |
15 #include "base/metrics/histogram.h" | |
16 #include "base/prefs/pref_service.h" | |
17 #include "base/prefs/scoped_user_pref_update.h" | |
18 #include "base/strings/string_split.h" | |
19 #include "base/time/clock.h" | |
20 #include "base/time/default_clock.h" | |
21 #include "chrome/browser/content_settings/content_settings_utils.h" | |
22 #include "chrome/browser/content_settings/host_content_settings_map.h" | |
23 #include "chrome/common/pref_names.h" | |
24 #include "components/content_settings/core/browser/content_settings_rule.h" | |
25 #include "components/content_settings/core/common/content_settings.h" | |
26 #include "components/content_settings/core/common/content_settings_pattern.h" | |
27 #include "components/pref_registry/pref_registry_syncable.h" | |
28 #include "url/gurl.h" | |
29 | |
30 namespace { | |
31 | |
32 typedef std::pair<std::string, std::string> StringPair; | |
33 typedef std::map<std::string, std::string> StringMap; | |
34 | |
35 const char kPerPluginPrefName[] = "per_plugin"; | |
36 const char kAudioKey[] = "audio"; | |
37 const char kVideoKey[] = "video"; | |
38 const char kLastUsed[] = "last_used"; | |
39 | |
40 ContentSetting FixObsoleteCookiePromptMode(ContentSettingsType content_type, | |
41 ContentSetting setting) { | |
42 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES && | |
43 setting == CONTENT_SETTING_ASK) { | |
44 return CONTENT_SETTING_BLOCK; | |
45 } | |
46 return setting; | |
47 } | |
48 | |
49 // If the given content type supports resource identifiers in user preferences, | |
50 // returns true and sets |pref_key| to the key in the content settings | |
51 // dictionary under which per-resource content settings are stored. | |
52 // Otherwise, returns false. | |
53 bool GetResourceTypeName(ContentSettingsType content_type, | |
54 std::string* pref_key) { | |
55 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) { | |
56 *pref_key = kPerPluginPrefName; | |
57 return true; | |
58 } | |
59 return false; | |
60 } | |
61 | |
62 } // namespace | |
63 | |
64 namespace content_settings { | |
65 | |
66 // //////////////////////////////////////////////////////////////////////////// | |
67 // PrefProvider: | |
68 // | |
69 | |
70 // static | |
71 void PrefProvider::RegisterProfilePrefs( | |
72 user_prefs::PrefRegistrySyncable* registry) { | |
73 registry->RegisterIntegerPref( | |
74 prefs::kContentSettingsVersion, | |
75 ContentSettingsPattern::kContentSettingsPatternVersion, | |
76 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); | |
77 registry->RegisterDictionaryPref( | |
78 prefs::kContentSettingsPatternPairs, | |
79 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); | |
80 } | |
81 | |
82 PrefProvider::PrefProvider(PrefService* prefs, bool incognito) | |
83 : prefs_(prefs), | |
84 clock_(new base::DefaultClock()), | |
85 is_incognito_(incognito), | |
86 updating_preferences_(false) { | |
87 DCHECK(prefs_); | |
88 // Verify preferences version. | |
89 if (!prefs_->HasPrefPath(prefs::kContentSettingsVersion)) { | |
90 prefs_->SetInteger(prefs::kContentSettingsVersion, | |
91 ContentSettingsPattern::kContentSettingsPatternVersion); | |
92 } | |
93 if (prefs_->GetInteger(prefs::kContentSettingsVersion) > | |
94 ContentSettingsPattern::kContentSettingsPatternVersion) { | |
95 return; | |
96 } | |
97 | |
98 // Read content settings exceptions. | |
99 ReadContentSettingsFromPref(false); | |
100 | |
101 if (!is_incognito_) { | |
102 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfExceptions", | |
103 value_map_.size()); | |
104 } | |
105 | |
106 // Migrate the obsolete media content setting exceptions to the new settings. | |
107 // This needs to be done after ReadContentSettingsFromPref(). | |
108 if (!is_incognito_) | |
109 MigrateObsoleteMediaContentSetting(); | |
110 | |
111 pref_change_registrar_.Init(prefs_); | |
112 pref_change_registrar_.Add( | |
113 prefs::kContentSettingsPatternPairs, | |
114 base::Bind(&PrefProvider::OnContentSettingsPatternPairsChanged, | |
115 base::Unretained(this))); | |
116 } | |
117 | |
118 bool PrefProvider::SetWebsiteSetting( | |
119 const ContentSettingsPattern& primary_pattern, | |
120 const ContentSettingsPattern& secondary_pattern, | |
121 ContentSettingsType content_type, | |
122 const ResourceIdentifier& resource_identifier, | |
123 base::Value* in_value) { | |
124 DCHECK(CalledOnValidThread()); | |
125 DCHECK(prefs_); | |
126 // Default settings are set using a wildcard pattern for both | |
127 // |primary_pattern| and |secondary_pattern|. Don't store default settings in | |
128 // the |PrefProvider|. The |PrefProvider| handles settings for specific | |
129 // sites/origins defined by the |primary_pattern| and the |secondary_pattern|. | |
130 // Default settings are handled by the |DefaultProvider|. | |
131 if (primary_pattern == ContentSettingsPattern::Wildcard() && | |
132 secondary_pattern == ContentSettingsPattern::Wildcard() && | |
133 resource_identifier.empty()) { | |
134 return false; | |
135 } | |
136 | |
137 // At this point take the ownership of the |in_value|. | |
138 scoped_ptr<base::Value> value(in_value); | |
139 // Update in memory value map. | |
140 OriginIdentifierValueMap* map_to_modify = &incognito_value_map_; | |
141 if (!is_incognito_) | |
142 map_to_modify = &value_map_; | |
143 | |
144 { | |
145 base::AutoLock auto_lock(lock_); | |
146 if (value.get()) { | |
147 map_to_modify->SetValue( | |
148 primary_pattern, | |
149 secondary_pattern, | |
150 content_type, | |
151 resource_identifier, | |
152 value->DeepCopy()); | |
153 } else { | |
154 map_to_modify->DeleteValue( | |
155 primary_pattern, | |
156 secondary_pattern, | |
157 content_type, | |
158 resource_identifier); | |
159 } | |
160 } | |
161 // Update the content settings preference. | |
162 if (!is_incognito_) { | |
163 UpdatePref(primary_pattern, | |
164 secondary_pattern, | |
165 content_type, | |
166 resource_identifier, | |
167 value.get()); | |
168 } | |
169 | |
170 NotifyObservers( | |
171 primary_pattern, secondary_pattern, content_type, resource_identifier); | |
172 | |
173 return true; | |
174 } | |
175 | |
176 void PrefProvider::ClearAllContentSettingsRules( | |
177 ContentSettingsType content_type) { | |
178 DCHECK(CalledOnValidThread()); | |
179 DCHECK(prefs_); | |
180 | |
181 OriginIdentifierValueMap* map_to_modify = &incognito_value_map_; | |
182 if (!is_incognito_) | |
183 map_to_modify = &value_map_; | |
184 | |
185 std::vector<Rule> rules_to_delete; | |
186 { | |
187 base::AutoLock auto_lock(lock_); | |
188 scoped_ptr<RuleIterator> rule_iterator( | |
189 map_to_modify->GetRuleIterator(content_type, std::string(), NULL)); | |
190 // Copy the rules; we cannot call |UpdatePref| while holding |lock_|. | |
191 while (rule_iterator->HasNext()) | |
192 rules_to_delete.push_back(rule_iterator->Next()); | |
193 | |
194 map_to_modify->DeleteValues(content_type, std::string()); | |
195 } | |
196 | |
197 for (std::vector<Rule>::const_iterator it = rules_to_delete.begin(); | |
198 it != rules_to_delete.end(); ++it) { | |
199 UpdatePref(it->primary_pattern, | |
200 it->secondary_pattern, | |
201 content_type, | |
202 std::string(), | |
203 NULL); | |
204 } | |
205 NotifyObservers(ContentSettingsPattern(), | |
206 ContentSettingsPattern(), | |
207 content_type, | |
208 std::string()); | |
209 } | |
210 | |
211 PrefProvider::~PrefProvider() { | |
212 DCHECK(!prefs_); | |
213 } | |
214 | |
215 RuleIterator* PrefProvider::GetRuleIterator( | |
216 ContentSettingsType content_type, | |
217 const ResourceIdentifier& resource_identifier, | |
218 bool incognito) const { | |
219 if (incognito) | |
220 return incognito_value_map_.GetRuleIterator(content_type, | |
221 resource_identifier, | |
222 &lock_); | |
223 return value_map_.GetRuleIterator(content_type, resource_identifier, &lock_); | |
224 } | |
225 | |
226 // //////////////////////////////////////////////////////////////////////////// | |
227 // Private | |
228 | |
229 void PrefProvider::UpdatePref( | |
230 const ContentSettingsPattern& primary_pattern, | |
231 const ContentSettingsPattern& secondary_pattern, | |
232 ContentSettingsType content_type, | |
233 const ResourceIdentifier& resource_identifier, | |
234 const base::Value* value) { | |
235 // Ensure that |lock_| is not held by this thread, since this function will | |
236 // send out notifications (by |~DictionaryPrefUpdate|). | |
237 AssertLockNotHeld(); | |
238 | |
239 base::AutoReset<bool> auto_reset(&updating_preferences_, true); | |
240 { | |
241 DictionaryPrefUpdate update(prefs_, | |
242 prefs::kContentSettingsPatternPairs); | |
243 base::DictionaryValue* pattern_pairs_settings = update.Get(); | |
244 | |
245 // Get settings dictionary for the given patterns. | |
246 std::string pattern_str(CreatePatternString(primary_pattern, | |
247 secondary_pattern)); | |
248 base::DictionaryValue* settings_dictionary = NULL; | |
249 bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion( | |
250 pattern_str, &settings_dictionary); | |
251 | |
252 if (!found && value) { | |
253 settings_dictionary = new base::DictionaryValue; | |
254 pattern_pairs_settings->SetWithoutPathExpansion( | |
255 pattern_str, settings_dictionary); | |
256 } | |
257 | |
258 if (settings_dictionary) { | |
259 std::string res_dictionary_path; | |
260 if (GetResourceTypeName(content_type, &res_dictionary_path) && | |
261 !resource_identifier.empty()) { | |
262 base::DictionaryValue* resource_dictionary = NULL; | |
263 found = settings_dictionary->GetDictionary( | |
264 res_dictionary_path, &resource_dictionary); | |
265 if (!found) { | |
266 if (value == NULL) | |
267 return; // Nothing to remove. Exit early. | |
268 resource_dictionary = new base::DictionaryValue; | |
269 settings_dictionary->Set(res_dictionary_path, resource_dictionary); | |
270 } | |
271 // Update resource dictionary. | |
272 if (value == NULL) { | |
273 resource_dictionary->RemoveWithoutPathExpansion(resource_identifier, | |
274 NULL); | |
275 if (resource_dictionary->empty()) { | |
276 settings_dictionary->RemoveWithoutPathExpansion( | |
277 res_dictionary_path, NULL); | |
278 } | |
279 } else { | |
280 resource_dictionary->SetWithoutPathExpansion( | |
281 resource_identifier, value->DeepCopy()); | |
282 } | |
283 } else { | |
284 // Update settings dictionary. | |
285 std::string setting_path = GetTypeName(content_type); | |
286 if (value == NULL) { | |
287 settings_dictionary->RemoveWithoutPathExpansion(setting_path, | |
288 NULL); | |
289 settings_dictionary->RemoveWithoutPathExpansion(kLastUsed, NULL); | |
290 } else { | |
291 settings_dictionary->SetWithoutPathExpansion( | |
292 setting_path, value->DeepCopy()); | |
293 } | |
294 } | |
295 // Remove the settings dictionary if it is empty. | |
296 if (settings_dictionary->empty()) { | |
297 pattern_pairs_settings->RemoveWithoutPathExpansion( | |
298 pattern_str, NULL); | |
299 } | |
300 } | |
301 } | |
302 } | |
303 | |
304 | |
305 void PrefProvider::MigrateObsoleteMediaContentSetting() { | |
306 std::vector<Rule> rules_to_delete; | |
307 { | |
308 scoped_ptr<RuleIterator> rule_iterator(GetRuleIterator( | |
309 CONTENT_SETTINGS_TYPE_MEDIASTREAM, std::string(), false)); | |
310 while (rule_iterator->HasNext()) { | |
311 // Skip default setting and rules without a value. | |
312 const content_settings::Rule& rule = rule_iterator->Next(); | |
313 DCHECK(rule.primary_pattern != ContentSettingsPattern::Wildcard()); | |
314 if (!rule.value.get()) | |
315 continue; | |
316 rules_to_delete.push_back(rule); | |
317 } | |
318 } | |
319 | |
320 for (std::vector<Rule>::const_iterator it = rules_to_delete.begin(); | |
321 it != rules_to_delete.end(); ++it) { | |
322 const base::DictionaryValue* value_dict = NULL; | |
323 if (!it->value->GetAsDictionary(&value_dict) || value_dict->empty()) | |
324 return; | |
325 | |
326 std::string audio_device, video_device; | |
327 value_dict->GetString(kAudioKey, &audio_device); | |
328 value_dict->GetString(kVideoKey, &video_device); | |
329 // Add the exception to the new microphone content setting. | |
330 if (!audio_device.empty()) { | |
331 SetWebsiteSetting(it->primary_pattern, | |
332 it->secondary_pattern, | |
333 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, | |
334 std::string(), | |
335 new base::FundamentalValue(CONTENT_SETTING_ALLOW)); | |
336 } | |
337 // Add the exception to the new camera content setting. | |
338 if (!video_device.empty()) { | |
339 SetWebsiteSetting(it->primary_pattern, | |
340 it->secondary_pattern, | |
341 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, | |
342 std::string(), | |
343 new base::FundamentalValue(CONTENT_SETTING_ALLOW)); | |
344 } | |
345 | |
346 // Remove the old exception in CONTENT_SETTINGS_TYPE_MEDIASTREAM. | |
347 SetWebsiteSetting(it->primary_pattern, | |
348 it->secondary_pattern, | |
349 CONTENT_SETTINGS_TYPE_MEDIASTREAM, | |
350 std::string(), | |
351 NULL); | |
352 } | |
353 } | |
354 | |
355 void PrefProvider::ReadContentSettingsFromPref(bool overwrite) { | |
356 // |DictionaryPrefUpdate| sends out notifications when destructed. This | |
357 // construction order ensures |AutoLock| gets destroyed first and |lock_| is | |
358 // not held when the notifications are sent. Also, |auto_reset| must be still | |
359 // valid when the notifications are sent, so that |Observe| skips the | |
360 // notification. | |
361 base::AutoReset<bool> auto_reset(&updating_preferences_, true); | |
362 DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs); | |
363 base::AutoLock auto_lock(lock_); | |
364 | |
365 const base::DictionaryValue* all_settings_dictionary = | |
366 prefs_->GetDictionary(prefs::kContentSettingsPatternPairs); | |
367 | |
368 if (overwrite) | |
369 value_map_.clear(); | |
370 | |
371 // Careful: The returned value could be NULL if the pref has never been set. | |
372 if (!all_settings_dictionary) | |
373 return; | |
374 | |
375 base::DictionaryValue* mutable_settings; | |
376 scoped_ptr<base::DictionaryValue> mutable_settings_scope; | |
377 | |
378 if (!is_incognito_) { | |
379 mutable_settings = update.Get(); | |
380 } else { | |
381 // Create copy as we do not want to persist anything in OTR prefs. | |
382 mutable_settings = all_settings_dictionary->DeepCopy(); | |
383 mutable_settings_scope.reset(mutable_settings); | |
384 } | |
385 // Convert all Unicode patterns into punycode form, then read. | |
386 CanonicalizeContentSettingsExceptions(mutable_settings); | |
387 | |
388 size_t cookies_block_exception_count = 0; | |
389 size_t cookies_allow_exception_count = 0; | |
390 size_t cookies_session_only_exception_count = 0; | |
391 for (base::DictionaryValue::Iterator i(*mutable_settings); !i.IsAtEnd(); | |
392 i.Advance()) { | |
393 const std::string& pattern_str(i.key()); | |
394 std::pair<ContentSettingsPattern, ContentSettingsPattern> pattern_pair = | |
395 ParsePatternString(pattern_str); | |
396 if (!pattern_pair.first.IsValid() || | |
397 !pattern_pair.second.IsValid()) { | |
398 // TODO: Change this to DFATAL when crbug.com/132659 is fixed. | |
399 LOG(ERROR) << "Invalid pattern strings: " << pattern_str; | |
400 continue; | |
401 } | |
402 | |
403 // Get settings dictionary for the current pattern string, and read | |
404 // settings from the dictionary. | |
405 const base::DictionaryValue* settings_dictionary = NULL; | |
406 bool is_dictionary = i.value().GetAsDictionary(&settings_dictionary); | |
407 DCHECK(is_dictionary); | |
408 | |
409 for (size_t i = 0; i < CONTENT_SETTINGS_NUM_TYPES; ++i) { | |
410 ContentSettingsType content_type = static_cast<ContentSettingsType>(i); | |
411 | |
412 std::string res_dictionary_path; | |
413 if (GetResourceTypeName(content_type, &res_dictionary_path)) { | |
414 const base::DictionaryValue* resource_dictionary = NULL; | |
415 if (settings_dictionary->GetDictionary( | |
416 res_dictionary_path, &resource_dictionary)) { | |
417 for (base::DictionaryValue::Iterator j(*resource_dictionary); | |
418 !j.IsAtEnd(); | |
419 j.Advance()) { | |
420 const std::string& resource_identifier(j.key()); | |
421 int setting = CONTENT_SETTING_DEFAULT; | |
422 bool is_integer = j.value().GetAsInteger(&setting); | |
423 DCHECK(is_integer); | |
424 DCHECK_NE(CONTENT_SETTING_DEFAULT, setting); | |
425 value_map_.SetValue(pattern_pair.first, | |
426 pattern_pair.second, | |
427 content_type, | |
428 resource_identifier, | |
429 new base::FundamentalValue(setting)); | |
430 } | |
431 } | |
432 } | |
433 base::Value* value = NULL; | |
434 if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) { | |
435 const base::DictionaryValue* setting = NULL; | |
436 // TODO(xians): Handle the non-dictionary types. | |
437 if (settings_dictionary->GetDictionaryWithoutPathExpansion( | |
438 GetTypeName(ContentSettingsType(i)), &setting)) { | |
439 DCHECK(!setting->empty()); | |
440 value = setting->DeepCopy(); | |
441 } | |
442 } else { | |
443 int setting = CONTENT_SETTING_DEFAULT; | |
444 if (settings_dictionary->GetIntegerWithoutPathExpansion( | |
445 GetTypeName(ContentSettingsType(i)), &setting)) { | |
446 DCHECK_NE(CONTENT_SETTING_DEFAULT, setting); | |
447 setting = FixObsoleteCookiePromptMode(content_type, | |
448 ContentSetting(setting)); | |
449 value = new base::FundamentalValue(setting); | |
450 } | |
451 } | |
452 | |
453 // |value_map_| will take the ownership of |value|. | |
454 if (value != NULL) { | |
455 value_map_.SetValue(pattern_pair.first, | |
456 pattern_pair.second, | |
457 content_type, | |
458 ResourceIdentifier(), | |
459 value); | |
460 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) { | |
461 ContentSetting s = ValueToContentSetting(value); | |
462 switch (s) { | |
463 case CONTENT_SETTING_ALLOW : | |
464 ++cookies_allow_exception_count; | |
465 break; | |
466 case CONTENT_SETTING_BLOCK : | |
467 ++cookies_block_exception_count; | |
468 break; | |
469 case CONTENT_SETTING_SESSION_ONLY : | |
470 ++cookies_session_only_exception_count; | |
471 break; | |
472 default: | |
473 NOTREACHED(); | |
474 break; | |
475 } | |
476 } | |
477 } | |
478 } | |
479 } | |
480 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfBlockCookiesExceptions", | |
481 cookies_block_exception_count); | |
482 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfAllowCookiesExceptions", | |
483 cookies_allow_exception_count); | |
484 UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfSessionOnlyCookiesExceptions", | |
485 cookies_session_only_exception_count); | |
486 } | |
487 | |
488 void PrefProvider::OnContentSettingsPatternPairsChanged() { | |
489 DCHECK(CalledOnValidThread()); | |
490 | |
491 if (updating_preferences_) | |
492 return; | |
493 | |
494 ReadContentSettingsFromPref(true); | |
495 | |
496 NotifyObservers(ContentSettingsPattern(), | |
497 ContentSettingsPattern(), | |
498 CONTENT_SETTINGS_TYPE_DEFAULT, | |
499 std::string()); | |
500 } | |
501 | |
502 // static | |
503 void PrefProvider::CanonicalizeContentSettingsExceptions( | |
504 base::DictionaryValue* all_settings_dictionary) { | |
505 DCHECK(all_settings_dictionary); | |
506 | |
507 std::vector<std::string> remove_items; | |
508 base::StringPairs move_items; | |
509 for (base::DictionaryValue::Iterator i(*all_settings_dictionary); | |
510 !i.IsAtEnd(); | |
511 i.Advance()) { | |
512 const std::string& pattern_str(i.key()); | |
513 std::pair<ContentSettingsPattern, ContentSettingsPattern> pattern_pair = | |
514 ParsePatternString(pattern_str); | |
515 if (!pattern_pair.first.IsValid() || | |
516 !pattern_pair.second.IsValid()) { | |
517 LOG(ERROR) << "Invalid pattern strings: " << pattern_str; | |
518 continue; | |
519 } | |
520 | |
521 const std::string canonicalized_pattern_str = CreatePatternString( | |
522 pattern_pair.first, pattern_pair.second); | |
523 | |
524 if (canonicalized_pattern_str.empty() || | |
525 canonicalized_pattern_str == pattern_str) { | |
526 continue; | |
527 } | |
528 | |
529 // Clear old pattern if prefs already have canonicalized pattern. | |
530 const base::DictionaryValue* new_pattern_settings_dictionary = NULL; | |
531 if (all_settings_dictionary->GetDictionaryWithoutPathExpansion( | |
532 canonicalized_pattern_str, &new_pattern_settings_dictionary)) { | |
533 remove_items.push_back(pattern_str); | |
534 continue; | |
535 } | |
536 | |
537 // Move old pattern to canonicalized pattern. | |
538 const base::DictionaryValue* old_pattern_settings_dictionary = NULL; | |
539 if (i.value().GetAsDictionary(&old_pattern_settings_dictionary)) { | |
540 move_items.push_back( | |
541 std::make_pair(pattern_str, canonicalized_pattern_str)); | |
542 } | |
543 } | |
544 | |
545 for (size_t i = 0; i < remove_items.size(); ++i) { | |
546 all_settings_dictionary->RemoveWithoutPathExpansion(remove_items[i], NULL); | |
547 } | |
548 | |
549 for (size_t i = 0; i < move_items.size(); ++i) { | |
550 scoped_ptr<base::Value> pattern_settings_dictionary; | |
551 all_settings_dictionary->RemoveWithoutPathExpansion( | |
552 move_items[i].first, &pattern_settings_dictionary); | |
553 all_settings_dictionary->SetWithoutPathExpansion( | |
554 move_items[i].second, pattern_settings_dictionary.release()); | |
555 } | |
556 } | |
557 | |
558 void PrefProvider::ShutdownOnUIThread() { | |
559 DCHECK(CalledOnValidThread()); | |
560 DCHECK(prefs_); | |
561 RemoveAllObservers(); | |
562 pref_change_registrar_.RemoveAll(); | |
563 prefs_ = NULL; | |
564 } | |
565 | |
566 void PrefProvider::UpdateLastUsage( | |
567 const ContentSettingsPattern& primary_pattern, | |
568 const ContentSettingsPattern& secondary_pattern, | |
569 ContentSettingsType content_type) { | |
570 // Don't write if in incognito. | |
571 if (is_incognito_) { | |
572 return; | |
573 } | |
574 | |
575 // Ensure that |lock_| is not held by this thread, since this function will | |
576 // send out notifications (by |~DictionaryPrefUpdate|). | |
577 AssertLockNotHeld(); | |
578 | |
579 base::AutoReset<bool> auto_reset(&updating_preferences_, true); | |
580 { | |
581 DictionaryPrefUpdate update(prefs_, prefs::kContentSettingsPatternPairs); | |
582 base::DictionaryValue* pattern_pairs_settings = update.Get(); | |
583 | |
584 std::string pattern_str( | |
585 CreatePatternString(primary_pattern, secondary_pattern)); | |
586 base::DictionaryValue* settings_dictionary = NULL; | |
587 bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion( | |
588 pattern_str, &settings_dictionary); | |
589 | |
590 if (!found) { | |
591 settings_dictionary = new base::DictionaryValue; | |
592 pattern_pairs_settings->SetWithoutPathExpansion(pattern_str, | |
593 settings_dictionary); | |
594 } | |
595 | |
596 base::DictionaryValue* last_used_dictionary = NULL; | |
597 found = settings_dictionary->GetDictionaryWithoutPathExpansion( | |
598 kLastUsed, &last_used_dictionary); | |
599 | |
600 if (!found) { | |
601 last_used_dictionary = new base::DictionaryValue; | |
602 settings_dictionary->SetWithoutPathExpansion(kLastUsed, | |
603 last_used_dictionary); | |
604 } | |
605 | |
606 std::string settings_path = GetTypeName(content_type); | |
607 last_used_dictionary->Set( | |
608 settings_path, new base::FundamentalValue(clock_->Now().ToDoubleT())); | |
609 } | |
610 } | |
611 | |
612 base::Time PrefProvider::GetLastUsage( | |
613 const ContentSettingsPattern& primary_pattern, | |
614 const ContentSettingsPattern& secondary_pattern, | |
615 ContentSettingsType content_type) { | |
616 const base::DictionaryValue* pattern_pairs_settings = | |
617 prefs_->GetDictionary(prefs::kContentSettingsPatternPairs); | |
618 std::string pattern_str( | |
619 CreatePatternString(primary_pattern, secondary_pattern)); | |
620 | |
621 const base::DictionaryValue* settings_dictionary = NULL; | |
622 bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion( | |
623 pattern_str, &settings_dictionary); | |
624 | |
625 if (!found) | |
626 return base::Time(); | |
627 | |
628 const base::DictionaryValue* last_used_dictionary = NULL; | |
629 found = settings_dictionary->GetDictionaryWithoutPathExpansion( | |
630 kLastUsed, &last_used_dictionary); | |
631 | |
632 if (!found) | |
633 return base::Time(); | |
634 | |
635 double last_used_time; | |
636 found = last_used_dictionary->GetDoubleWithoutPathExpansion( | |
637 GetTypeName(content_type), &last_used_time); | |
638 | |
639 if (!found) | |
640 return base::Time(); | |
641 | |
642 return base::Time::FromDoubleT(last_used_time); | |
643 } | |
644 | |
645 void PrefProvider::AssertLockNotHeld() const { | |
646 #if !defined(NDEBUG) | |
647 // |Lock::Acquire()| will assert if the lock is held by this thread. | |
648 lock_.Acquire(); | |
649 lock_.Release(); | |
650 #endif | |
651 } | |
652 | |
653 void PrefProvider::SetClockForTesting(scoped_ptr<base::Clock> clock) { | |
654 clock_ = clock.Pass(); | |
655 } | |
656 | |
657 } // namespace content_settings | |
OLD | NEW |