There’s a server in my pocket!

I’m not a psychopath, I’m just very creative.
(c) Harry Potter and the Methods of Rationality

Taking part in competitions like “eurobot”, where you have to do some coding in extreme conditions, on/under a table, on the floor, etc. and a few other trips like that convinced me that I should definitely make something more of my cell phone. Something, that will help me out in this case.

So, we have:

  • A dumb brick called ‘HD7 Pro’ from china, with android 2.3.5. One and a half years old.
  • /dev/brains
  • A few hours of free time

What we want to get:

  • A portable server with lighttpd, ssh, git, etc
  • WiFi AP with local dns, internet tethering (if we’re not roaming!)


Okay, getting to business now. Doing stuff below will most likely void the warranty, so be warned. With the right skills this will work on any android phone on the market.
Just a note – I got my phone rooted and had busybox installed ages ago, so I won’t describe this procedure. This is required for further stuff to work.
The first thing I’ve done – hacked the dnsmasq config file, so that it will do local dns.

Now, when we enable the android’s stock portable hotspot we have proper dns, and we can access different hosts on the network via their names. In my case I set the phone’s hostname to anomalia, so that I can just type http://anomalia. Everything else has their hostname set via dhcp hostname.
The master plan is simple: run a few services from a debian chroot, since cross-compiling software with ndk is really painful.
And, when everything works – throw up a GUI for starting and stopping the pocket server with one click touch.
Honestly – I never had a look what’s inside the firmware of my phone for nearly one and a half year that I owned it. And it’s kind of sucks – looks like I’m getting old. So, I fired up adb and had a good look around

/ # uname -a
Linux localhost #1 PREEMPT Wed Feb 8 19:45:24 CST 2012 armv6l GNU/Linux

/proc/filesystems looks really bad:

/ # cat /proc/filesystems 
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   tmpfs
nodev   sockfs
nodev   pipefs
nodev   anon_inodefs
nodev   devpts
nodev   ramfs
nodev   mqueue
nodev   mtd_inodefs

This is bad. We have no filesystem enabled (except yaffs2) that supports all the features we need for a debian chroot. And we can’t format block devices (e.g. SD card) in yaffs2. For SD we only have vfat & msdos.
Since the phone is based on MTК6573 chipset, and mediatek is not a really open company I already assumed that I won’t be able to recompile kernel. But again, I was lucky – the kernel had modules enabled, and twice as lucky – there was a ready to use ext2.ko in /system/lib/modules/.

/ # ls /system/lib/modules/

It just didn’t get loaded by default – looks like some factory leftover. Thanks for that!
loading and testing…

/ # cat /proc/filesystems 
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   tmpfs
nodev   sockfs
nodev   pipefs
nodev   anon_inodefs
nodev   devpts
nodev   ramfs
nodev   mqueue
nodev   mtd_inodefs
/ #

Next went a long backup of the 32GiB uSD card, since I had to repartition it. I made 2 primary partitions. First one, formatted as vfat serves for android as the usual storage and takes up most of the space. The second one is formatted is ext2 and is the root of our nice and shiny debian installation.
While the data was still backing up, I bootstrapped a debian installation for armel according to the official ™ article on Debian Wiki.
After doing that, there comes the voodoo, and some differences to the official manual.
First, I needed a script to mount all the filesystems, if needed and start/stop a bunch of daemons from a chrooted debian installation. This is what I eventually came up with:

DAEMONS="lighttpd ssh minidlna mysql"
export SDCARD=/sdcard
export ROOT=/data/debian
export DEV=/dev/block/mmcblk0p2
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
am broadcast -a org.ncrmnt.serverctl.log -e log "$*"
log "Mounting debian chroot..."
insmod /system/lib/modules/ext2.ko 
mount -o rw,noatime -t ext2 $DEV $ROOT
mount -o bind /sys $ROOT/sys
mount -o bind /dev $ROOT/dev
mount -o bind /proc $ROOT/proc
mount -o bind /dev/pts $ROOT/dev/pts
mount -o bind,users $SDCARD $ROOT/mnt
mount -t tmpfs none $ROOT/tmp
mount -o rw -t tmpfs none $ROOT/var/log
mkdir $ROOT/var/log/lighttpd
hostname `cat $ROOT/etc/hostname`
log "Hostname set to `cat $ROOT/etc/hostname`"
log `chroot $ROOT /etc/init.d/$1 $CMD`
 log "chroot environment fully unmounted. "
if [ "$CMD" == "terminate" ]; then
        echo "Cleaning up..."
        $0 stop
        #Kill any working ssh sessions.
        killall -9 sshd
        killall ssh
        umount $ROOT/var/log
        umount $ROOT/tmp
        umount $ROOT/dev/pts
        umount $ROOT/dev
        umount $ROOT/proc
        umount $ROOT/sys
        umount $ROOT/mnt
        umount $ROOT
        rmmod /system/lib/modules/ext2.ko
        [ -f "$ROOT/etc/hostname" ] || t_done
        log "ERROR: chroot is still mounted"
        log "ERROR: ditch any running ssh sessions and try again"
        log "ERROR: termination failed"
log "clean"
log "Necromant's pocket server"
[ -d $ROOT/dev ] || prepare 
for s in $DAEMONS; do
run_service $s
log "All done, have fun"

I will draw your attention to a few caveats here:

  • For ext2/3/4 there’s an option ‘noatime’. Add it whenever your rootfs is on an SD card, since it decreases wear.
  • /tmp and /var/log are mounted as tmpfs in ram – less SD card writes this way
  • For lighttpd to start happily we need to make a directory in /var/log.
  • Since we do NOT invoke debian’s init, we have to set our hostname with a small hack.
  • /dev in debian chroot serves as a marker file
  • Terminate as well kills all ssh/sshd to nuke any open sessions. Without that we won’t be able to unmount chroot.

Next we just start/stop/restart our array of “$DAEMONS”. I named this script ‘serverctl’ and dropped it into /system/xbin, so now I can just run

serverctl start/stop/restart

Next goes the usual work of installing and configuring the services: lighttpd, php, minidlna, gitweb, ssh, mysql
After that routine was done, it was the ‘web-time’.
I just grabbed something I liked from and started customizing it. Since I din’t want to install any huge CMS on my phone, I decided to make it just one index.html and fill most of the interesting stuff via ajax. A few small and dumb php scripts send out the data.
Looking through /sys I found a bunch of “tasty” files with useful info, that I wanted to display in web-ui. I quickly coded this ugly php script, that did that job. (Professional web-developers will want to shoot me in the head for that, I’m pretty sure 😉 )

echo $a;

This is how I got battery and charger state voltage in web ui and a lot of other useless useful data.
I added a bunch of other, even more ugly php files for stuff like getting the free space:

$fs = $_GET['fs'];
$data=shell_exec("df -h $fs");
$data = explode("\n",$data);
$data = preg_split ("/\s+/",$data[1]);
foreach ($data as $d) {
        echo "'$d',";

All in all I ended up with about 7 different scripts, called via ajax.

Next, was the gitweb installation and organizing my own ‘github-in-apocket’. The first thing I’ve done – added the user ‘git’.
Next I created the usual ~/.ssh, and the usual authorized_keys. Since we’re going to push and pull to git repositories via ssh, so we’ll need the public key authorization and the ability to add new keys via web interface. After a few attempts, I ended up running lighttpd as user git, instead of www-data. That made the task even easier, so I added the ability to create a new bare repo and clone a remote git repo right from the web ui. The webui also displays quick links for ‘git clone’ and ‘git remote add’.
Next went the awesome sticky-notes pastebin script. Yep, it requires both php and mysql. And since I got mysql up and running, I also installed… phpmyadmin.
There are a few screenshots showing off the webui.





Finally, I decided the throw an android app to start and stop all these goodies. So, I opened up eclipse, and squeezed some java code out of my brain. This is what the broadcasts in the bash script are for. The app just fires up the serverctl script as root with the corresponding argument and displays the result.


So, done already? Not yet! I decided to capture images from cameras right from the web interface. Why? What for? Just for fun. It looked like an easy task – just grab a pic via v4l.
It seems like it was NOT that simple. Code monkeys from mediatek just ditched the whole v4l/v4l2 infrastructure and hardcoded the cameras to android. In other words – finding out how to access them from debian chroot seemed to be time-killing task I didn’t have the resources for. (Btw! No bluez for bluetooth as well!)
So, I added a service to my java launcher app that listens for connections on port 8888 and in response to HTTP GET delivers pictures from front or back camera.
To make it look even better, I grabbed lightbox2, that makes a nice popup whenever I click on ‘front cam’ or ‘back cam’ links. See the screenshot below:


Now, the tasty stuff: all the sources for this thingie you can grab for free at my github (Warninig! It was all hacked in just two evenings, and code is UGLY! Really UGLY!)

Android app

Final thoughts
My mobile is in no way a top model, and android is sometimes laggy. Not that I really care about it – it just does whatever it is supposed to do.
Inside is an ARM 1176 Core running at 650Mhz and 512 megabytes of ram. 64 MiBs are consumed by the 3d accelerator, about a half of the remaining or even more – by android. And despite all that I get a smooth experience running gitweb, sticky notes… Even phpmyadmin that should be damned slow runs really smooth.
And with this thing in your pocket you can team up to hack some code on the run with maximum comfort, even if there is no internet connectivity and you are miles away from home.

Print Friendly