Sunday, 2 July 2017

Working with Native code, JNI and core Java from command line

Hello Guys!!! Hope You all are doing well.
Today I am going to discuss “How to work with Java, JNI and C/C++ libs from command line”.
Actually  when you compile and generate .so file for your native code (c/c++) via NDK and try to load this library in Java by calling System.loadLibrary() method, then you will encounter most famous exception UnsatisfiedLinkError
The same .so file (generated by NDK) work well in Android Application. 

This behavior shows that .so file generated by NDK is compatible for Android and normally it is not work well with Core Java code. That's why Today i am going to discuss step by step approach for working with Native code, JNI and core Java. 
Step 1 Create folder and necessary file
I am using Linux machine (Ubuntu) for my development, so I am going to create a jniAPP folder under u directory of my machine.  In that folder I will keep following file 
  • .java file (Java class)
  • .h file (JNI header file)
  • .c or .cpp file (Native code)
  • .class file(generated file for java class)
  • .so file (generated native shared library)
Step 2 Compile java class & generate JNI header file
Use javac command to compile java and javah to generate JNI header file. As for example 
/u/jniApp/$ javac HelloJNI.java
/u/jniApp/$ javah HelloJNI


Step 3 compile library
Here we compile native code (c/c++) and create one shared library (.so). This library is used by our Java Class. 
gcc  -I "$JAVA_HOME/include" -I "$JAVA_HOME/include/linux" hellojni.c -fPIC -shared -o libJniHello.so
you can provide full java path in place of $JAVA_HOME  like this  "/usr/lib/jvm/java-8-openjdk-amd64/include"
Brief detail of gcc option used above
  • -l  used to link other shared libraries for current compilation 
  •  -fPIC  is a gcc option for creating a  position-independent code shared library, so that the shared library can readily be loaded at (more or less) any address in memory.
  • -o is option to specify the output file name for the executable
for more detail use man gcc in your terminal. 
Step 4 Run Java class
Now everything is setup properly so you can run your compile java class by using java command.
java -Djava.library.path=/u/jniApp/ HelloJNI
Here we are setting our created shared library (.so) file path so that our java class load library smoothly and run properly. In our case we created our library in /u/jniApp/ folder.
If you don't want to give library(.so) path in java  command line like above, in that case you have to modify load library java code as below
  static {
    String libPath = null;
    try{
      String mPath = new File (".").getCanonicalPath()+"/";
       String langKey = "java.library.path" ;
       System.setProperty ( langKey, mPath ) ;

       libPath = System.getProperty("java.library.path");
       System.out.println("java.library.path=" + libPath);
    }catch(Exception e){
      e.printStackTrace();
    }
    System.load(libPath+"libjavahowto.so");
    //System.loadLibrary("javahowto");  
}  

HelloJNI.java

public class HelloJNI {
                static {
                                System.loadLibrary("JNIHello");
                }
                private native void sayHello();
                public static void main(String args[]) {
                                JNIHello jniHello = new JNIHello();
                                jniHello.sayHello();
                }
}
HelloJNI.h file genetated bt javah commmand
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JNIHello */

#ifndef _Included_JNIHello
#define _Included_JNIHello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNIHello
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNIHello_sayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
hellojni.c
#include <jni.h>
#include <stdio.h>
#include "JNIHello.h"
/*
 * Class:     JNIHello
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_JNIHello_sayHello
  (JNIEnv *env, jobject obj) {
        printf("Hello world!\n");
        return;
}
you can download whole project from above download link.

1 comment:

  1. hello,
    i just want to say that you have clearly mention the process very clearly and i also found it is very much easy to understand. keep sharing.

    android app development company in chennai

    ReplyDelete

Build a Custom Kernel Module for Android

Hi Guys!!!Hope you are doing well !!!. Today I will describe how you can write a custom kernel module(Hello world) for Android and load it a...