Jul 31

Recording and replaying events with Android

For benchmarking, I wanted to be able to replay an event sequence. For example, I wanted a test to open the browser, browse to a Web page, scroll around on the page, and then return to the application launcher. Android offers lots of ways to do this, but because I like systems programming (and haven't touched Java in years) I picked quite a low-level one: capturing and injecting Linux input device events.

Android uses the Linux input system in the standard way, which means events from the keyboard, touchpad, and so forth are available at /dev/input/eventX, where X is some number starting from 0. It is quite straightforward to record these events to a file -- each event arrives as a struct input_event, which is (on Android) a 128-byte structure containing a timestamp, an event type, and a payload.

Recording events is easy. What about playing them back? I started dreaming up something that would rename the /dev/input/eventX files and create PTYs for each, but then I discovered that there is a far easier way: thanks to a feature added early in the 2.6 kernel series, you can just inject events by writing struct input_events back to the relevant files!

This ease of debugging really is an advantage of using a fully-fledged kernel rather than a custom or cut-down operating system.

Anyway, the end result is two programs, "record" and "replay". The "record" program reads events from /dev/input/eventX and writes them to a file named /sdcard/events. The "replay" program reads this file and replays the events in real time.

The programs read from and write to /dev/input/eventX, even though /dev/uinput should in theory work -- it doesn't appear to on the ADP1.

Both programs are quite "proof of concept", and probably only work on the HTC Dream for now, but they are very simple and easy to adapt.

Update 30/Dec/2009: Aaron made some changes to "replay" which should give much smoother results on OpenMoko phones.

injectevents.tar.gz (6k)

Update 1/Jul/2012: there have been a few questions about this recently. Nice to see it's still being used! Here is some extra information.

To build the code:

Install the Android NDK and set it up so that ndk-build is in your path.

Then create a directory called jni/ and put into it.

Then move the src/ directory inside the jni/ directory.

Then you can run ndk-build to build the binaries.

To install:

You need root access to your phone, then run

adb shell

to get a shell

Put record and replay somewhere you can execute them. /data/local/tmp is a good place -- you can use adb push for this, eg

adb push record /data/local/tmp/record

You might then need to "chmod 555 /data/local/tmp/record" to make it executable.

Some people have emailed me asking for help on running the code from within a Java test framework. I can't help you there I'm sorry. You would run replay, and then you would have to check the expected result somehow. Robotium for example can tell you about the state of the GUI, so if you wanted to check that, e.g., a particular GUI change had occurred, you could run replay and then investigate the GUI with Robotium.

When I used the replay code, it was for benchmarking, not testing. So I wrote my own Android apps to call "replay" and then check the state of the GUI directly.