No implementation found for native / UnsatisfiedLinkError makes me crazy

1.1k views Asked by At

I'm having problem with this JNI thing...

I'm dealing with an FPGA and an Android device, and to make them communicate I use JNI library. There is 7-segment Controller in FPGA and Android-to-FPGA driver also.

But I found myself stuck in this implementation hell... and yes, I searched and searched. But most answer was "Look for the naming convention" or "Make sure you are referring .so file". I think I'm not in that case...

First here is my .java android code :

package com.hanback.segment;


import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class SegmentActivity extends Activity {

private int CountNumber;
private int flag = 0;
private boolean stop = false;

static{ System.loadLibrary("7segment"); } 

public native int SegmentControl(int data);
public native int SegmentStateControl(int data);

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_segment);
    CountNumber = 0;    

    SegmentControl(0);
    final Button Start = (Button) findViewById(R.id.butStart);
    final Button Set = (Button) findViewById(R.id.butSet);
    final Button Stop = (Button) findViewById(R.id.butStop);
    final EditText Ctno = (EditText) findViewById(R.id.etCountNo);  


    Start.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {

            if (Ctno.getText().toString().getBytes().length <= 0) {
                Toast.makeText(getApplicationContext(), R.string.error_ctrnotset,
                        Toast.LENGTH_SHORT).show();
                return;
            }           
            else if (CountNumber <= 0 || CountNumber >= 1000000){
                Toast.makeText(getApplicationContext(), R.string.error_ctrvalerr,
                        Toast.LENGTH_SHORT).show();
                return;
            }   
            SegmentStateControl(1);
        }
    });

    Set.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {

            if (Ctno.getText().toString().getBytes().length <= 0) {
                Toast.makeText(getApplicationContext(), R.string.error_ctrnotset,
                        Toast.LENGTH_SHORT).show();
                return;
            }
            else 
                CountNumber = Integer.parseInt(Ctno.getText().toString());

            if (CountNumber <= 0 || CountNumber >= 1000000){
                Toast.makeText(getApplicationContext(), R.string.error_ctrvalerr,
                        Toast.LENGTH_SHORT).show();
                return;
            }

            CountNumber = Integer.parseInt(Ctno.getText().toString());

            SegmentStateControl(0);             
            SegmentControl(CountNumber);
        }
    });

    Stop.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {

            SegmentStateControl(0);

        }
    });     

}
}

Then c code : (header skipped)

extern "C"{
jint Java_com_hanback_segment_SegmentActivity_SegmentControl(JNIEnv*  env, jobject thiz, jint data) {
    int dev, ret;
    dev = open("/dev/segment",O_RDWR | O_SYNC);

    if(dev != -1) {
        ret = write(dev, &data, 4); // write is pre-defined FPGA driver function
        close(dev);
    } else {
        __android_log_print(ANDROID_LOG_ERROR, "SegmentActivity", "Device Open ERROR!\n");
        exit(1);
    }

    return 0;
}

jint Java_com_hanback_segment_SegmentActivity_SegmentStateControl(JNIEnv* env, jobject thiz, jint data) {
    int dev, ret;

    dev = open("/dev/segment". O_RDWR | O_SYNC);

    if(dev != 1) {
        ret = ioctl(dev, data, NULL, NULL); // ioctl is pre-defined FPGA driver function
        close(dev);
    } else {
        __android_log_print_(ANDROID_LOG_ERROR, "SegmentActivitiy", "Device Open ERROR!\n");
        exit(1);
    }
}
}

And Android.mk and Application.mk has no error...

Finally Logcat error message :

01-01 15:07:02.429: D/dalvikvm(1318): Trying to load lib /data/data/com.hanback.segment/lib/lib7segment.so 0x40514760
01-01 15:07:02.429: D/dalvikvm(1318): Added shared lib /data/data/com.hanback.segment/lib/lib7segment.so 0x40514760
01-01 15:07:02.429: D/dalvikvm(1318): No JNI_OnLoad found in /data/data/com.hanback.segment/lib/lib7segment.so 0x40514760, skipping init
01-01 15:07:02.449: W/dalvikvm(1318): No implementation found for native Lcom/hanback/segment/SegmentActivity;.SegmentControl (I)I
01-01 15:07:02.457: D/AndroidRuntime(1318): Shutting down VM
01-01 15:07:02.457: W/dalvikvm(1318): threadid=1: thread exiting with uncaught exception (group=0x40015560)
01-01 15:07:02.460: E/AndroidRuntime(1318): FATAL EXCEPTION: main
01-01 15:07:02.460: E/AndroidRuntime(1318): java.lang.UnsatisfiedLinkError: SegmentControl
01-01 15:07:02.460: E/AndroidRuntime(1318):     at com.hanback.segment.SegmentActivity.SegmentControl(Native Method)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at com.hanback.segment.SegmentActivity.onCreate(SegmentActivity.java:40)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.os.Looper.loop(Looper.java:130)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at android.app.ActivityThread.main(ActivityThread.java:3683)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at java.lang.reflect.Method.invokeNative(Native Method)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at java.lang.reflect.Method.invoke(Method.java:507)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-01 15:07:02.460: E/AndroidRuntime(1318):     at dalvik.system.NativeStart.main(Native Method)

I'm a beginner for JNI and this has blown my 1.5 days... Please help me T_T

1

There are 1 answers

0
samgak On

Declare your functions like this:

JNIEXPORT jint JNICALL Java_com_hanback_segment_SegmentActivity_SegmentControl(JNIEnv*  env, jobject thiz, jint data) {

JNIEXPORT jint JNICALL Java_com_hanback_segment_SegmentActivity_SegmentStateControl(JNIEnv* env, jobject thiz, jint data) {

The JNIEXPORT macro is used to make your functions visible in the dynamic table of the .so file, so that Java can link them at run time. JNICALL is used to declare the calling convention.