[ Content | Sidebar ]

Installing GNU/Linux on my Samsung S7

April 6th, 2020

I want to do something useful with my old Samsung S7. Previously I’ve tried LineageOS, and while it works OK, it wasn’t as stable as the stock Samsung ROM and you still end up installing a lot of proprietary apps on it by necessity. I’d much rather run a proper GNU/Linux distro on it. This post is documenting my efforts at doing that, with some minor success.

A failed mainling

My first attempt was to use PostmarketOS. This is a proper free/libre distribution in that it doesn’t rely on any Android blobs for hardware access. Which is great if your SoC/GPU/modem/etc. has mainline Linux support. But I have the European S7 which contains the Samsung Exynos 8890 SoC, for which the only publicly available source code is the Android 3.18 kernel dump. For graphics this means you’re stuck with an unaccelerated framebuffer only which is a non-starter for any modern GUI.

The solution to this would be to update the Samsung provided kernel to a more recent version of Linux, which has free drivers for the Mali GPU, etc. I tried rebasing their code on a slightly more recent 4.4 kernel but once I looked into the SoC’s PCIe and USB drivers I realised how enormous the task was and gave up. Sadly unless Samsung do the work themselves or even just release the 8890 datasheet this device is never going to run anything later than 3.18.


Halium is an interesting project for devices stuck in this situation. Drivers for Android devices are usually split between a minimal GPL’d kernel driver and a proprietary userspace blob (HAL). Halium allows you to run the userspace blobs inside a LXC container, using a minimal Android system.img without any of the UI level components. Hybris then allows you to link to and call the Android libraries from normal Linux programs linked against glibc. It’s the basis of UBPorts and Plasma Mobile.

There’s already some progress getting Halium to run on the S7. I picked this up and got it to the point where it can run GNOME under X11.

Debugging in the initrd

The Halium boot.img contains a very useful init-script which is great for debugging. You can configure it enable the USB network device and then start a telnet server inside the initrd and wait for you to connect before it continues booting. This lets you chroot into the target filesystem, poke around, and most importantly read /proc/last_kmesg to debug kernel panics. Without this I would have given up pretty quickly, as will no serial port or other debug output there’s little feedback when something goes wrong.

The S7 has an annoying bug where the USB Ethernet MAC address is all zeros. I’ve put a patch for that here.

Systemd-journald hangs the system

The default Halium rootfs image hangs very early in boot. On the GitHub issue someone noticed this was caused by journald and it would boot a bit further if you stop this from running. You can do this with systemctl mask systemd-journald.service.

The problem here is caused by the max77854_fuelgauge battery driver not implementing some properties to read its status from /proc. Journald gets stuck in a loop of polling these files and locks up the system. Why is journald trying to read battery information? No idea, but it’s trivial to fix this behaviour with a patch to the kernel.

Disable Android “paranoid network”

Android has some patches to disable all network access unless the user is a member of some specific group. This is useless for a normal Linux userland so disable it in the defconfig.

Replacing the Halium system image with Debian

After this we can boot up into the default Halium rootfs which is based on Ubuntu 16.04. The LXC Android container boots, loads all the firmware, and WiFi is working but not much else. I thought about trying some other stock Halium rootfs like Plasma Mobile or UBPorts, but really I’d rather set my phone up like a regular computer so I used debootstrap to install a minimal Debian filesystem in the /data partition on the phone. My home directory is on a 64GB microSD card so I can safely blat the OS and reinstall. This requires tweaking the boot script in the initrd because Halium normally loopback mounts a rootfs image inside /data and then does a switch_root into that, but now we have the OS installed directly in /data.

Sadly this just hangs on boot. Debugging with the initrd telnet interface, systemd is stuck unable to start any processes. Turns out this is because systemd 245 depends on the “ambient capabilities” feature which isn’t present in the 3.18 kernel. Google have backported this to the Android 3.18 series so we can just apply that patch on the Samsung kernel.

This gets us a bit further and then the kernel panics while starting udevd.

<0>[  132.035960]  [5:         v4l_id:  787] Call trace:
<0>[  132.035979]  [5:         v4l_id:  787] [<ffffffc0000ec328>] dump_backtrace+0x0/0x144
<0>[  132.035990]  [5:         v4l_id:  787] [<ffffffc0000ec5ec>] die+0x140/0x228
<0>[  132.036009]  [5:         v4l_id:  787] [<ffffffc0000f82b8>] __do_kernel_fault+0xb4/0xd8
<0>[  132.036019]  [5:         v4l_id:  787] [<ffffffc0000f858c>] do_page_fault+0x2b0/0x2fc
<0>[  132.036029]  [5:         v4l_id:  787] [<ffffffc0000f86c0>] do_translation_fault+0xe8/0x150
<0>[  132.036039]  [5:         v4l_id:  787] [<ffffffc0000e5268>] do_mem_abort+0x38/0xa4
<0>[  132.036050]  [5:         v4l_id:  787] [<ffffffc0000e7d70>] el1_da+0x20/0x78
<0>[  132.036065]  [5:         v4l_id:  787] [<ffffffc00067d00c>] v4l_querycap+0x28/0x50
<0>[  132.036076]  [5:         v4l_id:  787] [<ffffffc000680eb4>] __video_do_ioctl+0x164/0x254
<0>[  132.036085]  [5:         v4l_id:  787] [<ffffffc000681250>] video_usercopy+0x2ac/0x504
<0>[  132.036094]  [5:         v4l_id:  787] [<ffffffc0006814b8>] video_ioctl2+0x10/0x1c
<0>[  132.036103]  [5:         v4l_id:  787] [<ffffffc00067bd3c>] v4l2_ioctl+0x78/0x130
<0>[  132.036117]  [5:         v4l_id:  787] [<ffffffc00068c468>] do_video_ioctl+0xfd8/0x1d04
<0>[  132.036128]  [5:         v4l_id:  787] [<ffffffc00068d1ec>] v4l2_compat_ioctl32+0x58/0xb4
<0>[  132.036142]  [5:         v4l_id:  787] [<ffffffc000230bc8>] compat_SyS_ioctl+0x10c/0x1250

This is in some ioctls for the camera sensor driver. I think the problem here is that udev is enumerating the devices before the Android HAL blobs have had a chance to do their initialisation. I sprinkled some random NULL checks and it does crash anymore but I’m not really happy with this so haven’t pushed the patch.

Halium LXC container

Next I copied all of the lxc-android repository onto the device, as well as the Android system.img from the default Halium install. This contains all the scripts to start the LXC Android container. The LXC config file in the repository is from an older version of LXC than current Debian unstable. It’s easy to upgrade in-place with lxc-update-config -c /var/lib/lxc/android/config.

Enable the services that mount the Android filesystems:

systemctl enable android-mount.service
systemctl enable system.mount

Then reboot and check the Android side started up with /system/bin/logcat. This should load all the firmware blobs and enable the WiFi interface.

Hybris tests and udev permission problems

Hybris comes with a bunch of useful test programs for checking the various Android wrappers like GLES, sound, camera, etc. are working. Unfortunately they all failed with some cryptic error messages:

nick@samsung:~$ test_glesv2 
library "libgui.so" wasn't loaded and RTLD_NOLOAD prevented it
ERROR: The DDK is not compatible with any of the Mali GPUs on the system.
The DDK was built for 0x880 r2p0 status range [0..15], but none of the GPUs matched:
test_glesv2: ../../tests/test_glesv2.c:113: main: Assertion `eglGetError() == EGL_SUCCESS' failed.

A quick check in Android’s logcat reveals a lot of failures to open devices:

03-21 08:15:14.350     0  1574 D libEGL  : failed to load libgui: dlopen failed: 
03-21 08:15:14.356     0  1574 D libEGL  : loaded /vendor/lib/egl/libGLES_mali.so
03-21 08:15:14.368     0  1574 E ion     : open /dev/ion failed!
03-21 08:15:14.368     0  1574 E gralloc : /dev/graphics/fb0 Open fail
03-21 08:15:14.368     0  1574 E gralloc : Fail to init framebuffer
03-21 08:15:14.368     0  1574 E ion     : open /dev/ion failed!
03-21 08:15:14.368     0  1574 W libEGL  : eglInitialize(0xf786da60) failed (EGL_NOT_INITIALIZED)

This looks like a simple permission problem where the permissions on the device files are not set up the way Android expects. Simply following the Halium documentation and generating the udev rules file for the device then rebooting fixes this. Patch here.

Now we get a little bit further and test_hwcomposer crashes inside some EGL initialisation function. I don’t really understand what’s going on but it seems to be some mismatch between the gralloc version libhybris is using and the gralloc version used by the Samsung blobs. (Gralloc is Android’s graphics memory allocation layer.) I hacked around this by forcing hybris to skip the check for gralloc v1. I’m not very happy about this so I’ll perhaps revisit it later.

--- a/hybris/gralloc/gralloc.c
+++ b/hybris/gralloc/gralloc.c
@@ -84,7 +84,7 @@ void hybris_gralloc_initialize(int framebuffer)
     if (version == -1) {
         if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (const struct hw_module_t **)&gralloc_hardware_module) == 0) {
-            if ((gralloc1_open(gralloc_hardware_module, &gralloc1_device) == 0) && (gralloc1_device != NULL)) {
+            if (0 && (gralloc1_open(gralloc_hardware_module, &gralloc1_device) == 0) && (gralloc1_device != NULL)) {
                 // success
                 version = 1;

And now all graphics, lights, and vibrator tests all work! I couldn’t immediately get camera and sound working, but I didn’t try very hard.

Wayland, X11, GNOME

I’ve been using GNOME3 on my desktop quite happily for a while now and I’d like to run it on my phone too. The launcher is touch friendly-ish and Purism have done a lot of work porting the various GNOME apps to a mobile form-factor using libhandy.

Ideally I’d run the Wayland variant of Mutter because both Wayland and the Android graphics stack are based on GLES and this should get us hardware accelearation for the UI. Unfortunately this is a bit of a non-starter as the Mutter Wayland backend is tied to DRM which Android kernels don’t support. So we’re stuck with X11 or using a different compositor entirely.

Thankfully there’s the xf86-video-hwcomposer project that provides an X driver using Android’s hwcomposer and libhybris. This provides hardware acceleration on the X server side but any client side drawing is unaccelerated and uses Mesa’s llvmpipe software fallback.

And finally…

There’s really nothing like the triumphant feeling of doing apt install emacs on your phone followed by the despair of discovering there’s no way to press those C- and M- meta keys.


February 20th, 2020

A few minutes too late. 🙁

Xcowsay 1.5

February 8th, 2020

Xcowsay is starting to show it’s age a bit, and with Gtk2 and legacy GDK fast disappearing from distributions it’s time to upgrade to Gtk3! (Yes I know Gtk4 is out soon…)

Migrating from GDK to Cairo was fairly painless as the drawing API is very similar. The main problem is the removal of the gtk_widget_shape_combine_mask function that xcowsay used to make the background of the cow and the bubble transparent. This took the 2D bitmask and cut an arbitrary hole in the window. In Gtk3 we instead have to use the window’s alpha channel to make portions transparent. The big drawback of this is that it requires a compositing X11 window manager or Wayland or it won’t work at all. If this affects you then you can just use 1.4 as there’s no functional difference. A side effect of this change is that the edge of the speech bubble is now anti-aliased, fixing a long-standing complaint.

The source zip is here: xcowsay-1.5.tar.gz.

Taking out the Rubbish

January 31st, 2020

Yes this will definitely protect me from the coronovirus

On the plus side I got an extra 10 days holiday. Downside is I can’t go outside.

What a waste of a sunny day

Eastbourne to Seaford

December 31st, 2019

Back in the UK for Christmas last week and the weather was lovely. Went for a walk on Monday from Eastbourne to Seaford along the coast.

This area is called the “Seven Sisters” which refers to the seven (?) huge chalk cliffs. You can see the famous lighthouse at Beachy Head below. The area is very scenic but I found cliff edge a bit terrifying. Especially as large chunks of it fall away every year.

I had to take a massive detour at a place called Cuckmere Haven as the way was blocked by a river with no bridge.

Abandoned Wharf

December 24th, 2019

Went out for a walk last Sunday along the Huangpu river, in the direction away from the city centre.

Some industrial ruin

Has a bit of an east-London docklands vibe to it. Lots of abandoned warehouses and docks, with some regeneration and new buildings. Bit gloomy and bleak.

Xupu bridge

A guy fishing

Fuxing Island

December 15th, 2019

Maybe you remember my shame of missing a station when I walked the length of metro line 12 a while back. Well I finally corrected that by going to the lonely stop of Fuxing Island.

There’s only two roads onto the island, and there’s not a lot there except a park and a huge shipyard.

The air quality has been quite bad recently. But every pollution cloud has a silver lining, and the extra particles in the air make nice sunsets.

Huangpu River

December 8th, 2019

Some pictures from a walk last month along the Huangpu river.

Walking along the west bank towards the financial district

I’m really fond of the path along the riverbank. I’ve been here quite a few times before but never so far into the city centre. I’m not sure how far it goes in either direction.

The light in the late afternoon was so good for taking photos. I’m really pleased with how some of these came out.

Nanpu Bridge, which I posted some night time photos of before


November 19th, 2019

I spent a few days recently at a company “offsite” meeting in Sanya, Hainan, a island in the very south of China. It’s a bit like a Chinese Hawaii. Not somewhere I’d usually visit but worth going once for the experience.

On the beach

The hotel we stayed in was a self-contained resort and there didn’t seem to be a lot else within walking distance, or even within a short taxi ride. But the hotel did have an aquarium and a water park.

Jellyfish in the aquarium

Carelessly got sunburnt on the first day. In November! But the latitude is similar to Thailand or Vietnam so guess I should have known better…

37th floor…

Shanghai Metro Line 12

November 10th, 2019

I sometimes feel a bit nostalgic for the time a few years ago when I would plan epic county-crossing adventures for the weekend. But there isn’t any reason why I can’t do that here in Shanghai, I just need … a goal. And what better goal than walking the entire length of metro line 12. I pass my local station every day, but where does it come from? Where does it go? Today we’ll find out.

I started at the western terminus Qixin Road. The first few hours were pretty boring as this area is mostly residential and I’ve explored most of it already. My own backyard, so to speak. Anyway things picked up when I got to the city centre after eight miles or so.

Qixin Road station

The air quality in the morning was pretty bad so I did the first half wearing a mask. Bit novel for a hiking adventure.

Start of the northern section

The best part of the route is the section north of the city centre to the Huangpu river. West Nanjing Road to Donglu Road if you fancy following it.

Looking at the financial district from Hongkou

I’ve never been to Hongkou before, it’s a really interesting area: a mix of (relatively) old and very new. There was a large population of Jewish refugees living here during WWII and there’s a Jewish museum I’ve made a note to visit in the future. You also get some good views across the river to the financial district.

My constant companion

The eagle eyed might have spotted I missed a station on the map above, Fuxing Island. In my defence it really is an island and would have required a massive detour to get to, and then double back to catch the ferry across the river. I was tired, had a long way to go, and so I skipped it. Maybe I’ll go back another time to tick it off.

The eastern section over the river was unbelievably dull and ended up in some industrial estate. But eventually I dragged myself to the eastern terminus, Jinhai Road station.

Jinhai Road station

Yes I know it says line 9. It’s an interchange station and I guess they forgot to add line 12 to the sign when they extended it here, *sigh*.