Grabbing SMSs from a USB connected Android phone

02 Dec 2011

Since moving abroad I've found myself in the position of being one of those guys that own more than one phone. It's a privileged and elite club for sure but I'll save the praise for another day. Now having two phones is useful as I can keep in contact with people in both countries for the smallest payout (although using my UK phone in the Netherlands is obviously expensive). I tend to carry my Dutch phone around with me during the day and leave my UK phone at home. That usually works fine but it's annoying if I get a text on the phone I don't have with me. Since the phone I leave at home is always connected via USB to a small server that sits on my desk, I figured it'd be easy to grab the new messages off it and shoot 'em over the internet to wherever I might be. Turns out it is.

A note here: this technique almost certainly only works on rooted phones - I don't imagine you'd have access to the SMS database with a non-rooted device. For reference, I'm using a rooted T-Mobile G1 running CM5 (because I'm too lazy to update it).

The method here is pretty straightforward: use adb to grab the SMS database off the phone, use python and sqlite3 to parse its contents, and send an email. In reality though there was no need to grab the database - everything could be done over adb. The first step was figuring out where the database was and what data it kept.

The database is located at

/data/data/com.android.providers.telephony/databases/mmssms.db

and can be browsed using sqlite3 directly on the phone. The schema for the sms table is:

_id INTEGER PRIMARY KEY,
thread_id INTEGER,
address TEXT,
person INTEGER,
date INTEGER,
protocol INTEGER,
read INTEGER DEFAULT 0,
status INTEGER DEFAULT -1,
type INTEGER,
reply_path_present INTEGER,
subject TEXT,
body TEXT,
service_center TEXT,
locked INTEGER DEFAULT 0

Some interesting data, but all I'm interested in is address, date and body. Now that we've got this far, we can get all messages with one call of adb from the server, like so:

$ adb shell 'sqlite3 /data/data/com.android.providers.telephony/databases/mmssms.db "SELECT address, date, body FROM sms"'

This gets us all of the messages on the phone. Since I wanted to just get new messages, we can limit the SELECT to just return anything newer than some date. I've already read all the messages on there so I only want to see new ones. So I created a text file, wrote the current date in milliseconds (since that's the format Android uses to timestamp its SMSs) to it and used that to limit the database query.

adb shell 'sqlite3 /data/data/com.android.providers.telephony/databases/mmssms.db "SELECT address, date, body FROM sms WHERE date > \'SOME_DATE\'"'

I wrapped this up in a Python script and scheduled it as a cron job, each time it runs it writes the current date to the file, which is read back in each execution. The server that the phone's connected to has a small landing page on it which I use to monitor backups and the like, so I figured that'd be a nice central point to display any new messages.

The SMS is also delivered to my Gmail inbox which I typically have open, so I get a notification usually within a couple of minutes of receiving an SMS.

Polling the phone every couple of minutes isn't the most optimal solution but I don't need to know about SMSs in realtime, so approximate is good enough.

As usual the code is on GitHub so check it out.

Further work

The nice thing about this setup is that it's not just useful for notifying about new messages but can be used to control the server by sending the phone a certain string. For example, I could send a message of "restart apache" to the phone, check for that string in the Python script then perform the necessary action. Options!

Comments