On the Android platform, code coverage is available using Ant+Emma. However, that only covers Java code, so if your app is composed of native code as well, you'll want another tool. Fortunately, Gcov is one such tool, and is reasonably easy to setup.

  1. First, compile your native code with gcov support:

    LOCAL_CFLAGS := -g -O0 --coverage
    LOCAL_LDLIBS := --coverage

    I got timestamp mismatch errors when targeting multiple ABI's, so I also recommend only selecting one ABI in Application.mk.

    (Optional) I'm not sure about Ant, but in Eclipse, you can define multiple native build configurations, which makes it much easier to switch back and forth between your coverage build and debug/release build. Simply add an argument to the build command, and branch on that argument in your Android.mk file.

  2. Designate the gcov output directory. This requires setting two environment variables. These variables need to be set from a native library that's loaded before your main library. We'll define a very small library composed of one source file.


    #include <stdlib.h>
    #include <jni.h>
    void Java_com_example_Example_initCoverage(JNIEnv *env, jclass class, jstring dataPath) {
    	const char *dataPathTemp = (*env)->GetStringUTFChars(env, dataPath, NULL);
    	/* GCOV_PREFIX_STRIP indicates how many
    	 * directory names are stripped off the
    	 * initial path. To avoid having to
    	 * calculate an exact number, and to
    	 * ensure that coverage data is saved
    	 * even if the source code is moved,
    	 * the variable is set to a high value
    	 * that will cause all initial directories
    	 * to be stripped off.
    	setenv("GCOV_PREFIX", dataPathTemp, 1);
    	setenv("GCOV_PREFIX_STRIP", "100", 1);
    	(*env)->ReleaseStringUTFChars(env, dataPath, dataPathTemp);

    The output path is passed in from Java, so you can change it without having to recompile your native code.


    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE     := Coverage
    LOCAL_SRC_FILES  := Coverage.c
    LOCAL_CFLAGS     := -std=c99

    Make sure you then load the coverage library:

    initCoverage(Environment.getExternalStorageDirectory().toURI().getPath() + "coverage_data");
  3. Due to the way Android terminates processes, you'll need to flush the coverage data manually at some point. This can be accomplished with a call to __gcov_flush().

  4. Run the app and you should start getting coverage data. The data will be in the form of .gcda files, which will appear in the dataPath directory.

Once you have coverage data, the next step is to generate a coverage report.