Context Framework Subsystem Architecture Description ==================================================== [width="30%"] |================================ |Author | Marius Vollmer |Status | Draft |Version | {sys:date +%Y-%m-%d} |Approver | Olli Finni |================================ Copyright (C) Nokia. All rights reserved. This material, including documentation and any related computer programs, is protected by copyright controlled by Nokia. All rights are reserved. Copying, including reproducing, storing, adapting or translating, any or all of this material requires the prior written consent of Nokia. This material also contains confidential information, which may not be disclosed to others without the prior written consent of Nokia. Nokia is a registered trademark of Nokia. Other company and product names mentioned herein may be trademarks or tradenames of their respective owners. Introduction ------------ The Context Framework, part of the Data Domain, provides a uniform, high level API to numerous context properties of the device. While many of these context properties are available without the context framework, each of them has its own specific way of accessing it. The context framework collects them all behind a uniform API, and applications thus have easy access to all of the context properties. The following lists some typical context properties: - Connectivity status of the device; whether it is connected to the Internet and by what means. - Location; the name of the current city. - Builtin sensors; orientation in space. - Current use; idle, plays media, web browsing. - Combined properties; current weather based on location and online weather database. More concretely, the information in the status bar of a device is provided exclusively by the Context Framework. Applications access context properties by using the +ContextProperty+ class that is implemented in api:libcontextsubscriber. The context framework is modular: context properties from multiple independent components are directly combined in the +libcontextsubscriber+ API and applications can access them without needing to know who is ultimately providing them. A component that wants to directly provide context properties needs to implement the relevant interfaces defined by the context framework. Currently, the only supported way to do that is to use the api:libcontextprovider library. In addition to information from multiple sources, the context framework is a provider of context properties itself: there is a _context daemon_ that collects information from low-level and legacy interfaces. This context daemon is a good default location for implementing context properties and for absorbing properties from existing subsystems that have aqcuired them for historical reasons and would rather get rid of them. The concrete list of properties is ultimately defined by their providers, but the context framework is the central authority: the `official' list of context properties of the Maemo platform is defined and documented by the context framework. To summarize, the context framework contributes value to the Maemo platform in the following ways: - It implements and documents a high-level, uniform API to a set of context properties that are provided by multiple components. - It defines and documents the concrete list of properties of the Maemo platform. This includes harmonizing the context ontology with other industry efforts. - It implements context properties that do not naturally belong to other subsystems and coordinates the implementation of context properties that do belong in specific subsystems. - It provides a debugging and exploration tool for inspecting and controlling context properties. Thus, the Context Framework does not drive the behavior of the system, it only provides the information that is needed for other components to decide for themselves. To makes this reasonably easy, the context properties are at a high level of abstraction and express the coarse grained states of the device. For example, the properties tell you whether it is completely idle, in passive use playing some media, or in active use. They don't give a real-time view of CPU load. Architecture ------------ Concepts ~~~~~~~~ Context properties are collected from all providers that have registered themselves with the link:context-providers.html[+context-providers+] interface. For each provider, this registration information includes the list of its properties with type information and a short description for each, and the D-Bus bus name where the provider can be reached. Providers can be both on the session and on the system bus, and the registration information indicates which bus it is. This registration information is read by the +libcontextsubscriber+ library and used by its +ContextProperty+ class to connect a requested property name to the right bus name. The registration information is compiled into a _cache_ that is optimized for use by +libcontextsubscriber+. When the set of registered properties changes, the cache is recompiled by a command line utility provided by the context framework. This will then trigger all libcontextsubscriber clients to reload the registry information, and existing +ContextProperty+ instances to be updated. (Note that the cache only caches property declarations, it does not ever contain the values of context properties.) When providers are installed from packages, recompilation of the cache happens automatically. _Triggers_ in the Context Framework packages are used to run the command line utility at the right times. The +libcontextsubscriber+ library gracefully handles start, stop and restart of providers. During system startup some applications may start to use the Context Framework before all providers are available. Properties become dynamically available as providers become available, and removed when providers are no longer available. Communication between a +ContextProperty+ and the provider happens using a private D-Bus interface. This interface allows for bulk retrieval of property values, bulk subscriptions, and bulk change notification. The values of properties are represented to clients as a +QVariant+ value. Properties can have a special _null_ value when they are not available, either because they are not provided by any provider, or because the provider is not able to deliver a value. In other words, the types of all context properties are "maybe types": subscribers might get a value or not. In general, the _null_ value means that the real value of the property is unknown. The _null_ value is different from the empty string or the empty list. For example, the "Location.City" property, which denotes the name of the current city as a string, will be _null_ when the name of the city is unknown (either because the current location of the device is unknown or because the database that maps from locations to city names is not reachable), but it will be the empty string when the current location is known to be outside of any city. The absence of a value can have many reasons: no provider is available for this property, the provider has not yet delivered a value, or the provider is deliberately not delivering a value, which it can in turn have many reasons. For example, necessary hardware might not be present or its use might be disallowed by the current power management policy, or a needed online database might not reachable. The Context Framework makes no attempt to distinguish these different reasons. Subscribers should make good use of a value when they get it, but they must not fail catastrophically when no value is available, or when it takes longer than expected for it to become available. It is expected that eventually the statusbar plugins, such as the battery charge monitor and the connectivity indicators, exclusively use the context properties to retrieve the information they display. Context providers need to implement the private D-Bus interface. This is done with the api:libcontextprovider library. This library is used by the context daemon itself, which can serve as an extended example. The Connectivity Framework and the Sensor Framework are expected to be context providers as described above. Additional context properties, such as those related to the Location Framework, are implemented by the _context daemon_ contained in the Context Framework. The +contextd+ Context Daemon will implement all context properties that don't have a native provider. It will at least implement properties for the information contained in HAL and for location related information. It is expected that +contextd+ runs the necessary reverse geocoding operations at a reasonable frequency. It will also perform Content Framework queries to retrieve the values of certain properties. If necessary for security reasons, the +contextd+ might need to be split into multiple instances. System context ~~~~~~~~~~~~~~ The context framework decouples context subscribers from context providers. [dotty,fig3.png] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ digraph G { graph [size="7,100"]; node [shape=box, style=filled, fontsize=11]; edge [fontsize=11]; "Direct UI Framework" -> "Context Framework" "Policy Engine" -> "Context Framework" "Sensor" -> "Context Framework" "Content Framework" -> "Context Framework" [dir="both"] "Context Framework" -> "Internet Connectivity" [dir="back"] "Context Framework" -> "Location Framework" "Context Framework" -> "Freedesktop Essentials" } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Structural view ~~~~~~~~~~~~~~~ The following figure summarizes the components of the Context Framework. [dotty,fig4.png] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ digraph G { graph [size="7,100"]; node [shape=box, style=filled, fontsize=11]; edge [fontsize=11]; { rank=source app [label="<>\n\napplication"]; } subgraph cluster0 { label="Context Framework" registry [label="<>\n\n/usr/share/context-providers/"]; cache [label="<>\n\ncache.cdb"]; libsub [label="<>\n\nlibcontextsubscriber"]; update [label="<>\n\nupdate-context-providers"]; libprov [label="<>\n\nlibcontextprovider"]; contextd [label="<>\n\ncontextd"]; commander [label="<>\n\ncontext-commander"]; corepros [label="<>\n\ncore context\nproperty declarations", shape=note]; // update -> registry [label="<>"] // update -> cache [label="<>"] registry -> update [label="<>", dir="back"] cache -> update [label="<>", dir="back"] libsub -> libprov [label="<>"] libsub -> registry [label="<>"] libsub -> cache [label="<>"] libprov -> contextd [label="<>", dir="back"] } { rank=sink props [label="<>\n\nicd2-props.xml", shape=note]; icd2 [label="<>\n\nicd2"]; libgeo [label="<>\n\nlibgeo"]; libhal [label="<>\n\nlibhal"]; } app -> libsub [label="<>"] registry -> props [dir="back"] contextd -> libgeo [label="<>"] contextd -> libhal [label="<>"] libprov -> icd2 [label="<>", dir="back"] } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are two fundamental options for exporting information via the context framework: - The context daemon can use existing platform interfaces, such as HAL, to collect this information, process it, and export it as a context property. + This applies to: HAL, Location subsystem, Kernel. - The principal producer of the information, such as the +icd2+ daemon in the Connectivity subsystem, can use the libcontextprovider API and export the information directly to applications without using the context daemon as a middle man. + This applies to: Sensor Framework, possibly Connectivity subsystem (needs agreeement), possibly Telephony subsystem (needs agreement) Provided Interfaces ~~~~~~~~~~~~~~~~~~~ .+libcontextsubscriber+ A C++ API for listening to context properties. link:libcontextsubscriber[Documentation] .+libcontextprovider+ A C++ and C API for providing values of context properties. link:libcontextprovider[Documentation] .+context-properties+ The canonical list of context properties in the Maemo platform. When a context property from the list is available, it must conform to its description there. link:context-properties.html[Documentation] .+context-providers+ The interface to register providers of context properties. A provider must use the api:libcontextprovider API. link:context-providers.html[Documentation] Development support ~~~~~~~~~~~~~~~~~~~ No special features are needed in the Context Framework components to make them work in a Scratchbox environment. Availability of individual properties depends on the ability of their providers to run in Scratchbox. The +contextd+ Context Daemon runs but might not be able to provide all properties. The Context Framework provides a graphical tool called the Context Commander to watch all available context properties. This can be used to test context providers during development. In addition, the Context Commander can be used to force context properties of selected applications to arbitrary values. This can be used to test the reaction of applications to context changes. The Context Commander runs on the device and either show its UI on the device itself or exports it to an external X11 server. This way, the testing can be done without disturbing the display of the device itself. When started, the Context Commander takes control of all subscribers with their cooperation: when the "org.freedesktop.ContextKit.Commander" name appears on the session D-Bus, all ContextProperty instances redirect their subcription requests to it. There are vague ideas about integrating the Context Commander into Eclipse. Licenses ~~~~~~~~ The components of the Context Framework will be developed publically, under the umbrella of the freedesktop.org organization. All source code is licensed with LGPL 2.1, including the daemon and context commander. Non-free source code can safely interact with the Context Framework components. User Data, Settings, and Configurability ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Context Framework does not store user data and is not configurable. Configurability ~~~~~~~~~~~~~~~ See above. Packages ~~~~~~~~ .+contextkit+ Languages:: C, C++, Vala License:: LGPL 2.1 Provided interfaces:: libcontextsubscriber, libcontextprovider, context-providers, context-properties, Used interfaces:: libdbus, libgee, libglib, libcdb, libqt4-dbus, libqt4-xml, libqtcore4 Binary packages:: libcontextsubscriber0, libcontextsubscriber0-dbg, libcontextsubscriber-dev, libcontextsubscriber-doc, libcontextprovider0, libcontextprovider0-dbg, libcontextprovider-dev, libcontextprovider-doc, contextkit, contextkit-doc, context-dbg Sources:: https://dvcs.projects.maemo.org/git/?p=ContextKit .+context-commander+ Languages:: C++ License:: LGPL 2.1 Provided interfaces:: none Used interfaces:: libcontextsubscriber, libqt4-dbus, libqt4-gui, libqt4-core Binary packages:: context-commander Sources:: https://dvcs.projects.maemo.org/git/?p=ContextCommander .+context-provider-example+ Languages:: C License:: LGPL 2.1 Provided interfaces:: Context.Example.* properties. Used interfaces:: libcontextprovider, sysfs files for accelerometer and ambient light sensor Binary packages:: context-provider-example Sources:: https://dvcs.projects.maemo.org/git/?p=ContextProviderExample .+context-subscriber-example+ Languages:: C++ License:: LGPL 2.1 Provided interfaces:: none. Used interfaces:: Context.Example.* properties, libcontextsubscriber, libqt4-gui, libqt4-core Binary packages:: context-subscriber-example Sources:: https://dvcs.projects.maemo.org/git/?p=ContextSubscriberExample Performance ----------- General ~~~~~~~ The Context Framework makes no real-time guarantees and does not rely on any. It is careful not to cause significant additional communication that wouldn't be needed anyway to communicate contextual information to the interested parties. We expect 5 to 10 providers, about 20 subscribers, each subscribed to an average of 5 properties. Property values can become arbitrarily big, but are expected to be mostly small, in the order of 10 bytes. The occasional big property value is expected to change correspondingly infrequently. Memory ~~~~~~ |======================================================================================== | OneNAND | All files are stored on the OneNAND, in their FHS mandated places | 200 KiB | eMMC | Not used | 0 | RAM/Idle | A couple of bytes per subscription plus a couple more per provided property | 200 KiB | RAM/Peak | The biggest property values might reach a KiB | 500 KiB |======================================================================================== Runtime ~~~~~~~ The Context Framework allows subscribers and providers to directly connect to each other (incurring only the usual D-Bus daemon overhead). Context properties are expected to change only infrequently and providers are urged to throttle the rate of change. The contextd daemon is started on the first subscription to one of its properties. This is expected to happen on every boot since it provides properties that are used by other daemons, such as the context engine. Power consumption ~~~~~~~~~~~~~~~~~ Providers of context properties know at any time whether someone in the system is subscribed to them. This allows them to avoid expensive operations for producing values that are not needed. The documentation for subscribers urges them to take the cost of producing property values into consideration. The subscriber API offers an easy way to temporarily suspend a subscription. Sometimes, increased granularity of control over a property is needed: instead of just switching it on and off, the subscriber might want to request different levels of quality. For example, some subscribers might need a higher update frequency than others and are willing to pay the associated price in power consumption. The recommended way to implement this increased control is to offer multiple properties that deliver the same value but with different qualities-of-service. For example, there could be both "Location.HighResCoordinates" and "Location.LowResCoordinates" properties that both deliver the current geographical coordinates. Subscribing to "Location.HighResCoordinates", however, would cause the location to be updated more frequently and maybe even activate a GPS device, if available. Security Impact --------------- Different context properties might need to have different access restrictions. A context provider can implement these access restriction in whatever way works, but should preferrably use the existing features of the Security Framework. The Security Framework can control access per D-Bus bus connection. Thus, a given context provider should only implement properties with the same access rights and leave it to the Security Framework to allow or disallow connections to the provider as a whole. The Context Daemon needs to follow the same rules, of course. The libcontextsubscriber library listens for a special D-Bus bus name to appear and then allows the service behind that name to override all values of context properties. The library protects this special name with a security token so that only specially certified software can own this name. The context commander might or might not be certified in this way; instead of certifying it, it might be preferrable to require developers to explicitly disable the name protection (via a developer certificate or a general device unlocking ceremony) before they can use the context commander. Open Items ----------- - The D-Bus interface needs to be reviewed and maybe redesigned. It might make sense to use one object path per property instead of one object path per subscriber like we do now. - Integration with Content Framework needs to be addressed. Snapshots of the current context need to be imported into the content database (as document tags, say) and content queries might be run periodically to provide contextual information (such as the ten most recently accessed documents). - The current plan for localization of context properties requires context providers to do it. They thusly need access to the current device language and rumour has it that everything about l10n is different in Harmattan. Appendices ---------- The Context Framework for Context Providers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The advantages of the Context Framework for application writers should be clear: they can access a rich set of useful contextual information with a simple API. The ultimate providers of this information, however, might feel that the context framework itself does not add significant value: after all, they already implement APIs to access all that information anyway. Hooking into the Context Framework means a duplication of effort and the requirement to express everything as a value (instead of a general query/response API) might be unwelcome. However, the unified API and central maintenance of the list of core properties carries a lot of value: - It makes using more contextual information trivial once you have used your first property. - It makes it possible to expose present and future context information in all kinds of places with a single effort. Once the context framework has been integrated into the Web runtime, into Python, or into any language that people care about, no additional effort is needed by anyone to track future developments of the context properties. - It decouples context providers from consumers. The context framework makes it possible to move the implementation of a property from one component to another without having to restart the consumers. - It makes it worthwhile to develop sophisticated tools such as the context commander and support for easy automated testing of context subscribers and providers. - It might allow some context providers to exit the "API business" altogether. + If a piece of information is available in a corner of the system but needed somewhere else, it is only human to see this as a nuisance and cobble together a few D-Bus methods to access that information. + The context framework provides a good alternative in those cases. It is thus our opinion that the context framework provides enough value to justify pushing it into other peoples subsystems, even if that means duplicated efforts. Moreover, the effort needed to integrate with the context framework is low. Relation to Policy Engine ~~~~~~~~~~~~~~~~~~~~~~~~~ The policy engine has the role in the Maemo platform to decide system global behavior and controls the various distributed enforcement points accordingly. This job will likely be done by OHMng. The policy engine can be both a subscriber to and provider of context properties. The policy engine will base its decisions (partly) on the current values of context properties and will publish (part of) its decisions as context properties. Most facts that need to be gathered as input for the policy engine can be communicted to it via the context framework. If necessary, non-public context properties can be defined that (while visible to everyone who knows where to look) are not maintained as part of the list of core properties. Decisions of the policy engine can be communicated to cooperating applications and potentially even to enforcement points. The set of values representable as context properties is quite rich so that hopefully all facts and decisions can be represented with them.