1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/debug/trace_event.h"
13 #include "base/files/file_path.h"
14 #include "base/metrics/field_trial.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/default_pref_store.h"
17 #include "base/prefs/json_pref_store.h"
18 #include "base/prefs/pref_filter.h"
19 #include "base/prefs/pref_notifier_impl.h"
20 #include "base/prefs/pref_registry.h"
21 #include "base/prefs/pref_registry_simple.h"
22 #include "base/prefs/pref_service.h"
23 #include "base/prefs/pref_store.h"
24 #include "base/prefs/pref_value_store.h"
25 #include "base/threading/sequenced_worker_pool.h"
26 #include "base/time/time.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/prefs/command_line_pref_store.h"
29 #include "chrome/browser/prefs/pref_hash_filter.h"
30 #include "chrome/browser/prefs/pref_model_associator.h"
31 #include "chrome/browser/prefs/pref_service_syncable.h"
32 #include "chrome/browser/prefs/pref_service_syncable_factory.h"
33 #include "chrome/browser/prefs/profile_pref_store_manager.h"
34 #include "chrome/browser/profiles/file_path_verifier_win.h"
35 #include "chrome/browser/profiles/profile.h"
36 #include "chrome/browser/search_engines/default_search_manager.h"
37 #include "chrome/browser/search_engines/default_search_pref_migration.h"
38 #include "chrome/browser/sync/glue/sync_start_util.h"
39 #include "chrome/browser/ui/profile_error_dialog.h"
40 #include "chrome/common/chrome_constants.h"
41 #include "chrome/common/pref_names.h"
42 #include "components/pref_registry/pref_registry_syncable.h"
43 #include "components/sync_driver/pref_names.h"
44 #include "content/public/browser/browser_context.h"
45 #include "content/public/browser/browser_thread.h"
46 #include "extensions/browser/pref_names.h"
47 #include "grit/browser_resources.h"
48 #include "grit/chromium_strings.h"
49 #include "grit/generated_resources.h"
50 #include "sync/internal_api/public/base/model_type.h"
51 #include "ui/base/resource/resource_bundle.h"
52
53 #if defined(ENABLE_CONFIGURATION_POLICY)
54 #include "components/policy/core/browser/browser_policy_connector.h"
55 #include "components/policy/core/browser/configuration_policy_pref_store.h"
56 #include "components/policy/core/common/policy_types.h"
57 #endif
58
59 #if defined(ENABLE_MANAGED_USERS)
60 #include "chrome/browser/supervised_user/supervised_user_pref_store.h"
61 #endif
62
63 #if defined(OS_WIN)
64 #include "base/win/win_util.h"
65 #if defined(ENABLE_RLZ)
66 #include "rlz/lib/machine_id.h"
67 #endif // defined(ENABLE_RLZ)
68 #endif // defined(OS_WIN)
69
70 using content::BrowserContext;
71 using content::BrowserThread;
72
73 namespace {
74
75 // Whether we are in testing mode; can be enabled via
76 // DisableDelaysAndDomainCheckForTesting(). Forces startup checks to occur
77 // with no delay and ignores the presence of a domain when determining the
78 // active SettingsEnforcement group.
79 bool g_disable_delays_and_domain_check_for_testing = false;
80
81 // These preferences must be kept in sync with the TrackedPreference enum in
82 // tools/metrics/histograms/histograms.xml. To add a new preference, append it
83 // to the array and add a corresponding value to the histogram enum. Each
84 // tracked preference must be given a unique reporting ID.
85 const PrefHashFilter::TrackedPreferenceMetadata kTrackedPrefs[] = {
86 {
87 0, prefs::kShowHomeButton,
88 PrefHashFilter::ENFORCE_ON_LOAD,
89 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
90 },
91 {
92 1, prefs::kHomePageIsNewTabPage,
93 PrefHashFilter::ENFORCE_ON_LOAD,
94 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
95 },
96 {
97 2, prefs::kHomePage,
98 PrefHashFilter::ENFORCE_ON_LOAD,
99 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
100 },
101 {
102 3, prefs::kRestoreOnStartup,
103 PrefHashFilter::ENFORCE_ON_LOAD,
104 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
105 },
106 {
107 4, prefs::kURLsToRestoreOnStartup,
108 PrefHashFilter::ENFORCE_ON_LOAD,
109 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
110 },
111 {
112 5, extensions::pref_names::kExtensions,
113 PrefHashFilter::NO_ENFORCEMENT,
114 PrefHashFilter::TRACKING_STRATEGY_SPLIT
115 },
116 {
117 6, prefs::kGoogleServicesLastUsername,
118 PrefHashFilter::ENFORCE_ON_LOAD,
119 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
120 },
121 {
122 7, prefs::kSearchProviderOverrides,
123 PrefHashFilter::ENFORCE_ON_LOAD,
124 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
125 },
126 {
127 8, prefs::kDefaultSearchProviderSearchURL,
128 PrefHashFilter::ENFORCE_ON_LOAD,
129 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
130 },
131 {
132 9, prefs::kDefaultSearchProviderKeyword,
133 PrefHashFilter::ENFORCE_ON_LOAD,
134 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
135 },
136 {
137 10, prefs::kDefaultSearchProviderName,
138 PrefHashFilter::ENFORCE_ON_LOAD,
139 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
140 },
141 #if !defined(OS_ANDROID)
142 {
143 11, prefs::kPinnedTabs,
144 PrefHashFilter::ENFORCE_ON_LOAD,
145 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
146 },
147 #endif
148 {
149 12, extensions::pref_names::kKnownDisabled,
150 PrefHashFilter::NO_ENFORCEMENT,
151 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
152 },
153 {
154 13, prefs::kProfileResetPromptMemento,
155 PrefHashFilter::ENFORCE_ON_LOAD,
156 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
157 },
158 {
159 14, DefaultSearchManager::kDefaultSearchProviderDataPrefName,
160 PrefHashFilter::NO_ENFORCEMENT,
161 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
162 },
163 {
164 // Protecting kPreferenceResetTime does two things:
165 // 1) It ensures this isn't accidently set by someone stomping the pref
166 // file.
167 // 2) More importantly, it declares kPreferenceResetTime as a protected
168 // pref which is required for it to be visible when queried via the
169 // SegregatedPrefStore. This is because it's written directly in the
170 // protected JsonPrefStore by that store's PrefHashFilter if there was
171 // a reset in FilterOnLoad and SegregatedPrefStore will not look for it
172 // in the protected JsonPrefStore unless it's declared as a protected
173 // preference here.
174 15, prefs::kPreferenceResetTime,
175 PrefHashFilter::ENFORCE_ON_LOAD,
176 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
177 },
178 {
179 16, prefs::kSafeBrowsingIncidentReportSent,
180 PrefHashFilter::ENFORCE_ON_LOAD,
181 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
182 },
183 {
184 17, sync_driver::prefs::kSyncRemainingRollbackTries,
185 PrefHashFilter::ENFORCE_ON_LOAD,
186 PrefHashFilter::TRACKING_STRATEGY_ATOMIC
187 },
188 };
189
190 // The count of tracked preferences IDs across all platforms.
191 const size_t kTrackedPrefsReportingIDsCount = 18;
192 COMPILE_ASSERT(kTrackedPrefsReportingIDsCount >= arraysize(kTrackedPrefs),
193 need_to_increment_ids_count);
194
195 // Each group enforces a superset of the protection provided by the previous
196 // one.
197 enum SettingsEnforcementGroup {
198 GROUP_NO_ENFORCEMENT,
199 // Enforce protected settings on profile loads.
200 GROUP_ENFORCE_ALWAYS,
201 // Also enforce extension default search.
202 GROUP_ENFORCE_ALWAYS_WITH_DSE,
203 // Also enforce extension settings and default search.
204 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE,
205 // The default enforcement group contains all protection features.
206 GROUP_ENFORCE_DEFAULT
207 };
208
GetSettingsEnforcementGroup()209 SettingsEnforcementGroup GetSettingsEnforcementGroup() {
210 # if defined(OS_WIN)
211 if (!g_disable_delays_and_domain_check_for_testing) {
212 static bool first_call = true;
213 static const bool is_enrolled_to_domain = base::win::IsEnrolledToDomain();
214 if (first_call) {
215 UMA_HISTOGRAM_BOOLEAN("Settings.TrackedPreferencesNoEnforcementOnDomain",
216 is_enrolled_to_domain);
217 first_call = false;
218 }
219 if (is_enrolled_to_domain)
220 return GROUP_NO_ENFORCEMENT;
221 }
222 #endif
223
224 struct {
225 const char* group_name;
226 SettingsEnforcementGroup group;
227 } static const kEnforcementLevelMap[] = {
228 { chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,
229 GROUP_NO_ENFORCEMENT },
230 { chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways,
231 GROUP_ENFORCE_ALWAYS },
232 { chrome_prefs::internals::
233 kSettingsEnforcementGroupEnforceAlwaysWithDSE,
234 GROUP_ENFORCE_ALWAYS_WITH_DSE },
235 { chrome_prefs::internals::
236 kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE,
237 GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE },
238 };
239
240 // Use the strongest enforcement setting in the absence of a field trial
241 // config on Windows. Remember to update the OFFICIAL_BUILD section of
242 // extension_startup_browsertest.cc when updating the default value below.
243 // TODO(gab): Enforce this on all platforms.
244 SettingsEnforcementGroup enforcement_group =
245 #if defined(OS_WIN)
246 GROUP_ENFORCE_DEFAULT;
247 #else
248 GROUP_NO_ENFORCEMENT;
249 #endif
250 bool group_determined_from_trial = false;
251 base::FieldTrial* trial =
252 base::FieldTrialList::Find(
253 chrome_prefs::internals::kSettingsEnforcementTrialName);
254 if (trial) {
255 const std::string& group_name = trial->group_name();
256 // ARRAYSIZE_UNSAFE must be used since the array is declared locally; it is
257 // only unsafe because it could not trigger a compile error on some
258 // non-array pointer types; this is fine since kEnforcementLevelMap is
259 // clearly an array.
260 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kEnforcementLevelMap); ++i) {
261 if (kEnforcementLevelMap[i].group_name == group_name) {
262 enforcement_group = kEnforcementLevelMap[i].group;
263 group_determined_from_trial = true;
264 break;
265 }
266 }
267 }
268 UMA_HISTOGRAM_BOOLEAN("Settings.EnforcementGroupDeterminedFromTrial",
269 group_determined_from_trial);
270 return enforcement_group;
271 }
272
273 // Returns the effective preference tracking configuration.
274 std::vector<PrefHashFilter::TrackedPreferenceMetadata>
GetTrackingConfiguration()275 GetTrackingConfiguration() {
276 const SettingsEnforcementGroup enforcement_group =
277 GetSettingsEnforcementGroup();
278
279 std::vector<PrefHashFilter::TrackedPreferenceMetadata> result;
280 for (size_t i = 0; i < arraysize(kTrackedPrefs); ++i) {
281 PrefHashFilter::TrackedPreferenceMetadata data = kTrackedPrefs[i];
282
283 if (GROUP_NO_ENFORCEMENT == enforcement_group) {
284 // Remove enforcement for all tracked preferences.
285 data.enforcement_level = PrefHashFilter::NO_ENFORCEMENT;
286 }
287
288 if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_DSE &&
289 data.name == DefaultSearchManager::kDefaultSearchProviderDataPrefName) {
290 // Specifically enable default search settings enforcement.
291 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD;
292 }
293
294 if (enforcement_group >= GROUP_ENFORCE_ALWAYS_WITH_EXTENSIONS_AND_DSE &&
295 (data.name == extensions::pref_names::kExtensions ||
296 data.name == extensions::pref_names::kKnownDisabled)) {
297 // Specifically enable extension settings enforcement and ensure
298 // kKnownDisabled follows it in the Protected Preferences.
299 // TODO(gab): Get rid of kKnownDisabled altogether.
300 data.enforcement_level = PrefHashFilter::ENFORCE_ON_LOAD;
301 }
302
303 result.push_back(data);
304 }
305 return result;
306 }
307
308
309 // Shows notifications which correspond to PersistentPrefStore's reading errors.
HandleReadError(PersistentPrefStore::PrefReadError error)310 void HandleReadError(PersistentPrefStore::PrefReadError error) {
311 // Sample the histogram also for the successful case in order to get a
312 // baseline on the success rate in addition to the error distribution.
313 UMA_HISTOGRAM_ENUMERATION("PrefService.ReadError", error,
314 PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM);
315
316 if (error != PersistentPrefStore::PREF_READ_ERROR_NONE) {
317 #if !defined(OS_CHROMEOS)
318 // Failing to load prefs on startup is a bad thing(TM). See bug 38352 for
319 // an example problem that this can cause.
320 // Do some diagnosis and try to avoid losing data.
321 int message_id = 0;
322 if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE ||
323 error == PersistentPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION) {
324 message_id = IDS_PREFERENCES_CORRUPT_ERROR;
325 } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
326 message_id = IDS_PREFERENCES_UNREADABLE_ERROR;
327 }
328
329 if (message_id) {
330 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
331 base::Bind(&ShowProfileErrorDialog,
332 PROFILE_ERROR_PREFERENCES,
333 message_id));
334 }
335 #else
336 // On ChromeOS error screen with message about broken local state
337 // will be displayed.
338 #endif
339 }
340 }
341
CreateProfilePrefStoreManager(const base::FilePath & profile_path)342 scoped_ptr<ProfilePrefStoreManager> CreateProfilePrefStoreManager(
343 const base::FilePath& profile_path) {
344 std::string device_id;
345 #if defined(OS_WIN) && defined(ENABLE_RLZ)
346 // This is used by
347 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc
348 // but that API is private (http://crbug.com/276485) and other platforms are
349 // not available synchronously.
350 // As part of improving pref metrics on other platforms we may want to find
351 // ways to defer preference loading until the device ID can be used.
352 rlz_lib::GetMachineId(&device_id);
353 #endif
354 return make_scoped_ptr(new ProfilePrefStoreManager(
355 profile_path,
356 GetTrackingConfiguration(),
357 kTrackedPrefsReportingIDsCount,
358 ResourceBundle::GetSharedInstance()
359 .GetRawDataResource(IDR_PREF_HASH_SEED_BIN)
360 .as_string(),
361 device_id,
362 g_browser_process->local_state()));
363 }
364
PrepareFactory(PrefServiceSyncableFactory * factory,policy::PolicyService * policy_service,SupervisedUserSettingsService * supervised_user_settings,scoped_refptr<PersistentPrefStore> user_pref_store,const scoped_refptr<PrefStore> & extension_prefs,bool async)365 void PrepareFactory(
366 PrefServiceSyncableFactory* factory,
367 policy::PolicyService* policy_service,
368 SupervisedUserSettingsService* supervised_user_settings,
369 scoped_refptr<PersistentPrefStore> user_pref_store,
370 const scoped_refptr<PrefStore>& extension_prefs,
371 bool async) {
372 #if defined(ENABLE_CONFIGURATION_POLICY)
373 using policy::ConfigurationPolicyPrefStore;
374 factory->set_managed_prefs(
375 make_scoped_refptr(new ConfigurationPolicyPrefStore(
376 policy_service,
377 g_browser_process->browser_policy_connector()->GetHandlerList(),
378 policy::POLICY_LEVEL_MANDATORY)));
379 factory->set_recommended_prefs(
380 make_scoped_refptr(new ConfigurationPolicyPrefStore(
381 policy_service,
382 g_browser_process->browser_policy_connector()->GetHandlerList(),
383 policy::POLICY_LEVEL_RECOMMENDED)));
384 #endif // ENABLE_CONFIGURATION_POLICY
385
386 #if defined(ENABLE_MANAGED_USERS)
387 if (supervised_user_settings) {
388 factory->set_supervised_user_prefs(
389 make_scoped_refptr(
390 new SupervisedUserPrefStore(supervised_user_settings)));
391 }
392 #endif
393
394 factory->set_async(async);
395 factory->set_extension_prefs(extension_prefs);
396 factory->set_command_line_prefs(
397 make_scoped_refptr(
398 new CommandLinePrefStore(CommandLine::ForCurrentProcess())));
399 factory->set_read_error_callback(base::Bind(&HandleReadError));
400 factory->set_user_prefs(user_pref_store);
401 }
402
403 } // namespace
404
405 namespace chrome_prefs {
406
407 namespace internals {
408
409 const char kSettingsEnforcementTrialName[] = "SettingsEnforcement";
410 const char kSettingsEnforcementGroupNoEnforcement[] = "no_enforcement";
411 const char kSettingsEnforcementGroupEnforceAlways[] = "enforce_always";
412 const char kSettingsEnforcementGroupEnforceAlwaysWithDSE[] =
413 "enforce_always_with_dse";
414 const char kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE[] =
415 "enforce_always_with_extensions_and_dse";
416
417 } // namespace internals
418
CreateLocalState(const base::FilePath & pref_filename,base::SequencedTaskRunner * pref_io_task_runner,policy::PolicyService * policy_service,const scoped_refptr<PrefRegistry> & pref_registry,bool async)419 scoped_ptr<PrefService> CreateLocalState(
420 const base::FilePath& pref_filename,
421 base::SequencedTaskRunner* pref_io_task_runner,
422 policy::PolicyService* policy_service,
423 const scoped_refptr<PrefRegistry>& pref_registry,
424 bool async) {
425 PrefServiceSyncableFactory factory;
426 PrepareFactory(
427 &factory,
428 policy_service,
429 NULL, // supervised_user_settings
430 new JsonPrefStore(
431 pref_filename, pref_io_task_runner, scoped_ptr<PrefFilter>()),
432 NULL, // extension_prefs
433 async);
434 return factory.Create(pref_registry.get());
435 }
436
CreateProfilePrefs(const base::FilePath & profile_path,base::SequencedTaskRunner * pref_io_task_runner,TrackedPreferenceValidationDelegate * validation_delegate,policy::PolicyService * policy_service,SupervisedUserSettingsService * supervised_user_settings,const scoped_refptr<PrefStore> & extension_prefs,const scoped_refptr<user_prefs::PrefRegistrySyncable> & pref_registry,bool async)437 scoped_ptr<PrefServiceSyncable> CreateProfilePrefs(
438 const base::FilePath& profile_path,
439 base::SequencedTaskRunner* pref_io_task_runner,
440 TrackedPreferenceValidationDelegate* validation_delegate,
441 policy::PolicyService* policy_service,
442 SupervisedUserSettingsService* supervised_user_settings,
443 const scoped_refptr<PrefStore>& extension_prefs,
444 const scoped_refptr<user_prefs::PrefRegistrySyncable>& pref_registry,
445 bool async) {
446 TRACE_EVENT0("browser", "chrome_prefs::CreateProfilePrefs");
447
448 // A StartSyncFlare used to kick sync early in case of a reset event. This is
449 // done since sync may bring back the user's server value post-reset which
450 // could potentially cause a "settings flash" between the factory default and
451 // the re-instantiated server value. Starting sync ASAP minimizes the window
452 // before the server value is re-instantiated (this window can otherwise be
453 // as long as 10 seconds by default).
454 const base::Closure start_sync_flare_for_prefs =
455 base::Bind(sync_start_util::GetFlareForSyncableService(profile_path),
456 syncer::PREFERENCES);
457
458 PrefServiceSyncableFactory factory;
459 PrepareFactory(&factory,
460 policy_service,
461 supervised_user_settings,
462 scoped_refptr<PersistentPrefStore>(
463 CreateProfilePrefStoreManager(profile_path)
464 ->CreateProfilePrefStore(pref_io_task_runner,
465 start_sync_flare_for_prefs,
466 validation_delegate)),
467 extension_prefs,
468 async);
469 scoped_ptr<PrefServiceSyncable> pref_service =
470 factory.CreateSyncable(pref_registry.get());
471
472 ConfigureDefaultSearchPrefMigrationToDictionaryValue(pref_service.get());
473
474 return pref_service.Pass();
475 }
476
SchedulePrefsFilePathVerification(const base::FilePath & profile_path)477 void SchedulePrefsFilePathVerification(const base::FilePath& profile_path) {
478 #if defined(OS_WIN)
479 // Only do prefs file verification on Windows.
480 const int kVerifyPrefsFileDelaySeconds = 60;
481 BrowserThread::GetBlockingPool()->PostDelayedTask(
482 FROM_HERE,
483 base::Bind(&VerifyPreferencesFile,
484 ProfilePrefStoreManager::GetPrefFilePathFromProfilePath(
485 profile_path)),
486 base::TimeDelta::FromSeconds(g_disable_delays_and_domain_check_for_testing
487 ? 0
488 : kVerifyPrefsFileDelaySeconds));
489 #endif
490 }
491
DisableDelaysAndDomainCheckForTesting()492 void DisableDelaysAndDomainCheckForTesting() {
493 g_disable_delays_and_domain_check_for_testing = true;
494 }
495
InitializePrefsFromMasterPrefs(const base::FilePath & profile_path,const base::DictionaryValue & master_prefs)496 bool InitializePrefsFromMasterPrefs(
497 const base::FilePath& profile_path,
498 const base::DictionaryValue& master_prefs) {
499 return CreateProfilePrefStoreManager(profile_path)
500 ->InitializePrefsFromMasterPrefs(master_prefs);
501 }
502
GetResetTime(Profile * profile)503 base::Time GetResetTime(Profile* profile) {
504 return ProfilePrefStoreManager::GetResetTime(profile->GetPrefs());
505 }
506
ClearResetTime(Profile * profile)507 void ClearResetTime(Profile* profile) {
508 ProfilePrefStoreManager::ClearResetTime(profile->GetPrefs());
509 }
510
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)511 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
512 ProfilePrefStoreManager::RegisterProfilePrefs(registry);
513 }
514
RegisterPrefs(PrefRegistrySimple * registry)515 void RegisterPrefs(PrefRegistrySimple* registry) {
516 ProfilePrefStoreManager::RegisterPrefs(registry);
517 }
518
519 } // namespace chrome_prefs
520