Jump to page content

Layer Config

Caveat

If, from reading these notes, you conclude that I am off my rocker, you won’t be the first, and you may even be right.

No doubt there is a dozen and one reasons why none of this would ever work, but perhaps somewhere deep down there is a tiny fragment that could be used for something.

Contents

Overview

The name “Layer Config” and the original idea are both from Jennifer Elaan. So far as I can recall, we never decided on any particular implementation.

Layer Config is a configuration service that defines factory defaults and stores both policies and preferences. Unlike Microsoft’s brutally unwieldy Group Policy system, policies and preferences use identical settings. Unlike Linux’s random assortment of make-it-up-as-you-go-along configuration file formats, all configuration is centralised and standardised. This means that, unlike Windows where settings are stored in random places and impossible to port between computers, all settings are stored in a single location that can be ported from anywhere to anywhere. The settings for a single application, a whole user account or the entire computer can be exported and imported as needed.

Settings live in a stack of layers; each layer contains a set of independent slices. Definition slices provide the setting names, formats (including enumeration lists), captions, long descriptions and security configuration as well as the default values and whether the setting is to appear in the Preferences dialog box. Settings are hierarchical in nature (referenced by hierarchical name, e.g. System$Region.Date and Time.Time Zone and Foo Writer$Defaults.Paper Size) and security settings can exist on a per-setting and per-category basis. Definition slices for applications are provided within the configuration directory of each application. The captions, long descriptions and default values can have override definitions in language-specific slices. Categories can be defined as arrays to allow multiple parallel subtrees and settings themselves can be arrays, e.g. System$Display.Monitors[0].Resolution (Monitors is a parallel-subtree category, each subtree being bound to the category definition) or System$Network.Adapters[1].IPv4 Addresses[0] (IPv4 Addresses[0] is an array setting while Adapters is a parallel-subtree category).

The layers run from bottom to top as follows:

  1. Fully disjoint definition slices, comprising:
    • Operating system setting definition slices, including the default settings; each category of the system will have its own slice
    • Application setting definition slices, including the default settings, one disjoint slice per application
  2. Operating system settings slice(s)
  3. Administrative policies, one slice per policy (these slices may overlap according to policy order)
  4. User preferences slices

Each layer inherits from the layer below it. Administrative policies may operate as defaults, as advisories (user settings are replaced on initial application but can be changed by the user afterwards) or as mandates. Mandatory settings within policy slices take precedence over (but do not change) the corresponding settings in the user slices. User settings that would override policy values are simply ignored rather than deleted and will reappear if the policy in question is removed. Multi-value settings can inherit the parent entries or start anew. The user may be permitted to append to the list, or the list may be completely locked. The ability to remove or clear inherited entries is possible but not guaranteed to be provided.

It is most likely that default settings and applied policy settings would be copied into the user’s configuration database to become their actual settings. If the settings were dynamically inherited then policy removal or changes to the application defaults resulting from a program update would cause the user’s settings to unexpectedly change. Possibly each setting could have a flag to indicate whether the user has actively modified it, if this would help indicate which settings are non-default.

Setting definitions can include privilege levels required to define them. Privilege levels include:

Creation of arbitrary settings is impossible. Applications are not able to bury hidden settings inside the system. Applications can at the most update settings that are already defined. Applications are free to modify unprotected system settings but they may not reconfigure other applications without the user’s consent.

Possibly programs would need to define in advance what settings they wish to modify:

Updates

Application updates will often involve changes to the available settings. This may also include changes to the defaults, both for user convenience and for reasons of security, stability and perfomance. The update process should prompt for or consider alerting the user to each of the following as needed:

  1. The following settings are new, and will change default behaviours for security or stability reasons; choose which settings to override back to how they are set at present (all settings default to the new secure/stable choices)
  2. The following settings are new, and will change default behaviours for ease of use only; by default, the system layer will be updated to reflect the prior factory state, overriding the application factory layer

This will be presented to the user a table of affected settings:

Name, Keep new|Revert old, Help topic button linking to help topic in settings definitions manifest

Formats

Formats include:

Any setting can be set to an array of any of the above formats.

Programmatic access

Settings will be programmatically accessible to avoid needing to manually build strings. This process also allows pop, push, append and splice operations in order to maintain entry priority. For example:


	# N functions include an additional parameter for the Nth parallel subtree or array index
	LayerConfig::slice('System$Display')->catN('Monitors', monIdx)->set('Resolution', newRes);
	
	# Set primary address of secondary adapter, ignoring all additional adapters and addresses
	LayerConfig::slice('System$Network')->catN('Adapters', 1)->setN('IPv4 Addresses', 0, '192.168.19.80');
	
	recents := LayerConfig::appSlice()->cat('General')->setting('Recent Files');
	if (defined(currPos := recents->findIndex(requestedPath)) {
		# If we know this file, move it to the top
		recents->moveN(currPos, 0);
	}
	else {
		# Add to the list and trim the list size
		recents->unshift(requestedPath);
		# Alternatively, we could allow the item count limit to be set in the definition itself
		recents->limit(MAX_RECENT_ITEMS);
	}

Hierarchy

Currently we have described a means by which a particular point in the settings tree can be a list of items, with its descendants being repeated for each list item.

However, there is one aspect that is not covered by this: hierarchy. In rare occasions, a settings system will need a recursive node type. There are effectively two such patterns:

The current description allows for a fixed path, i.e. you know that setting C is always at A.B[x].C regardless of the index of B. For hierarchy, we could do one of two:

  1. Relational form, where we retain A.B[x].C, but also have virtual nodes A.B[x]::parent and A.B[x]::children
  2. Hierarchical form, with a path as: A.B[x/y/z].C

In both approaches, the general syntax does not change.

Automatic Preferences window generation

Definition slices are sufficient to allow automated construction of a program’s settings dialog box. Topmost categories could be presented (according to the window manager’s choice) as tabs or a side-panel list. For this to be effective, the definition slice must flag all settings to be made accessible as main preferences. For example, many program settings are behind-the-scenes or reflect other parts of the UI and would be out of place in the Preferences window or simply add unnecessary clutter. Categories would be best off with icons and it would be plausible to attach icons to any settings or categories as desired. Enumerated values could have icons assigned also, e.g. paper orientation.

This principle not only saves a lot of time building the settings window, but it automatically handles translation (using the language-specific slices that also provide language-specific defaults) and furthermore ensures that program configuration remains consistent from one program to another.

Automated UI construction also handles automatic provisioning of advanced features such as clearing a setting so that the default takes over, and unlimited undo/redo handling througout the window’s display lifetime so that user can revert any change to any setting no matter what the control type is. Hidden settings in the manner of Firefox’s about:config can be provided automatically also, although this would be to a much higher standard, in the form of a settings tree with properly-captioned settings.

The preferences window could have a button in the corner that provides options such as clearing a single setting or a whole panel back to factory defaults. This has a precedent in Royal TS where the user can choose which settings to apply in bulk, using essentially the same UI.

UI bindings

When using the automated Preferences dialog box generation, the program may register callbacks for any setting:


	appSlice := LayerConfig::appSlice();
	dialog := AutoPreferences::getDialog();
	
	bgColourRef := appSlice->getRef('Defaults', 'Page', 'Background Colour');
	dialog->registerCallback(bgColourRef, onChangeBgColour);
	
	# Add our own custom control to show the result of the setting
	bgPreview := new BackgroundPreviewControl();
	dialog->setValuePresentationControl(bgColourRef, bgPreview);
	
	# pPref is an AutoPreferences::PreferencesControl object that knows the new value, old value, handle to the preference itself, handle to the
	# dialog box and handle to the dialog box sub-panel that contains the control, such that there is no need to pass in all of these separately
	bool onChangeBgColour(pPref, pEvent) {
		switch (pEvent) {
			# Equivalent to:
			# case LayerConfig::EVT_DISPLAY, LayerConfig::EVT_CHANGE, LayerConfig::EVT_UNDO:
			# (case in expects an array reference of permissible values)
			case in LayerConfig::ALL_DISPLAY_EVENTS:
				bgPreview->updateBackgroundColor(pPref->value);
				return true;
				
			case LayerConfig::EVT_BEGIN_CHANGE:
				# No-op — just accept the colour after it has been set
				# Return true if we took over handling the request
				return false;
		}
	}

Regions and languages

All settings would be named internally in a single language, typically English but not constrained as such. Setting captions however would pick the nearest and most suitable regional override slice where available. Users would generally never interact with the internal settings names, although there is no reason why a utility that works as such could not be created if anyone deemed it advantageous to them in some manner.

Language override slices would also incorporate region definitions, for example en.US and en.GB, as part of a fallback hierarchy. This would not only separate out British and American spelling, but allow for variations such as start-of-week difference (Monday in Britain, Sunday in the US) and paper size conventions (A4 in Britain, Letter in the US).

Aliases

Aliases are entries within a definitions slice that indicate that a setting has been moved or renamed. This allows developers to rename and relocate settings without breaking user’s existing configuration. The default IDE will accumulate these changes and remove any intermediate ones during a final build. E.g. renaming A to B to C during development will be collapsed to a transformation of A → C in the final output file.

Settings storage

Settings are going to live in some kind of database system. Possibly a relational database engine would suffice, and this could be the same database engine used for the multidimensional filing system and the package management. Live SQL access might be seen as excessive considering that only very trivial queries would be needed: queries could instead be pre-compiled into permanent query plans, one for each request type. For settings this may be excessive but for the file system the maximum efficiency is needed.

Management

Annotations

Text-based configuration has an advantage over typical graphical configuration systems in being able to annotate each setting, to indicate why it was set the way it is, and when that change was made. Such annotations will be supported by the settings storage engine. Some means of adding and reviewing such annotations will be needed. F-Secure Policy Manager Console places a speech bubble icon next to each setting so that annotations can be entered; this does introduce visual clutter and it may be preferable for this behaviour to be enabled only on demand, with annotation icons only shown normally if an annotation exists.

Temporary changes

There is often a need to temporarily alter an individual setting or temporarily disable all of an application’s settings. Some consideration is required as to how best to provide these abilities.

Settings editor

The OS should have both graphical and command-line utilities for managing settings, similar to the Registry editor but using the automated UI generation facility to provide an intelligent interface. The graphical tool invites the name “Settings Manager” but this is not a valid choice for two reasons: users would not use it to manage settings in normal operation, and the term “manager” refers to a service that actively manages part of the system.

Conceivably the settings editor would also provide the means to manage policies, at least for a standalone machine. Network-based policies may end up using a separate tool akin to the Windows Group Policy management console on an Active Directory domain controller.

Backup and restore

Perhaps the most important role for the settings editor is backup and restore of settings. The program will allow the settings for the system, a user or a program to be both exported and imported.

A user should be able to open the settings store on any volume for recovery purposes (subject to security restrictions).

Quite possibly the backup and restore process would use the same database format in which the live configuration data lives. Exporting the data for a user would be no different to simply cloning their settings backing store, and exporting the settings for a program would simply involve copying just a portion of their settings store into a new database.