Index: trunk/src/chrome/browser/prefs/pref_metrics_service.cc |
=================================================================== |
--- trunk/src/chrome/browser/prefs/pref_metrics_service.cc (revision 221965) |
+++ trunk/src/chrome/browser/prefs/pref_metrics_service.cc (working copy) |
@@ -5,119 +5,48 @@ |
#include "chrome/browser/prefs/pref_metrics_service.h" |
#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/json/json_string_value_serializer.h" |
#include "base/metrics/histogram.h" |
-#include "base/prefs/pref_registry_simple.h" |
#include "base/prefs/pref_service.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/browser_shutdown.h" |
-// Accessing the Device ID API here is a layering violation. |
-// TODO(bbudge) Move the API so it's usable here. |
-// http://crbug.com/276485 |
-#include "chrome/browser/extensions/api/music_manager_private/device_id.h" |
-#include "chrome/browser/extensions/extension_prefs.h" |
#include "chrome/browser/prefs/pref_service_syncable.h" |
-#include "chrome/browser/prefs/scoped_user_pref_update.h" |
#include "chrome/browser/prefs/session_startup_pref.h" |
#include "chrome/browser/prefs/synced_pref_change_registrar.h" |
#include "chrome/browser/profiles/incognito_helpers.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/search_engines/template_url_prepopulate_data.h" |
-#include "chrome/common/chrome_switches.h" |
#include "chrome/common/pref_names.h" |
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" |
-#include "crypto/hmac.h" |
-#include "grit/browser_resources.h" |
#include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
-#include "ui/base/resource/resource_bundle.h" |
namespace { |
+// Converts a host name into a domain name for easier matching. |
+std::string GetDomainFromHost(const std::string& host) { |
+ return net::registry_controlled_domains::GetDomainAndRegistry( |
+ host, |
+ net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); |
+} |
+ |
const int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax; |
-// These preferences must be kept in sync with the TrackedPreference enum in |
-// tools/metrics/histograms/histograms.xml. To add a new preference, append it |
-// to the array and add a corresponding value to the histogram enum. |
-const char* kTrackedPrefs[] = { |
- prefs::kShowHomeButton, |
- prefs::kHomePageIsNewTabPage, |
- prefs::kHomePage, |
- prefs::kRestoreOnStartup, |
- prefs::kURLsToRestoreOnStartup, |
- prefs::kExtensionsPref, |
- prefs::kGoogleServicesLastUsername, |
- prefs::kSearchProviderOverrides, |
- prefs::kDefaultSearchProviderSearchURL, |
- prefs::kDefaultSearchProviderKeyword, |
- prefs::kDefaultSearchProviderName, |
-#if !defined(OS_ANDROID) |
- prefs::kPinnedTabs, |
-#endif |
-}; |
- |
-static const size_t kSHA256DigestSize = 32; |
- |
} // namespace |
PrefMetricsService::PrefMetricsService(Profile* profile) |
- : profile_(profile), |
- prefs_(profile_->GetPrefs()), |
- local_state_(g_browser_process->local_state()), |
- profile_name_(profile_->GetPath().AsUTF8Unsafe()), |
- tracked_pref_paths_(kTrackedPrefs), |
- tracked_pref_path_count_(arraysize(kTrackedPrefs)), |
- checked_tracked_prefs_(false), |
- weak_factory_(this) { |
- pref_hash_seed_ = ResourceBundle::GetSharedInstance().GetRawDataResource( |
- IDR_PREF_HASH_SEED_BIN).as_string(); |
- |
+ : profile_(profile) { |
RecordLaunchPrefs(); |
PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); |
synced_pref_change_registrar_.reset(new SyncedPrefChangeRegistrar(prefs)); |
RegisterSyncedPrefObservers(); |
- |
- // The following code might cause callbacks into this instance before we exit |
- // the constructor. This instance should be initialized at this point. |
- |
- // Android has no GetDeviceId. |
-#if !defined(OS_ANDROID) |
- // We need the machine id to compute pref value hashes. Fetch that, and then |
- // call CheckTrackedPreferences in the callback. |
- extensions::api::DeviceId::GetDeviceId( |
- "PrefMetricsService", // non-empty string to obfuscate the device id. |
- Bind(&PrefMetricsService::GetDeviceIdCallback, |
- weak_factory_.GetWeakPtr())); |
-#endif // !defined(OS_ANDROID) |
} |
-// For unit testing only. |
-PrefMetricsService::PrefMetricsService(Profile* profile, |
- PrefService* local_state, |
- const std::string& device_id, |
- const char** tracked_pref_paths, |
- int tracked_pref_path_count) |
- : profile_(profile), |
- prefs_(profile->GetPrefs()), |
- local_state_(local_state), |
- pref_hash_seed_(kSHA256DigestSize, 0), |
- device_id_(device_id), |
- tracked_pref_paths_(tracked_pref_paths), |
- tracked_pref_path_count_(tracked_pref_path_count), |
- checked_tracked_prefs_(false), |
- weak_factory_(this) { |
- CheckTrackedPreferences(); |
-} |
- |
PrefMetricsService::~PrefMetricsService() { |
} |
void PrefMetricsService::RecordLaunchPrefs() { |
- bool show_home_button = prefs_->GetBoolean(prefs::kShowHomeButton); |
- bool home_page_is_ntp = prefs_->GetBoolean(prefs::kHomePageIsNewTabPage); |
+ PrefService* prefs = profile_->GetPrefs(); |
+ bool show_home_button = prefs->GetBoolean(prefs::kShowHomeButton); |
+ bool home_page_is_ntp = prefs->GetBoolean(prefs::kHomePageIsNewTabPage); |
UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button); |
if (show_home_button) { |
UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage", |
@@ -131,7 +60,7 @@ |
// (pages that share a TLD+1 with a known engine but aren't actually search |
// pages, e.g. plus.google.com). |
if (!home_page_is_ntp) { |
- GURL homepage_url(prefs_->GetString(prefs::kHomePage)); |
+ GURL homepage_url(prefs->GetString(prefs::kHomePage)); |
if (homepage_url.is_valid()) { |
UMA_HISTOGRAM_ENUMERATION( |
"Settings.HomePageEngineType", |
@@ -140,11 +69,11 @@ |
} |
} |
- int restore_on_startup = prefs_->GetInteger(prefs::kRestoreOnStartup); |
+ int restore_on_startup = prefs->GetInteger(prefs::kRestoreOnStartup); |
UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings", |
restore_on_startup, kSessionStartupPrefValueMax); |
if (restore_on_startup == SessionStartupPref::kPrefValueURLs) { |
- const ListValue* url_list = prefs_->GetList(prefs::kURLsToRestoreOnStartup); |
+ const ListValue* url_list = prefs->GetList(prefs::kURLsToRestoreOnStartup); |
UMA_HISTOGRAM_CUSTOM_COUNTS("Settings.StartupPageLoadURLs", |
url_list->GetSize(), 1, 50, 20); |
// Similarly, check startup pages for known search engine TLD+1s. |
@@ -163,13 +92,6 @@ |
} |
} |
-// static |
-void PrefMetricsService::RegisterPrefs(PrefRegistrySimple* registry) { |
- // Register the top level dictionary to map profile names to dictionaries of |
- // tracked preferences. |
- registry->RegisterDictionaryPref(prefs::kProfilePreferenceHashes); |
-} |
- |
void PrefMetricsService::RegisterSyncedPrefObservers() { |
LogHistogramValueCallback booleanHandler = base::Bind( |
&PrefMetricsService::LogBooleanPrefChange, base::Unretained(this)); |
@@ -247,140 +169,6 @@ |
} |
} |
-void PrefMetricsService::GetDeviceIdCallback(const std::string& device_id) { |
- device_id_ = device_id; |
- // On Aura, this seems to be called twice. |
- if (!checked_tracked_prefs_) |
- CheckTrackedPreferences(); |
-} |
- |
-// To detect changes to Preferences that happen outside of Chrome, we hash |
-// selected pref values and save them in local state. CheckTrackedPreferences |
-// compares the saved values to the values observed in the profile's prefs. A |
-// dictionary of dictionaries in local state holds the hashed values, grouped by |
-// profile. To make the system more resistant to spoofing, pref values are |
-// hashed with the pref path and the device id. |
-void PrefMetricsService::CheckTrackedPreferences() { |
- DCHECK(!checked_tracked_prefs_); |
- |
- const base::DictionaryValue* pref_hash_dicts = |
- local_state_->GetDictionary(prefs::kProfilePreferenceHashes); |
- // Get the hashed prefs dictionary if it exists. If it doesn't, it will be |
- // created if we set preference values below. |
- const base::DictionaryValue* hashed_prefs = NULL; |
- pref_hash_dicts->GetDictionary(profile_name_, &hashed_prefs); |
- for (int i = 0; i < tracked_pref_path_count_; ++i) { |
- // Skip prefs that haven't been registered. |
- if (!prefs_->FindPreference(tracked_pref_paths_[i])) |
- continue; |
- |
- bool changed = false; |
- const base::Value* value = prefs_->GetUserPrefValue(tracked_pref_paths_[i]); |
- if (value) { |
- std::string value_hash = |
- GetHashedPrefValue(tracked_pref_paths_[i], value); |
- std::string last_hash; |
- if (hashed_prefs && |
- hashed_prefs->GetString(tracked_pref_paths_[i], &last_hash)) { |
- if (value_hash != last_hash) { |
- changed = true; |
- // Record that the preference changed from its last value. |
- UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceChanged", |
- i, tracked_pref_path_count_); |
- UpdateTrackedPreference(tracked_pref_paths_[i]); |
- } |
- } else { |
- changed = true; |
- // Record that we haven't tracked this preference yet, or the hash in |
- // local state was removed. |
- UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceInitialized", |
- i, tracked_pref_path_count_); |
- UpdateTrackedPreference(tracked_pref_paths_[i]); |
- } |
- } else { |
- // There is no preference set. Remove any hashed value from local state |
- // and if one was present, record that a pref was cleared. |
- if (RemoveTrackedPreference(tracked_pref_paths_[i])) { |
- changed = true; |
- UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceCleared", |
- i, tracked_pref_path_count_); |
- } |
- } |
- if (!changed) { |
- UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceUnchanged", |
- i, tracked_pref_path_count_); |
- } |
- } |
- |
- checked_tracked_prefs_ = true; |
- |
- // Now that we've checked the incoming preferences, register for change |
- // notifications, unless this is test code. |
- // TODO(bbudge) Fix failing browser_tests so we can remove this test. Several |
- // tests fail when they shutdown before they can write local state. |
- if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) |
- InitializePrefObservers(); |
-} |
- |
-void PrefMetricsService::UpdateTrackedPreference(const char* path) { |
- const base::Value* value = prefs_->GetUserPrefValue(path); |
- if (value) { |
- DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes); |
- update->SetString(GetHashedPrefPath(path), |
- GetHashedPrefValue(path, value)); |
- } else { |
- RemoveTrackedPreference(path); |
- } |
-} |
- |
-bool PrefMetricsService::RemoveTrackedPreference(const char* path) { |
- DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes); |
- return update->Remove(GetHashedPrefPath(path), NULL); |
-} |
- |
-std::string PrefMetricsService::GetHashedPrefPath(const char* path) { |
- std::string hash_pref_path(profile_name_); |
- hash_pref_path.append("."); |
- hash_pref_path.append(path); |
- return hash_pref_path; |
-} |
- |
-std::string PrefMetricsService::GetHashedPrefValue( |
- const char* path, |
- const base::Value* value) { |
- DCHECK(value); |
- |
- std::string string_to_hash(device_id_); |
- string_to_hash.append(path); |
- JSONStringValueSerializer serializer(&string_to_hash); |
- serializer.Serialize(*value); |
- |
- crypto::HMAC hmac(crypto::HMAC::SHA256); |
- unsigned char digest[kSHA256DigestSize]; |
- if (!hmac.Init(pref_hash_seed_) || |
- !hmac.Sign(string_to_hash, digest, kSHA256DigestSize)) { |
- NOTREACHED(); |
- return std::string(); |
- } |
- |
- return base::HexEncode(digest, kSHA256DigestSize); |
-} |
- |
-void PrefMetricsService::InitializePrefObservers() { |
- pref_registrar_.Init(prefs_); |
- for (int i = 0; i < tracked_pref_path_count_; ++i) { |
- // Skip prefs that haven't been registered. |
- if (!prefs_->FindPreference(tracked_pref_paths_[i])) |
- continue; |
- |
- pref_registrar_.Add( |
- tracked_pref_paths_[i], |
- base::Bind(&PrefMetricsService::UpdateTrackedPreference, |
- weak_factory_.GetWeakPtr(), |
- tracked_pref_paths_[i])); |
- } |
-} |
- |
// static |
PrefMetricsService::Factory* PrefMetricsService::Factory::GetInstance() { |
return Singleton<PrefMetricsService::Factory>::get(); |