mlainez

mlainez

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!

Most Liked

mlainez

mlainez

After working on porting Nerves to this fairphone 2, it got me thinking: “how far back can I go ?”.

It turns out I have a few Android devices in a drawer here, and one of my oldest devices is the Google Nexus 7 tablet from 2012.

I was pleased to find out that this tablet supports U-Boot so I embarked, yet again, on a most probably useless journey to bring Nerves to Android e-waste. They sold several millions back in the days, so maybe this will be useful for someone out there :smiley:

Replacing the stock bootloader by UBoot was not so easy. You need the battery to be charged enough (mine is quite dead), and bring the device in APX mode, which meant starting the device with an unplugged battery then plugging it in again while connected. Anyway…

After some tinkering with some nerve configuration, I got it working.

Ethernet over USB works, wifi too, there are a couple of things I need to look into but I managed to burn a simple firmware to it.

Overall, despite replacing the stock bootloader, the process was quite easier than I thought, there were less custom packages involved and with U-Boot, I have full access to the internal memory, the original Android partition table is gone.

For those interested, the system is here :alien_monster:

My next victim might be a Samsung Galaxy S3 Neo from 2014… but if you have some popular old Android devices you would like to get rid of and you are coming to NervesConfEU/Goatmire Elixir in September, maybe you can bring them… :smile:

mlainez

mlainez

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.

beamologist

beamologist

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!

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
laiboonh
Hi all, I am trying to convince my team to use liveview over the current react. What are some of the points where one should consider us...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
WolfDan
After doing a port from a c++ library to my project in phoenix I’ve seen that I need a faster way to run this algorithm and I found this ...
New
mmport80
I have put far too much effort into Dialyzer over the last year or so - and basically - I doubt it’s worth the effort. It’s not as easy ...
New
PragTob
Hey everyone, this has been on my mind for some time and I’d love your input on it! TLDR: I feel like maps are superioer for storing and...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
Markusxmr
Since Drab has been developed for a while in the open, introducing the Liveview functionality in a way it happend appears to undermine th...
New

Other popular topics Top

siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

We're in Beta

About us Mission Statement