I'm working on a Android project which uses JNI. After 2 days of debugging, i still get an error: An unsatisfied link error:
Java.lang.UnsatisfiedLinkError: Native method not found: org.opencv.samples.facedetect.Hello.sayHello:()V
There are many people who have had this problem before, so i have read and tried many possible solutions but i still can't get it to work :(
My code:
Hello.java =
public class Hello {
public static native void sayHello();
static {
Log.i("JNI", "Loading hello");
System.loadLibrary("hello");
}
}
Hello_jni.cpp =
#include <jni.h>
#include <Hello_jni.h>
#include <stdio.h>
#include <android/log.h>
#define LOG_TAG "FaceDetection/DetectionBasedTracker"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
extern "C" JNIEXPORT void JNICALL Java_org_opencv_samples_facedetect_Hello_sayHello
(JNIEnv *env, jclass obj)
{
printf("Hello world!\n");
LOGD("werkt");
return;
}
Hello_jni.h =
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_opencv_samples_facedetect_Hello */
#ifndef _Included_org_opencv_samples_facedetect_Hello
#define _Included_org_opencv_samples_facedetect_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_opencv_samples_facedetect_Hello
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_opencv_samples_facedetect_Hello_sayHello
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
Android.mk = (first part is for other module from openCV. I'm using the facedetection example from openCV as template for my application)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#OPENCV_CAMERA_MODULES:=off
#OPENCV_INSTALL_MODULES:=off
#OPENCV_LIB_TYPE:=SHARED
include ../../sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := DetectionBasedTracker_jni.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := detection_based_tracker
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILE := org_opencv_samples_facedetect_Hello_jni.cpp
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
from my main activity, i call Hello.sayHello() (static). This triggers the error.
Tried:
- Removing/adding 'Extern "C"' to sayHello() in the cpp file.
- Change function from native to not-native
The library seems to load fine, this is the whole error:
I/JNI(21440): Hello.sayHello() called
I/JNI(21440): Loading hello
D/dalvikvm(21440): Trying to load lib /data/data/org.opencv.samples.facedetect/lib/libhello.so 0x4248c960
D/dalvikvm(21440): Added shared lib /data/data/org.opencv.samples.facedetect/lib/libhello.so 0x4248c960
D/dalvikvm(21440): No JNI_OnLoad found in /data/data/org.opencv.samples.facedetect/lib/libhello.so 0x4248c960, skipping init
W/dalvikvm(21440): No implementation found for native Lorg/opencv/samples/facedetect/Hello;.sayHello:()V
D/AndroidRuntime(21440): Shutting down VM
W/dalvikvm(21440): threadid=1: thread exiting with uncaught exception (group=0x41a4e2a0)
E/AndroidRuntime(21440): FATAL EXCEPTION: main
E/AndroidRuntime(21440): java.lang.UnsatisfiedLinkError: Native method not found: org.opencv.samples.facedetect.Hello.sayHello:()V
E/AndroidRuntime(21440): at org.opencv.samples.facedetect.Hello.sayHello(Native Method)
If anybody can help me out, you would be a hero! I just can't get it to work...
Thanks in advance :)
Jelmer
Your dalvik runtime tells you exactly what is wrong:
W/dalvikvm(21440): No implementation found for native Lorg/opencv/samples/facedetect/Hello;.sayHello:()V
D/AndroidRuntime(21440): Shutting down VM
Which means that you haven't properly implemented your native method and java runtime can't find it. Such error occurs in runtime only, the lib compiles ok, which gives me a hunch, that either method name (in .h and .cpp file) is wrong and doesn't correspond to the jni naming format, or that there is an error in .cpp file.
It's working now, the problem was the Android.mk file. Thanks Vorren for giving the solution ;)
The working make file is:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#OPENCV_CAMERA_MODULES:=off
#OPENCV_INSTALL_MODULES:=off
#OPENCV_LIB_TYPE:=SHARED
include ../../sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := DetectionBasedTracker_jni.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := detection_based_tracker
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := Hello_jni.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_LDLIBS += -llog
LOCAL_MODULE := hello
include $(BUILD_SHARED_LIBRARY)
there were two errors; syntax error LOCAL_SRC_FILE (missing the S), and i called 'my-dir' 2 times in the make file, which is prohibited (found this here: https://groups.google.com/forum/#!topic/android-ndk/Qmr_WQH-uKk)
Related
I am new in android programming so I tried to write just a simple program that can call jni folder native cpp file method from java.. Though I have tried to run OPENCV example and tried the same way to call but none of the m worked out not even OpenCV Tutorial 2 - Mixed Processing. It launch and crash in my emulator.
com_rukna_myfirstandroidimageapp_MainActivity.h
extern "C"{
* Class: com_rukna_myfirstandroidimageapp_MainActivity
* Method: getStringfromNative
* Signature: (I)Ljava/lang/String;
JNIEXPORT jstring JNICALL Java_com_rukna_myfirstandroidimageapp_MainActivity_getStringfromNative
(JNIEnv *, jobject, jint);
}
CPPCALL.cpp
#include <com_rukna_myfirstandroidimageapp_MainActivity.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
JNIEXPORT jstring JNICALL Java_com_rukna_myfirstandroidimageapp_MainActivity_getStringfromNative (JNIEnv *env , jobject obj, jint src)
{
return (env)->NewStringUTF("HELLO from JNI CPPCALL !!");
}
using command prompt I also used this at MYProject/bin/classpath/ javap -s -p MainActivity
----I got many with this---
public native java.lang.String getStringfromNative(int);
descriptor: (I)Ljava/lang/String;
but when I call this method from my MainActivity like below
package com.rukna.myfirstandroidimageapp;
import library
public class MainActivity extends Activity {
/* some declarations and other functions */
int a = 0;int b = 1;
String s = getStringfromNative( a); /*---> error when call for the cpp method*/
_field.setText(s);
_field.setSelection(_field.getText().toString().length());
public native String getStringfromNative(int a);
static {
if (!OpenCVLoader.initDebug()) {
// Handle initialization error
}
else{
System.loadLibrary("MyLib");}
}
}
I got the following error while running application:
java.lang.UnsatisfiedLinkError: Native method not found: com.rukna.myfirstandroidimageapp.MainActivity.getStringfromNative:(I)Ljava/lang/String;
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#OPENCV_CAMERA_MODULES:=off
#OPENCV_INSTALL_MODULES:=on
#OPENCV_LIB_TYPE:=SHARED
#OPENCV_LIB_TYPE:=STATIC
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=STATIC
include D:/OpenCV-2.4.11-android-sdk/sdk/native/jni/OpenCV.mk
#LOCAL_MODULE := CLAHE_test
LOCAL_MODULE := MyLib
LOCAL_SRC_FILES := CPPCALL.cpp
#LOCAL_SRC_FILES := CLAHE_test.cpp
#LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := x86
APP_PLATFORM := android-19
When I check in myproject.apk then I found under MyFirstAndroidImageApp.apk\lib\x86
libhydrogen.so
libimageutils.so
liblept.so
libMyLib.so
libnative_camera_r2.3.3.so
libnative_camera_r3.0.1.so
libnative_camera_r4.0.3.so
libnative_camera_r4.1.1.so
libnative_camera_r4.2.0.so
libnative_camera_r4.3.0.so
libnative_camera_r4.4.0.so
libopticalflow.so
libtess.so
Project Properties->C/C++ general-> Paths and Symbols-> Includes -> GNU C++
${NDKROOT}/platforms/android-9/arch-arm/usr/include
${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/include
${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include
${NDKROOT}/toolchains/arm-linux-androideabi-4.8/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.8/include
D:/OpenCV-2.4.11-android-sdk/sdk/native/jni/include
D:\android-ndk-r10d\platforms\android-19\arch-x86\usr\include
Help me as when I call same method without any argument then it runs normal I didn't get it why..... Do I need to give a constructor kind of thing if Yes then where and how?
Did you try to modify APP_ABI := armeabi-v7a in Application.mk. Also, if the cpp is successfully compiled, you should find so file in libs/armeabi-v7a
My native method cannot be found and I cannot solve it.
java code:
package org.cocos2dx.cppemptytest;
public class TestJNI {
static {
System.loadLibrary("cpp_empty_test");
}
public native String moveto();
}
native code:
#include "AppDelegate.h"
#include "platform/android/jni/JniHelper.h"
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include "cocos2d.h"
#define LOG_TAG "main"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
using namespace cocos2d;
AppDelegate *pAppDelegate;
void cocos_android_app_init (JNIEnv* env, jobject thiz) {
LOGD("cocos_android_app_init");
pAppDelegate = new AppDelegate();
}
extern "C" {
JNIEXPORT jstring JNICALL Java_org_cocos2dx_cppemptytest_TestJNI_moveto
( JNIEnv* env, jobject thiz){
return env->NewStringUTF("default");
}
}
in Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cpp_empty_test
LOCAL_MODULE_FILENAME := libcpp_empty_test
LOCAL_SRC_FILES := main.cpp \
../../Classes/AppDelegate.cpp \
../../Classes/HelloWorldScene.cpp
LOCAL_LDLIBS := -llog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
$(LOCAL_PATH)/../../../../extensions \
$(LOCAL_PATH)/../../../.. \
$(LOCAL_PATH)/../../../../cocos/editor-support
LOCAL_STATIC_LIBRARIES := cocos2dx_static
include $(BUILD_SHARED_LIBRARY)
$(call import-module,.)
Output gives unsatisfied link error, but my naming is correct I guess. Are there any other reasons why this error occurrs?
E/AndroidRuntime(30310): java.lang.UnsatisfiedLinkError:
Native method not found:
org.cocos2dx.cppemptytest.TestJNI.moveto:()Ljava/lang/String;
Try to change your in Android.mk to this:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libcpp_empty_test
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
I'm trying to create a cpp JNI file to allow me to do pretty much this tutorial in two calls so I can use this SURF Feature Detection in a Google Glass app. This error/problem that I'm having is not Google Glass related, but I believe Eclipse build environment related. I'm still relatively new to making projects in Eclipse, much less Android projects in Eclipse, so I'm pretty sure I'm missing something that's just ridiculously obvious and I need it pointed out to me. My main problem is that my final shared library file from the JNI is not being built, but the inbetween file is and my output from the build isn't indicating any explicit errors.
I know I should be able to build a JNI lib file that I can use in the Java in Android because JNI has been used in Android and I was also trying to follow the tutorials provided by the awesome person who made them here and here. These tutorials explain how to side-build the nonfree Opencv libs (the ones that contain SURF and SIFT) and put them in an Android project and how to utilize the libraries in JNI in the Android project.
My JNI code is the code from the very first link split into two functions, one that get called to setup the object keypoint setup that only needs to happen once and the other to get called on every frame in the Activity onCameraFrame() function.
#include <jni.h>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/nonfree/nonfree.hpp>
using namespace std;
using namespace cv;
extern "C" {
// SURF Vars
Mat mat_object;
int minHessian = 500;
SurfFeatureDetector detector( minHessian );
vector<KeyPoint> kp_object;
SurfDescriptorExtractor extractor;
Mat des_object;
FlannBasedMatcher matcher;
vector<Point2f> obj_corners(4);
JNIEXPORT void JNICALL Java_com_example_android_glass_surfobjrec_Init_Surf(JNIEnv*,jobject, jlong addr_mat_object);
JNIEXPORT void JNICALL Java_com_example_android_glass_surfobjrec_Proc_Surf(JNIEnv*,jobject, jlong addr_mat_scene);
JNIEXPORT void JNICALL Java_com_example_android_glass_surfobjrec_Init_Surf(JNIEnv*,jobject, jlong addr_mat_object) {
Mat& mat_obj = *(Mat*) addr_mat_object;
mat_object = mat_obj;
//Detect the keypoints using SURF Detector
detector.detect( mat_object, kp_object );
// Calculate descriptors (feature vectors)
extractor.compute(mat_object, kp_object, des_object);
//Get the corners from the object
obj_corners[0] = cvPoint(0,0);
obj_corners[1] = cvPoint( mat_object.cols, 0 );
obj_corners[2] = cvPoint( mat_object.cols, mat_object.rows );
obj_corners[3] = cvPoint( 0, mat_object.rows );
}
JNIEXPORT void JNICALL Java_com_example_android_glass_surfobjrec_Proc_Surf(JNIEnv*,jobject, jlong addr_mat_scene) {
// Do all the stuff in the while loop in the oneDrive example
// EXCEPT, draw the keypoints using DrawKeypoints, don't use DrawMatches
Mat& mat_outputImg = *(Mat*) addr_mat_scene;
Mat mat_scene;
Mat des_scene;
vector<KeyPoint> kp_scene;
vector<vector<DMatch> > matches;
//vector<DMatch> matches;
vector<DMatch> good_matches;
vector<Point2f> obj;
vector<Point2f> scene;
vector<Point2f> scene_corners(4);
double max_dist = 0;
double min_dist = 100.0;
Mat H;
cvtColor(mat_outputImg, mat_scene, CV_BGR2GRAY);
// Detect and calculate keypoints on scene image
detector.detect(mat_scene, kp_scene);
extractor.compute(mat_scene, kp_scene, des_scene);
matcher.knnMatch(des_object, des_scene, matches, 2);
for(int k = 0; k < min(des_scene.rows-1,(int) matches.size()); k++) { //THIS LOOP IS SENSITIVE TO SEGFAULTS
if((matches[k][0].distance < 0.6*(matches[k][7].distance)) && ((int) matches[k].size()<=2 && (int) matches[k].size()>0)) {
good_matches.push_back(matches[k][0]);
}
}
}
}
The only error that I am getting is matches[k][0].distance is saying "Field distance could not be resolved." I'm getting the same error with matches[k].size() and good_matches.push_back(matches[k][0]) says that matches is an invalid argument, but I've compiled all of this same code and run it fine from a regular CPP project in Eclipse using the code on the onedrive link. And these errors do not appear in the build messages.
And for the ndk-build I've pasted the Application.mk and Android.mk files below.
My Application.mk file is as below:
#APP_ABI := armeabi
APP_ABI += armeabi-v7a # you can do either armeabi or armeabi-v7a, steps are the same.
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_PLATFORM := android-15
My Android.mk file is as below:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nonfree_prebuilt
LOCAL_SRC_FILES := libnonfree.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_java_prebuilt
LOCAL_SRC_FILES := libopencv_java.so
include $(PREBUILT_SHARED_LIBRARY)
LOCAL_C_INCLUDES:= /Users/samanthahuston/Development/OpenCV-2.4.8-android-sdk/sdk/native/jni/include
LOCAL_MODULE := nonfree_jni
LOCAL_CFLAGS := -Werror -O3 -ffast-math
LOCAL_LDLIBS += -llog
LOCAL_SHARED_LIBRARIES := nonfree_prebuilt opencv_java_prebuilt
LOCAL_SRC_FILES := nonfree_jni.cpp
include $(BUILD_SHARED_LIBRARY)
Any help is greatly appreciated.
This is the .cpp file and the code is
JNIEXPORT jint JNICALL Java_com_example_compute_MainActivity_AddNumbers(JNIEnv *env, jobject obj, jint v1, jint v2)
{
_android_log_print(ANDROID_LOG_VERBOSE, "VaxVoIP", "The value of 1 + 1 is %d", 1+1);
return -1;
//return (v1 + v2);
}
This is the Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
Here we give our module name and source file(s)
LOCAL_MODULE := add
LOCAL_LDLIBS := -llog
LOCAL_SRC_FILES := add.cpp\
add.h\
include $(BUILD_SHARED_LIBRARY)
And the other error that I'm trying to solve is while making the .so file
_android_log_print(ANDROID_LOG_VERBOSE, "VaxVoIP", "The value of 1 + 1 is %d", 1+1);
was not declared in this scope
John is right about it. I just got it resolved by including #include <android/log.h>and also add LOCAL_LDLIBS += -llog -ldl -landroid in android.mk file
If that's the whole .cpp file, you're going to need to #include something that defines _android_log_print.
Don't forget to include
#include <android/log.h>
It's probably because of the buffer. Put \n at the end of the string.
__android_log_print(ANDROID_LOG_VERBOSE, "VaxVoIP", "The value of 1 + 1 is %d\n", 1+1);
Also don't forget to put double underscores rather than one single underscore.
I got this "java.lang.UnsatisfiedLinkError: Native method not found:" when I was trying to access jni natvie methods
11-20 10:52:29.246 E/AndroidRuntime( 2742): at com.example.nativeegl.MyRenderer.nativeGetHelloString(Native Method)
11-20 10:52:29.246 E/AndroidRuntime( 2742): at com.example.nativeegl.MyRenderer.onDrawFrame(MyRenderer.java:36)
11-20 10:52:29.246 E/AndroidRuntime( 2742): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
11-20 10:52:29.246 E/AndroidRuntime( 2742): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
Then I found out that if I remove the .h file and only keep the .cpp native file. The error will not occur.
This is my header file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <string.h>
/* Header for class com_example_nativeegl_MyRenderer */
#ifndef _Included_com_example_nativeegl_MyRenderer
#define _Included_com_example_nativeegl_MyRenderer
extern "C" {
/*
* Class: com_example_nativeegl_MyRenderer
* Method: nativeGetHelloString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_nativeegl_MyRenderer_nativeGetHelloString
(JNIEnv *, jobject);
}
#endif
And this is my cpp file
#include "com_example_nativeegl_MyRenderer.h"
#ifndef _Included_com_example_nativeegl_MyRenderer
#define _Included_com_example_nativeegl_MyRenderer
extern "C" {
/*
* Class: com_example_nativeegl_MyRenderer
* Method: nativeGetHelloString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_nativeegl_MyRenderer_nativeGetHelloString
(JNIEnv *env, jobject obj) {
return env->NewStringUTF((char*)" This is calling from JNI suckers!");
}
}
#endif
My Android.mk file is as follow:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -Wall
LOCAL_MODULE := myegl_jni
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPP_EXTENSION := .cpp
LOCAL_SRC_FILES := com_example_nativeegl_MyRenderer.cpp
include $(BUILD_SHARED_LIBRARY)
I found out that the error will not occur if I do remove the header file and only keeps the cpp file. But I have no idea the reason for it.
I suggest you remove the
#ifndef _Included_com_example_nativeegl_MyRenderer
#define _Included_com_example_nativeegl_MyRenderer
and
#endif
from the cpp file.
They get defined when you include the header, and therefore the definition of the actual function doesn't happen, so it won't link.
When you remove the header, they don't get defined, so the function is defined.
The include guards are for headers: be careful what you copy and paste!