Shared mobile devices
The need for device sharing has become increasingly important for our partners. And it’s easy to understand why: imagine a scenario where a mobile device is required for executing certain actions during a business process. Each workstation has a mobile device and when a work shift changes the previous shift logs out of it and the new shift logs in. In this case the mobile device is more of a shared resource than a personal device.
One of the major new features that we’re excited to have included in the latest 3.4 Pallas-Yllästunturi release is the ability to have multiple users on the same device that can be switched between in this way. For regular everyday use of Sailfish OS this doesn’t have any impact, the device owner (the primary user) works just as it used to. However, release 3.4 will have a new ‘defaultuser’ (devices flashed prior to 3.4.0 keep ‘nemo’ user, but it’s only the name that’s different). The new ‘defaultuser’ name is mostly visible behind the scenes for application developers; end users can ignore this detail.
The big change is that unlike previous versions a device can now have six additional users on top of the device owner. These additional users have fewer capabilities. For instance, additional users can’t install new applications to or remove existing applications from the device, nor can they perform a system upgrade. All installed apps that the device owner has installed are visible for additional users, but as the home directory is different for the additional users the actual application data is not shared between different users. As you can see, we are following the standard way of handling users and user data for Unix-like systems. If you are an application developer and have previously stored data outside XDG directories you should start using them now. This has always been a Harbour requirement, and Qt and Silica make it easy with QStandardPaths and StandardPaths . Protecting user data is done by applying discretionary access control (DAC) rules for each user and limiting read and write access from groups and others users. There’s an exception to this when it comes to Android App support. More on this later in the blog.
First let’s discuss a bit about the access rights in more detail. The device owner’s permissions are just as they used to be, but as explained above, the newly created users do have some access limitations, such as the limitations on package installation rights and device upgrades. In addition WLAN access points and VPN connections have changed so that they are user-specific. Each of the users now has their own set of WLAN access points and VPN connections. The mobile data connection is shared between all users. Of course, each user also has their own security code. When a device is booted up and home encryption is enabled all of the users are able to unlock home encryption with their individual unlock code, a requirement since each user’s data is stored under the home directory.
On the Lock Screen the security code is matched against the user that’s currently logging in. This leads to a user switch, during which all running applications for the current user are stopped and new ones started for the next user, similar to if the device had been rebooted. The most convenient way to change the user is via the Top Menu that can be opened by swiping down from the top edge of the screen. When two or more users have been created on the device, the last item on the Top Menu shows the active user. Tapping this opens a list which can be used to switch user. This user-switching option is also available from the Top Menu of the Lock Screen.
Only the device owner (the so-called “primary user”) is allowed to create new users, remove existing users or modify access rights. In terms of access rights, at the moment they can control whether additional users have SMS or phone access rights. When the device owner grants an access right to a feature, the granted permissions are visible for the user to whom the access right was granted upon next device login. In the future we plan to introduce other access control points for the device owner over newly created users. This will complement the evolution of the Mobile device management (MDM) API that we’ve been introducing to Sailfish OS over the last few releases.
We know that many of our users are technically-minded and will be interested in how the architecture evolved during development. Let me try to shed some light on this and get into some of the detail. As mentioned above all access control is achieved using POSIX-standard DAC. When the device owner grants access rights to an additional user for use of the phone or SMS, the additional user is added to a group that has these access rights. So we’ve not invented anything new here, rather we’re just using Unix groups and users in the usual way.
To implement the UI for user-switching and management we created a new user-managerd service that’s responsible for controlling which users or processes may alter the users on the device. This service is started on-demand whenever we need to create, remove or change the current user. The user-managerd API documentation is available on our developer site. In addition, we created the sailfish-access-control component to help check whether a user belongs to a certain group or not. This is used for checking permissions at the application level. The sailfish-access-control component provides both glib (C) and Qt (QML) interfaces. In order to implement the user interface changes we needed, we also enhanced nemo-qml-plugin-systemsetting by adding the UserModel and UserInfo components. These provide access to the underlying data structures and user-managerd service APIs. Some systemd system services such as Connman have been made aware of the active user through systemd-logind, controlled via user-managerd. When the user is changed a new set of connectivity rules is loaded. All systemd user services are stopped and started when a user switch occurs.
Sometimes it’s necessary to clean up files and settings or move them around when updating software. We have our own oneshot project for this, which manages the execution of relevant scripts on device boot. Originally oneshot was designed to understand only one user so we had to change it to take additional users into account. We needed a way to allow the same changes to be applied for all users and thus we added the –all-users argument to the add-oneshot command which you may have noticed if you’ve ever explored any Sailfish OS spec files. This has been implemented to iterate though the existing users and schedule the same oneshot script for each of them. We also needed a way to create oneshots that are fired for new users when the user is created. Another argument, –new-users, was added for this. It marks the oneshot script to run and then when the user session for a new user starts, the oneshot is scheduled for that user. During this process two additional arguments were also added, –user and –uid, to allow oneshots to be executed for specific users. In practice we’ve found they’re rarely used as it’s much more common to need a oneshot that affects all users or only future users.
A similar situation arose for systemd unit files. These are a nice way to describe background services and their dependencies, but prior to this release we often built them with the assumption that there would only ever be one user on the device. In practice this meant that many of our systemd units had User=nemo in them. Sometime this was because the service was really meant to be a session service run under the control of the session manager instead of the system manager, but which for some reason was implemented as a system service. One situation where this arose was for services activated by the system D-Bus, but which had the characteristics of user services. After the multi-user upgrade this was no longer acceptable and we had to find ways to have them run as system services (running as a system user) or move them inside the user session to be run as user services. In the latter case that may have involved moving a service’s data and settings inside the home directory, for example.
To achieve all the above we ended up having to update and fix a large number of packages. Many packages needed updating so they no longer used hardcoded paths to user-specific directories. The flashable Sailfish OS software images no longer require knowledge of who the primary user of the device is. The hardware access permissions come from the droid-hal (hardware adaptation layer). The droid-hal groups are applied to newly created users before a user logs in. This approach applies to all devices. All Sailfish system users now come from the sailfish-setup package. The groups to which a user may belong are also now created by sailfish-setup rather than being baked into the image.
There are some things that could have been achieved more simply using an upgraded systemd, but that’s still on our roadmap. No promises yet on the systemd upgrade schedule.
Finally, let’s return to Android App support. Additional users do not currently have rights to open Android Apps, install new ones, or remove old ones. The decision to do it this way was made so that we could simplify scoping of the overall task, allowing us to deliver the new shared-user feature to market and for customers. We’re looking at ways to improve this further in the future.
I’m very excited about this new feature and already looking forward to what the future will bring. It’s a major feature upgrade and the whole team working on this deserves a big hand for making it all happen.