Abstract: Preferences are used to store configuration parameters that can be modified at run-time rather than compile-time. This document describes the architecture of Chromium’s preferences system and explains how to use it in the context of extensions and policies. Authors: battre, pamg Last modification: March 16, 2013 (updated code search links) IntroductionPreferences are a means to store configuration options in Chromium. Each preference is identified by a key (a string like “proxy.mode”) and points to a value that we call the preference value. These values can be represented by any data-type that is defined in “values.h”, i.e. booleans, integers, strings, lists, dictionaries, et cetera. Preferences can be associated with a browser profile or with local state. Local state contains everything that is not directly associated to a specific profile but rather represents values that are associated with the user account on the host computer (e.g. “Was the browser shut down correctly last time?”, “When was the ‘GPU black list’ downloaded the last time?”, etc.). Due to its nature, local state is never synced across machines. The preference values that are effective at runtime can be set from various sources like default values, files of persisted settings, extensions and policies. The preference system is responsible for and allows for
BasicsRegistering preferencesEach preference needs to be registered before being used as in the following example:PrefService* prefs = …; prefs->RegisterBooleanPref(prefs::kSavingBrowserHistoryDisabled, false, PrefService::UNSYNCABLE_PREF); where prefs::kSavingBrowserHistoryDisabled is a string defined in pref_names.{h,cc} .Here we register a boolean preference with the key “history.saving_disabled” and a default value of false . The default value determines the type of value that can be stored under the key (in this case: boolean). Prefs associated with a profile may be labeled as sync-able and un-sync-able (see sync).Registering preferences is important to define their type and guarantee valid default values but also because only registered preference keys can be queried for their current value. Preferences are persisted to disk in the “Preferences” file as JSON with nested dictionaries. The “.” in the preference key is used as the nesting operator: { “history”: { “saving_disabled”: false } } This hierarchical namespace is not exposed within Chromium. You must not query “history” and expect a dictionary containing “saving_disabled” . Always access registered preferences by their full key.To register new preferences, add your RegisterPrefs call to RegisterLocalState or RegisterUserPrefs in browser_prefs.cc .Accessing preference valuesThe preferences system lives entirely on the UI thread. In the following we assume that we want to access it from there. The preferences associated with the profile can be accessed using the PrefService provided by Profile::GetPrefs() . The PrefService responsible for local_state is accessible by calling g_browser_process->local_state() .The PrefService provides getter and setter methods like bool GetBoolean(const char* path) const; void SetBoolean(const char* path, bool value); As we want to be sure that modifications trigger notifications (see below), GetDictionary() and GetList() return const-pointers. To modify the values, there are two choices:
You do not need to save modified preferences. All set and update operations trigger a timer to write the modified preferences to disk. This reduces the number of incremental write operations. If you really need to be sure that the preferences are written to disk (during shutdown), use PrefService::CommitPendingWrite() .NotificationObserver interface (notification_observer.h ) can have a member variablePrefChangeRegistrar registrar_; In its constructor, the class would initialize the registrar as follows registrar_.Init(pref_service); registrar_.Add(prefs::kPreference, this); prefs::kPreference would call the Observe() method of this .The PrefMember classes ( BooleanPrefMember , IntegerPrefMember , …, see pref_member.h ) are helper classes that stay in sync with preference values beyond the scope of the UI thread. This allows simple reading of preference values even outside the UI thread.PrefStores and PrecedencesChromium knows several locations where preferences can be stored:
Source: pref_value_store.h The locations are sorted in decreasing order of precedence meaning that a higher preference store overrides preference values returned by a lower preference store. This is important because it means for example that an extension can override command-line configured preferences and that policies can overrule extension controlled preference values. The default_prefs PrefStore contains the values set by PrefService::Register...Value (see above).The four policy related PrefStore s are discussed in a chapter below.The user_prefs PrefStore represents a persisted pref store. It contains preference values configured by Chromium’s “Preferences” dialogs (and also preferences set by extensions stored under extension-specific preference keys “extensions.settings.$extensionid.preferences ”).The extension_prefs PrefStore maintains an in-memory view of the currently effective preference values that are set by extensions. As multiple extensions can try to override the same preference, this PrefStore respects their relative preferences (more on this below). It provides a view over the “extensions.settings.*.preferences ” paths in the user_prefs .The command_line_prefs represent preferences activated by command-line flags.Incognito ProfileThe incognito profile is designed to overlay the regular profile. Preferences defined in the regular profile are visible in the incognito profile unless they are overridden. The following table illustrates which PrefStore s are shared between the profiles and which are handled differently.
Extension controlled preferences can be defined for three different scopes:
The in-memory overlay for user_prefs can be used to ensure that specific changes to the preferences do not get persisted in the regular user prefs. Class StructureThe following figure illustrates the PrefStores (the figures use UML syntax: dashed lines with triangles represent inheritance; solid lines with arrows and filled diamonds represent composition; solid lines with arrows and empty diamonds represent aggregation):PrefStore is an interface that allows read access and subscription to changed values.The PersistentPrefStore interface extends this with setter methods as well as read and write operations to load and persist the preferences to disk. The JsonPrefStore implements this interface to store the “Preferences” file in the profile on disk. The IncognitoUserPrefStore provides means for an in-memory overlay. This allows storing incognito preferences that are not written to disk but forgotten when the last incognito window is closed.The ConfigurationPolicyPrefStore s handle policy driven preferences. They are discussed in a separate chapter.The CommandLinePrefStore , DefaultPrefStore and ExtensionPrefStore store the respective types of preference values. The ExtensionPrefStore is discussed in a separate chapter. These three PrefStores are based on the ValueMapPrefStore which provides an in-memory implementation of a PrefStore and relies on the PrefValueMap for this.The PrefValueStore is a facade around all PrefStores that enforces the precedence presented above. It maintains ownership of the respective PrefStore s and asks them one by one until the first PrefStore contains a specific key. PrefValueStore also answers questions about where a preference value comes from. For example, client code occasionally wants to know whether a preference is under control of the user, i.e., not forced by configuration management or extensions.The PrefService is the global interface to preferences. It supports registering default values, and simple access to currently effective preference values. At this abstraction layer, the PrefValueStore becomes an implementation detail of the PrefService :The PrefService serves three purposes:
ExtensionPrefs class manages preference values that extensions want to set. It persists values to disk using the PrefService and feeds values to the ExtensionPrefStore so that the PrefValueStore can consider extension controlled preferences for effective preference values. The latter happens indirectly. The ExtensionPrefs instance writes the preference values into the ExtensionPrefValueMap which knows about regular and incognito preferences. The ExtensionPrefStore , which is specific to either a regular profile or an incognito profile, subscribes to the ExtensionPrefValueMap and retrieves the respective regular or incognito preferences.Notification MechanismsThe following figure indicates how preferences are set (blue arrows) and how change notifications are propagated to subscribers (red arrows). The blue paths are triggered in three different ways:
PrefChangeRegistrar and PrefMember can be used to subscribe to changes as outlined above.Extension Controlled PreferencesSome (selected) preferences can be controlled by extensions (such as the proxy settings). These preferences need to be made available to extensions explicitly as we do not want to allow extensions to configure all preferences. Some particularities of extension controlled preferences need to be addressed:
Exposing preferences to extensionsIn order to expose a preference to an extension, you need to follow these steps: Add a property of type ChromeSettings to your extension namespace in the respective file in chrome/common/extensions/api . This is an example from the proxy extension:"properties": { "settings": { // “settings” is the name of the preference exposed to the extension "$ref": "ChromeSetting", "description": "Proxy settings to be used. The value of this setting is a ProxyConfig object.", "value": [ "proxy", // this is an internal, unique key referred to as “preference key” below {"$ref": "ProxyConfig"} // this is the schema to which preferences need to comply ] } } Add an PrefMappingEntry to kPrefMapping[] in extension_preference_api.cc . You require three entries:
PrefTransformer to PrefMapping::PrefMapping() in extension_preference_api.cc . This allows for a transformation of how preferences are structured within the browser and in the extension. For example, the Proxy Settings API exposes preferences differently to extensions than they are stored internally.By following these steps, we guarantee that all preferences are made available in the same way. We provide get() , set() , and clear() functions as well as an onChanged event.Configuration PolicyConfiguration policy, a.k.a. admin policy, uses preferences as the main way of exposing policy settings in the Chromium code. There are two levels policy can come in:
The ConfigurationPolicyPrefStore objects always keep the latest known policy configuration. Behind the scenes, the policy settings are read from the platform's native management APIs through the ConfigurationPolicyProvider abstraction, which monitors the platform's policy configuration an notifies ConfigurationPolicyPrefStore to reexamine policy configuration as provided by the ConfigurationPolicyProvider on changes. ConfigurationPolicyProvider will then map the new configuration to preferences and expose them to PrefValueStore, generating PREF_CHANGED notifications as appropriate.Covering the design of all ConfigurationPolicyProvider implementations is out of scope for this document, but here is a quick overview (see also http://dev.chromium.org/administrators):
In order to map command line parameters to preference values, you can edit command_line_pref_store.cc and follow the examples therein. Note that it may be advantageous to copy command-line flags into the CommandLinePrefStore . This decouples our code from a static global CommandLine instance. |
For Developers > Design Documents >