| # Prefs |
| Prefs is meant to store lightweight state that reflects user preferences (e.g. |
| chrome://settings, position of windows on last exit, etc.). Browser-wide prefs |
| are stored in Local State (`g_browser_process->local_state()`) and per-profile |
| prefs are stored in Preferences (`Profile::GetPrefs()`). The `base::PrefService` |
| API is used to read/write registered prefs. Prefs are saved as JSON and any |
| modification forces serialization of the entire JSON dictionary. The |
| `LOSSY_PREF` flag can be used when registering a pref to indicate that |
| modifications to it shouldn't schedule a write (in which case the write will be |
| bundled with the next change that does schedule a write or wait until the final |
| write on shutdown; the update is lost in case of a crash). |
| |
| Prefs are not for: |
| * Large collections of data (prefs are loaded and parsed on startup and |
| serialized for writing on the UI thread) |
| * Things that change very frequently (every change triggers a write unless |
| using the `LOSSY_PREF` flag) |
| |
| ## Adding a new pref |
| 1. Pick a name that resembles / shares a pref namespace with existing related |
| prefs if possible. |
| 1. Define a new unique name in a pref_names.cc file. Either in: |
| * chrome/common/pref_names.cc -- being careful to put it in the right |
| section (LOCAL STATE versus PROFILE PREFS) and alongside similar prefs |
| (existing ifdefs and/or pref namespaces); or, ideally in: |
| * a pref_names.cc local to your component (typically inside a prefs:: C++ |
| namespace nested in your component's namespace) |
| 1. Add a registration call from chrome/browser/prefs/browser_prefs.cc to your |
| component to register your new pref using `RegisterLocalState()` or |
| `RegisterProfilePrefs()` as appropriate. |
| 1. If your pref should be synced (only an option for profile prefs), add the |
| `SYNCABLE_PREF` flag when registering it. |
| |
| ## Querying a pref |
| Use `base::PrefService::Get*()` APIs on `g_browser_process->local_state()` or |
| `Profile::GetPrefs()`, as appropriate, to read/write your pref. |
| |
| Reading (`GetValue()`) will query the following `base::PrefStore`'s in order, |
| the first one with a value will win (implemented in `base::PrefValueStore`): |
| 1. Managed Prefs (cloud policy) |
| 1. Supervised User Prefs (parental controls) |
| 1. Extension Prefs (extension overrides) |
| 1. Command-line Prefs (command-line overrides) |
| 1. User Prefs (the actual pref files on disk which reflect user choice) |
| 1. Recommended Prefs (cloud policy to override defaults but not explicit user |
| choice) |
| 1. Default Prefs (the default value you provided at registration) |
| |
| Writing (`SetValue()`) will always write to User Prefs (the only modifiable |
| store). As such, if a value is already set in a PrefStore with precedence over |
| User Prefs, re-reading the value might not return the value you just set. |
| Visually such settings are typically grayed out to prevent confusing the user |
| but nothing prevents C++ from setting a user pref that doesn't take effect. |
| |
| ## Deleting an old pref |
| Deleted prefs should be left in a delete-self state for 1 year in an attempt to |
| avoid leaving unused text in JSON files storing User Prefs. To avoid leaving a |
| bunch of TODOs and pinging owners to cleanup, you will be asked to follow-up |
| your CL with another CL that removes 1+ year old deletions; someone else will |
| cleanup after you in 1 year. |
| |
| 0. If the pref is also a policy, you will need to mark it deprecated as |
| described in |
| [add_new_policy.md](https://chromium.googlesource.com/chromium/src/+/master/docs/enterprise/add_new_policy.md#deprecating-a-policy). |
| Deleting the pref logic (steps below) will need to wait a few milestones. |
| |
| 1. Move the pref name declaration to the anonymous namespace of |
| [chrome/browser/prefs/browser_prefs.cc](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/prefs/browser_prefs.cc) |
| 1. Move registration code into `RegisterProfilePrefsForMigration()` or |
| `RegisterLocalStatePrefsForMigration()` as appropriate. |
| 1. If the old registration code had the `SYNCABLE_PREF` flag, remove it now |
| (syncing the deletion would break clients on older versions). |
| 1. Add a `ClearPref()` call in `MigrateObsoleteProfilePrefs()` or |
| `MigrateObsoleteLocalStatePrefs()` as appropriate, with today's date |
| (MM/YYYY) in a comment. |
| 1. Delete the old code. |
| 1. In a follow-up CL, delete any 1+ year old `ClearPref()` calls in |
| browser_prefs.cc; someone else will clean up after you in 1 year. |
| |
| ## Migrating a pref |
| Instead of merely deleting a pref you might want to run migration code from an |
| old to a new pref. This uses the same hooks as deletion and will be left in |
| place for 1 year as well. `MigrateObsoleteLocalStatePrefs()` is invoked as part |
| of initializing `g_browser_process` and `MigrateObsoleteProfilePrefs()` is |
| invoked as part of initializing each `Profile`. In both cases this is before |
| each `PrefService` is query-able by the rest of //chrome, your code can |
| therefore assume the migration has taken place if it's accessing the |
| `PrefService` via an initialized `BrowserProcess` or `Profile`. |
| |
| As per [deleting an old pref](#deleting-an-old-pref), if the old pref is also a |
| policy, you will need to mark it deprecated for a few milestones first as |
| described in |
| [add_new_policy.md](https://chromium.googlesource.com/chromium/src/+/master/docs/enterprise/add_new_policy.md#deprecating-a-policy). |
| |
| Migration code will want to read the old pref using |
| `base::PrefService::GetUserPrefValue()` (as opposed to |
| `base::PrefService::Get*()`). This will ensure that the user configured value is |
| migrated instead of a value from a higher-priority PrefStore like the one |
| containing Managed Prefs. It also covers a second case: If no explicit value is |
| set in any PrefStore, GetValue() returns the default value. You don't want to |
| write that to the target location of your migration as that would prevent future |
| changes to default or recommended prefs from taking effect. |
| |
| If non-User PrefStores need to keep supporting the old pref for a grace period, |
| you will need to either: |
| 1. Support both for the grace period (like policies above). In which case you |
| should still migrate the User Prefs as described above but keep reading the |
| old pref name in your code if a higher-priority store is setting the old |
| value |
| (`!base::PrefService::FindPreference(old_pref_name)->IsUserModifiable()`); or |
| 2. Make sure that relevant PrefStores automatically map the old pref name to the |
| new pref name. There are ad-hoc examples of this in the codebase but this is |
| generally trickier. If you do add/find a generic way of doing this, please |
| augment this documentation :). |