Running Nerves on Android e-waste

Millions of phones are thrown away each year, very few are recycled and the pollution this e-waste creates is significant. There can be many reasons for consumers to throw away their phones. The asbence of updates from the phone’s manufacturer can be one of them. There are several projects that aim to extend the life of mobile phones, PostmarketOS is one of them.

But a lot of these devices have quite powerful system on chip, even 10 year old phones have a decent computing power for today’s use cases. So what if we could reuse them for other purposes? And more importantly, “can android e-waste run Nerves?”

This post describes the steps I took to have nerves running on an old Fairphone2. The phone features a Qualcomm Snapdragon 801 with 4 cores running at 2.26Ghz, 2GB LPDDR3 RAM and up to 32Gb of eMMC storage. Being a phone, it also has an LTE modem with dual sim, which can be useful for some projects.

“It’s just buildroot”

Nerves uses buildroot underneath, so before jumping into nerves itself, getting the phone to boot a buildroot system is the first priority.

In order to run Linux on such a device, you need 3 things minimum:

  • A kernel that actually boots on the device
  • A device tree
  • A root filesystem that the kernel can run an init script from

Fortunately, the Fairphone 2’s core functions are supported in PostmarketOS and there is a linux kernel fork specifically for this type of soc available here that also includes the proper devicetree.

Looking into how PostmarketOS works, I managed to find the kernel configuration they used. At first I just used it in my buildroot config. I added a few things later on but the necessary config remains the same. You can find my buildroot port for the Fairphone2 here

Booting buildroot on the Fairphone2

All Android devices rely on a particular partition table. Some devices will not boot if you tamper with it. Usually, the stock bootloader will look for a bootable Android kernel on the partition labeleled boot and then will mount the systempartition to boot android. The stock bootloader will most likely ignore what you flash on the boot partition unless it’s a valid Android kernel.

Once again, the amount of information you can get from the Postmarketos wiki is quite valuable. What they do, for the Fairphone2, is flash a 2nd level bootloader called lk2nd on the boot partition. It’s a bootloader that the stock bootloader launches… And that second bootloader scans for an extlinux.conf file on one of the other phone partitions. You can find more info about lk2nd on it’s github page
Note that lk2nd should only be used on devices that it supports…

So all we need is to flash lk2nd on the boot partition, then flash our buildroot image on one of the other partitions of the phone and we should be good to go…

I used buildroot to create an img file containing the complete filesystem (including /boot) and proceeded to flash it on the phone using fastboot. Wich got me to a login prompt :partying_face:

Creating the Fairphone2 Nerves System

I reused the same kernel config I had to use for my buildroot port, and compared the nerves_defconfig from the raspberrypi system with the one I used in the buildroot port to cherry pick what I needed in this new system.

I then proceeded to adapt a few files:

  • fwup config files
  • fw_env.config
  • erlinit.config

You can find the whole system here

Booting Nerves

The workflow is slightly different. We will not be using an SD card, and we must use fastboot to flash the device the first time.

After flashing lk2nd on the boot partition, I proceeded to build a simple nerves firmware using this system. In order to have an img file that I could flash, I used:

mix firmware.image

Then flashed the file on the userdata partition. This is only needed the first time or in case you mess up your firmware and need to start from scratch. After that, with your phone connected to your computer using USB, you should be good to go with the usual mix firmware && mix upload.

You should end up with the Nerves prompt on your phone screen.

What’s next

Alghouth I managed to make the modem work in buildroot, I still haven’t got a chance to get it to work in Nerves. There are also several sensors on the Fairphone2 that are not used at the moment (accelerometer/gyro). So there is still a bit of work to do in order to really use the whole potential of the device.

Wifi is already supported, and the touchscreen allows you to build kiosk applications quite easily.

What about other devices

This journey got me into many rabbit holes. I learnt a ton about linux, Android, buildroot and Nerves in the process. As soon as I got buildroot to work on the Fairphone2, I knew that if an Android device is supported by PostmarketOS, then we can run Nerves on it. A complete list of booting devices can be found on their wiki.

I didn’t suddenly decide to port Nerves on the Fairphone2 by myself. It turns out that in December 2024, I met a guy living in my city. His business is to create the first circular computer. The company is called citronics and his first prototype is… using a Fairphone2. When we met, I told him I’d try to run Nerves on his device.

I have at least two other old Android devices supported by PostmarketOS in my drawer, and I’m sure you also have a bunch of them in yours… So let’s put Nerves on all the things!

29 Likes

This is very cool!

4 Likes

I didn’t want the original post to be too long but for those really curious about some of the particularities of working with Android phones, here’s an additional part about partitioning.

On Android devices, you can’t always reshape the partition table. Sometimes, the stock bootloader will not even boot if you mess with it. I have no idea if that’s the case on the Fairphone2 but at this point, I don’t want to brick my device.

The good thing, once more, is that PostmarketOS figured it out since they flash several partitions inside an existing Android partition and manage to boot from it. I just need to do something similar.

After quite a lot of headaches and a steep learning curve, I created a (temporary) initramfs that is litteraly a trimmed and modified version of the one used by PostmarketOS. You’ll find the source code here

I mention it as temporary because it’s clearly not ideal at the moment and I don’t have an easy way to update the kernel and so on… I’m working on an initramfs generator that will remove all these issues but that’s good enough for now.

This initramfs uses two kernal command line arguments: rootfs and bootpart to pass the device partitions where the root filesystem and boot partitions are located. Note that we will generate an image that looks like this with nerves:

+----------------------------+
| MBR                        |
+----------------------------+
| Firmware config data       |
| as uboot env               |
+----------------------------+
| p0*: boot a partition      |
+----------------------------+
| p0*: boot b partition      |
+----------------------------+
| p1*: rootfs a (squashfs)   |
+----------------------------+
| p1*: Rootfs B (squashfs)   |
+----------------------------+
| p2: Application (f2fs)     |
+----------------------------+

We need to flash this somewhere. The biggest partition on most Android devices is the userdata partition. In the case of the Fairphone2, we have about 20+GB on this partition. On my device, it is located at /dev/mmcblk0p20. It means that when we flash our nerves firmware on it, our boot partition will be /dev/mmcblk0p20p1, and rootfs and application will be mmcblk0p20p2 and mmcblk0p20p3 respectively.

But using “subpartitions” is not something the kernel supports out of the box. We need a userspace tool to help us with that and the one PostmarketOS is using is kpartx.

By now you probably get what the initramfs is for. It maps the subpartitions to “real” device files thanks to kpartx and then proceeds to mount them. Once mounted, it uses switch_root to pass the ball to the rootfs and boot nerves which in turn will run erlinit.

7 Likes

What a great idea - and what a fantastic first post Marc! Welcome to the forum! :023:

3 Likes

I was literally thinking of the feasibility of this just the other day for my pinephone pro. I was thinking of throwing scenic on there and making a dumb phone that can do calling/etc. but have other priorities right now, But you have inspired me! Well done and very cool!

3 Likes

What an interesting idea. For some reason I never realized the obviousness of re-using old android devices as something else than phones - and nerves seems like a great fit to create a network of those devices.

The insights that you are sharing here are quite valuable, thanks for that!

3 Likes

Thanks! The pinephone would actually be a good device for running buildroot and Nerves. It was built to run Linux. It’s more open than most phones and there is a ton of resources online on how to flash and tinker with it.

I don’t own a pinephone myself but I would have loved to get my hands on one to be honest :smile: If you want to get started, you can reach out to me on the nerves slack or discord.

2 Likes

This is truly awesome!
Ever since the breakdown of trust in BigTech, my interest in massively decentralized applications has grown into a mild obsession, researching tech like Zenoh (Zero Overhead Network Protocol) or WAMP (cfr. the Bondy project at https://bondy.io).
Having Nerves on (old) phones might open a whole new universe of possibilities in the decentralized applications space. Bravo!

5 Likes

This is truly amazing and very promising as PostmarketOS supports a pretty good variety of devices.

I was thinking before about modifying the android firmware to have a OTP application installed as a system application, but this is even a better solution as you have the added benefit of OTA upgrades that are offered by nerves.

Hopefully supporting cellular is just as straightforward, as this will be a game changer compared to the current RPI (or other singleboard) solutions.

Have you managed to get scenic or something like phoenix liveview running already? If yes, then this is huge.

I have a old xiaomi poco f1, if you will ever post a short tutorial on how to do the modifications I would gladly give a try to modify the firmware for it. I am very interested in letting it run for prolonged amounts of time and see if it is up to the task in terms of stability, as I’ve tried once to run a phoenix server as a android app and I was seeing some very strange performance degradation.

3 Likes

Does anybody know of previous attempts to run Nerves on some kind of consumer electronics device (off the shelf, non-rpi)?

1 Like

Connor ran it on a Nintendo DS I think… right @ConnorRigby?

People have run it on a few x86es.

Then we have someone putting it on the abandoned Spotify Car Thing:

And then we are disregarding the people building consumer devices to put on shelves with Nerves in them by default. Most Nerves projects I hear about are not consumer-facing but rather commercial, industrial, etc but I l know there are some.

4 Likes

Thanks for your comment!

I can connect to my APN using qmicli in buildroot, but I haven’t managed to make it work with vintage_net_qmi yet. Due to the fact it’s dual sim, you also need to run a couple of commands before you can use the modem. PostmarketOS has a service that does all that and I just copy pasted it in my buildroot port. It looks at the two SIM card slots, checks which one has a card inserted, then reconfigures the modem to use that one.

To support cellular in the Nerves system, it “just” means translating that service into Elixir code, most probably wrapping qmicli itself and providing a nice Elixir library to include in your firmware. I’ll try to get it done during the next weeks.

It’s my first time using scenic but here you go:

There is a drm device exposed so anything using this will work. Wpewebkit or similar should work out of the box, and since I’ve been using flutter with Nerves on some other projects, it might be a good thing to try here as well.

I’d say the very first step is to install PostmarketOS on it by following their doc on the wiki for your device.

You can install PostmarketOS in console mode (no GUI), and then you basically have Alpine Linux, so if you only aim to get an OTP app running on it, you should already be able to install OTP and Elixir on Alpine and have what you want.

To get Nerves on it requires more digging, and the first step is to get the kernel config and firmware for your device. All the work on the SOC present on this phone seems to be happening here so it seems promising. Digging into the PostmarketOS Alpine packages for your device will give you all the information you need to translate it into a buildroot port.

But first things first, make sure you can run PostmarketOS on it.

4 Likes

Love this!

Is this on a vanilla phone? I know you knew a company that is repurposing the phones.

2 Likes

Yes, this is all on a vanilla phone.

And indeed, the company that repurposes the phones is Citronics, the link is already in this thread. I actually have on my desk one of their motherboards where you screw the Fairphone on.

The motherboard is basically a power supply for the phone, a USB 2.0 hub with an Ethernet adapter, and, also connected via USB, an STM32 that controls the GPIO connector. This one is an early prototype, the V1.0 will be easier to use.

6 Likes

Thanks, missed that part when skimming the details :smiley: ended up a win because I got more hardware pictures.

2 Likes