From Fedora Project Wiki
Fedora 7 has full support for fast user switching. This page provides the detailed specification for the development and integration work done to enable this feature

It would be nice if Fedora easily supported fast user switching / multiple sessions. This feature is described in detail here

There's been support in GNOME via the Fast User Switching Applet and GDM for this for some time. However, especially with GNOME being increasingly integrated with the OS (g-p-m, g-v-m, NetworkManager etc.) and the way device permissions are managed (via pam_console), making fast-user-switching work is more than just shipping f-u-s-a.

This document outlines the problems and provides a roadmap for how to implement this in the Fedora 7 timeframe.

Problems

Device Ownership

At the moment we chown the device node for certain devices to the user of the unprivileged desktop session. In a f-u-s scenario with two users logged in, A and B, the last one to log in wins. Hence, when switching back to the first session, some devices are now not accessible.

Proposed fix is to use ACL's on device nodes; hence more than one user can own the device node.

Refuse Service To Inactive Sessions

Each session runs policy daemons such as g-v-m, nm-applet, g-p-m to enforce policy - for example, gnome-power-manager looks at when your system is idle and then turns off the screen (via DPMS), suspends your system or whatever the configuration is. This breaks with fast-user-switching, e.g. suppose the inactive session becomes idle, then g-p-m from the inactive session either turns off the screen or suspend the system.

Proposed fix is to refuse service to inactive sessions. As policy daemons all use HAL (and other system daemons, e.g. NetworkManager) as the mechanism for enforcing policy, the fix is to teach HAL (and other mechnamisms) about what desktop session the caller via D-Bus (e.g. the policy daemon) originates from. This involves a new component called ConsoleKit - see below for discussion.

Better GDM integration and face browser by default

GDM should automatically default to using the face browser when there is only a few local users on the system. Today, using f-u-s-a, it's weird if you want to log in a new user, what happens is

  1. user Foo is running in session A
  2. from session A, user Bar is selected in the f-u-s-a applet
  3. a new instance of g-d-m is launched and switched to (notably this instance has a "Quit" button!) and it asks for the user name
  4. can now type in username Bar and a new session is launched

We need to look into this user interaction.

Transitioning from one session to another

Right now, when the user switches from one session to another, there's a bunch of virtual terminal switches happening that involves mode setting of the graphics card resulting in nasty flicker and other artifacts. With some drivers DRI works only in the first session. Some drivers further have problems when it comes to running multiple X-Servers in parallel. It's slow too. This is not necessary at all and ideally we'd be able to do nice BlingBling effects as seen in e.g. Mac OS X.

Needs input from X hackers here.

Enhance applications

With ConsoleKit, applications can easily query whether the session they're running in is currently active as well as subscribe to D-Bus notifications when activity changes. Hence, instannt messaging software, email software, media players and so forth can be enhanced to Do The Right Thing(tm) (what ever that may be) depending on whether the desktop session is active or not.

ConsoleKit

ConsoleKit is a system-wide service that tracks seats and sessions. It's existence is justified by that it's needed for both multi-seat and f-u-s.

It's a pretty simple service that exports a few interfaces

  • to enumerate the physical seats that is part of the system. A "Seat" corresponds to a physical console, e.g. a monitor + keybord/mouse.
  • to enumerate desktop sessions, what seat the desktop session is on, and whether it's active (multiple desktop sessions can run on the same console, that's fast-user-switching)
  • Given a UNIX process ID, ConsoleKit can return what session the given UNIX process ID belongs to. This is to be used by system-level mechanisms (such as HAL and NetworkManager) to deny service to policy daemons in inactive desktop sessions.
  • Implementation details; currently ConsoleKit relies on login managers setting an environment variable, XDG_SESSION_COOKIE, for processes in the session. Membership in a desktop session (from ConsoleKit point of view) is thus defined as knowledge of the value of $XDG_SESSION_COOKIE.
  • Need patches for kdm and other KDE components too

See the end of this document for ConsoleKit API details

Roadmap

  • Core work (most items scheduled to be completed around Dec 15th 2006)
  • Get f-u-s-a into Rawhide. Done
  • Get ConsoleKit into Rawhide. Done
  • Rebuild gdm with ConsoleKit support. Done
  • Make f-u-s-a use ConsoleKit
  • Turn on user switching in gnome-screensaver by default
  • Get PolicyKit to use ConsoleKit and make new release
  • Done in davidz's local tree
  • New PolicyKit release before Dec 15th 2006
  • Get PolicyKit into Rawhide
  • Need to file bug
  • Get HAL release that uses PolicyKit into Rawhide
  • Next HAL release is scheduled for Dec 15th 2006
  • Make pam-console use ACL's
  • Need to file bug
  • Additional work (need more details)
  • Work on gdm face browser / investigate better user experience
  • Enhance applications to take advantage of ConsoleKit
  • X.org BlingBling work and avoid mode setting
  • KDE integration

Upstreams

Most of this work is not Fedora specific and it is anticipated other distributions can easily benefit from it.

Experimental Packages

See http://people.redhat.com/davidz/nitro/source/ though these are a bit outdated now.


ConsoleKit API details

[davidz@zelda ~] $ ck-list-consoles
uid='500' realname='David Zeuthen' seat='Seat1' session='Session1' session-type='default' active=TRUE x11-display=':0' display-device='/dev/tty7' host-name='zelda' is-local=TRUE
uid='501' realname='' seat='Seat1' session='Session2' session-type='default' active=FALSE x11-display=':20' display-device='/dev/tty8' host-name='zelda' is-local=TRUE

[davidz@zelda ~] $ echo $XDG_SESSION_COOKIE
1161664650.703379-1102681915
[davidz@zelda ~] $ dbus-send --system --print-reply --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.GetSessionForCookie string:1161664650.703379-1102681915
method return sender=:1.97 -> dest=:1.144
object path "/org/freedesktop/ConsoleKit/Session1"
[davidz@zelda ~] $ /sbin/pidof gnome-power-manager
3092 2800
[davidz@zelda ~] $ dbus-send --system --print-reply --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.GetSessionForUnixProcess uint32:2800
method return sender=:1.97 -> dest=:1.145
object path "/org/freedesktop/ConsoleKit/Session1"
[davidz@zelda ~] $ dbus-send --system --print-reply --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.ConsoleKit.Manager.GetSessionForUnixProcess uint32:3092
method return sender=:1.97 -> dest=:1.146
object path "/org/freedesktop/ConsoleKit/Session2"


[davidz@zelda ~] $ dbus-send --system --print-reply --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Manager org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.97 -> dest=:1.134
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
</interface>
<interface name="org.freedesktop.ConsoleKit.Manager">
<method name="GetSessionsForUser">
<arg name="uid" type="u" direction="in"/>
<arg name="sessions" type="ao" direction="out"/>
</method>
<method name="GetSessionForUnixProcess">
<arg name="pid" type="u" direction="in"/>
<arg name="ssid" type="o" direction="out"/>
</method>
<method name="GetSessionForCookie">
<arg name="cookie" type="s" direction="in"/>
<arg name="ssid" type="o" direction="out"/>
</method>
<method name="GetCurrentSession">
<arg name="ssid" type="o" direction="out"/>
</method>
<method name="GetSeats">
<arg name="seats" type="ao" direction="out"/>
</method>
<method name="CloseSession">
<arg name="cookie" type="s" direction="in"/>
<arg name="result" type="b" direction="out"/>
</method>
<method name="OpenSessionWithParameters">
<arg name="parameters" type="a(sv)" direction="in"/>
<arg name="cookie" type="s" direction="out"/>
</method>
<method name="OpenSession">
<arg name="cookie" type="s" direction="out"/>
</method>
<signal name="SeatRemoved">
<arg type="s"/>
</signal>
<signal name="SeatAdded">
<arg type="s"/>
</signal>
</interface>
</node>
"

[davidz@zelda ~] $ dbus-send --system --print-reply --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Session1 org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.97 -> dest=:1.147
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
</interface>
<interface name="org.freedesktop.ConsoleKit.Session">
<method name="Unlock">
</method>
<method name="Lock">
</method>
<method name="Activate">
</method>
<method name="IsLocal">
<arg name="local" type="b" direction="out"/>
</method>
<method name="IsActive">
<arg name="active" type="b" direction="out"/>
</method>
<method name="GetHostName">
<arg name="host_name" type="s" direction="out"/>
</method>
<method name="GetDisplayDevice">
<arg name="display_device" type="s" direction="out"/>
</method>
<method name="GetX11Display">
<arg name="display" type="s" direction="out"/>
</method>
<method name="GetUser">
<arg name="uid" type="i" direction="out"/>
</method>
<method name="GetSessionType">
<arg name="type" type="s" direction="out"/>
</method>
<method name="GetSeatId">
<arg name="sid" type="o" direction="out"/>
</method>
<method name="GetId">
<arg name="ssid" type="o" direction="out"/>
</method>
<signal name="Unlock">
</signal>
<signal name="Lock">
</signal>
<signal name="ActiveChanged">
<arg type="b"/>
</signal>
</interface>
</node>
"

[davidz@zelda ~] $ dbus-send --system --print-reply --dest=org.freedesktop.ConsoleKit /org/freedesktop/ConsoleKit/Seat1 org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.97 -> dest=:1.148
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
</interface>
<interface name="org.freedesktop.ConsoleKit.Seat">
<method name="ActivateSession">
<arg name="ssid" type="o" direction="in"/>
</method>
<method name="GetActiveSession">
<arg name="ssid" type="o" direction="out"/>
</method>
<method name="GetSessions">
<arg name="sessions" type="ao" direction="out"/>
</method>
<method name="GetId">
<arg name="sid" type="o" direction="out"/>
</method>
<signal name="SessionRemoved">
<arg type="s"/>
</signal>
<signal name="SessionAdded">
<arg type="s"/>
</signal>
<signal name="ActiveSessionChanged">
<arg type="s"/>
</signal>
</interface>
</node>
"

Other work

Another feature that can benefit from ConsoleKit is Multi Seat, e.g. the process of having multiple monitors / keyboards attached

Multiterminal

and, indeed, ConsoleKit have been designed with this in mind. Multi seat is not something that is currently targeted for Fedora 7.