Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: chrome/browser/prefs/pref_metrics_service.cc

Issue 22676002: Add UMA to report Preferences File Corruption (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compile error. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/prefs/pref_metrics_service.h" 5 #include "chrome/browser/prefs/pref_metrics_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/json/json_string_value_serializer.h"
9 #include "base/md5.h"
8 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_registry_simple.h"
9 #include "base/prefs/pref_service.h" 12 #include "base/prefs/pref_service.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/browser_shutdown.h"
15 #include "chrome/browser/extensions/api/music_manager_private/device_id.h"
16 #include "chrome/browser/extensions/extension_prefs.h"
10 #include "chrome/browser/prefs/pref_service_syncable.h" 17 #include "chrome/browser/prefs/pref_service_syncable.h"
18 #include "chrome/browser/prefs/scoped_user_pref_update.h"
11 #include "chrome/browser/prefs/session_startup_pref.h" 19 #include "chrome/browser/prefs/session_startup_pref.h"
12 #include "chrome/browser/prefs/synced_pref_change_registrar.h" 20 #include "chrome/browser/prefs/synced_pref_change_registrar.h"
13 #include "chrome/browser/profiles/incognito_helpers.h" 21 #include "chrome/browser/profiles/incognito_helpers.h"
14 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/pref_names.h" 23 #include "chrome/common/pref_names.h"
16 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h" 24 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h"
17 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 25 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
18 26
19 namespace { 27 namespace {
20 28
21 // Converts a host name into a domain name for easier matching. 29 const int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax;
22 std::string GetDomainFromHost(const std::string& host) { 30
23 return net::registry_controlled_domains::GetDomainAndRegistry( 31 // In order to detect changes to Preferences that happen outside of Chrome, we
24 host, 32 // save selected prefs in local state. When Chrome is started up, we compare
25 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); 33 // the saved values against the values observed in the user's Preferences file.
34 // We add a dictionary of dictionaries to local state to hold the saved values,
35 // grouped by profile. To make the system more resistant to spoofing, each
36 // preference value is hashed with its path and the device id.
37 const char kProfilePreferenceHashes[] = "profile.preference_hashes";
Mattias Nissler (ping if slow) 2013/08/20 12:53:54 This should be in pref_names.{h,cc}
bbudge 2013/08/20 18:17:50 Done. I reworked the comment and moved it in front
38
39 // These preferences must be kept in sync with the TrackedPreference enum in
40 // tools/metrics/histograms/histograms.xml. To add a new preference, append it
41 // to the array and add a corresponding value to the histogram enum.
42 const char* kTrackedPrefs[] = {
43 prefs::kShowHomeButton,
44 prefs::kHomePageIsNewTabPage,
45 prefs::kHomePage,
46 prefs::kRestoreOnStartup,
47 prefs::kURLsToRestoreOnStartup,
48 extensions::ExtensionPrefs::kExtensionsPref,
49 };
50
51 bool BrowserShuttingDown() {
52 return browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID;
26 } 53 }
27 54
28 const int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax;
29
30 } // namespace 55 } // namespace
31 56
32 PrefMetricsService::PrefMetricsService(Profile* profile) 57 PrefMetricsService::PrefMetricsService(Profile* profile)
33 : profile_(profile) { 58 : weak_factory_(this),
59 profile_(profile),
60 prefs_(profile_->GetPrefs()),
61 local_state_(g_browser_process->local_state()),
62 tracked_pref_paths_(kTrackedPrefs),
63 tracked_pref_path_count_(arraysize(kTrackedPrefs)) {
64 // Get the profile name (some browser tests don't set this up, in which
65 // case profile_name_ is the empty string).
66 if (prefs_->FindPreference(prefs::kGoogleServicesUsername))
67 profile_name_ = profile_->GetProfileName();
68
34 RecordLaunchPrefs(); 69 RecordLaunchPrefs();
35 70
71 #if !defined(OS_ANDROID)
72 // We need the machine id to compute pref value hashes. Fetch that, and then
73 // call CheckTrackedPreferences in the callback.
74 extensions::api::DeviceId::GetDeviceId(
75 "PrefMetricsService", // non-empty string to obfuscate the device id.
76 Bind(&PrefMetricsService::GetDeviceIdCallback,
77 weak_factory_.GetWeakPtr()));
78 #else
79 // Android has no GetDeviceId.
80 CheckTrackedPreferences();
81 #endif // !defined(OS_ANDROID)
82
83 InitializePrefObservers();
84
36 PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); 85 PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
37 synced_pref_change_registrar_.reset(new SyncedPrefChangeRegistrar(prefs)); 86 synced_pref_change_registrar_.reset(new SyncedPrefChangeRegistrar(prefs));
38 87
39 RegisterSyncedPrefObservers(); 88 RegisterSyncedPrefObservers();
40 } 89 }
41 90
91 PrefMetricsService::PrefMetricsService(Profile* profile,
92 PrefService* local_state,
93 const std::string& device_id,
94 const char** tracked_pref_paths,
95 int tracked_pref_path_count)
96 : weak_factory_(this),
97 profile_(profile),
98 prefs_(profile->GetPrefs()),
99 local_state_(local_state),
100 device_id_(device_id),
101 tracked_pref_paths_(tracked_pref_paths),
102 tracked_pref_path_count_(tracked_pref_path_count) {
103 CheckTrackedPreferences();
104 InitializePrefObservers();
105 }
106
42 PrefMetricsService::~PrefMetricsService() { 107 PrefMetricsService::~PrefMetricsService() {
43 } 108 }
44 109
45 void PrefMetricsService::RecordLaunchPrefs() { 110 void PrefMetricsService::RecordLaunchPrefs() {
46 PrefService* prefs = profile_->GetPrefs(); 111 bool show_home_button = prefs_->GetBoolean(prefs::kShowHomeButton);
47 bool show_home_button = prefs->GetBoolean(prefs::kShowHomeButton); 112 bool home_page_is_ntp = prefs_->GetBoolean(prefs::kHomePageIsNewTabPage);
48 bool home_page_is_ntp = prefs->GetBoolean(prefs::kHomePageIsNewTabPage);
49 UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button); 113 UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button);
50 if (show_home_button) { 114 if (show_home_button) {
51 UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage", 115 UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage",
52 home_page_is_ntp); 116 home_page_is_ntp);
53 } 117 }
54 int restore_on_startup = prefs->GetInteger(prefs::kRestoreOnStartup); 118 int restore_on_startup = prefs_->GetInteger(prefs::kRestoreOnStartup);
55 UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings", 119 UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings",
56 restore_on_startup, kSessionStartupPrefValueMax); 120 restore_on_startup, kSessionStartupPrefValueMax);
57 if (restore_on_startup == SessionStartupPref::kPrefValueURLs) { 121 if (restore_on_startup == SessionStartupPref::kPrefValueURLs) {
58 const int url_list_size = prefs->GetList( 122 const int url_list_size = prefs_->GetList(
59 prefs::kURLsToRestoreOnStartup)->GetSize(); 123 prefs::kURLsToRestoreOnStartup)->GetSize();
60 UMA_HISTOGRAM_CUSTOM_COUNTS( 124 UMA_HISTOGRAM_CUSTOM_COUNTS(
61 "Settings.StartupPageLoadURLs", url_list_size, 1, 50, 20); 125 "Settings.StartupPageLoadURLs", url_list_size, 1, 50, 20);
62 } 126 }
63 } 127 }
64 128
129 // static
130 void PrefMetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
131 // Register the top level dictionary to map profile names to dictionaries of
132 // tracked preferences.
133 registry->RegisterDictionaryPref(kProfilePreferenceHashes);
134 }
135
65 void PrefMetricsService::RegisterSyncedPrefObservers() { 136 void PrefMetricsService::RegisterSyncedPrefObservers() {
66 LogHistogramValueCallback booleanHandler = base::Bind( 137 LogHistogramValueCallback booleanHandler = base::Bind(
67 &PrefMetricsService::LogBooleanPrefChange, base::Unretained(this)); 138 &PrefMetricsService::LogBooleanPrefChange, base::Unretained(this));
68 139
69 AddPrefObserver(prefs::kShowHomeButton, "ShowHomeButton", booleanHandler); 140 AddPrefObserver(prefs::kShowHomeButton, "ShowHomeButton", booleanHandler);
70 AddPrefObserver(prefs::kHomePageIsNewTabPage, "HomePageIsNewTabPage", 141 AddPrefObserver(prefs::kHomePageIsNewTabPage, "HomePageIsNewTabPage",
71 booleanHandler); 142 booleanHandler);
72 143
73 AddPrefObserver(prefs::kRestoreOnStartup, "StartupPageLoadSettings", 144 AddPrefObserver(prefs::kRestoreOnStartup, "StartupPageLoadSettings",
74 base::Bind(&PrefMetricsService::LogIntegerPrefChange, 145 base::Bind(&PrefMetricsService::LogIntegerPrefChange,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 const ListValue* items = NULL; 203 const ListValue* items = NULL;
133 if (!value->GetAsList(&items)) 204 if (!value->GetAsList(&items))
134 return; 205 return;
135 for (size_t i = 0; i < items->GetSize(); ++i) { 206 for (size_t i = 0; i < items->GetSize(); ++i) {
136 const Value *item_value = NULL; 207 const Value *item_value = NULL;
137 if (items->Get(i, &item_value)) 208 if (items->Get(i, &item_value))
138 item_callback.Run(histogram_name, item_value); 209 item_callback.Run(histogram_name, item_value);
139 } 210 }
140 } 211 }
141 212
213 void PrefMetricsService::GetDeviceIdCallback(const std::string& device_id) {
214 device_id_ = device_id;
215 CheckTrackedPreferences();
216 }
217
218 void PrefMetricsService::CheckTrackedPreferences() {
219 UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesChecked", true);
220
221 const base::DictionaryValue* pref_hash_dicts =
222 local_state_->GetDictionary(kProfilePreferenceHashes);
223
224 // Get the hashed prefs dictionary if it exists. If it doesn't, it will be
225 // created if we set preference values below.
226 const base::DictionaryValue* hashed_prefs = NULL;
227 pref_hash_dicts->GetDictionary(profile_name_, &hashed_prefs);
228 for (int i = 0; i < tracked_pref_path_count_; ++i) {
229 const base::Value* value = prefs_->GetUserPrefValue(tracked_pref_paths_[i]);
230 if (value) {
231 std::string value_hash =
232 GetHashedPrefValue(tracked_pref_paths_[i], value);
233 std::string last_hash;
234 if (hashed_prefs &&
235 hashed_prefs->GetString(tracked_pref_paths_[i], &last_hash)) {
236 if (value_hash != last_hash) {
237 // Record that the preference changed from its last value.
238 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceChanged",
239 i, tracked_pref_path_count_);
240 UpdateTrackedPreference(tracked_pref_paths_[i]);
241 }
242 } else {
243 // Record that we haven't tracked this preference yet, or the hash in
244 // local state was removed.
245 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceInitialized",
246 i, tracked_pref_path_count_);
247 UpdateTrackedPreference(tracked_pref_paths_[i]);
248 }
249 } else {
250 // There is no preference set. Remove any hashed value from local state
251 // and if one was present, record that a pref was removed.
252 if (RemoveTrackedPreference(tracked_pref_paths_[i])) {
253 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceRemoved",
254 i, tracked_pref_path_count_);
255 }
256 }
257 }
258 }
259
260 void PrefMetricsService::UpdateTrackedPreference(const char* path) {
261 // Don't try to change local state during browser shutdown.
262 if (BrowserShuttingDown())
263 return;
264
265 const base::Value* value = prefs_->GetUserPrefValue(path);
266 if (value) {
267 DictionaryPrefUpdate update(local_state_, kProfilePreferenceHashes);
268 base::DictionaryValue* prefs = update.Get();
269 if (prefs) {
270 prefs->SetString(GetHashedPrefPath(path),
271 GetHashedPrefValue(path, value));
272 }
273 } else {
274 RemoveTrackedPreference(path);
275 }
276 }
277
278 bool PrefMetricsService::RemoveTrackedPreference(const char* path) {
279 // Don't try to change local state during browser shutdown.
280 if (BrowserShuttingDown())
281 return false;
282
283 DictionaryPrefUpdate update(local_state_, kProfilePreferenceHashes);
284 base::DictionaryValue* prefs = update.Get();
285 if (prefs)
286 return prefs->Remove(GetHashedPrefPath(path), NULL);
287
288 return false;
289 }
290
291 std::string PrefMetricsService::GetHashedPrefPath(const char* path) {
292 std::string hash_pref_path(profile_name_);
293 hash_pref_path.append(".");
294 hash_pref_path.append(path);
295 return hash_pref_path;
296 }
297
298 std::string PrefMetricsService::GetHashedPrefValue(
299 const char* path,
300 const base::Value* value) {
301 DCHECK(value);
302 std::string value_string;
303 JSONStringValueSerializer serializer(&value_string);
304 serializer.Serialize(*value);
305
306 base::MD5Context context;
307 base::MD5Init(&context);
308 base::MD5Update(&context, device_id_); // Salt with device id.
309 base::MD5Update(&context, path); // Salt with pref path.
310 base::MD5Update(&context, value_string);
311 base::MD5Digest digest;
312 base::MD5Final(&digest, &context);
313 return base::MD5DigestToBase16(digest);
314 }
315
316 void PrefMetricsService::InitializePrefObservers() {
317 // It's tricky to save preference value hashes on browser shutdown. Instead,
318 // register for notifications when tracked preferences change so we can update
319 // the hashes in local state.
320 pref_registrar_.Init(prefs_);
321 for (int i = 0; i < tracked_pref_path_count_; ++i) {
322 pref_registrar_.Add(
323 tracked_pref_paths_[i],
324 base::Bind(&PrefMetricsService::UpdateTrackedPreference,
325 weak_factory_.GetWeakPtr(),
326 tracked_pref_paths_[i]));
327 }
328 }
329
142 // static 330 // static
143 PrefMetricsService::Factory* PrefMetricsService::Factory::GetInstance() { 331 PrefMetricsService::Factory* PrefMetricsService::Factory::GetInstance() {
144 return Singleton<PrefMetricsService::Factory>::get(); 332 return Singleton<PrefMetricsService::Factory>::get();
145 } 333 }
146 334
147 // static 335 // static
148 PrefMetricsService* PrefMetricsService::Factory::GetForProfile( 336 PrefMetricsService* PrefMetricsService::Factory::GetForProfile(
149 Profile* profile) { 337 Profile* profile) {
150 return static_cast<PrefMetricsService*>( 338 return static_cast<PrefMetricsService*>(
151 GetInstance()->GetServiceForBrowserContext(profile, true)); 339 GetInstance()->GetServiceForBrowserContext(profile, true));
(...skipping 19 matching lines...) Expand all
171 } 359 }
172 360
173 bool PrefMetricsService::Factory::ServiceIsNULLWhileTesting() const { 361 bool PrefMetricsService::Factory::ServiceIsNULLWhileTesting() const {
174 return false; 362 return false;
175 } 363 }
176 364
177 content::BrowserContext* PrefMetricsService::Factory::GetBrowserContextToUse( 365 content::BrowserContext* PrefMetricsService::Factory::GetBrowserContextToUse(
178 content::BrowserContext* context) const { 366 content::BrowserContext* context) const {
179 return chrome::GetBrowserContextRedirectedInIncognito(context); 367 return chrome::GetBrowserContextRedirectedInIncognito(context);
180 } 368 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698