Introduction to porting¶
This first section will introduce you to the specifics of porting Ubuntu Touch to an Android device. Note that it is written with the general public in mind, not primarily the experienced porting developer. In subsequent sections we have made an effort to differentiate by keeping the main text more concise in order to meet the needs of the more experienced reader, while providing links to supplementary reading for the less experienced.
The guide as a whole is written as a sequence of steps describing how an ideal port might proceed. However, porting is unpredictable and messy. Every device is different and in reality you will likely iterate and revisit some steps, skip over other steps and uncover new and undocumented challenges.
What is Ubuntu Touch?¶
Ubuntu Touch is an open source operating system for mobile devices. It can be ported to devices that originally shipped with Android OS. Alas, the majority of these devices are dependent to some degree on proprietary software.
To be specific, device vendors tend to keep the code that speaks directly to the device hardware (the low level device drivers) proprietary. These components are commonly called the vendor ‘blobs’ (Binary Large OBjects). The vendor blobs need to be incorporated into an Ubuntu Touch port. Note that these components are specific not only to each device, but also to each Android version. It is therefore necessary to secure the correct version of these components when building a port.
This is why Ubuntu Touch cannot be built completely from source code for most commercial devices. Instead, porting the system to these devices involves integrating the previously mentioned vendor blobs into the rest of the system, which can be built from source.
The next component of Ubuntu Touch is a pre-compiled root filesystem which needs to be installed on the device. This component does not communicate directly with the device hardware. Instead, this communication is mediated by a Hardware Abstraction Layer (HAL) which needs to be built for each specific device, because each device has its specific hardware architecture. This component is called Halium and is available in different versions (5.1 which is largely obsolete, 7.1, 9, 10 and 11 as of writing) corresponding to different Android versions.
The Halium project enables Linux systems to run on Android hardware. It is a joint effort by multiple mobile operating systems, notably Lune OS and UBports.
UBports porting builds on top of Halium porting. Consequently, you will be using both the Halium porting guide and the UBports porting guide. At times it may also be helpful to test with one of the other operating systems to debug a problem from different angles.
Halium is an indispensible part of an Ubuntu Touch port and is available in the form of open source software. Developing a new version of Halium is a very considerable task which is why only a few versions of Halium are available. Each port of Ubuntu Touch has to be based on one of the available Halium versions and vendor blobs from the corresponding Android version. See the first two columns of the table below for details.
- The Ubuntu Touch (UT) root filesystem (rootfs)
- Halium (contained in the boot and system images)
- The vendor blobs
You, the porter, need to build Halium (in part or in whole, depending on porting method ) and install this together with the Ubuntu Touch rootfs in order to create a functioning Ubuntu Touch port.
Android and Halium versions¶
Halium is built using source code for a modified version of the Android operating system called LineageOS (see the LineageOS website and wiki). The required source code is available online and needs to be downloaded and configured to build the correct Halium version for each individual device port. The table below shows which versions are required for the different Halium versions.
Kernel and hardware abstraction¶
This page documents the resources and processes to build the kernel and hardware abstraction for UT devices. This document is useful if you would like to work on:
- A hardware related issue (camera, sensors, radios)
- A Linux kernel related issue
- An issue related to the system-image upgrade process
This document is not useful if you would like to modify Preinstalled apps or System software . See the respective documentation for each.
There are a few different groups of Ubuntu Touch devices with respect to how the kernel and hardware abstraction is implemented:
Android 5.1 based ports¶
Android 5.1 based ports of Ubuntu Touch consist of the Linux kernel for this device plus a minimal Android system that is used to enable all the hardware. Every device has it’s own fork of the Linux kernel. They are all heavily modified for the specific hardware used in that device. These forks are also based off quite old Linux kernel versions.
For some devices continuous integration (CI) has been set up to build both the Kernel as well as the Android system. Other devices have to be built manually from their repositories. For a third group of devices, we do not unfortunately, have the full source code available. The Bq and Meizu devices have kernel sources, but the “Android device tree” is not publicly available. The manufacturers of these devices provided binary builds instead.
- With CI
- Nexus 5 (hammerhead)
- OnePlus One (bacon)
- Fairphone 2 (FP2)
- Nexus 4 (mako)
- Nexus 7 2013 Wifi (flo)
- Bq Aquaris E4.5 (krillin)
- Bq Aquaris E5 (vegetahd)
- Bq Aquaris M10 HD (cooler)
- Bq Aquaris M10 FHD (frieza)
- Meizu MX4 (arale)
- Meizu Pro 5 (turbo)
- Nexus 7 2013 GSM (deb)
Detailed steps for the three CI enabled devices can be found under HAL for Nexus 5, OnePlus One, and Fairphone 2 .
For the Nexus 7 2013 Wifi (flo) head over to the Community Ports repository for flo.
The port for the Nexus 7 2013 GSM (deb) was created by a community member. Unfortunately those repositories have disappeared over time. So this build also falls into the group of prebuilt binaries.
Document the process for Nexus 4 (mako)
Halium based ports¶
Newer ports to Android devices are based on Halium. In some aspects Halium is similar to the 5.1 based ports:
- It also uses the device specific fork of the Linux kernel provided by the manufacturer.
- It also uses a minimal Android system to enable some hardware.
However, Halium permits a more generic way of porting to Android devices. This allows the work to be shared between multiple projects that bring different flavours of Linux systems to Android devices. Halium ports are also based on newer Android versions 7.1 and above.
Some examples of Halium ports are those for Sony Xperia X and Oneplus 3. Basically all devices that are listed on devices.ubuntu-touch.io, expect those explicitly mentioned above as 5.1, or below as Linux based ports.
All new ports of UT to Android devices should follow the Halium process. Further details can be found under Halium porting
Linux based ports¶
Linux based port refers to devices where a Linux kernel is used without any Android parts. The following devices are in this group:
- Desktop PC (x86)
- Librem 5 (librem5)
- Pinebook (pinebook)
- Pinephone (pinephone)
- Pinetab (pinetab)
- Raspberry Pi (rpi) (see also this blog post)
Linux ports to android
We are private in protest of the API changes. https://www.theverge.com/2023/6/8/23754780/reddit-api-updates-changes-news-announcements Don’t message us for access, everyone is blocked out site-wide. See http://redd.it/1476ioa for more info.
Its been almost a decade since the release of AOSP, a variant of linux developed for smart phones and tablets, but I’m surprised that none of the popular packaging systems such as apt, yum or even pacman have been ported to android!
Even more surprising is that nobody has taken the time to even develop an inferior substitute or workaround. Though my knowledge of linux is limited, I know that given a rooted phone (which should be a given amongst us linux folks!), it shouldn’t be that difficult. The only major difference in android linux is that /system/bin and /system/xbin are the places to store binaries instead of /bin and /usr/bin , and then its only a matter of pulling the files to /system/bin/ and /etc .
Granted that an init system is lacking (maybe there are AOSP specifications, but don’t think there is an easy way like systemd), but the least a packaging manager can do is copy the package files in the proper places and verify that the package is properly signed/authentic.
At least on larger devices like tablets, I know there are lots of power users who use the command line using terminal emulation apps, so CLI apps like say nano, vim, git, nmap, python, gcc, etc. can be made available provided they could be ported to AOSP. I know some of these tools are available using busybox, but busybox is just a hack and contains only a small subset of the entire CLI universe of linux.
Porting C based linux application to the Android platform
I have C Linux based application and now I want to port it to Android. I figured out, that I can extract the toolchain from Android NDK and build my application, but how to make the APK such that I can install it on the android devices without the need of root access. In Linux, I used to install it using a bash script which used to put my application related files in different folders like /opt , /etc (files shared with other applications) and /var . How can we handle this in Android. Is there a folder similar to /etc in Android where I can put files that other applications can read. Thanks
-M1 Answer 1
First of all, you are lucky if your project compiles «as is» with NDK standalone toolchain. Often, bionic is not enough, and people need to tweak the build environment (from libpthread to full-blown buildroot alternate toolchain with static C runtime).
As for the shared files location, on Android it’s named «external storage». Your app and other app may require special permissions to write and read to this location. Directory /opt does not exist here. You don’t have write access to /etc , but files like /etc/hosts are available for read.
Regarding the APK. You are right, this is the ultimate way to distribute and install apps on Android. But you can, even without root, to locally install and run a command-line executable. Usually it’s done with Developers Options turned on, and enabled USB debugging. Now you can open an adb shell, install and run your program. The trick is that external storage (see above) is marked as ‘non-executable’. Therefore, you must find another place for your binary. Usually, /data/local/tmp will be a good choice.
Instead of adb, you can use a terminal emulator on the device.
If you choose to build an APK, you will probably prefer to convert your app to shared library that will perform actions for Java via JNI. But it is also possible to package your command-line binary as part of the APK and use Java Runtime.exec().