A Race Detector for Android

Try Online


Application analysis overview

Select Android application APK file for analysis


Note: To perform a more thorough analysis of your application, please download the tool.

Android Concurrency

Android applications are based on an event-based programming model where event handlers are executed in response to messages arriving from various sources, including the framework, the network, the sensors, and the user interface. An illustrative example of concurrency issues that can arise when two event handlers can be executed in arbitrary order is shown below.

Sample Application

Application launch

An example of event handler invoked by the framework is onResume called when the user starts interacting with the activity. This is a common place to register for a periodic updates from sensors such as GPS.

@Override
protected void onResume() {
  super.onResume();
  locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, mListener);
  mDbHelper = new SQLiteOpenHelper(this, DB_NAME, DB_VERSION);
}

Application running

After the application registers for location updates, the system periodically invokes provided callback mListener with the device's geographical location that is shown on the screen and saved into the database.

LocationListener mListener = new LocationListener() {
  @Override
  public void onLocationChanged(Location location) {
    //show location on map
    mDbHelper.getWritableDatabase().insert(loc);
  }
};
Application close

Eventually, currently shown screen with the map goes into the background and framework invokes onPause event handler. Here the developer removes location updates and closes the database.

@Override
protected void onPause() {
  super.onPause();
  locationManager.removeUpdates(mListener);
  mDbHelper.close();
}

Concurrency Bug

Intuitively, the onLocationChanged callback should be executed only after executing onResume and before executing onPause, yet this is not always the case. It is possible that the framework executes onLocationChanged callback even after the developer explicitly removed location updates in onPause callback.

@Override
void onResume() {
  ...
}


@Override
void onPause() {
  ...
  mDbHelper.close();
}

@Override
void onLocationChanged(Location loc) {
  ...
  //error: inserting into closed database
  mDbHelper.getWritableDatabase().insert(loc);
}

In the execution trace where onLocationChanged is executed after onPause, the application behaviour depends on which class was used to access the database.

Class accessing the database Application Behaviour
SQLiteDatabase The application crashes with the following exception:
E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: java.lang.IllegalStateException: 
  attempt to re-open an already-closed object: SQLiteDatabase  
SQLiteOpenHelper The database instance is reopened and will be left consuming resources although the user stops interacting with the application.

How it Works?

We present an online tool for detecting harmful data races in event-driven Android applications. The overview of analysis steps is provided below.

Android Application

The input to the tool is a standard Android application apk file that is installed on a instrumented emulator. To automatically explore the application we use Android UI/Application Exerciser Monkey thet generates a pseudo-random streams of user events such as clicks, touches and gestures.

Instrumented System Image

Android version 4.4 is instrumented to collect following information during the runtime.

Memory Locations


Reads and writes to a Java object fields are the basic memory locations on which concurrent operation can race. In order to not miss harmfull data races we instrument both user and framework memory locations.
Original Code Instrumentation Log
void onLocationChanged(Location location) {
    double lat = location.getLatitude();
    double lon = location.getLongtitude();
    this.mLastLocation = new Location(lat, lon);
}
void onLocationChanged(Location location) {
  READ 32647 android.location.Location;.mLatitude 
  READ 32647 android.location.Location;.mLongitude 
  WRITE 17743 example.gps.Main;.mLastLocation 
}

Operations Capturing Event-Driven Behavior of Android Applications


In Android various APIs are used to generate and introduce ordering between events. For example the Handler class is a standard mechanism to send and process Message and Runnable objects on the application MainThread. We translate these APIs into a small set of operations that cleanly capture the essential features of event-driven Android applications.

Happens-before Graph Construction

After exploring the application we obtain an execution trace consisting of dispatched events and operations that capture the essential features of event-driven Android applications. At this step we introduce happens-before edges between individual operations and events in the execution trace. For example when analyzing sample application events executed on the application MainThread include onResume, onPause and onLocationChanged. We introduce following happens-before ordering.

onResume is ordered before both onPause and onLocationChanged
onResume() {
  ...
}
onPause() {
  ...
}
onResume() {
  ...
}
onLocationChanged() {
  ...
}
onPause and onLocationChanged are not ordered
onPause() {
  ...
}
onLocationChanged() {
  ...
}

Race Detection

Given the happens-before graph we use dynamic race detector to find data races. Intuitivelly, the race detector goes through all acceses of the same memory location and finds all pairs such that, one of the accesses is a write and accesses were performed in an unordered events.

Race Explorer

Finally we process all the reported data races and report them to the user in an interactive race explorer tool. An example report that reveals the harmful data race in sample application is shown below.

The races are shown in a two level hierarchical grouping. The first level shows the event source (either IPC, user input, application thread or a display subsystem) and the second level groups races observed in a similar method call context.
Event source 1 Event source 2
IPC async, interface(android.location.ILocationListener), code(onLocationChanged) IPC async, interface(android.app.IApplicationThread), code(SCHEDULE_STOP_ACTIVITY)
Call stack context 1 Call stack context 2
Landroid/database/sqlite/SQLiteDatabase;
.insert(String;String;ContentValues;)
Landroid/database/sqlite/SQLiteClosable;
.close()
UPDATE-UPDATE - 63568 Landroid/database/sqlite/SQLiteConnectionPool;.mAvailablePrimaryConnection
READ-UPDATE - 63568 Landroid/database/sqlite/SQLiteConnectionPool;.mIsOpen
READ-UPDATE - 63576 Landroid/database/sqlite/SQLiteConnection;.mConnectionPtr
READ-UPDATE - 63576 Landroid/database/sqlite/SQLiteConnection;.mPreparedStatementPool
...

Analyzed Applications

We evaluated EventRacer for Android on a number of applications. The applications were installed on a Nexus 10 device with a custom ROM with EventRacer instrumentation. The number of uncovered data races found in each application is shown in the following table:

ApplicationNumber of Races
Application iconOI File Manager2251
Application iconFeedEx News2004
Application iconNPR News455
Application iconA Time Tracker685
Application iconAard Dictionary1201
Application iconAnyMemo925

A key challenge with race detectors is that in general, they may report too many races, beyond what is reasonable to expect of a developer to inspect manually. To address this issue, we employ several techniques that classify races into small number of groups which are presented to the developer. We have manualy inspected each of the reported groups to assess their harm from the source code as shown in following table:

High Priority Groups
ApplicationHarmfulCommutativeSynchronizationHarmlessTotal
Application iconOI File Manager31004
Application iconFeedEx News11204
Application iconNPR News10124
Application iconA Time Tracker00000
Application iconAard Dictionary20136
Application iconAnyMemo21003
Normal Priority Groups
ApplicationHarmfulCommutativeSynchronizationHarmlessTotal
Application iconOI File Manager60039
Application iconFeedEx News1100112
Application iconNPR News12227
Application iconA Time Tracker10056
Application iconAard Dictionary01157
Application iconAnyMemo343313

Below we provide analysis results. Clicking on any application will open the list of races from our exploration in the EventRacer user interface where Debug information is provided. Parsing the entire the debug information may require knowledge of the apps and/or the android framework.

Application icon OI File Manager Google Playstore F-Droid

Application icon FeedEx Google Playstore F-Droid

Application icon NPR News Google Playstore F-Droid

Application icon ATimeTracker Google Playstore F-Droid

Application icon Aard Dict Google Playstore F-Droid

Application icon AnyMemo Google Playstore F-Droid

Download

EventRacer for Android consists of two parts - an instrumented Android version 4.4 that dumps a logfile and a race analyzer that analyses the output.

As compiled binary

64-bit binary for Ubuntu (Tested for 12.04 and 13.04) - Download EventRacerAndroid.tar.gz [322MB]

Team

Pavol Bielik

Pavol Bielik

Student
Software Reliability Lab, ETH Zurich

Veselin Raychev

Veselin Raychev

PhD Student
Software Reliability Lab, ETH Zurich
Website

Martin Vechev

Prof. Martin Vechev

Assistant Professor
Software Reliability Lab, ETH Zurich
Website

Contact

Have a question or comment? We'd love to hear feedback on your experience with EventRacer. You can reach us at
android@eventracer.org