I am trying to call a constructor from my JNI Android code; but somehow it fails with the following exception..
I am sure I am missing something really small ; but I am not able to figure out ... can anyone please point out ?
02-14 16:56:56.689: W/dalvikvm(397): JNI WARNING: JNI method called with exception raised
02-14 16:56:56.710: W/dalvikvm(397): in Lpv/ndk/Employee;.createWithAge (I)Lpv/ndk/Employee; (GetMethodID)
02-14 16:56:56.710: W/dalvikvm(397): Pending exception is:
02-14 16:56:56.710: I/dalvikvm(397): Ljava/lang/NoClassDefFoundError;: pv.ndk.Employee;
02-14 16:56:56.723: I/dalvikvm(397): at pv.ndk.Employee.createWithAge(Native Method)
02-14 16:56:56.740: I/dalvikvm(397): Caused by:
02-14 16:56:56.740: I/dalvikvm(397): Ljava/lang/ClassNotFoundException;: pv.ndk.Employee; in loader dalvik.system.PathClassLoader[/data/app/pv.ndk-2.apk]
Here is my code :
Employee class has 2 constructors and a method to return the age
Employee()
Employee(int age)
int getAge();
suprisingly when I invoke the method getAge()..the call goes through and fetches the age... But when I try to call the "Employee constructor" and then try to getAge() this exception is thrown...
somehow It is not able to find the class:
I have tried with all the possiblities I came across for GetObjectClass()
this works ; when I pass the Employee object in the call
JNIEXPORT jint JNICALL Java_pv_ndk_Employee_getAgeC(JNIEnv *env, jobject callingObject, jobject employeeObject)
{
jclass employeeClass = env->GetObjectClass(employeeObject);
jmethodID midGetName = env->GetMethodID(employeeClass, "getAge", "()I");
int age = env->CallIntMethod(employeeObject, midGetName);
//other code
}
THIS DOES NOT WORK ; I am not sure why it is not able to find the class..
I have tried with "Lpv/ndk/Emploee" "LEmployee" "pv/ndk/Employee" .. and even tried with the following approach:
jclass localRefCls = env->FindClass("pv/ndk/Employee");
jclass clazzEmployee = (_jclass*)env->NewGlobalRef(localRefCls);
JNIEXPORT jobject JNICALL Java_pv_ndk_Employee_createWithAge(JNIEnv *env, jobject callingObject, jint age) {
jclass employeeClass = env->FindClass("pv/ndk/Employee");
jmethodID midConstructor = env->GetMethodID(employeeClass, "<init>", "(I)V"); // BOOM SCREWED HERE .. !!
}
But everytime my code comes to env->GetMethodID - the vm Aborts ...
surprisingly the same code works today :)
probably it had to do with the way I was deploying the code... I believed that "auto build" should have taken care of it... Really sorry for creating confusion here regarding a working code snippet... I am new to NDK and JNI development ...
This definately works
jclass employeeClass = env->FindClass("pv/ndk/Employee");
//constructor call depicted by <init> and it's parameters (I) and return type V
jmethodID midConstructor = env->GetMethodID(employeeClass, "<init>", "(I)V");
I think the reason might have to do with the "native shared-library" not getting deployed after new modification... These are the steps I used to follow :
[1] I re-built the "Shared-library" with the modification ; using the "ndk-build"
__[2] Then I deploy the android project on my device
but seems Eclipse caches the "library" ??? [ please correct me if I am wrong ]
Hence the changes were taken into account...
Solution : [ possibly ]
[1] I rebuilt the library __ [2] I cleaned the whole project __ [3] then deployed the project on device...
FindClass method needs full class signature.
Note:if you have any inner classes / will not work,you have to use $
for example if your package name is A.B.C and your main class name is D and your subclass name is E then you have to use FindClass("LA/B/C/D$E;");
Related
Android Studio is showing this error. Here's a snippet of the relevant code:
public class MainActivity extends AppCompatActivity {
...
static native void runTests(String path);
static {
System.loadLibrary("TestLib");
}
}
In that first line, runTests is highlit in red and if you hover over it, you see the message "Cannot resolve corresponding JNI function"
To be clear, the app does build and run just fine. It's just that Android Studio thinks that this symbol can't be resolved.
OK, I figured it out. If my function is defined using the standard naming convention, e.g.
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_runTests(JNIEnv *env, jclass cls, jstring path)
Then Android Studio figures it out.
My problem was that I was just defining it as
static void
runTests(JNIEnv *env, jclass cls, jstring path)
and using env->RegisterNatives() to link it into Java. It was too much to ask of Android Studio to figure that out.
I have created a pre-built Native library libNative.so, that has a JNI function to be called from the Android application.
libNative.so is located in the device at /system/x86_64.
Now, I want to call the JNI function implemented in my pre-built Native library from Android application. I am following below Procedure.
1> Load the Native lib in MainActivity:
static { System.loadLibrary("Native"); }
2> Declared the native method as:
public native int Init();
3> Function definition in the shared lib is:
JNIEXPORT jint Java_App_PACKAGE_NAME_MainActivity_Init(JNIEnv* env, jobject callingObject){
return 0;
}
4>I'm calling the native function in onCreate:
int i = Init();
Now If I build and run the application. I get the error as:
AndroidRuntime: java.lang.UnsatisfiedLinkError: No implementation found for int App_PACKAGE_NAME_MainActivity.Init() (tried Java_App_PACKAGE_NAME_MainActivity_Init and Java_App_PACKAGE_NAME_MainActivity_Init__)
Please help me to resolve the above error.
Why is it that I get linker error even though loading of the library is success.
Thanks in advance !
I found the mistake I was doing.The definition of JNI function in the native library was wrong. I changed as below and everything started working!.
extern "C" JNIEXPORT jint JNICALL
Java_App_PACKAGE_NAME_MainActivity_Init(JNIEnv* env, jobject callingObject){
}
I use follow code to handle JNI array in Android and JNI.
However I found return "jobjectArray" cannot complete on API 21/22 (Android 5.0) but works on API 19. (Android 4.4)
(cannot complete mean it return on JNI part but it hang and no response on Java)
Here is the pseudo code I try to implement in my Android App.
jobjectArray Java_com_test_Simplejni(JNIEnv* env, jobject thisObj)
jclass localClass = env->FindClass("java/lang/Object");
jclass objClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass));
args = env->NewObjectArray(len, objClass, 0);
return args;
}
The java part function as follow:
String[] Simplejni();
The error message as follow:
JNI DETECTED ERROR IN APPLICATION: attempt to return an instance of java.lang.Object[] from com.test.Simplejni
Please advise any suggestion how to investigate this issue, thank you.
Update: 20150427
I try to simpreturn empty jobjectArray which works in Android 4.4 but failed in Android 5.0 (with the same code)
My IDE is Android Studio
I found a way to solve this:
you just replace java/lang/Object with your java object class on API 21+, for example,
jclass localClass = env->FindClass("com/example/YourLocalClass");,
From the logs, we can know the object class is not the instance of yourJavaLocalObject class.
I am trying to add PJSip to a project I am working on. I have this method for registering my account but a 'Fatal signal 11' error occurs everytime.
Here is the method
public int setRegistration() {
int status = pjsuaConstants.PJ_FALSE;
/* Register to SIP server by creating SIP account. */
int[] accId = new int[1];
accId[0] = 1;
String uName = getUserName();
String passwd = getPassword();
String server = getSIPServer();
pjsua_acc_config acc_cfg = new pjsua_acc_config();
pjsua.acc_config_default(acc_cfg);
acc_cfg.setId(pjsua.pj_str_copy("sip:" + uName + "#" + server));
acc_cfg.setReg_uri(pjsua.pj_str_copy("sip:" + server));
acc_cfg.setCred_count(1);
acc_cfg.getCred_info().setRealm(pjsua.pj_str_copy(server));
acc_cfg.getCred_info().setScheme(pjsua.pj_str_copy("digest"));
acc_cfg.getCred_info().setUsername(pjsua.pj_str_copy(uName));
acc_cfg.getCred_info().setData_type(pjsip_cred_data_type.PJSIP_CRED_DATA_PLAIN_PASSWD.swigValue());
acc_cfg.getCred_info().setData(pjsua.pj_str_copy(passwd));
Log.d("status", "acc is adding..");
status = pjsua.acc_add(acc_cfg, pjsuaConstants.PJ_TRUE, accId);
Log.d("status", "acc is added");
if (status == pjsuaConstants.PJ_SUCCESS) {
status = pjsua.acc_set_online_status(accId[0], 1);
Log.d("acc_set_online_status returned stauts=", String.valueOf(status));
} else {
Log.d("Error status=", String.valueOf(status));
}
return status;
}
I receive the error on the status = pjsua.acc_add(acc_cfg, pjsuaConstants.PJ_TRUE, accId); line. I know that the username, server, and password are not null. I have looked at multiple questions relating to this and no use.
How can I register my account?
Thanks
*****EDIT******
After tracking down this through blogs and forums I got passed this error but received another. The reason this error occurred was because pjsua_init was never successful. It was successful because it gave me this error
11-04 10:19:20.973: E/AndroidRuntime(2961): FATAL EXCEPTION: main
11-04 10:19:20.973: E/AndroidRuntime(2961): java.lang.UnsatisfiedLinkError: Native method not found: org.pjsip.pjsua.pjsuaJNI.init:(JLorg/pjsip/pjsua/pjsua_config;JLorg/pjsip/pjsua/pjsua_logging_config;JLorg/pjsip/pjsua/pjsua_media_config;)I
11-04 10:19:20.973: E/AndroidRuntime(2961): at org.pjsip.pjsua.pjsuaJNI.init(Native Method)
11-04 10:19:20.973: E/AndroidRuntime(2961): at org.pjsip.pjsua.pjsua.init(pjsua.java:812)
I have received this warning as well
No implementation found for native Lorg/pjsip/pjsua/pjsuaJNI;.init (JLorg/pjsip/pjsua/pjsua_config;JLorg/pjsip/pjsua/pjsua_logging_config;JLorg/pjsip/pjsua/pjsua_media_config;)I
Why isn't this a native method? I am looking into the libraries I have called but other than that I don't know why this isn't working.
Any help on this matter would be great.
Thanks
PJ Code
pjsua.java
public synchronized static int init(pjsua_config ua_cfg, pjsua_logging_config log_cfg, pjsua_media_config media_cfg) {
return pjsuaJNI.init(pjsua_config.getCPtr(ua_cfg), ua_cfg, pjsua_logging_config.getCPtr(log_cfg), log_cfg, pjsua_media_config.getCPtr(media_cfg), media_cfg);
}
pjsuaJNI.java
public final static native int init(long jarg1, pjsua_config jarg1_, long jarg2, pjsua_logging_config jarg2_, long jarg3, pjsua_media_config jarg3_);
pjsua_wrap.cpp
SWIGEXPORT jint JNICALL Java_org_pjsip_pjsua_pjsuaJNI_init(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2, jobject jarg2_, jlong jarg3, jobject jarg3_) {
jint jresult = 0 ;
pjsua_config *arg1 = (pjsua_config *) 0 ;
pjsua_logging_config *arg2 = (pjsua_logging_config *) 0 ;
pjsua_media_config *arg3 = (pjsua_media_config *) 0 ;
pj_status_t result;
(void)jenv;
(void)jcls;
(void)jarg1_;
(void)jarg2_;
(void)jarg3_;
arg1 = *(pjsua_config **)&jarg1;
arg2 = *(pjsua_logging_config **)&jarg2;
arg3 = *(pjsua_media_config **)&jarg3;
result = (pj_status_t)pjsua_init((pjsua_config const *)arg1,(pjsua_logging_config const *)arg2,(pjsua_media_config const *)arg3);
jresult = (jint)result;
return jresult;
}
{"init", "(JLorg/pjsip/pjsua/pjsua_config;JLorg/pjsip/pjsua/pjsua_logging_config;JLorg/pjsip/pjsua/pjsua_media_config;)I", (void*)& Java_org_pjsip_pjsua_pjsuaJNI_init},
EDIT 2
So after working on this I have gotten to a point of frustration. I am not seeing what I am doing wrong so I will put my entire process here to see if someone has a suggestion.
I start by getting the pjsip library: svn co http://svn.pjsip.org/repos/pjproject/trunk pjproject
run `./configure --prefix=/usr/local
make dep & make
sudo make install
I then get the pjjni code svn checkout svn://svn.code.sf.net/p/pjsip-jni/code/ pjsip-jni-code
I follow the Makefile instructions
After Makefile runs successfully (after some code cleanup) I have 2 .so files (libpjsua_jni.so and libpjsua_jni_x64.so)
Create jni folder with Android.mk file and .so libraries
Run ndk-build (How to load another .so file in your android project?)
Add to ADT
Close project. Change native support from Java to Android. Open project
(Convert existing project into Android project in Eclipse?)
Add that project to my TestPJ project (Android -> Library -> Add)
Call System.loadLibrary("pjsualib") -- Name of the new lib.so
Receive Error
11-22 13:55:44.784: W/dalvikvm(11464): No implementation found for native Lorg/pjsip/pjsua/pjsuaJNI;.swig_module_init:()V
11-22 13:55:48.792: W/dalvikvm(11464): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lorg/pjsip/pjsua/pjsuaJNI;
11-22 13:55:51.417: E/AndroidRuntime(11464): java.lang.UnsatisfiedLinkError: Native method not found: org.pjsip.pjsua.pjsuaJNI.swig_module_init:()V
11-22 13:55:51.417: E/AndroidRuntime(11464): at org.pjsip.pjsua.pjsuaJNI.swig_module_init(Native Method)
11-22 13:55:51.417: E/AndroidRuntime(11464): at org.pjsip.pjsua.pjsuaJNI.(pjsuaJNI.java:1450)
Any help would be great. Thanks!
An example of project which explores JNI calls from Java and from C can be found here.
The error mentioned in the question (java.lang.UnsatisfiedLinkError: Native method not found: org.pjsip.pjsua.pjsuaJNI) means one of the following problems:
- wrong native method name or/and its arguments/return value. If you have access to native code of the library than you can fix it. According to the error message and JNI considerations native method must have name Java_org_pjsip_pjsua_pjsuaJNI_init(JNIEnv *env, jobject obj, ..), where env is a pointer to JVM interface, obj is a "this" pointer and the remaining arguments can be determined from java init method of pjsuaJNI class of package org.pjsip.pjsua. Simple parameter types must be jint, jstring etc. Also return value must be correct as well. Fixing all these allows to use this method from pjsuaJNI class. Additional details can be found from Oracle Documentation to Oracle Documentation to Java 6 JNI (or Java 7 if you're using android 4.4).
- wrong java method name/signature/class name or package name. This case is almost reverse to the first one. Again, according to the mentioned error name of the method must be "init", class name pjsuaJNI and package org.pjsip.pjsua. If at least one of them is wrong the mentioned exception will happen. Signature or parameters must also be correct. In the boundaries of this error it can be considered as a parameters of the method (in addition in native JNIEnv* and jobject appears). So also must be checked and fixed if necessary.
In case of call from native code to java signature can be considered as a representation of java method with parameters as a string and can be viewed with javap -s *.class command applied to java *.class file. And in the last warning from question this signature of the method can be seen.
Also to use method pjsip library must be loaded with System.loadLibrary() in some static section of the Java class.
Unfortunately, this problem happens at runtime (it would be nice if it happened during compilation time).
It's a bit late but I'll try to help on this. I think that your problem should be related to your native method not been surrounded by extern "C"{} and name mangling in C++.
If you don't declare one native C function as extern "C", C++ build mangles it and JNI mechanism can not find native method matching provided signature. On the other hand, declaring it as external C function, the builder creates both, mangled and unmanged, versions and JNI can find the proper one.
Hope this helps.
I'm trying to run and understand ths example: http://answers.oreilly.com/topic/2689-how-to-use-the-android-ndk-to-improve-performance/
It's a quite simple example with the following files:
FibActivity.java - main activity file
FibLib - class implementing and calling the native functions
fib.c - the C source file with the native functions and code
FibLib.h - the C header file, automatically created from the FibLib class
Android.mk - the makefile
I've implemented the example exactly as described. Still, when I run it, I get this (UnsatisfiedLinkError) error when the app tries to access the native code:
12-21 11:31:53.042: D/dalvikvm(1491): Trying to load lib /data/data
/com.frank.android.ndk/lib/libfib.so 0x405143b8
12-21 11:31:53.042: D/dalvikvm(1491): Added shared lib /data/data/com.frank.android.ndk
/lib/libfib.so 0x405143b8
12-21 11:31:53.042: D/dalvikvm(1491): No JNI_OnLoad found in /data/data
/com.frank.android.ndk/lib/libfib.so 0x405143b8, skipping init
12-21 11:31:53.093: W/dalvikvm(1491): No implementation found for native Lcom/frank
/android/ndk/FibLib;.fibN (I)J
12-21 11:31:53.102: D/AndroidRuntime(1491): Shutting down VM
12-21 11:31:53.102: W/dalvikvm(1491): threadid=1: thread exiting with uncaught
exception (group=0x40015560)
12-21 11:31:53.112: E/AndroidRuntime(1491): FATAL EXCEPTION: main
12-21 11:31:53.112: E/AndroidRuntime(1491): java.lang.UnsatisfiedLinkError: fibN
12-21 11:31:53.112: E/AndroidRuntime(1491): at
com.frank.android.ndk.FibLib.fibN(Native Method)
12-21 11:31:53.112: E/AndroidRuntime(1491): at
com.frank.android.ndk.JavaNativeFibonacciAct
ivity.onClick(JavaNativeFibonacciActivity.java:52)
The only strange thing I notice is, according to the logcat, that eclipse tries to load the library from the /lib folder, while the automatically created folder is called /libs. However, renaming the /lib folder to /libs and rebuilding everything makes no difference.
Anyone got any ideas? I've been trying for days to get examples to work that include using javah to create a header file. Creating only the main activity and the c file, and then calling the native code from the main activity seems to work, but as soon as I begin using header file(s) I get the UnsatisfiedLinkError.
UPDATE:
From FibLib.java:
// Native implementation
static {
System.loadLibrary("fib"); //
}
// Native implementation - recursive
public static native long fibN (int n);
// Native implementation - iterative
public static native long fibNI (int n);
The fib.c file:
#include "com_frank_android_ndk_FibLib.h" /* */
/* Recursive Fibonacci Algorithm */
long fibN(long n) {
if(n<=0) return 0;
if(n==1) return 1;
return fibN(n-1) + fibN(n-2);
}
/* Iterative Fibonacci Algorithm */
long fibNI(long n) {
long previous = -1;
long result = 1;
long i=0;
int sum=0;
for (i = 0; i <= n; i++) {
sum = result + previous;
previous = result;
result = sum;
}
return result;
}
/* Signature of the JNI method as generated in header file */
JNIEXPORT jlong JNICALL Java_com_frank_android__ndk_fibN (JNIEnv *env, jclass obj, jlong n) {
return fibN(n);
}
/* Signature of the JNI method as generated in header file */
JNIEXPORT jlong JNICALL Java_com_frank_android__ndk_fibNI (JNIEnv *env, jclass obj, jlong n) {
return fibNI(n);
}
The Andoid.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fib
LOCAL_SRC_FILES := fib.c
include $(BUILD_SHARED_LIBRARY)
Your Java package name appears to be named "com.frank.android.ndk" and your Java class name appears to be named "FibLib" and in turn the name of the C function matching FibN should be Java_com_frank_android_ndk_FibLib_fibN. This page is referened by the Android docs and details the JNI naming convention for C functions.
Does it only seem, or your C function names really use double underscore before word ndk? It should be single underscore IMHO.
It can't find Lcom/frank/android/ndk/FibLib;.fibN. The log indicates that the library was loaded successfully.
The method should be called Java_com_frank_android_ndk_FibLib_fibN; in the question you have a double underscore and you're missing the class name. If you have two different methods that resolve to the same thing, you can differentiate them by encoding the arguments as well, but that doesn't seem necessary here.
You said this is a C program, but sometimes people conflate C and C++, so I'll also point out that if this is a ".cpp" file you'll need to put extern "C" in the declaration or C++ will "mangle" the function name.
See also http://developer.android.com/training/articles/perf-jni.html#faq_ULE
have you complied the JNi Code Using ndk-build ?
the class Name Should be same as Described in JNI and in Java
Java_com_qualcomm_QCARSamples_VideoPlayback_VideoPlayback_initApplicationNative
the initApplicationNative is method name that should be same on both Java and JNi
if not then you will get this error