I’ve spent most of the last year working with the Android Open Source Project (AOSP) in production. Previously I had worked with Android to build proof of concept prototypes and been relatively happy but developing something of production quality with the latest AOSP threw up a few issues that made it a less than enjoyable process.
The Android build system started out based on make and I always thought it was quite a nice piece of work, at least as nice a system as you can build with make. It was quite slow for some operations, particularly for builds where very little or nothing has changed but it worked and was consistent.
More recently Android has added the soong build system, which is a custom build system used only by Android as far as I can tell. soong is intended to be faster than the make build system but does not replace it. In some ways it is the future of building Android but in other ways it is incredibly deficient. For example, if you want to install a single file into the filesystem (e.g. a configuration file) you can do this easily with an Android.mk but not an Android.bp. This makes it unclear which build system you are supposed to use and gives the whole thing a half-finished air. soong has superficial similarities to Bazel, which is another Google-developed build system, but Bazel wasn’t chosen for Android for reasons that aren’t clear.
If you would like to build an Android app then you will most likely be using Gradle. It’s possible to build apps with other tools like Maven but for modern applications Gradle is fairly standard. However AOSP has no support for building with Gradle, so if you have an Android Studio developed app you want to build as part of your firmware image you need to write custom Android.mk or Android.bp files and keep them in sync with the build.gradle files by hand.
Building system apps is painful
System apps are apps that are signed with the system key and have access to APIs and permissions that are not available to normal apps. For some functionality, for example an OTA update tool, running as a system app is essential. Developing system apps using Android Studio is very painful however.
Accessing system APIs from Android Studio requires modifying your Android SDK install by copying a JAR file over the top of it to make the system APIs visible. This is ugly and not an clean repeatable step for a team of developers or a CI system. Even when you have done this Andriod Studio will still give warnings for accessing various system APIs and permissions and there is no way to say that you are developing a system app and disable these warnings.
Once you have built your app and need to test it there is no easy way to do this either. The standard emulator keys are not available so it is not possible to sign your app with a key that will run as a system app in the emulator. It is theoretically possible to build an emulator image with custom system keys and get Android Studio to use this image somehow but all this seems like a lot of work and customization, and again you want to be able to deploy this for your team and CI system not be making custom hacks on your development machine.
There are other annoyances. If you build an app with Android Studio you will be pushed towards using ConstraintLayout for your UI. It’s faster, it’s more flexible, it’s the future. But it’s not part of the base system, so even if you would like to use it in an app in your firmware image you can’t and you only get to figure this out when you come to try and build it.
Grab bag of random software components
Android has always taken software from a variety of sources and brought it together in the manner of a Linux distribution. This model works well but has costs in terms of keeping your components up to date and the AOSP does not always seem to keep their components up to date. When you rely on a provider of software like Google you have an expectation that the software provided will be reasonably up to date, not just for reasons of security and stability but also whether or not you can integrate further third party components that may rely on newer versions of these underlying components.
As an example protobuf, a Google project, is on version 3.6.1 upstream as of this writing but the version in AOSP identifies as 3.0.0–beta–3. Yes, a beta version in production software that millions of people rely on. The AOSP protobuf implementation also ships with the nano runtime which the upstream protobuf project claims is never released and not to be used. And these are both Google projects!
Further examples of this include zxing, the barcode scanner library. Again, this is a project owned by Google but the version shipped with AOSP is well out of date and is poorly integrated. tinyalsa, the project used to provide sound device access in a number of places seems well behind the upstream too and this caused me some trouble due to a bug in tinycap that had long been fixed upstream.
The overall impression is of a poorly maintained set of software components. I would suggest you could pick any random package from the external directory of the AOSP tree and you will find many of them are several releases behind the upstream. libvorbis for example, is on version 1.3.1 but 1.3.6 was released earlier this year with fixes for three different CVEs. Is this a problem? I don’t know, but I can’t easily prove it is not a problem.
Android is not AOSP
Increasingly Google has been nibbling away at the functionality provided by Android and moving it to Google Play Services. This is really old news, but things like location APIs and push messaging are only available to devices that are certified by Google and have Google Play Services installed. Google are working on making it harder for devices to circumvent this arrangement by sideloading Play Services. microG exists for providing an open source replacement for Play Services but it seems to be a long way from production quality and requires some patches to core security protections of the Android framework to enable it to work.
From the other side SoC vendors (such as Qualcomm) ship a large quantity of add-on code and modifications to the core Android frameworks in order to not just support their hardware but add features. For example, Qualcomm have their own camera, gallery and music apps and large parts of their telephony, camera and media stacks are closed source and shipped as add-ons for system integrators. This means that the majority of Android devices in the field are actually running custom implementations of the core apps and frameworks, causing compatibility issues and diluting the benefits of the open source project. The Qualcomm deliverables are not publically available so producing a fully functional open source image is very difficult and keeping it up to date is almost impossible.
Google and Linaro are doing some work to integrate Qualcomm’s huge pile of changes into the mainline of AOSP and Linux, but this only benefits a small number of SoCs and progress so far has been understandably slow.
Working with AOSP to build products is a frustrating process, particularly if you work for a smaller company that has little leverage with Google or Qualcomm. Google have to be commended for the amount of code they have released as part of AOSP and the work they do in maintaining and supporting it, however there is an opportunity for them to do much better.