Here's Android application utilizing JNI and NDK which

is now extended to display native Linux platform interrupts.

1. inside project's dir we create jni folder with our native code

and Android.mk file with instructions how to build it:

geo@fermat:~/workspace/geondk$ l
total 32
-rw-r----- 1 geo geo  678 2010-06-27 19:24 AndroidManifest.xml
drwxr-xr-x 4 geo geo 4096 2010-07-25 19:21 bin
-rw-r----- 1 geo geo  364 2010-06-27 15:46 default.properties
drwxr-xr-x 3 geo geo 4096 2010-06-27 19:32 gen
drwxr-xr-x 2 geo geo 4096 2010-06-27 19:23 jni
drwxr-xr-x 3 geo geo 4096 2010-06-27 15:47 libs
drwxr-xr-x 3 geo geo 4096 2010-06-27 15:46 res
drwxr-xr-x 3 geo geo 4096 2010-06-27 15:46 src
geo@fermat:~/workspace/geondk$ l jni
total 8
-rw-r----- 1 geo geo 141 2010-06-27 19:22 Android.mk
-rw-r----- 1 geo geo 414 2010-07-24 14:12 hijni.c
geo@fermat:~/workspace/geondk$ cat jni/Android.mk
#

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hijni
LOCAL_SRC_FILES := hijni.c

include $(BUILD_SHARED_LIBRARY)
geo@fermat:~/workspace/geondk$

2. when native code is ready we build it with new command ndk-build

available in android-ndk installation directory:

geo@fermat:~/workspace/geondk$ $ANDROIDNDK/ndk-build
Gdbserver      : [arm-eabi-4.4.0] /home/geo/workspace/geondk/libs/armeabi/gdbserver
Gdbsetup       : /home/geo/workspace/geondk/libs/armeabi/gdb.setup
Gdbsetup       : + source directory /home/geo/workspace/geondk/jni
Compile thumb  : hijni <= /home/geo/workspace/geondk/jni/hijni.c
SharedLibrary  : libhijni.so
Install        : libhijni.so => /home/geo/workspace/geondk/libs/armeabi
geo@fermat:~/workspace/geondk$

as you can see the result is dynamically linked library (libhijni.so)

which is automatically installed in project's libs directory (libs/armeabi).

3. this library contains code of two native Linux functions,

one of which returns static native string:

/* This is a trivial JNI example where we use a native method
 * to return a new VM String.
 */
jstring Java_se_matveev_ndk_App_stringFromJNI( JNIEnv* env, jobject thiz)
{
  return (*env)->NewStringUTF(env, "Hi George, welcome to JNI :-)");
}

here's how string looks in Android 2.2 emulator:

4. another function implemented in the library contains native code

which opens Linux platform /proc/interrupts file, reads its contents

into the buffer and returns it to the Java application layer:

/* This is JNI example where we use a native method
 * to return a new VM String which contains native
 * ARM platform interrupts. 
 */

jstring Java_se_matveev_ndk_App_getNativeEnv( JNIEnv* env, jobject thiz)
{
  FILE* fp;
  char buff[3200];
  
  fp = fopen("/proc/interrupts", "r");
  int nbr = fread(buff, 1, sizeof(buff), fp);
  fclose(fp);
  
  if(nbr > 0)
    return (*env)->NewStringUTF(env, buff);
  else
    return (*env)->NewStringUTF(env, "ERROR reading /proc/interrupts");
}

here's how Linux interrupts look in Android 2.2 emulator:

as you see timer, tty, eth0 and framebuffer (goldfish_fb) are quite busy.

5. All one has to do to achieve this is code a standard Android application

which loads shared library statically (that is on app start-up) and then

calls a native method (e.g. getNativeEnv() ) implemented in the library:


    final TextView tv = new TextView(this);
    tv.setBackgroundColor(Color.CYAN);
    tv.setTextColor(Color.DKGRAY);
    tv.setTextSize(23);
    tv.setHorizontalScrollBarEnabled(true);
    tv.setVerticalScrollBarEnabled(true);
        
    tv.setOnTouchListener(new OnTouchListener()
    {
      public boolean onTouch(View v, MotionEvent e)
      {
       	if (e.getAction() == (e.ACTION_MOVE))
        {
          tv.setText( getNativeEnv() );
        }
       	return true;
      }
    });

    tv.setText( getNativeEnv() );
    .
    .
    .

    /* native method that is implemented in the
     * 'hijni' native library
     * returns static native string
     */
    
    public native String  getNativeEnv();

    /* The 'hijni' library contains native Linux code
     * which is packed with this application and loaded
     * on application startup. It's been unpacked into
     * /data/data/se.matveev.ndk/App/lib/libhijni.so at
     * installation time by the package manager.
     */
    static { System.loadLibrary("hijni"); }

6. To make this text view look nice on all devices I made it scrollable and put

it inside another container (HorizontalScrollView) before setting content view.

Event listener makes this application update actual IRQ counts as you touch

and move the screen with your finger or mouse (on emulator).

Here's what application looks like on real droid device (HTC Wildfire S):

As you see there are several times more interrupts on real device

so one simply has to use scrollable container to display them all:

There are certainly much more development/hacking opportunities in Android NDK than displaying native IRQs :-)

(native debugging, cpufeatures library with NEON optimized code, support for ARMv7 machine code, etc)

Possibly we are going to explore some of them in our next demo project quite soon!

Application package (geondk.apk) can be downloaded from here.