NixOS on my phone?

It’s quickly becoming a reality! Look at the devices list to see if your device is already supported. Otherwise, read about the porting process to understand if you can get NixOS on your phone.

News Items

2020 in the rear-view mirror

January 11th 2021

The year 2020 was my first full calendar year dedicated to working on the Mobile NixOS project. Let’s look at the progress, from the state of the project before January 2020, up to the state after December 2020.

Comparisons will start from the last commit of 2019, 7803d9ec0e35fe602f75d08e6bcb6db720ad897c. They are compared against the last commit for 2020, d5869523869eb029b712a3f2b7b1c3199874f221.

You might also be interested in looking at all the merged pull requests for 2020.

Some numbers

They’re quite arbitrary. I don’t know what other relevant stats could be used here.

  • 111 merged pull requests

  • 805 commits (skipping merge commits)

  • 10 commit authors (filtering duplicates)

  • Devices: 10 → 16

  • Modules: 39 → 56 (Nix files in modules/)

And here’s what cloc reveals:

[nix-shell:~/.../mobile-nixos/2019]$ cloc .
     274 text files.
     263 unique files.
      36 files ignored.

--------------------------------------------------------------------------------
Language                      files          blank        comment           code
--------------------------------------------------------------------------------
diff                             55            741           2623          16308
Nix                             108            719            772           4311
SVG                               7              4              4           2950
LESS                             24            263            333           1257
Ruby                             16            147             85            706
AsciiDoc                          7            130              3            243
XML                               5             19             12            160
ERB                               8              4              0             89
Markdown                          4             43              0             85
Lua                               1             15             41             58
Bourne Again Shell                2              9             10             21
C/C++ Header                      1             13             35             21
C                                 1              1              0             17
--------------------------------------------------------------------------------
SUM:                            239           2108           3918          26226
--------------------------------------------------------------------------------

[nix-shell:~/.../mobile-nixos/2020]$ cloc .
     482 text files.
     463 unique files.
      54 files ignored.

--------------------------------------------------------------------------------
Language                      files          blank        comment           code
--------------------------------------------------------------------------------
diff                             89           1429           5081          22047
Nix                             170           1266           1149           7576
Ruby                             76            690            575           4132
SVG                              10              4              4           3538
LESS                             25            291            334           1413
JSON                              6              0              0            959
AsciiDoc                         25            396              3            844
XML                               5             19             12            160
Markdown                          8             88              0            159
ERB                              10             23              0            130
Lua                               1             15             41             58
YAML                              1              1              0             40
C                                 1             11              5             37
C/C++ Header                      1             13             35             21
Bourne Again Shell                1              2              0              4
--------------------------------------------------------------------------------
SUM:                            429           4248           7239          41118
--------------------------------------------------------------------------------

Stage-1 improvements

This is where almost all of the work time this year was spent. Work started in January. Continuing through February, with the graphical interface. Further work punctuated the year. Neither words, screen captures or video can properly convey the amount of work spent on producing the best stage-1 experience that works across this wide range of devices.

We went from a rigid shell-script based approach, to a list of tasks handled through dependency resolution.

Additionally, before February, there was no way to select a previous generation. With the added GUI, generation selection is possible, error reporting in early boot is verbose, and boot progress is shown graphically.

Builds on Hydra

Before March 2020, no pre-built artifacts were produced. This is quite obvious when you try to build artifacts from the January checkout.

More important than build artifacts, this gave us continuous delivery of builds. With this we can track regressions, both in Mobile NixOS proper, or from changes in Nixpkgs.

Device support

Introduced in March 2020 the Pinephone is one of those devices with the biggest mind share in the community. Though, I personally don’t think it is the most interesting. After all, it is a somewhat boring device (in all the right ways!). Things with the Pinephone are expected to just work, and they mostly do, once the time is invested in implementing them.

Personally, at the top of the list of surprises are the Asus Zenfone Max Plus (M1) and the Moto E6. While less of the hardware is working, they are personally notable for me because they both do not have any alternative operating available. They were acquired as a challenge for me, to work strictly with sources from the vendor. This proved to myself that, yes, it is possible to work with devices that does not have a strong community behind them.

Closing word

I’m excited to continue working on this project. Let’s see what we can make out of 2021.

Don’t forget you can keep tabs on the project either by coming to the website regularly, or better yet, subscribe to the RSS feed!

December 2020 round-up

January 5th 2021

This update is the thirteenth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

Some interesting improvements landed, let’s dive in.

stage-0: boot in generation kernel+initrd

One of the biggest flaw with the approach Mobile NixOS takes with the boot flow is that it completely ignores the system generation’s kernel and stage-1 image. In turn, this reduces some of the benefits from NixOS, by reducing the coherency of the running system; the kernel and stage-1 are managed out of band.

With the changes from #262, devices can opt-in to a stage-0 scheme. A stage-0 image is the same as a stage-1 image, except that it will use kexec to boot into the generation’s kernel and stage-1 image.

Devices, and their kernels, need to support kexec. This is not a given for vendor kernels. At the time being, none of the Android-based devices (all using the vendor kernels) can use this feature. On the bright side, the Pinephone has been verified to work well. Additionally, UEFI x86_64 based devices, too, can use the stage-0 scheme.

Device-specific changes

pine64-pinephone: Crust firmware support

To use U-Boot with Crust, you will need to build it, then install it manually on your boot media. (A helper to upgrade the firmware is planned for the future.)

Not related to Crust, the usual kernel upgrade for the Pinephone has been made.

Introduction of uefi-x86_64

The introduction of the Generic UEFI build (x86_64) "device" may seem odd. It is meant to be used on a standard computer. But a standard computer is not a mobile device.

Really, this is a dogfooding measure. With this change, it is now possible for me to replace the usual NixOS stage-1 from my personal machines, ensuring I take the stability of Mobile NixOS seriously!

Additionally, this should allow supporting some x86_64 Windows-based tablets with the Mobile NixOS toolchain. While not required, the touchscreen-first boot flow will be helpful for those without a keyboard.

These changes also help exercising the foundations, by creating a new system type.

Removal of qemu-x86_64

As part of the changes for #253, the qemu-x86_64 device has been removed. Instead, a more generic device has been added, which by default builds images that can boot on standard UEFI, and which in turn provide the build.vm output to boot that generic UEFI image with QEMU, using Tianocore.

Ports

Two new devices were merged in December, one was removed.

Bringing the total of devices to 16.

November 2020 round-up

December 1st 2020

This update is the twelfth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

Some major improvements landed, let’s take a peek.

Progress in stage-1

The boot splash utility now shows the progress of the boot. This is done with a simple progress bar shows how much of the tasks have been handled. Long-running tasks can provide a message to show so the user knows things aren’t necessarily hung.

Speaking of hung tasks. Our init now detects when no tasks resolved in a given amount of time. When this happens, the boot is being failed with, hopefully enough context in the error message to help the user.

Speaking of error messages. Error messages are now less of a dead-end for our users. The interface has been reviewed to put the text message front and center. Previously we were showing a big image because we didn’t even have text rendering at this state. Now that we do, let’s use it.

In addition to that, the error applet is now somewhat interactive. There is now a cancellable countdown; when the time is elapsed the kernel is crashed, which allows the platform to do its default action (generally reboot). When canceled, the user can select different options, either through the touch screen, using a mouse, a keyboard or using volume-keys navigation.

The user can select to power off their device, which default action (so mashing the power key will power off the device). Depending on whether the platform supports it, the usual different reboot options are given.

Encrypted root filesystem support

Thought we were done with stage-1 updates? No! What if it was now able to decrypt LUKS encrypted filesystems? Well it can! For now, this is mainly the plumbing to make it all work. Getting a LUKS encrypted filesystem on your device is left as an exercise to the reader.

Our stage-1 can now ask for a passphrase during the early boot process phases. This is done through an on-screen keyboard. For the time being the keyboard is hard-coded to be the US QWERTY layout, and this is bad. Further improvements are planned, but out of scope for releasing the feature. The on-screen keyboard will be necessary for other upcoming planned features.

While using an on-screen keyboard is useful when you don’t have a physical keyboard, physical keyboards also can be used with that interface. Similarly to the previous note, it is hardcoded to be the US QWERTY keyboard, but the tooling chosen to drive the keyboard mapping (libxkbcommon) will give us the ability to configure both the on-screen and physical keyboard.

Ports

No new ports were made in November. There is still a total of 15 devices you can build for.

October 2020 round-up

November 3rd 2020

This update is the eleventh in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

Some interesting changes were made during the month, let’s look at some of them.

Re-done kernel builder ergonomics

The goal of this change is to make the kernel derivations as lean as possible, relying on the builder, rather than relying on copy-pasting common patterns around.

This is a change that was needed since the project was started. Though, it could not have happened much earlier than this late in the project. This is because multiple different quirky kernels needed to exist to properly show what needed to be abstracted.

With this, all common patterns for quirks have been identified and put behind flags. Those flags are described in Notes about the kernel builder.

End-users shouldn’t see any difference, this will help people who make ports.

Compile kernels only once

While testing the previous change, it was observed by @danielfullmer that kernel compilation happened twice for some devices.

This was not a regression. Though looking at things trying to find problems you are bound to see the existing flaws!

This was worked around by doing everything in one make invocation. The end-result is that some kernel builds will finish twice as quickly!

Pinephone Modem support improvements

With that said, there’s more to it. End-users shouldn’t have to care about a deeply-rooted /sys fs path to turn the modem off or on. This is why the modem-control service has been added. It mirrors the modem’s state using bindsTo and wantedBy.

With this service, the modem is better integrated with systemd, but more importantly the user can stop and start it using systemctl, rather than to dig for a particular less user-friendly path.

Calls and SMS will be tested at a later point in time. Though it is expected that calls will require some work for the audio to work properly (a known upstream issue).

New ports

One new device was merged this time.

Bringing the total of devices to 15.

This update is the tenth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

As with the last update, a big part of the 10 pull requests merged were bug fixes or minor changes.

Here’s a quick look at some of the nicer things achieved.

Forced kernel configuration normalization

The kernel-builder infrastructure now forces the configuration file used in its build to be normalized.

What is normalization? Simply put, it’s about updating the kernel configuration file so all of the options represent the values set in the current kernel build.

This is a somewhat breaking change, as it forces kernel configurations to be kept up to date even if no changes were made by the maintainer. Though this makes the final build somewhat more declarative, as options removed and new options will be reflected in the kernel configuration in the repository.

Autoporter

The new Mobile NixOS Autoporter project is an experimental tooling intended to expedite the first step in porting to a new device.

In a few words, it finds as many facts about a given device as it can. The current implementation uses pre-expanded factory images from OEM, but plans are in the work to work from files the user provide instead or in addition of.

This enables the porter-developer to start from known true values for the device, rather than needing them to find out those values. The more valuable ones are the subtle ones, like the USB gadget modes, or system as root.

It does not provide a complete skeleton yet. Mainly for now it’s missing the kernel derivation. Though we might be able to provide likely source locations depending on some factors.

All of this is not theoretical. We already have one port done through following this process! Look at the pull request #205 where the commits also tries to show the work that was needed to go from the skeleton files to a working port.

Note that this port was made easier by the presence of another Snapdragon 660 port existing. Many quirks end up working similarly between devices on the same base platform.

Hopefully this will help some of you take the plunge into trying to make a new port! Though note that this does not replace the still non-existent documentation about porting guidelines. It might still not be trivial.

New ports

One new device was merged this time.

Bringing the total of devices to 14.

Closing words

The last month’s update was skipped due to the lower amount of work being complete, the main contributor (me, samueldr) was tied-up working on implementing the NixOS.org redesign. Fear not, it’s not lack of motivation, but temporary engagements that slowed things down. For the time being this project is still my main focus, and I hope it can stay for longer.

July 2020 round-up

August 4th 2020

This update is the ninth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

As with last month, a big part of the 10 pull requests merged were bug fixes or minor changes. Though some valuable work was also finished.

Asus Zenfone Max Plus (M1)

The port for asus-x018d is mainly notable for being the only alternative system to the OEM-provided Android system, with the exception to a TWRP that is using the OEM-built kernel.

This means that, for the first time, Mobile NixOS this is the only alternative system for a device, including other Android-based systems.

Finishing with a last note, this device has an older Mediatek SoC, compared to the other ported Mediatek device. There is not much to say, except that it was found that older Mediatek devices may exhibit a similar quirk to Qualcomm devices, where the framebuffer has to be refreshed explicitly for the display to be updated.

External device definitions

I hesitate to openly discuss about this pull request, as it might make contributors think they should not contribute their devices back. #162 adds a mechanism to maintain and build external device definitions.

These external definitions should only be used for devices that are not welcome to the main project. The main reason a device would not be welcome is if it is not a “Mobile device”. An example of such a device is the Pinebook Pro, which is a laptop. Another example would be porting to SBCs like a Raspberry Pi.

Updates for the boot GUI

This change, #189, is where most if this month’s development time was spent. The toolkit used for the boot GUI has been forked and adapted to serve the goal of providing a GUI for mobile devices better.

As part of the changes, some minor UX (User eXperience) changes have been made, but more importantly, major changes like properly supporting mouse and touch screens in an independent manner, and providing keyboard-driven input. This also adds support to navigate the GUI with the volume keys and the power button, which is a common scheme used to provide a fall-back navigation when touchscreen support is possible.

Except for the new way added to interact with the GUI, there are no major changes to how the GUI is used. Though the work is a first step to provide more in-depth options during the boot process, like tracking progress, and required user input for actions during boot like passphrase input.

New ports

One new device was merged this month.

Bringing the total of devices to 13.

June 2020 round-up

July 7th 2020

This update is the eighth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

Most of the 9 pull requests merged were trivial or minor changes. Though there’s still some notable changes.

Pinephone bluetooth support

It turns out all it needed was a trivial fix. Giving it the firmware it wanted adds proper support for bluetooth on the Pinephone.

If you are using the examples/demo rootfs, its configuration does not currently configure the system for audio with bluetooth. The instructions to configure audio for bluetooth are the same as usual, as Mobile NixOS is composed on top of NixOS.

Redmi Note 8 Pro

The port for xiaomi-begonia is mainly notable for being the first port for a Mediatek SoC.

I am singling out this port as a proof that the breadth-first development style is working well. Since Mobile NixOS had many abstractions needed for the existing different platforms, this new platform, and device, was ported without a sweat.

This also paves the way for other Mediatek ports by providing a working example. Coupled with #175, another, older, Mediatek device (merged in early July), there is enough material to give clues for future ports by community members.

New ports

One new device was merged this month.

Bringing the total of devices to 12.

May 2020 round-up

June 2nd 2020

This update is the seventh in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

11 PRs were merged during the month. Changes are mostly cleanup and documentation related.

Documentation changes

The biggest change is the addition of an overview of the terms used to define a device (#148). This documentation section should help better understand how devices are composed.

The README (#138) as shown on GitHub has been reviewed to better guide users and contributors around the ecosystem, borrowing the organization of the main Nixpkgs README. Though the main reason for this change is that the README started to diverge with the documentation. Removing all examples and referring to the actual documentation files reduces the burden of maintaining multiple documentation fragments.

Code and architecture cleanup

Through some of the pull requests, a bunch of either dead, or ossified code was found and removed. The main user-facing change is the removal of device.info.

The device.info option was a mixed bag of misshapen, undefined options that were at the foundation of all device definitions. The replacement are discrete well-defined options that are defined in understandable categories. Systems define options that they use, making it easier to understand why an option is defined.

The main consequence of that change is that the current work-in-progress ports will need to be reviewed to use the new options.

As part of #155, additional cleanup was made in the first few commits.

New examples/hello system

While technically a new feature, the new examples/hello system (#155) is more of a first-user-experience "bugfix" than a useful new feature.

This introduces a new example system that can be cross-compiled entirely, and shows an interface to the end-user. This helps fix the biggest complaint about the project: the default build looks as if the system has stopped responding.

Though this is not actually fixing that complaint, it does not replace the default build output. Users making a new port, or testing an existing port, will rather be encouraged to first try building and using this example to confirm the port works.

 $ nix-build examples/hello --argstr device DEVICE-NAME -A build.default

A planned addition to this feature will be more features to test and validate support for different subsystems of the device. Currently this only tests the touchscreen (through requiring it for navigation) and validates the display shows the colours appropriately.

Additional highlights

Ports

No new port were made in May. There is still a total of 11 devices you can build for.

April 2020 round-up

May 6th 2020

This update is the sixth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

11 PRs were merged during the month. Not an exciting month with fun and visible progress, but let’s point out interesting changes

Device specific website pages

The Devices List section is now formatted as a table, and links to one page per device.

This page can contain device-specific notes, and generally contains generic instructions depending on the device type. The side-bar uses generated content, but the page will use the README.adoc file when found in the device directory.

All of this is part of PR #120.

Supported way to include from system configuration

In PR #123 a supported way to include a device configuration to the system configuration was added. The Getting Started page explains the details.

This is useful when combined with the next higlighted changes. The device specific configuration doesn’t have to be handled by the end-user, the Mobile NixOS configuration handles it.

WCNSS WLAN quirk

PR #126 adds support for WCNSS WLAN in Mobile NixOS, while enabling it for the only device that supports it.

This is the simplest Wi-Fi setup for Qualcomm-based hardware. Sadly, for other devices it’s much more involved.

Though, this does mean that we now have Wi-Fi support for one more device!

Bonus change: Buried in that same PR, we now use boot.initrd.enable = false rather than using isContainer. This fixes a couple of weird and annoying issues with the running system.

Device-specific polishing

These start implementing some polishing, in what I hope becomes the gold standard for device ports.

First, we configure the LEDs so the Linux kernel controls it during boot (z00t, oneplus3). This provides a tangible proof to the end-user that the kernel is currently in control and running.

Then, for asus-z00t, some kernel cleanup patches have been added. The first kind of change is to remove idiotic behaviour from the OEM kernel, like trampling over the kernel module load path. The second is more subtle, but welcomed when reading dmesg: reduce the useless logging present in some modules. The amount of logging is useless.

Finally, for oneplus-oneplus3, there’s a quirk to fix USB OTG support during boot. I don’t think any other device will need it, from a quick glance, but it’s still a good example of how to implement a quirk.

Ports

No new port were made in April. There is still a total of 11 devices you can build for.

March 2020 round-up

April 7th 2020

This update is the fifth in a series of regular updates on the state of the project.

Only changes that have been accepted and merged in Mobile NixOS are chronicled here. There’s always more work currently in-progress.

Notable changes

17 PRs were merged during the month. (The link says 18, but one of them was, to me, late in February, read the previous news item).

Let’s look at some of these.

Pine64 Pinephone “Braveheart”

This was teased about on the author’s twitter account. The inexpensive Pinephone is the latest new device added to Mobile NixOS.

This brings a bit more than only a new device. This is the fourth system type added to Mobile NixOS. The added system type (U-Boot) in theory will give us the ability to support any U-Boot-based system in a common way. In practice the still unmerged and WIP #94 shows how this is true by using U-Boot with another Pine64 device, the Pinebook Pro.

A nice thing that was verified again with this new device port is that the stage-2 image (the rootfs, the system.img) is indeed universal. It is using the same AArch64 build of the system image as Android-based devices, and Depthcharge-based devices.

Our build for the Pinephone relies on the downstream kernel from the Pine64 community, with only one added patch. The same is done for the U-Boot build.

The added patches are user-experience-focused patches that are using the RGB LED of the phone to show the boot status.

Other than that, the hardware support is not complete, but it is supported at the same level as other devices, plus Wi-Fi working.

See PR #96 for all the details.

Hydra builds

This is not entirely an in-repository change. There’s #97 and #133 that are relevant to this. The mobile-nixos:unstable jobset on Hydra is the other part of the puzzle.

What this gives us is automatic continuous builds of Mobile NixOS against the nixos-unstable NixOS channel. From this, we can track changes that break the Mobile NixOS builds, and track internal breakage to some parts of Mobile NixOS.

This is not even the best part. As can be seen in #133, we are now delivering up-to-date stage-2 rootfs, which allows end-users without the required hardware to bootstrap themselves using a pre-built image. The requirement to have a native AArch64 machine to build the system image is no more. While not ideal, users could make use of their phone to build a customized image, or simply, do a nixos-rebuild on it.

It already paid its worth in gold, as by the time this was developed, two regressions were spotted and quickly fixed. And furthermore, I hope that the exercising of the cross-compilation framework will help the NixOS developers working on making cross-compilation better in NixOS.

Other mentions

  • Using GitHub Actions, #112 checks new PRs for some simple breakage.

  • Developers can now use nconfig to configure their kernel using the “porcelain” bin/menuconfig, as added in #109.

Ports

One new device has been merged during March.

  • Pine64 Pinephone “Braveheart” (pine64-pinephone-braveheart) [@samueldr] (#96)

Bringing the total of devices to 11.