In re: iPhone Tracking

To catch up: last week, a couple O’Reilly analysts discovered a database file on the iPhone that appears to track the location of the phone, over time. They also released a companion program to view the data, on any computer used to sync an iPhone.

My life, according to my iPhone

Inspired by this piece in The Atlantic, I downloaded the iPhoneTracker application to take a look at my own data. Below is my full location track over a map of the United States.

(Note: I intentionally reset my iPhone and removed my backups so I could “start clean” in May 2010. This is unfortunate, but I think the following map would have rendered exactly the same since I’ve repeated road trips and routes over the past few years.)

my iPhone location tracking map

Of note:

  • Proud to say that I practically own the majority of the I-70 corridor.
  • There is an interestingly large “dead spot” in coverage over Eastern Montana, Wyoming, and South Dakota, along I-90.
  • I’ve never stepped foot in New Mexico, so I don’t know why it placed points there.
  • I believe I’ve travelled south of the 37th parallel within the United States a mere handful of times in my life, and this map is slightly representative of that fact. Connecting flights make up the bulk of my experience through the Southwestern United States.

For fun, here’s a map of my trip to the New Jersey / New York City area last June.


We need to go deeper

Unimpressed with the granularity of iPhoneTracker’s maps at high-zoom (example), I decided to take apart the data myself. (Python’s native sqlite3 support helped. I’ll likely publish some source code when I follow-up on this.)

Here’s a very rough map of every point my iPhone stored in the Spokane area: blue points from the “CellLocation” table (likely AT&T cell signal transmitters), red points from the “WifiLocation” table (likely a list of every access point seen).

Spokane wifi map

(Compare to iPhoneTracker’s version.)

And, for good measure, a detail view of Downtown Spokane:

Downtown Spokane map

Future analysis

The above images are fairly rough: I’m not filtering duplicate MAC addresses, nor am I taking into account the accuracy of any of the data points. I do no date filtering or time-based analysis — it’s just a mass of points. But, I think visualizing the density of information stored on my device is interesting nonetheless. There are at least 10,000 data points in the above maps, dating as far back as the end of June last year.

As an en masse set of points, the data isn’t nearly as damning as the “location tracking log” moniker would suggest — there are no telltale “dense spots” to give away locations I frequent. But, as I said, it’s a rough view of the data and not representative of an actual attempt to run forensics.

Where can I go from here?

  • With the higher granularity in the raw data: how precise can I guesstimate my whereabouts at any given moment in time solely on the nearby Wifi locations? Can I pull together an accurate location track such as this one, detailing the movements of German politician, Malte Spitz? (See also: the corresponding report published by Zeit Online and this perspective from the EFF.)
  • Noticed that MAC addresses are part of the data stored for WifiLocation. Could be interesting to see what manufacturers make the most common routers/access points.

Complexity is the enemy

It turns out that, much like it’s easier to write a long blog post than it is to make the same point succinctly, it’s difficult to write software that is straightforward. […]

Another word for this problem is cleverness: to quote another one of the C hackers, “Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”

Great frozen tundra of a city.




pdb: Using the Python debugger in Django

A couple conversations I had at DjangoCon last week reminded me that I’d never gotten around to finishing this little post.

Since I started taking my first iOS development baby steps last year, I’ve become quite dependent on breakpoints and stepping as part of my Objective-C debugging workflow.

…And yet, in Python/Django — the stack I spend most of my time working with — I’d stuck to the poor habit of throwing print statements around any found exceptions — for example, to figure out what lies in request.POST for a Django view. And then I came across and started tinkering with pdb.

Here’s a brief overview on how to rock your Python debugging workflow by using an actual interactive debugger. The example below highlights the most basic of usecases, but it’s a good start.

Using pdb with Django

Say, you have a view that looks like this:

from django.http import HttpResponse

def default(request):
    # completely innocuous variables
    foo = 1
    bar = 0
    # completely innocuous division
    ni = foo/bar
    return HttpResponse("Foo says %d" % ni, mimetype="text/plain")

And say, you run your local development server with: runserver

When accessed, this view will generally throw you something like this:

thumbnail of error example

By replacing the runserver command with one wrapped in PDB, we can start digging a little bit deeper into this problem view.

python -m pdb runserver

You will notice that the shell hangs on a (Pdb) prompt. Enter c for “continue” (command reference here) and hit enter. (You’ll also notice that control-c restarts runserver, since the default PDB behavior is to restart a script after it ends. Just hit control-c a few times to break PDB’s execution loop when you want to kill the server.)

You’ll notice that running under PDB doesn’t do anything by itself.

You’ll need to set a breakpoint to actually tell PDB where to stop execution. Inserting the following line of code causes PDB to break when it executes — which, in turn, triggers the debugging shell.

import pdb; pdb.set_trace()

In our example, we’d like to inspect where our exception is getting thrown, so we’ll throw it right before the offending line of code:

from django.http import HttpResponse

def default(request):
    # completely innocuous variables
    foo = 1
    bar = 0
    # well, this is where our error is, so let's trace it
    import pdb; pdb.set_trace()
    ni = foo/bar
    return HttpResponse("Foo says %d" % ni, mimetype="text/plain")

Congrats! Your browser is now waiting for your view to finish, your view is waiting (at the breakpoint) for PDB to finish, and PDB is waiting for you in the shell.

Doing things in PDB

At this point, the PDB shell acts like the normal python/ipython shell. You can look at variables right in the scope of the breakpoint.

thumbnail of debugging example

When working with a breakpoint, you can even screw around with local variables to try and find a fix, but note that only the last line you execute is remembered when you continue. You can still execute several statements by using the semicolon:

thumbnail of debugging example

Other neat things to try:

  • If you’re working with utility functions that can be called from various places, you can use the where command get a full trace of how Python got to that point in your script. This is pretty much exactly as advertised.
  • In addition, the Python globals() and locals() functions (which spit out all global or local variables, respectively) can be used within this (Pdb) prompt, which can be nifty if you’re debugging a GET/POST/COOKIES/SESSION issue.

I can’t say that I’ve been using PDB nearly as often as I’d like, but I have found it useful for the occasional mis-assigned variable or other super enigmatic bug.

Hope someone else finds it nearly as helpful as I have.