the Chromium logo

The Chromium Projects

Preferences

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

Introduction

Preferences 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 block 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

These aspects are addressed in the following.

Basics

Registering preferences

Each 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 values

The 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:

  1. Use void PrefService::Set(const char* path, const Value& value) to set a new dictionary value.
  2. Use a ScopedUserPrefUpdate (see scoped_user_perf_update.h) to modify a dictionary or list. For updating a dictionary, the code would look as follows: DictionaryPrefUpdate update(pref_service, prefs::kPrefName); update->SetBoolean(“member_key”, true); update->Remove(“other_key”, NULL); At the time when “update” leaves its scope, a “value has changed” notification is automatically triggered.

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().

The PrefChangeRegistrar allows to subscribe to preference change events. A class that wants to be notified of preferences changing can have a member variable

PrefChangeRegistrar registrar_;

In its constructor, the class would initialize the registrar as follows

registrar_.Init(pref_service);
registrar_.Add(prefs::kPreference, base::BindRepeating(/* … */));

passing either a base::RepeatingClosure or a base::RepeatingCallback taking a const std::string& (if the changed preference path is required). Then, any changes to prefs::kPreference will call the provided callback.

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 Precedences

Chromium knows several locations where preferences can be stored:

Store Purpose
managed_platform_prefs contains all managed platform (non-cloud policy) preference values
managed_cloud_prefs contains all managed cloud policy preference values
extension_prefs contains preference values set by extensions
command_line_prefs contains preference values set by command-line switches
user_prefs contains all user-set preference values
recommended_platform_prefs contains all recommended platform policy preference values
recommended_cloud_prefs contains all recommended platform cloud preference values
default_prefs contains all default preference values
Source: [pref_value_store.h](https://code.google.com/p/chromium/codesearch#chromium/src/base/prefs/pref_value_store.h&q=file:pref_value_store.h%20%22decreasing%20order%20of%20precedence%22&sq=package:chromium&type=cs&l=34)

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 PrefStores 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 Profile

The 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 PrefStores are shared between the profiles and which are handled differently.

Store in regular profile Incognito profile
managed_platform_prefs Same PrefStore as in regular profile
managed_cloud_prefs Same PrefStore as in regular profile
extension_prefs Special handling for different life-cycles (see below)
command_line_prefs Same PrefStore as in regular profile
user_prefs In-memory overlay that prevents persistence to disk
recommended_platform_prefs Same PrefStore as in regular profile
recommended_cloud_prefs Same PrefStore as in regular profile
default_prefs Same PrefStore as in regular profile
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 Structure

The 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):image 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 ConfigurationPolicyPrefStores 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 PrefStores 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:

image The PrefService serves three purposes:

The 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 Mechanisms

The following figure indicates how preferences are set (blue arrows) and how change notifications are propagated to subscribers (red arrows).

image The blue paths are triggered in three different ways:

Helper classes like the PrefChangeRegistrar and PrefMember can be used to subscribe to changes as outlined above.

Extension Controlled Preferences

Some (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 extensions

In 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:

Optionally you can register a 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 Policy

Configuration 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 https://www.chromium.org/administrators):

Command line parameters

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.