Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/command_line.h" | |
| 9 #include "base/json/json_string_value_serializer.h" | |
| 10 #include "base/md5.h" | |
| 8 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/prefs/pref_registry_simple.h" | |
| 9 #include "base/prefs/pref_service.h" | 13 #include "base/prefs/pref_service.h" |
| 14 #include "chrome/browser/browser_process.h" | |
| 15 #include "chrome/browser/browser_shutdown.h" | |
| 16 // Accessing the Device ID API here is a layering violation. | |
| 17 // TODO(bbudge) Move the API so it's usable here. | |
| 18 // http://crbug.com/276485 | |
| 19 #include "chrome/browser/extensions/api/music_manager_private/device_id.h" | |
| 20 #include "chrome/browser/extensions/extension_prefs.h" | |
| 10 #include "chrome/browser/prefs/pref_service_syncable.h" | 21 #include "chrome/browser/prefs/pref_service_syncable.h" |
| 22 #include "chrome/browser/prefs/scoped_user_pref_update.h" | |
| 11 #include "chrome/browser/prefs/session_startup_pref.h" | 23 #include "chrome/browser/prefs/session_startup_pref.h" |
| 12 #include "chrome/browser/prefs/synced_pref_change_registrar.h" | 24 #include "chrome/browser/prefs/synced_pref_change_registrar.h" |
| 13 #include "chrome/browser/profiles/incognito_helpers.h" | 25 #include "chrome/browser/profiles/incognito_helpers.h" |
| 14 #include "chrome/browser/profiles/profile.h" | 26 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" | 27 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" |
| 28 #include "chrome/common/chrome_switches.h" | |
| 16 #include "chrome/common/pref_names.h" | 29 #include "chrome/common/pref_names.h" |
| 17 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h" | 30 #include "components/browser_context_keyed_service/browser_context_dependency_ma nager.h" |
| 31 #include "grit/browser_resources.h" | |
| 18 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 32 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 33 #include "ui/base/resource/resource_bundle.h" | |
| 19 | 34 |
| 20 namespace { | 35 namespace { |
| 21 | 36 |
| 22 // Converts a host name into a domain name for easier matching. | 37 const int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax; |
| 23 std::string GetDomainFromHost(const std::string& host) { | 38 |
| 24 return net::registry_controlled_domains::GetDomainAndRegistry( | 39 // These preferences must be kept in sync with the TrackedPreference enum in |
| 25 host, | 40 // tools/metrics/histograms/histograms.xml. To add a new preference, append it |
| 26 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); | 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 prefs::kExtensionsPref, | |
| 49 prefs::kGoogleServicesLastUsername, | |
| 50 prefs::kSearchProviderOverrides, | |
| 51 prefs::kDefaultSearchProviderSearchURL, | |
| 52 prefs::kDefaultSearchProviderKeyword, | |
| 53 prefs::kDefaultSearchProviderName, | |
| 54 prefs::kPinnedTabs, | |
| 55 }; | |
| 56 | |
| 57 bool BrowserShuttingDown() { | |
| 58 return browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID; | |
| 27 } | 59 } |
| 28 | 60 |
| 29 const int kSessionStartupPrefValueMax = SessionStartupPref::kPrefValueMax; | |
| 30 | |
| 31 } // namespace | 61 } // namespace |
| 32 | 62 |
| 33 PrefMetricsService::PrefMetricsService(Profile* profile) | 63 PrefMetricsService::PrefMetricsService(Profile* profile) |
| 34 : profile_(profile) { | 64 : weak_factory_(this), |
| 65 profile_(profile), | |
| 66 prefs_(profile_->GetPrefs()), | |
| 67 local_state_(g_browser_process->local_state()), | |
| 68 tracked_pref_paths_(kTrackedPrefs), | |
| 69 tracked_pref_path_count_(arraysize(kTrackedPrefs)) { | |
| 70 // Check that the pref is registered; otherwise some browser_tests crash. | |
| 71 if (prefs_->FindPreference(prefs::kGoogleServicesUsername)) | |
| 72 profile_name_ = profile_->GetProfileName(); | |
| 73 | |
| 74 pref_hash_seed_ = ResourceBundle::GetSharedInstance().GetRawDataResource( | |
| 75 IDR_PREF_HASH_SEED_BIN).as_string(); | |
| 76 | |
| 35 RecordLaunchPrefs(); | 77 RecordLaunchPrefs(); |
| 36 | 78 |
| 79 // Don't track preferences in browser tests. Otherwise, tests that change | |
| 80 // prefs after shutdown begins will write to local state, which will DCHECK | |
| 81 // when trying to write. | |
| 82 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)) | |
| 83 InitializePrefObservers(); | |
| 84 | |
| 85 #if !defined(OS_ANDROID) | |
| 86 // We need the machine id to compute pref value hashes. Fetch that, and then | |
| 87 // call CheckTrackedPreferences in the callback. | |
| 88 extensions::api::DeviceId::GetDeviceId( | |
| 89 "PrefMetricsService", // non-empty string to obfuscate the device id. | |
| 90 Bind(&PrefMetricsService::GetDeviceIdCallback, | |
| 91 weak_factory_.GetWeakPtr())); | |
| 92 #else | |
| 93 // Android has no GetDeviceId. | |
| 94 CheckTrackedPreferences(); | |
| 95 #endif // !defined(OS_ANDROID) | |
| 96 | |
| 37 PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); | 97 PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_); |
| 38 synced_pref_change_registrar_.reset(new SyncedPrefChangeRegistrar(prefs)); | 98 synced_pref_change_registrar_.reset(new SyncedPrefChangeRegistrar(prefs)); |
| 39 | 99 |
| 40 RegisterSyncedPrefObservers(); | 100 RegisterSyncedPrefObservers(); |
| 41 } | 101 } |
| 42 | 102 |
| 103 PrefMetricsService::PrefMetricsService(Profile* profile, | |
| 104 PrefService* local_state, | |
| 105 const std::string& device_id, | |
| 106 const char** tracked_pref_paths, | |
| 107 int tracked_pref_path_count) | |
| 108 : weak_factory_(this), | |
| 109 profile_(profile), | |
| 110 prefs_(profile->GetPrefs()), | |
| 111 local_state_(local_state), | |
| 112 device_id_(device_id), | |
| 113 tracked_pref_paths_(tracked_pref_paths), | |
| 114 tracked_pref_path_count_(tracked_pref_path_count) { | |
| 115 CheckTrackedPreferences(); | |
| 116 InitializePrefObservers(); | |
| 117 } | |
| 118 | |
| 43 PrefMetricsService::~PrefMetricsService() { | 119 PrefMetricsService::~PrefMetricsService() { |
| 44 } | 120 } |
| 45 | 121 |
| 46 void PrefMetricsService::RecordLaunchPrefs() { | 122 void PrefMetricsService::RecordLaunchPrefs() { |
| 47 PrefService* prefs = profile_->GetPrefs(); | 123 bool show_home_button = prefs_->GetBoolean(prefs::kShowHomeButton); |
| 48 bool show_home_button = prefs->GetBoolean(prefs::kShowHomeButton); | 124 bool home_page_is_ntp = prefs_->GetBoolean(prefs::kHomePageIsNewTabPage); |
| 49 bool home_page_is_ntp = prefs->GetBoolean(prefs::kHomePageIsNewTabPage); | |
| 50 UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button); | 125 UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button); |
| 51 if (show_home_button) { | 126 if (show_home_button) { |
| 52 UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage", | 127 UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage", |
| 53 home_page_is_ntp); | 128 home_page_is_ntp); |
| 54 } | 129 } |
| 55 | 130 |
| 56 // For non-NTP homepages, see if the URL comes from the same TLD+1 as a known | 131 // For non-NTP homepages, see if the URL comes from the same TLD+1 as a known |
| 57 // search engine. Note that this is only an approximation of search engine | 132 // search engine. Note that this is only an approximation of search engine |
| 58 // use, due to both false negatives (pages that come from unknown TLD+1 X but | 133 // use, due to both false negatives (pages that come from unknown TLD+1 X but |
| 59 // consist of a search box that sends to known TLD+1 Y) and false positives | 134 // consist of a search box that sends to known TLD+1 Y) and false positives |
| 60 // (pages that share a TLD+1 with a known engine but aren't actually search | 135 // (pages that share a TLD+1 with a known engine but aren't actually search |
| 61 // pages, e.g. plus.google.com). | 136 // pages, e.g. plus.google.com). |
| 62 if (!home_page_is_ntp) { | 137 if (!home_page_is_ntp) { |
| 63 GURL homepage_url(prefs->GetString(prefs::kHomePage)); | 138 GURL homepage_url(prefs_->GetString(prefs::kHomePage)); |
| 64 if (homepage_url.is_valid()) { | 139 if (homepage_url.is_valid()) { |
| 65 UMA_HISTOGRAM_ENUMERATION( | 140 UMA_HISTOGRAM_ENUMERATION( |
| 66 "Settings.HomePageEngineType", | 141 "Settings.HomePageEngineType", |
| 67 TemplateURLPrepopulateData::GetEngineType(homepage_url), | 142 TemplateURLPrepopulateData::GetEngineType(homepage_url), |
| 68 SEARCH_ENGINE_MAX); | 143 SEARCH_ENGINE_MAX); |
| 69 } | 144 } |
| 70 } | 145 } |
| 71 | 146 |
| 72 int restore_on_startup = prefs->GetInteger(prefs::kRestoreOnStartup); | 147 int restore_on_startup = prefs_->GetInteger(prefs::kRestoreOnStartup); |
| 73 UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings", | 148 UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings", |
| 74 restore_on_startup, kSessionStartupPrefValueMax); | 149 restore_on_startup, kSessionStartupPrefValueMax); |
| 75 if (restore_on_startup == SessionStartupPref::kPrefValueURLs) { | 150 if (restore_on_startup == SessionStartupPref::kPrefValueURLs) { |
| 76 const ListValue* url_list = prefs->GetList(prefs::kURLsToRestoreOnStartup); | 151 const ListValue* url_list = prefs_->GetList(prefs::kURLsToRestoreOnStartup); |
| 77 UMA_HISTOGRAM_CUSTOM_COUNTS("Settings.StartupPageLoadURLs", | 152 UMA_HISTOGRAM_CUSTOM_COUNTS("Settings.StartupPageLoadURLs", |
| 78 url_list->GetSize(), 1, 50, 20); | 153 url_list->GetSize(), 1, 50, 20); |
| 79 // Similarly, check startup pages for known search engine TLD+1s. | 154 // Similarly, check startup pages for known search engine TLD+1s. |
| 80 std::string url_text; | 155 std::string url_text; |
| 81 for (size_t i = 0; i < url_list->GetSize(); i++) { | 156 for (size_t i = 0; i < url_list->GetSize(); i++) { |
| 82 if (url_list->GetString(i, &url_text)) { | 157 if (url_list->GetString(i, &url_text)) { |
| 83 GURL start_url(url_text); | 158 GURL start_url(url_text); |
| 84 if (start_url.is_valid()) { | 159 if (start_url.is_valid()) { |
| 85 UMA_HISTOGRAM_ENUMERATION( | 160 UMA_HISTOGRAM_ENUMERATION( |
| 86 "Settings.StartupPageEngineTypes", | 161 "Settings.StartupPageEngineTypes", |
| 87 TemplateURLPrepopulateData::GetEngineType(start_url), | 162 TemplateURLPrepopulateData::GetEngineType(start_url), |
| 88 SEARCH_ENGINE_MAX); | 163 SEARCH_ENGINE_MAX); |
| 89 } | 164 } |
| 90 } | 165 } |
| 91 } | 166 } |
| 92 } | 167 } |
| 93 } | 168 } |
| 94 | 169 |
| 170 // static | |
| 171 void PrefMetricsService::RegisterPrefs(PrefRegistrySimple* registry) { | |
| 172 // Register the top level dictionary to map profile names to dictionaries of | |
| 173 // tracked preferences. | |
| 174 registry->RegisterDictionaryPref(prefs::kProfilePreferenceHashes); | |
| 175 } | |
| 176 | |
| 95 void PrefMetricsService::RegisterSyncedPrefObservers() { | 177 void PrefMetricsService::RegisterSyncedPrefObservers() { |
| 96 LogHistogramValueCallback booleanHandler = base::Bind( | 178 LogHistogramValueCallback booleanHandler = base::Bind( |
| 97 &PrefMetricsService::LogBooleanPrefChange, base::Unretained(this)); | 179 &PrefMetricsService::LogBooleanPrefChange, base::Unretained(this)); |
| 98 | 180 |
| 99 AddPrefObserver(prefs::kShowHomeButton, "ShowHomeButton", booleanHandler); | 181 AddPrefObserver(prefs::kShowHomeButton, "ShowHomeButton", booleanHandler); |
| 100 AddPrefObserver(prefs::kHomePageIsNewTabPage, "HomePageIsNewTabPage", | 182 AddPrefObserver(prefs::kHomePageIsNewTabPage, "HomePageIsNewTabPage", |
| 101 booleanHandler); | 183 booleanHandler); |
| 102 | 184 |
| 103 AddPrefObserver(prefs::kRestoreOnStartup, "StartupPageLoadSettings", | 185 AddPrefObserver(prefs::kRestoreOnStartup, "StartupPageLoadSettings", |
| 104 base::Bind(&PrefMetricsService::LogIntegerPrefChange, | 186 base::Bind(&PrefMetricsService::LogIntegerPrefChange, |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 const ListValue* items = NULL; | 244 const ListValue* items = NULL; |
| 163 if (!value->GetAsList(&items)) | 245 if (!value->GetAsList(&items)) |
| 164 return; | 246 return; |
| 165 for (size_t i = 0; i < items->GetSize(); ++i) { | 247 for (size_t i = 0; i < items->GetSize(); ++i) { |
| 166 const Value *item_value = NULL; | 248 const Value *item_value = NULL; |
| 167 if (items->Get(i, &item_value)) | 249 if (items->Get(i, &item_value)) |
| 168 item_callback.Run(histogram_name, item_value); | 250 item_callback.Run(histogram_name, item_value); |
| 169 } | 251 } |
| 170 } | 252 } |
| 171 | 253 |
| 254 void PrefMetricsService::GetDeviceIdCallback(const std::string& device_id) { | |
| 255 device_id_ = device_id; | |
| 256 CheckTrackedPreferences(); | |
| 257 } | |
| 258 | |
| 259 // To detect changes to Preferences that happen outside of Chrome, we hash | |
| 260 // selected pref values and save them in local state. CheckTrackedPreferences | |
| 261 // compares the saved values to the values observed in the profile's prefs. A | |
| 262 // dictionary of dictionaries in local state holds the hashed values, grouped by | |
| 263 // profile. To make the system more resistant to spoofing, pref values are | |
| 264 // hashed with the pref path and the device id. | |
| 265 void PrefMetricsService::CheckTrackedPreferences() { | |
| 266 // Don't attempt to change local state during browser shutdown. | |
| 267 if (BrowserShuttingDown()) | |
|
battre
2013/09/02 08:33:46
Don't you want to move this down so that it become
bbudge
2013/09/04 15:00:09
I added these guards to get some browser_tests to
| |
| 268 return; | |
| 269 | |
| 270 const base::DictionaryValue* pref_hash_dicts = | |
| 271 local_state_->GetDictionary(prefs::kProfilePreferenceHashes); | |
| 272 // Get the hashed prefs dictionary if it exists. If it doesn't, it will be | |
| 273 // created if we set preference values below. | |
| 274 const base::DictionaryValue* hashed_prefs = NULL; | |
| 275 pref_hash_dicts->GetDictionary(profile_name_, &hashed_prefs); | |
| 276 for (int i = 0; i < tracked_pref_path_count_; ++i) { | |
| 277 // Skip prefs that haven't been registered (e.g. in browser_tests). | |
| 278 if (!prefs_->FindPreference(tracked_pref_paths_[i])) | |
| 279 continue; | |
| 280 | |
| 281 bool unchanged = true; | |
|
battre
2013/09/02 08:33:46
how about removing one negation and calling it cha
bbudge
2013/09/04 15:00:09
Done.
| |
| 282 const base::Value* value = prefs_->GetUserPrefValue(tracked_pref_paths_[i]); | |
| 283 if (value) { | |
| 284 std::string value_hash = | |
| 285 GetHashedPrefValue(tracked_pref_paths_[i], value); | |
| 286 std::string last_hash; | |
| 287 if (hashed_prefs && | |
| 288 hashed_prefs->GetString(tracked_pref_paths_[i], &last_hash)) { | |
| 289 if (value_hash != last_hash) { | |
| 290 unchanged = false; | |
| 291 // Record that the preference changed from its last value. | |
| 292 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceChanged", | |
| 293 i, tracked_pref_path_count_); | |
| 294 UpdateTrackedPreference(tracked_pref_paths_[i]); | |
| 295 } | |
| 296 } else { | |
| 297 unchanged = false; | |
| 298 // Record that we haven't tracked this preference yet, or the hash in | |
| 299 // local state was removed. | |
| 300 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceInitialized", | |
| 301 i, tracked_pref_path_count_); | |
| 302 UpdateTrackedPreference(tracked_pref_paths_[i]); | |
| 303 } | |
| 304 } else { | |
| 305 // There is no preference set. Remove any hashed value from local state | |
| 306 // and if one was present, record that a pref was cleared. | |
| 307 if (RemoveTrackedPreference(tracked_pref_paths_[i])) { | |
| 308 unchanged = false; | |
| 309 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceCleared", | |
| 310 i, tracked_pref_path_count_); | |
| 311 } | |
| 312 } | |
| 313 if (unchanged) { | |
| 314 UMA_HISTOGRAM_ENUMERATION("Settings.TrackedPreferenceUnchanged", | |
| 315 i, tracked_pref_path_count_); | |
| 316 } | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 void PrefMetricsService::UpdateTrackedPreference(const char* path) { | |
| 321 // Don't attempt to change local state during browser shutdown. | |
| 322 if (BrowserShuttingDown()) | |
| 323 return; | |
| 324 | |
| 325 const base::Value* value = prefs_->GetUserPrefValue(path); | |
| 326 if (value) { | |
| 327 DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes); | |
| 328 base::DictionaryValue* dict = update.Get(); | |
| 329 if (dict) { | |
| 330 dict->SetString(GetHashedPrefPath(path), | |
| 331 GetHashedPrefValue(path, value)); | |
| 332 } | |
| 333 } else { | |
| 334 RemoveTrackedPreference(path); | |
| 335 } | |
| 336 } | |
| 337 | |
| 338 bool PrefMetricsService::RemoveTrackedPreference(const char* path) { | |
| 339 DictionaryPrefUpdate update(local_state_, prefs::kProfilePreferenceHashes); | |
| 340 base::DictionaryValue* dict = update.Get(); | |
| 341 if (dict) | |
| 342 return dict->Remove(GetHashedPrefPath(path), NULL); | |
| 343 | |
| 344 return false; | |
| 345 } | |
| 346 | |
| 347 std::string PrefMetricsService::GetHashedPrefPath(const char* path) { | |
| 348 std::string hash_pref_path(profile_name_); | |
| 349 hash_pref_path.append("."); | |
| 350 hash_pref_path.append(path); | |
| 351 return hash_pref_path; | |
| 352 } | |
| 353 | |
| 354 std::string PrefMetricsService::GetHashedPrefValue( | |
| 355 const char* path, | |
| 356 const base::Value* value) { | |
| 357 DCHECK(value); | |
| 358 std::string value_string; | |
| 359 JSONStringValueSerializer serializer(&value_string); | |
| 360 serializer.Serialize(*value); | |
|
battre
2013/09/02 08:33:46
This is pretty brittle. If somebody modifies the s
bbudge
2013/09/04 15:00:09
Good point. I added some test code to protect agai
| |
| 361 | |
| 362 base::MD5Context context; | |
| 363 base::MD5Init(&context); | |
| 364 // Salt the hash with an initial seed, the device id, and the pref path. | |
| 365 base::MD5Update(&context, pref_hash_seed_); | |
| 366 base::MD5Update(&context, device_id_); | |
| 367 base::MD5Update(&context, path); | |
| 368 base::MD5Update(&context, value_string); | |
| 369 base::MD5Digest digest; | |
| 370 base::MD5Final(&digest, &context); | |
| 371 return base::MD5DigestToBase16(digest); | |
| 372 } | |
| 373 | |
| 374 void PrefMetricsService::InitializePrefObservers() { | |
| 375 pref_registrar_.Init(prefs_); | |
| 376 for (int i = 0; i < tracked_pref_path_count_; ++i) { | |
| 377 pref_registrar_.Add( | |
| 378 tracked_pref_paths_[i], | |
| 379 base::Bind(&PrefMetricsService::UpdateTrackedPreference, | |
| 380 weak_factory_.GetWeakPtr(), | |
| 381 tracked_pref_paths_[i])); | |
| 382 } | |
| 383 } | |
| 384 | |
| 172 // static | 385 // static |
| 173 PrefMetricsService::Factory* PrefMetricsService::Factory::GetInstance() { | 386 PrefMetricsService::Factory* PrefMetricsService::Factory::GetInstance() { |
| 174 return Singleton<PrefMetricsService::Factory>::get(); | 387 return Singleton<PrefMetricsService::Factory>::get(); |
| 175 } | 388 } |
| 176 | 389 |
| 177 // static | 390 // static |
| 178 PrefMetricsService* PrefMetricsService::Factory::GetForProfile( | 391 PrefMetricsService* PrefMetricsService::Factory::GetForProfile( |
| 179 Profile* profile) { | 392 Profile* profile) { |
| 180 return static_cast<PrefMetricsService*>( | 393 return static_cast<PrefMetricsService*>( |
| 181 GetInstance()->GetServiceForBrowserContext(profile, true)); | 394 GetInstance()->GetServiceForBrowserContext(profile, true)); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 201 } | 414 } |
| 202 | 415 |
| 203 bool PrefMetricsService::Factory::ServiceIsNULLWhileTesting() const { | 416 bool PrefMetricsService::Factory::ServiceIsNULLWhileTesting() const { |
| 204 return false; | 417 return false; |
| 205 } | 418 } |
| 206 | 419 |
| 207 content::BrowserContext* PrefMetricsService::Factory::GetBrowserContextToUse( | 420 content::BrowserContext* PrefMetricsService::Factory::GetBrowserContextToUse( |
| 208 content::BrowserContext* context) const { | 421 content::BrowserContext* context) const { |
| 209 return chrome::GetBrowserContextRedirectedInIncognito(context); | 422 return chrome::GetBrowserContextRedirectedInIncognito(context); |
| 210 } | 423 } |
| OLD | NEW |