What's Inside the Black Box of Ubuntu Touch?
Hello all. I'm doing a Youtube video on the internals of Ubuntu Touch.
The goal is to promote UT by removing the 'black box' image, especially to those who use Linux already. And hopefully this will carry on to the new UT users that will come from the Pinephone.
I did manage to figure most things out without having to bother anyone.
But it's probably easier to just ask so I don't give out wrong information.
So I will ask questions in this thread and hopefully it will shortcut the searches I've had to do. I will likely already have the video ready before I get answers but it will be a series of videos so I can always expand later.
My first question is: where is the actual Kernel found? And is this a recompiled Kernel? Or stock Kernel?
I see that /system/boot has android-ramdisk.img which I assume is one of first loaded code. Is that like initramfs?
If someone could tell me the boot sequence that would be great.
I'm also interested in a comparison of a boot sequence between a legacy port like a Nexus5, versus a Halium port, and vs a Pinephone.
Thanks in advance and I'm sure there will be plenty more questions..
Question 1: All kernels come from the original device manufacturer and are superold (a general problem in the Android world, but not fixable). Due to the fact that we need the Android drivers to control the hardware, and the problem that they are not open source, we need to stick with the kernel version that they were initially compiled with by the phone vendor.
Little chances are given to get to a supported mainline version on some devices, but in general our kernels are 3.4, 3.10 and 3.18 for the older devices, and some series from 4.x for newer ones. They are heavily modified by Google and the vendors, and most of the time it is great pain to update code there with patches from mainline kernels.
Question 2: Thats actually a part of the LXC container that runs the Android userland for certain vendor binaries that communicate with drivers, for firmware loading, algorithms like camera focus etc. You might find this graphic helpful: https://imgur.com/UQMfGjX - while quite old, it still stands for the idea. Though, we are of course also communicating directly with the kernel, not only via the container!
Question 3: The boot sequence is roughly: Kernel runs through startup, then mounts an initramfs which contains a few scripts that will mount the main rootfs readonly, then applies a ton of bindmounts for customizations and writable directories. Among those is also the mounting of the Android container into its place. Then, the normal Ubuntu upstart is being called to start its services. So technically, Ubuntu boots first.
Then comes the LXC startup, which fires up the original Android init with its scripts, which in turn will start a ton of services inside its container.
I cant comment on the Pinephone yet, but that one is merely the same without the LXC container stuff. So they are pretty similar. The differences between Halium and classic ports is not that big: Its about how we mount all necessary stuff in place, and how the container is included into the directory space. But from a highlevel point of view thats all.
That explains this uname (Nexus 5):
Linux ubuntu-phablet 3.4.0-cyanogenmod-gc95a726 #1 SMP PREEMPT Wed Oct 16 04:30:42 CEST 2019 armv7l armv7l armv7l GNU/Linux
But where is the actual Kernel located, on let's say, a Nexus 5.
BTW - I'm only looking for a boot sequence that's pre-Init. Once Ubuntu Touch actually gets control, it looks pretty straightforward.
ly looking for a boot sequence that's pre-Init. Once Ubuntu Touch actually gets control, it looks pretty straightforward.
The kernel is packed together with the small initramfs and flashed into the boot partition of each device with the usual fastboot flash command thats also used for Android kernels, and replaces that part entirely.
Here's part 1 of the video series, Exploring Ubuntu Touch - Dissecting the Black Box
There's a lot more to explore but this is a beginning.
So exploring this further, Florian, it sounds to me like a Nexus 5 (for example) is really following an Android boot sequence like this
and then Ubuntu 16.04 takes over somewhere wherever its Init is...which then initializes Ubuntu Touch. Right?
(Just for my own edification, it would be great to know what the first code is for Ubuntu in this kind of environment)
I would guess then that a Pinephone would have a more traditional bootloader and starts the kernel from /boot?
@rob Yes you are absolutely right in your understanding. On Android devices, fastboot takes care of loading the kernel and the initrd, while on a Pinephone this task is done by uBoot. Thats kinda standard bootloader now for arm based open hardware.
So is the first executable on Ubuntu /sbin/init? Or does something else happen before that?
Also, I noticed on the Development release, that Libertine applications are now mixed in with regular applications. Is it safe to manually create *.desktop files in /usr/share/applications on the Libertine container?
If you'd like to read exactly how Ubuntu Touch is booted, this is the script: https://github.com/Halium/initramfs-tools-halium/blob/halium/scripts/halium
The steps are:
- Android bootloader(s) load Linux kernel, dts, and initramfs into memory
- Android bootloader executes Linux
- Linux finds initramfs (ours is basically a Debian initramfs with the script I linked above added)
- Linux runs
/sbin/initin the initramfs
The init in an Debian initramfs is Busybox configured to run a few scripts. The one that handles actually booting Ubuntu Touch is, again, linked above. It mounts the system image (
/root, does a few more mounts for Android filesystems (for example, your
/persistpartition on Android goes to
/android/persist/), mounts the read-write filesystem parts (like your home folder), then chroots into
PID 1 on an Ubuntu Touch system is Upstart provided by the 16.04 rootfs. Android runs in a lxc container.
None of these are required on the PinePhone, that basically boots like any embedded Linux system, with Pine64's u-boot and ARM Trusted Firmware build taking the system up to a point where it can load and execute Linux (steps 1 and 2 above). Then, we currently don't have a custom rootfs compared to Ubuntu, basically executing
/sbin/initand going with it.
You can create your own desktop files in your Libertine containers, I guess, but I don't expect they'll do what you want them to do.
@UniSuperBox This is great! Exactly the detail I'm looking for. Thanks!
By "Pine64's u-boot", I meant the one that all of us in the Pine64 community maintain together. All of the projects that are shared among almost all of the OSs are here: https://gitlab.com/pine64-org
@UniSuperBox didn't realize you were Dalton. Good to talk to you!
"PID 1 on an Ubuntu Touch system is Upstart provided by the 16.04 rootfs. Android runs in a lxc container."
You say Android runs in an lxc container. Is this what is referred to as the Halium container?
@rob, the stealth is not entirely accidental! I can turn on special badges, but prefer not to. Seems like a weird status symbol. Not having a profile picture is sloth, though.
Yes, that could be referred to as the Halium container I suppose. It's really just a stripped-down Android build with no Java stack, though. It exists to allow our software to communicate with Android Services (capital-S Services) through Unix domain sockets. The camera Service and rild (Radio Interface Layer Daemon) are two examples that we communicate to. Using these services directly allows us to reuse closed-source drivers from Android and bring up Ubuntu Touch on a variety of Android phones faster than if we had to reverse-engineer drivers.
@UniSuperBox LOL. I didn't identify myself here before either but someone outed me. Haha..,
The specific details of what you have to access with halium is definitely very interesting and I'll get to that! LOL. My focus right now is understanding the big picture (by understanding the detailed fundamentals). I'm not originally a Linux developer so some of the internal processes for each project are definitely illuminating.
So is the Pinephone Kernel an actual mainline image or is it custom-compiled by someone? And if so where did ubports acquire it?
@rob, the PinePhone's Linux kernel is tracked at https://gitlab.com/pine64-org/linux and compiled by GitLab CI for consumption. More information on how our images are built can be found in the README at https://gitlab.com/ubports/community-ports/pinephone
I see the familiar names now in that Kernel project! Thank you for passing that!
Now in an earlier question on the Libertine Container, you implied that there's more to running an application to just creating it in the Libertine-Container. And I've tried non-graphical python applications and they appear to work fine.
So back-pedaling here, I presume that the issue is the display server mapping from the container to Mir? This is clearly very vague to me.
Is there code that I can look at that shows what needs to be done, first in a manual way? 90% of the time adding a package from the Libertine UI doesn't tell me what's happening. It just stops without an error message so I prefer to install things manually so I understand what the limitations are.
For example, I've had issues running Python3 apps due to Gtk dependency issues. My guess is that Xenial doesn't support them. Although Xenial supposedly supports Gtk3, Python in Xenial does not.
If I can unlock the complexities of Libertine-Containers, a lot of people will start to see Ubuntu touch to be more open that it is perceived to be.
Right now, without full understanding, the difficulty in installing Desktop apps will push people to PostmarketOS since it won't have this lxc/chroot jail built in.
dobey last edited by
Although Xenial supposedly supports Gtk3, Python in Xenial does not.
It certainly does via https://packages.ubuntu.com/xenial/python3-gi though the necessary GObject Introspection libraries are probably not installed by default in the container, and if you haven't installed any apps via packages which depend on them in the container, you would need to install them manually to run your own python3 apps that use GTK+.
@dobey I converted my app to Python 2.7 for other compatibility reasons (with Xenial) but even after successfully installing gi and gobject, I get this error on my python program:
raise ValueError('Namespace %s not available' % namespace)
ValueError: Namespace Gtk not available
I realize that it is recommended that I learn Qt/QML and rewrite the app but I was just testing what's possible on Libertine-Containers.
And so far I haven't had success using Libertine-Launch. I'm only starting things from bash within the container itself,
If running a GUI in a Libertine-Container, does it use Xmir or Xwayland or is there something else that has to be enabled on the host, after setting the DISPLAY environment variable? This is one of those Ubuntu specific things that just make it different and a little bit frustrating for those who don't know.
I've tried searching all over to understand this but there is so little documentation on this. And all I'm trying to do is demonstrate that I can make my own app only load it on my own phone.
dobey last edited by
ValueError: Namespace Gtk not available
Yes, this means that the package which provides the GObject Introspection code for GTK+ (
gir1.2-gtk-3.0) is not installed. Each
gir1.2-foopackage must be installed for the libraries you want to use in your app, if using python and gtk libraries.