(One of the nice things about my new job is working ‘in public’. I’m tagging posts like these with ‘Canonical’, if you want to filter them)
Hybris (aka libHybris) is a piece of enabling technology that lets an OS distribution like Ubuntu use parts of Android software in binary form, without needing a recompile of those binaries. Ubuntu is using it for its ARM based Ubuntu Touch distributions, which re-use the Android BSP for the underlying hardware platform.
libHybris is two things: A dynamic linker, which provides the generic functionality, and then a set of wrapper libraries that provide particular Android libraries to the other OS. Whilst the code is clearly organised, it might be helpful to have a separate sample which demonstrates how to use the core Hybris features. That is where Bionic JPEG comes in.
Bionic is the name of Android’s C runtime library. On Ubuntu the conventional C runtime is glibC. So another way of looking at Hybris is to regard it as a way to use bionic based binaries in a glibC based OS. Hence the name of this project.
Bionic JPEG aims to demonstrate how to call a library compiled for use on Android (In this case the IJG JPEG library) from an Ubuntu binary. To do this, I’ve divided the IJG code into its library and client components, then compiled the library with the Android NDK, and the client with the Ubuntu Touch toolchain. In order for the clients to use the Android library, a small ‘bridge’ library that calls libHybris glues the two together. By designing this bridge library to present the same API as the IJG library, no changes are needed to any of the IJG source code.
The core of Hybris is clearly derived from the Bionic source, and is a port of the Android dynamic linker to Ubuntu. This knows how to load an Android Elf32 binary into an Ubuntu process, which is a trick the standard Ubuntu dynamic linker can’t do. From the look of the code, Android can effectively link/prelink binaries in several ways, and it is loading these binaries that is the key Hybris feature. In addition, as it resolves symbols present in the binary it loads, it can hook them to somewhere else. Hybris then uses this to hook all the bionic entrypoints, and re-direct them to glibC. This isn’t always a simple symbol substitution – there are differences between the C libraries that means Hybris has some implementations within it, that then call on to glibC.
Whilst the IJG code is unmodified, I have changed the name of the library produced. It turned out that the Android images I was using (derived from CyanogenMod 10.1 images for the Nexus 4) already have a copy of libJPEG, from an earlier version of the IJG code. In order to avoid a collision, Bionic JPEG names its library libjpeg2.
For more details, see the README in the source tarball (available in the project downloads). Note that I don’t anticipate Bionic JPEG demonstrates something commonly done by Ubuntu SDK users. Over time (several release cycles), I think the Ubuntu community hope to phase out our dependence on Android, in favour of the common Linux upstreams Ubuntu and Android share. That will take time, and need us to be successful enough for hardware manufacturers to offer direct support. For now, using Android gets us that support for the cost of maintaining Hybris.
That being said, even while libHybris exists, I don’t think it will be a common thing for people to extend it: for most cases, the Android libraries on a given device will already have a complete libHybris bridge.
For the teams that need to maintain those Android parts, there may be a need to extend libHybris, or even just to understand it a little better. It is with that use case in mind that I created this example.
Bionic JPEG’s homepage on Launchpad.
I intend to refine the sample with clearer instructions on how to add it to the system image, as Ubuntu’s tools here finalise in the run up to the 13.10 release.