pref_metrics_service.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// found in the LICENSE file.
4bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
5bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "chrome/browser/prefs/pref_metrics_service.h"
6bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/bind.h"
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/command_line.h"
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_string_value_serializer.h"
10bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/metrics/histogram.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
12bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/prefs/pref_service.h"
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/browser_process.h"
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Accessing the Device ID API here is a layering violation.
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// TODO(bbudge) Move the API so it's usable here.
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// http://crbug.com/276485
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/extensions/api/music_manager_private/device_id.h"
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/extensions/extension_prefs.h"
21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chrome/browser/prefs/pref_service_syncable.h"
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/prefs/scoped_user_pref_update.h"
23fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch#include "chrome/browser/prefs/session_startup_pref.h"
24ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chrome/browser/prefs/synced_pref_change_registrar.h"
25bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "chrome/browser/profiles/incognito_helpers.h"
26bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "chrome/browser/profiles/profile.h"
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/tabs/pinned_tab_codec.h"
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
30bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "chrome/common/pref_names.h"
31bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "crypto/hmac.h"
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "grit/browser_resources.h"
34ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
36ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
37ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochnamespace {
38ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
39ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochconst int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax;
40ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// These preferences must be kept in sync with the TrackedPreference enum in
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// tools/metrics/histograms/histograms.xml. To add a new preference, append it
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// to the array and add a corresponding value to the histogram enum.
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const char* kTrackedPrefs[] = {
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kShowHomeButton,
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kHomePageIsNewTabPage,
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kHomePage,
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kRestoreOnStartup,
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kURLsToRestoreOnStartup,
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kExtensionsPref,
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kGoogleServicesLastUsername,
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kSearchProviderOverrides,
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kDefaultSearchProviderSearchURL,
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kDefaultSearchProviderKeyword,
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kDefaultSearchProviderName,
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if !defined(OS_ANDROID)
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  prefs::kPinnedTabs,
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)};
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static const size_t kSHA256DigestSize = 32;
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
63ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}  // namespace
64bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
65bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService::PrefMetricsService(Profile* profile)
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : profile_(profile),
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      prefs_(profile_->GetPrefs()),
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      local_state_(g_browser_process->local_state()),
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      profile_name_(profile_->GetPath().AsUTF8Unsafe()),
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      tracked_pref_paths_(kTrackedPrefs),
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      tracked_pref_path_count_(arraysize(kTrackedPrefs)),
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      checked_tracked_prefs_(false),
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      weak_factory_(this) {
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  pref_hash_seed_ = ResourceBundle::GetSharedInstance().GetRawDataResource(
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      IDR_PREF_HASH_SEED_BIN).as_string();
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
77bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  RecordLaunchPrefs();
78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  synced_pref_change_registrar_.reset(new SyncedPrefChangeRegistrar(prefs));
81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  RegisterSyncedPrefObservers();
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // The following code might cause callbacks into this instance before we exit
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // the constructor. This instance should be initialized at this point.
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Android has no GetDeviceId.
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if !defined(OS_ANDROID)
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // We need the machine id to compute pref value hashes. Fetch that, and then
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // call CheckTrackedPreferences in the callback.
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  extensions::api::DeviceId::GetDeviceId(
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      "PrefMetricsService",  // non-empty string to obfuscate the device id.
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      Bind(&PrefMetricsService::GetDeviceIdCallback,
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)           weak_factory_.GetWeakPtr()));
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif  // !defined(OS_ANDROID)
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// For unit testing only.
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)PrefMetricsService::PrefMetricsService(Profile* profile,
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       PrefService* local_state,
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       const std::string& device_id,
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       const char** tracked_pref_paths,
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       int tracked_pref_path_count)
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : profile_(profile),
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      prefs_(profile->GetPrefs()),
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      local_state_(local_state),
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      pref_hash_seed_(kSHA256DigestSize, 0),
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      device_id_(device_id),
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      tracked_pref_paths_(tracked_pref_paths),
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      tracked_pref_path_count_(tracked_pref_path_count),
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      checked_tracked_prefs_(false),
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      weak_factory_(this) {
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CheckTrackedPreferences();
114bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
115bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
116bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService::~PrefMetricsService() {
117bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
118bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
119bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochvoid PrefMetricsService::RecordLaunchPrefs() {
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool show_home_button = prefs_->GetBoolean(prefs::kShowHomeButton);
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  bool home_page_is_ntp = prefs_->GetBoolean(prefs::kHomePageIsNewTabPage);
1223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button);
1233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (show_home_button) {
1243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage",
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                          home_page_is_ntp);
1263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  }
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // For non-NTP homepages, see if the URL comes from the same TLD+1 as a known
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // search engine.  Note that this is only an approximation of search engine
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // use, due to both false negatives (pages that come from unknown TLD+1 X but
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // consist of a search box that sends to known TLD+1 Y) and false positives
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // (pages that share a TLD+1 with a known engine but aren't actually search
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // pages, e.g. plus.google.com).
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!home_page_is_ntp) {
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GURL homepage_url(prefs_->GetString(prefs::kHomePage));
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (homepage_url.is_valid()) {
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION(
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          "Settings.HomePageEngineType",
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          TemplateURLPrepopulateData::GetEngineType(homepage_url),
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          SEARCH_ENGINE_MAX);
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  int restore_on_startup = prefs_->GetInteger(prefs::kRestoreOnStartup);
145fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings",
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            restore_on_startup, kSessionStartupPrefValueMax);
147fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  if (restore_on_startup == SessionStartupPref::kPrefValueURLs) {
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const ListValue* url_list = prefs_->GetList(prefs::kURLsToRestoreOnStartup);
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_COUNTS("Settings.StartupPageLoadURLs",
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                url_list->GetSize(), 1, 50, 20);
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Similarly, check startup pages for known search engine TLD+1s.
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string url_text;
15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (size_t i = 0; i < url_list->GetSize(); ++i) {
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (url_list->GetString(i, &url_text)) {
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GURL start_url(url_text);
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (start_url.is_valid()) {
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          UMA_HISTOGRAM_ENUMERATION(
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              "Settings.StartupPageEngineTypes",
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              TemplateURLPrepopulateData::GetEngineType(start_url),
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              SEARCH_ENGINE_MAX);
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
164fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdoch  }
16558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
16658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if !defined(OS_ANDROID)
16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  StartupTabs startup_tabs = PinnedTabCodec::ReadPinnedTabs(profile_);
16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_COUNTS("Settings.PinnedTabs",
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                              startup_tabs.size(), 1, 50, 20);
17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (size_t i = 0; i < startup_tabs.size(); ++i) {
17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GURL start_url(startup_tabs.at(i).url);
17258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (start_url.is_valid()) {
17358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION(
17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          "Settings.PinnedTabEngineTypes",
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          TemplateURLPrepopulateData::GetEngineType(start_url),
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          SEARCH_ENGINE_MAX);
17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif
18058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// static
18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrefMetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Register the top level dictionary to map profile names to dictionaries of
18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // tracked preferences.
18658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  registry->RegisterDictionaryPref(prefs::kProfilePreferenceHashes);
187bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
188bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
189ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PrefMetricsService::RegisterSyncedPrefObservers() {
190ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  LogHistogramValueCallback booleanHandler = base::Bind(
191ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      &PrefMetricsService::LogBooleanPrefChange, base::Unretained(this));
192ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
193ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  AddPrefObserver(prefs::kShowHomeButton, "ShowHomeButton", booleanHandler);
194ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  AddPrefObserver(prefs::kHomePageIsNewTabPage, "HomePageIsNewTabPage",
195ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                  booleanHandler);
196ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
197ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  AddPrefObserver(prefs::kRestoreOnStartup, "StartupPageLoadSettings",
198ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                  base::Bind(&PrefMetricsService::LogIntegerPrefChange,
199ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                             base::Unretained(this),
200ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                             kSessionStartupPrefValueMax));
201ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
202ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
203ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PrefMetricsService::AddPrefObserver(
204ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& path,
205ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& histogram_name_prefix,
206ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const LogHistogramValueCallback& callback) {
207ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  synced_pref_change_registrar_->Add(path.c_str(),
208ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::Bind(&PrefMetricsService::OnPrefChanged,
209ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 base::Unretained(this),
210ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                 histogram_name_prefix, callback));
211ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
212ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
213ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PrefMetricsService::OnPrefChanged(
214ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& histogram_name_prefix,
215ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const LogHistogramValueCallback& callback,
216ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& path,
217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    bool from_sync) {
218ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
219ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const PrefService::Preference* pref = prefs->FindPreference(path.c_str());
220ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  DCHECK(pref);
221ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string source_name(
222ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      from_sync ? ".PulledFromSync" : ".PushedToSync");
223ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  std::string histogram_name("Settings." + histogram_name_prefix + source_name);
224ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  callback.Run(histogram_name, pref->GetValue());
225ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch};
226ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
227ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PrefMetricsService::LogBooleanPrefChange(const std::string& histogram_name,
228ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              const Value* value) {
229ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  bool boolean_value = false;
230ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!value->GetAsBoolean(&boolean_value))
231ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
232ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::HistogramBase* histogram = base::BooleanHistogram::FactoryGet(
233ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag);
234ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  histogram->Add(boolean_value);
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PrefMetricsService::LogIntegerPrefChange(int boundary_value,
238ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              const std::string& histogram_name,
239ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                                              const Value* value) {
240ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  int integer_value = 0;
241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!value->GetAsInteger(&integer_value))
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      histogram_name,
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      1,
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      boundary_value,
247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      boundary_value + 1,
248ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      base::HistogramBase::kUmaTargetedHistogramFlag);
249ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  histogram->Add(integer_value);
250ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
251ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
252ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid PrefMetricsService::LogListPrefChange(
253ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const LogHistogramValueCallback& item_callback,
254ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const std::string& histogram_name,
255ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const Value* value) {
256ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  const ListValue* items = NULL;
257ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if (!value->GetAsList(&items))
258ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return;
259ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  for (size_t i = 0; i < items->GetSize(); ++i) {
260ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    const Value *item_value = NULL;
261ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if (items->Get(i, &item_value))
262ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      item_callback.Run(histogram_name, item_value);
263ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  }
264ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
265ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrefMetricsService::GetDeviceIdCallback(const std::string& device_id) {
26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  device_id_ = device_id;
26858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // On Aura, this seems to be called twice.
26958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!checked_tracked_prefs_)
27058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    CheckTrackedPreferences();
27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// To detect changes to Preferences that happen outside of Chrome, we hash
27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// selected pref values and save them in local state. CheckTrackedPreferences
27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// compares the saved values to the values observed in the profile's prefs. A
27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// dictionary of dictionaries in local state holds the hashed values, grouped by
27758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// profile. To make the system more resistant to spoofing, pref values are
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// hashed with the pref path and the device id.
27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrefMetricsService::CheckTrackedPreferences() {
28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(!checked_tracked_prefs_);
28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::DictionaryValue* pref_hash_dicts =
28358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      local_state_->GetDictionary(prefs::kProfilePreferenceHashes);
28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Get the hashed prefs dictionary if it exists. If it doesn't, it will be
28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // created if we set preference values below.
28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::DictionaryValue* hashed_prefs = NULL;
28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  pref_hash_dicts->GetDictionary(profile_name_, &hashed_prefs);
28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (int i = 0; i < tracked_pref_path_count_; ++i) {
28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Skip prefs that haven't been registered.
29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!prefs_->FindPreference(tracked_pref_paths_[i]))
29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      continue;
29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    bool changed = false;
29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const base::Value* value = prefs_->GetUserPrefValue(tracked_pref_paths_[i]);
29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (value) {
29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      std::string value_hash =
29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          GetHashedPrefValue(tracked_pref_paths_[i], value);
29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      std::string last_hash;
29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (hashed_prefs &&
30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          hashed_prefs->GetString(tracked_pref_paths_[i], &last_hash)) {
30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if (value_hash != last_hash) {
30258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          changed = true;
30358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          // Record that the preference changed from its last value.
30458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceChanged",
30558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              i, tracked_pref_path_count_);
30658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          UpdateTrackedPreference(tracked_pref_paths_[i]);
30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      } else {
30958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        changed = true;
31058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        // Record that we haven't tracked this preference yet, or the hash in
31158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        // local state was removed.
31258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceInitialized",
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            i, tracked_pref_path_count_);
31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        UpdateTrackedPreference(tracked_pref_paths_[i]);
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
31658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    } else {
31758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // There is no preference set. Remove any hashed value from local state
31858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      // and if one was present, record that a pref was cleared.
31958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (RemoveTrackedPreference(tracked_pref_paths_[i])) {
32058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        changed = true;
32158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceCleared",
32258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            i, tracked_pref_path_count_);
32358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
32558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!changed) {
32658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceUnchanged",
32758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          i, tracked_pref_path_count_);
32858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
32958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
33158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  checked_tracked_prefs_ = true;
33258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Now that we've checked the incoming preferences, register for change
33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // notifications, unless this is test code.
33558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // TODO(bbudge) Fix failing browser_tests and so we can remove this test.
33658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Several tests fail when they shutdown before they can write local state.
33758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType) &&
33858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame)) {
33958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    InitializePrefObservers();
34058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
34158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
34258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
34358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrefMetricsService::UpdateTrackedPreference(const char* path) {
34458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const base::Value* value = prefs_->GetUserPrefValue(path);
34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (value) {
34658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes);
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    update->SetString(GetHashedPrefPath(path),
34858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                      GetHashedPrefValue(path, value));
34958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
35058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RemoveTrackedPreference(path);
35158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
35358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
35458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool PrefMetricsService::RemoveTrackedPreference(const char* path) {
35558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes);
35658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return update->Remove(GetHashedPrefPath(path), NULL);
35758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
35858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
35958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string PrefMetricsService::GetHashedPrefPath(const char* path) {
36058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string hash_pref_path(profile_name_);
36158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hash_pref_path.append(".");
36258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  hash_pref_path.append(path);
36358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return hash_pref_path;
36458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
36558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string PrefMetricsService::GetHashedPrefValue(
36758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const char* path,
36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const base::Value* value) {
36958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(value);
37058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Dictionary values may contain empty lists and sub-dictionaries. Create
37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // a deep copy with those stripped to make the hash more stable.
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  scoped_ptr<DictionaryValue> dict_value;
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (value->IsType(Value::TYPE_DICTIONARY)) {
37558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    dict_value.reset(static_cast<const DictionaryValue*>(value)
37658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                         ->DeepCopyWithoutEmptyChildren());
37758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    value = dict_value.get();
37858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
37958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
38058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string string_to_hash(device_id_);
38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  string_to_hash.append(path);
38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  JSONStringValueSerializer serializer(&string_to_hash);
38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  serializer.Serialize(*value);
38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
38558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  crypto::HMAC hmac(crypto::HMAC::SHA256);
38658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  unsigned char digest[kSHA256DigestSize];
38758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!hmac.Init(pref_hash_seed_) ||
38858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      !hmac.Sign(string_to_hash, digest, kSHA256DigestSize)) {
38958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    NOTREACHED();
39058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return std::string();
39158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
39258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
39358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return base::HexEncode(digest, kSHA256DigestSize);
39458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
39558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
39658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PrefMetricsService::InitializePrefObservers() {
39758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  pref_registrar_.Init(prefs_);
39858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (int i = 0; i < tracked_pref_path_count_; ++i) {
39958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Skip prefs that haven't been registered.
40058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!prefs_->FindPreference(tracked_pref_paths_[i]))
40158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      continue;
40258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
40358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    pref_registrar_.Add(
40458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        tracked_pref_paths_[i],
40558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        base::Bind(&PrefMetricsService::UpdateTrackedPreference,
40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   weak_factory_.GetWeakPtr(),
40758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   tracked_pref_paths_[i]));
40858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
40958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
41058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
411bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// static
412bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService::Factory* PrefMetricsService::Factory::GetInstance() {
413bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return Singleton<PrefMetricsService::Factory>::get();
414bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
415bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
416bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch// static
417bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService* PrefMetricsService::Factory::GetForProfile(
418bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    Profile* profile) {
419bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return static_cast<PrefMetricsService*>(
420bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      GetInstance()->GetServiceForBrowserContext(profile, true));
421bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
422bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
423bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService::Factory::Factory()
424bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    : BrowserContextKeyedServiceFactory(
425bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        "PrefMetricsService",
426bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        BrowserContextDependencyManager::GetInstance()) {
427bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
428bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
429bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService::Factory::~Factory() {
430bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
431bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
432bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochBrowserContextKeyedService*
433bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben MurdochPrefMetricsService::Factory::BuildServiceInstanceFor(
434bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    content::BrowserContext* profile) const {
435bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return new PrefMetricsService(static_cast<Profile*>(profile));
436bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
437bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
438bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochbool PrefMetricsService::Factory::ServiceIsCreatedWithBrowserContext() const {
439bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return true;
440bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
441bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
442bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochbool PrefMetricsService::Factory::ServiceIsNULLWhileTesting() const {
443bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return false;
444bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
445bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
446bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochcontent::BrowserContext* PrefMetricsService::Factory::GetBrowserContextToUse(
447bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    content::BrowserContext* context) const {
448bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return chrome::GetBrowserContextRedirectedInIncognito(context);
449bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
450