In order to have access to the various hardware capabilities, LuneOS makes use of Android drivers through the libhybris framework. LuneOS also relies on Android runtime to access some hardware-oriented services, like camera or telephony services.
The Halium project aims to facilitate and streamline this dependency by providing a standard and easy access to the Android base runtime, ready to be used with libhybris.
Here are some considerations, from LuneOS's perspective, that could help Halium converge on a common solution for all the interested downstream projects.
LuneOS uses the Yocto Project as a base, and therefore also uses the OpenEmbedded build framework. Each package is built out of a "recipe", which describes how the result should be produced. It is a very flexible infrastructure, allowing for multiple targets, multiple architectures, together with a good code re-use.
The core bricks of LuneOS are nearly all managed by OpenEmbedded: systemd, glibc, wayland... These recipes are also usually following upstream regularly: on the krogoth version, that we use today, we get systemd 229, glibc 2.23, Qt 5.6... Upgrading these packages means usually simply switching to the next OpenEmbedded version.
The supported target hardware is currently the following :
- Galaxy Nexus (codename "tuna")
- Nexus 4 (codename "mako")
- Nexus 5 (codename "hammerhead")
- HP Touchpad (codename "tenderloin")
There is also some partial support for Raspberry Pi 2, which is not using Android drivers.
Architecture overview of Android runtime usage
LuneOS relies on an existing installation of a "classic" Android 5.1, and will only override the libraries that need to be patched for a usage with libhybris. The complete untouched Android /system partition is mounted, together with the other /firmware, /persist... needed partitions.
We provide the patched Android base libraries in a separate directory ( /usr/libexec/hal-hybris/system/lib/* ), and our libhybris library is configured (at build-time) to first look for Android libraries in this directory.
LuneOS starts the Android runtime within a lxc container. The needed android partitions are also bind-mounted there. LuneOS provides a modified initramfs, which is unpacked in the lxc container too.
Due to our usage of libcompat, some of the Android libraries had to be modified to communicate with libcompat. We also provide these modified Android libraries in the lxc container, in a separate directory. Using the LD_LIBRARY_PATH variable, we tell the Android runtime to look in that directory first.
This architecture is pretty new: before January 2017, we used a complete minimal build of Android 4.2.2 (without the Java parts, for instance), and handled the Android patches ourselves. We shipped the Android runtime base together with our LuneOS images. When switching to Android 5.1.1, we realized a lot of work had already been done by the Mer project for getting an Android base working. Therefore basing our work on theirs, and providing only a light overlay, like SailfishOS is doing, was a logical direction to take. We will see in the long run if avoiding re-using an existing Android installation is a better approach.
How the Android base is built
The repository used are taken from this main manifest (forked as-is from mer-hybris) to which we add our local manifest. The goal is to isolate the modifications specific to LuneOS and minimize the work needed for a port.
In order to minimize the work needed for each port, LuneOS only rebuilds the Android code that is directly impacted by the libhybris patches. The modifications done to init.rc are minimal, and mostly consists in removing the unused services from the init.
A basic porting guide was written in January 2017, summarizing the various steps needed to do a port for LuneOS. It may - or may not - help understand how LuneOS uses the Android bits.
The HP Touchpad exception
For the HP Touchpad, we couldn't reuse the standard CM12.1 code base that we used for the other devices. The reason is that the graphic code and APIs have been modified by HP, and therefore don't match anymore. However, this device already works well with the Android 4.2.2 build, so we decided for now to keep our old Android build and use it as-is.
Therefore, for this device, we end up using a whole minimalist Android build, together with the lxc container approach. The only difference is that /system isn't a mounted partition but the content of our own build.
Current issues which will impact Halium
Our build system is very flexible, and will certainly handle Halium fairly easily. However the following points will have to be taken into account:
- The kernel has to match the Android version - mainly because of the drivers. It means Halium will have to provide a matching Linux kernel, for each Android build proposed.
- There is usually a big gap between the kernel version used in Android devices and the kernel version recommended for reasonably up-to-date system packages. This can lead to missing functionalities (some needed by LXC for example), build issues (Linux 3.4 needs to be patched to build on GCC 5+) or other peculiarities. Here is the 3.4 kernel we use today for the Nexus 4 - note the last 10 commits, needed to have it working on a fairly recent system.
- We are integrating libhybris/libcompat in our middleware. This means a dedicated "flavor" of the Android build is needed, or a way to overlay a base system with specific bits.