IT

JNI Tutorial

Java JNI Tutorial – getting the pid of the current running java process
This tutorial tries to show how to write Java JNI code, and how to generate the corresponding shared library for both Windows and Linux.

It is based on the http://java.sun.com/docs/books/tutorial/native1.1/stepbystep/index.html.

If you’re new to JNI, please read the Sun’s tutorial first as there are lots of things explained better there. I consider this tutorial only as an addon to that one, completed with minor stuff I have learned while working with Java during the past years.

You can download a zip file containing all the example files here. Please notice that there are some adjustments you have to make so you can make it compilable on your system, changes mostly related to the paths. Also, on Windows – I have used the lcc-win32 free compiler to generate the .dll. With some code adjustments, you can generate the .dll using other compilers, as the C implementation for this example is pretty simple.

Write java code

This is the first step, to write the java code that will call the native methods. Save the contents below inside a file called GetPid.java.

class GetPid {
    /**
     * getPid() is the method which will return the pid. As it’s
     * declared in an external library (either a .dll or a .so)
     * we must let java know of this by using the "native" keyword
     */

    public native int getPid();

    /**
     * Ask java to load the library that includes the native method
     * -> Windows – it will look for a file called getpid.dll
     * -> Linux – it will look for a file called libgetpid.so
     */
    static {
        System.loadLibrary("getpid");
    }

    public static void main(String args[]) {
        /**
         * Invoque the native method. Uses a new instance of this 
         * class so we can have a static variable inside the static main. 
         * "this" is not static so we cannot use it.
         */
        System.out.println("Current pid: "
                + (new GetPid()).getPid());
    }
} 

* If you already have a code that needs the getPid() functionality, edit the .java class that needs it by adding the “native” declaration and the static call.

* Make sure you choose the proper class which holds the static method, as well as the proper method name, as if you move the method to another class you will have to regenerate the header file, update the C code, and recompile the external library (check below).

Compile the code

javac GetPid.java

* javac executable must be in the PATH.

Generate the .h file

The next step is to generate a header file (.h) from the class file just compiled. Issue this command:

Windows

javah -d C -jni GetPid

Linux

javah -d CLinux -jni GetPid

* javah executable must be in the PATH

* -d C tells javah to generate the header file inside the C directory found in the current path. Without the -d parameter, the header is generated under the same directory as GetPid.class, but I’ve chosen the C (or CLinux for Linux) directory because it makes the code more organized.

The most important stuff in the generated header file is the native method call signature:

JNIEXPORT jint JNICALL Java_GetPid_getPid (JNIEnv *, jobject);

* It is computed like this:

Java + “_” + ClassName (including the package name if it exists) + “_” + native method name from the class (the name you chosen at 1) ). So if you change your mind and move the native method to another class, or change the method’s name, you will have to regenerate this header file and the additional C code implementing the native method.

* One other thing, the first parameter of the method is an interface pointer which you might use to read parameters send from java when invoking the native call (in our case there are none), or you can use it to propagate exceptions from the native code back to the jvm. The second parameter is a pointer to the current object, kinda of “this” in java.

Write the C code

Writing the implementation is not hard. Mainly, you have to write a .c file that is going to include the header above and implement the Java_GetPid_getPid method. This will simply return the value from the getpid().

However, the C file has to include the jni.h header provided with the JDK; the file has to also be compilable to a .dll file on Windows, and to a .so (shared object) file under Linux.

Full .c implementations for both OSes are found in the zip file. Please check inside the “C” directory for Windows implementation, and inside “CLinux” for linux implementation.

On Windows, using lcc-win32, you will also have to implement another JNI method, like this:

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
    return JNI_VERSION_1_2; 
};

If you don’t define the method, or if you fail to return the JNI_VERSION_1_2, you will get an exception like this, after running the java code:

D:\GetPid>java GetPid
Exception in thread "main" java.lang.UnsatisfiedLinkError: unsupported JNI version 0x00000000
required by D:\GetPid\C\getpid.dll
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1560)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1485)
at java.lang.Runtime.loadLibrary0(Runtime.java:788)
at java.lang.System.loadLibrary(System.java:834)
at GetPid.(GetPid.java:17)

* Beside JNI_VERSION_1_2, there is another possible return value: JNI_VERSION_1_4.

Generate the library

The next step is to compile the .c file into a shared library.

Windows

Assuming that lcc-win32 was installed in it’s default location (c:\lcc) all you need to do is to issue the command below while you are in the “C” directory. Please use the win32.mak file I have provided in the zip file, it will make your life easier 🙂

c:\lcc\bin\make -f win32.mak

Linux

Go into the “CLinux” directory, and issue these commands (the linux.mak file is a Makefile found in the zip file too).

make -f linux.mak

Run the code

On Windows, JVM looks for the requested shared library inside the directories in the PATH. So you have to put the .dll where JVM can find it OR update the path so it includes the directory where the .dll is.

The output is something like this:

D:\GetPid>java GetPid
Current pid: 2112

On Linux, JVM looks for the requested shared library inside the java.library.path.
Please check the run.sh file in the zip archive for example of how to specify this. The output is something like this:

[root@glimpses GetPid]# ./run.sh
Current pid: 2839

Having questions

If you have questions, appreciations, or constructive criticism 🙂 please use the forum! I just put it online, so is rather empty right now; but I’ll answer any question you have.

Licence and Warranty

The code is freeware, you can do whatever you want with it 🙂 however I provide no warranty for it. It should give you an idea on how to write a shared library which you can use on Windows or Linux. With some adjustments, you can have this code running on other *NIXes too.

Leave a Reply