Hellaphone was a project we did at Sandia that stripped out the Java portions of an Android stack and put Inferno in its place. We did this in the summer of 2011, which placed us in the Gingerbread (Android 2.3) era. And by “we”, I mean Ron Minnich, myself, and our two summer interns, Joel Armstrong and Josh Landgraf.
Our motivation was frustration with existing phone operating systems. All except Android were closed-source. RIM would decrypt your “secure” Blackberry messages if your government asked. We saw malware pre-installed by carriers in the form of CarrierIQ. The iPhone was keeping track of your movements.
Android, though open, had its own share of bugs and malware–like accepting fake OTA updates, as demonstrated at Defcon 19. As of 2011, there were 15 million lines of code in Android, not counting the similarly-large Linux kernel it ran on! Your only options for coding were Java (unpleasant), C++ (really unpleasant), or C (Android even managed to make writing C suck). And, worst of all, it ran like an absolute DOG on your average 1.2 GHz, 512MB smartphone of the day. It sucked down your battery pretty quick too.
So we poked around in Android, thinking we could do better. We discovered that Android was more or less a thick layer of Java spread atop a relatively thin Linux cracker. Get rid of the Java and you’ve got a basic little Linux system, more or less standard, with a halfway-decent busybox environment on top of it. We decided we’d put our own software directly on top of the Linux part and just throw out all the Java.
We decided on Inferno, because Inferno was 1) lightweight, 2) open-source, and 3) familiar to Ron Minnich and me. Inferno is an operating system that can run on bare metal or on top of Linux, Plan 9, or Windows. It manages this by running on the Dis virtual machine. It compiles fast, launches fast, and runs fast. The total distribution comes up to around 1 million lines of code, which includes quite a few applications and the code for booting on bare metal, which we didn’t use. We figured it would be pretty easy to get Inferno running on top of Android’s Linux system, drawing its GUI directly to the framebuffer and reading pointer events from the screen.
Before we could run Inferno, we had to kill off Java. Turns out every Java process spawns from one ur-process called “zygote”. We simply modified the init script to prevent it from starting zygote. This left us with a phone that would turn on and go to a blank screen–Linux was booted, but nobody was using the screen.
We figured out how to make Android’s compilers build Inferno (we used a script called AGCC) and set about porting it. Inferno’s Linux code was mostly suitable already, it just needed a few tweaks due to differences in the standard library (you’d be surprised how non-standard standard libraries can be). Pretty quick we had Inferno working to the point where we could run it in text mode over Android’s “adb” serial debug console.
To get graphics, we made some slight adaptations to code Andrey Mirtchovski for the OLPC. We pointed it at the phone’s framebuffer devices and suddenly we had graphics! The more complicated part was getting touch input. We ended up writing a mouse driver for Inferno that read events from /dev/input and parsed the touchscreen events into sensible mouse-clicks. The touchscreen driver remained one of the biggest pain points, because touchscreens are so naturally inaccurate.
We hacked on the Inferno window manager to make it more touch-friendly. The biggest improvement was creating a large drop-down application menu which provided easy-to-touch access to applications, instead of trying to navigate the tiny Windows 95-style menu it shipped with. We also modified the on-screen keyboard to make it a little more friendly, and configured the phone’s hardware buttons to perform useful tasks like closing an application, opening the keyboard, or returning to the “desktop”.
Here’s the “desktop” with nothing running:
And here’s the application menu when opened:
We made a simple SMS client:
And a phone dialer–you could make phone calls, but we didn’t figure out how to make the phone ring for incoming calls.
Dealing with the cell radio was interesting. We eventually wrote “devphone”, an Inferno device which spoke to Android’s radio interfaces and presented the capabilities as a synthetic filesystem. So for example you could say
% echo 'dial 5551234567' > /phone/phone
to make a phone call. If you read from /phone/phone, the read will block until you get an incoming phone call. We had a similar interface for SMS messaging. Of course, since nobody wants to enter commands at a tiny onscreen keyboard to make a phone call, we wrote the applications you see above to provide graphical interfaces to the device.
What about now?
We built Hellaphone 4 years ago. I don’t think the phone situation has really improved much–for instance, look at the recent discovery of an Android bug that lets an attacker do remote code execution simply by sending you an MMS. Phones keep getting bigger and faster but the software keeps demanding more and more, so your battery is much bigger than 5 years ago yet it still only lasts you a day.
How was Hellaphone different? For starters, it was simple–one person could come to understand the whole system quickly. Our high school intern, who had no prior experience, was hacking the Inferno virtual machine and writing Limbo code proficiently within a few weeks. Because the code was so simple, there wasn’t a lot going on all the time, meaning the battery didn’t drain as fast. Our test platform was the Nexus S; where Android would drain the battery in a day or two even just sitting with the screen off, Inferno would regularly run a week on a charge. It also took less than a second to boot–try that with Android!
The Limbo programming language you use to write Inferno applications is also quite pleasant. It shares many features with Go (since it was written by some of the same people). Its greatest weakness is the GUI toolkit, which is Tk, but that could be replaced with another library.
The whole Hellaphone system was also easy to hack on. If you make a change in Android, it takes forever to rebuild and package up a new image. We, on the other hand, could rebuild the entire Hellaphone tree in about 30 seconds and just push it over the ADB port as a live update.
Because Hellaphone is built on Android hardware, it comes with a huge ecosystem of potential devices–if you want to make your own Hellaphone device, just buy a Nexus 5 and start hacking. It’s so customizable that you should be able to add whatever features you want easily–locking, sandboxing, remote wipe, etc.