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
Related
I am working on an Android firmware for an embedded device which streams an encoded video signal using rtp. The underlying library is MediaStreamer2 because it comes with Android support, various codecs and libortp. Therefore I integrated libmediastreamer and its dependencies into my firmware build process.
As a second step, I wrote a simple Android command line application as a PoC which streams audio or video through the network. Unfortunatly, the first call to ms_init() fails due to:
bctbx-fatal-Calling ms_get_jni_env() while no jvm has been set using ms_set_jvm()
Digging a little deeper into the problem, it seems Androids version of libmediastreamer was designed from an NDK point of view: It can be called as a part of an Android app and therefore automatically gets a reference to the JVM (DVM?). Unfortunatly, this is not my use case.
I tried to to remove the dependencies (Querying Sdk version, hardware echo cancelation support, etc.) without success. So my next approach would be starting a VM manually and passing it to the library. I tried Oracles APIs like:
JNIEnv env;
JavaVM vm;
JavaVMInitArgs vm_args;
JavaVMOption options[4];
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = TRUE;
jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
But the application quits with a simple "aborted". Nevertheless, I am not sure whether this is a way to go because its Android and Dalvik world.
Any suggestions?
It is possible to build executable for shell on Android on both rooted and non-rooted devices, see reference How to build an executable for Android shell
.
Try below code and build it using NDK to get an executable:
#include <jni.h>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char **argv) {
JavaVMOption jvmopt[1];
jvmopt[0].optionString = "-Djava.class.path=" + ".";
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 1;
vmArgs.options = jvmopt;
vmArgs.ignoreUnrecognized = JNI_TRUE;
// Create the JVM
JavaVM *javaVM;
JNIEnv *jniEnv;
long flag = JNI_CreateJavaVM(&javaVM, (void**)
&jniEnv, &vmArgs);
if (flag == JNI_ERR) {
cout << "Error creating VM. Exiting...\n";
return 1;
}
/** ----------------------------------------------
* Put your own JNI related code from here if any.
* -----------------------------------------------
**/
javaVM->DestroyJavaVM();
return 0;
}
Do a check on <jni.h> about the interfaces you can use, e.g.
/*
* VM initialization functions.
*
* Note these are the only symbols exported for JNI by the VM.
*/
jint JNI_GetDefaultJavaVMInitArgs(void*);
jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
You can refer to below to see if they are helpful:
how-to-create-a-jvm-instance-in-jni
https://calebfenton.github.io/2017/04/05/creating_java_vm_from_android_native_code/
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 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 looking for clues why my Android app sporadically throws an UnsatisfiedlinkError exception on a specific ndk call:
I have an Android app that loads one native library through ndk.
The native library is written in C++ and uses STL (in my makefile I have set APP_STL := stlport_static). No other libraries are used or required. The native library has about 300 native methods for about 20 java classes.
All works fine, most of the time. But every now and then my users get an UnsatisfiedLinkError exception. The exception is always triggered at the same spot with the same native function call, but strangely enough it is not even the first call to a native function, not even the first call to that specific native function.
Any clue would be welcome why one specific native call could fails. Can ndk easily be corrupted? How do you debug for such a problem?
Simple test programs with the same call work just fine. Nevertheless here's some parts of the source code:
Here's the problem ndk function in Java:
public class Server {
...
static private native long longObserveError( );
...
}
Here's the header file:
extern "C" {
...
JNIEXPORT jlong JNICALL Java_be_gentgo_tetsuki_Server_longObserveError
(JNIEnv *, jclass);
...
}
And here's the implementation:
IGSProtocol *server = 0; // initialized later...
JNIEXPORT jlong JNICALL Java_be_gentgo_tetsuki_Server_longObserveError
(JNIEnv *env, jclass)
{
Messenger &mess = server->ObserveError( );
return (long)(&mess);
}
What is the name of your library file? I came across another SO post (https://stackoverflow.com/a/18024816) where the guy had a library name that was conflicting with a system library that was only present on some devices. Renaming his library fixed the problem.
I'm trying to use the NDK with C++ and can't seem to get the method naming convention correct. my native method is as follows:
extern "C" {
JNIEXPORT void JNICALL Java_com_test_jnitest_SurfaceRenderer_drawFromJni
(JNIEnv* env, jclass c)
{
//
}
}
with a header wrapped in extern "C" {} aslo.
Everything compiles fine, creates a .so file and copies to the libs folder under my project, but when I debug and run in Eclipse I keep getting a log cat message that of "no implementation found for native...". Is there something i'm missing as all the NDK examples are in C?
Thanks.
There are a couple of things that can lead to "no implementation found". One is getting the function prototype name wrong, another is failing to load the .so at all. Are you sure that System.loadLibrary() is being called before the method is used?
If you don't have a JNI_OnLoad function defined, you may want to create one and have it spit out a log message just to verify that the lib is getting pulled in successfully.
You already dodged the most common problem -- forgetting to use extern "C" -- so it's either the above or some slight misspelling. What does the Java declaration look like?
An additional cause for this error: your undecorated native method name must not contain an underscore!
For example, I wanted to export a C function named AudioCapture_Ping(). Here is my export declaration in C:
JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapture_Ping(JNIEnv *pJniEnv, jobject object); //Notice the underscore before Ping
Here was my Java class importing the function:
package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
private native int AudioCapture_Ping(); // FAILS
...
I could not get Android to dynamically link to my native method until I removed the underscore:
JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapturePing(JNIEnv *pJniEnv, jobject object);
package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
private native int AudioCapturePing(); // THIS WORKS!
...
I had the same problem, but to me the error was in the file Android.mk. I had it:
LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES := B.cpp
but should have this:
LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES += B.cpp
note the detail += instead :=
I hope that helps.
Called extern "C" as provided in the automatically-generated Studio example, but forgot to wrap the entire rest of the file, including following functions, in {} brackets. Only the first function worked.
An additional reason: Use LOCAL_WHOLE_STATIC_LIBRARIES instead of LOCAL_STATIC_LIBRARIES in android.mk. This stops the library from optimizing out unused API calls because the NDK cannot detect the use of the native bindings from java code.
There is a cpp example under apps in ndk:
https://github.com/android/ndk-samples/blob/master/hello-gl2/app/src/main/cpp/gl_code.cpp
Use javah (part of Java SDK). Its the tool exactly for this (generates .h header from .class file).
If your package name includes _ character, you should write 1(one) after _ character as shown below:
MainActivity.java
package com.example.testcpp_2;
native-lib.cpp
JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(
I try all above solutions, but no one can solved my build error(jni java.lang.UnsatisfiedLinkError: No implementation found for...),
at last I found that I forget to add my verify.cpp source file to CMakeList.txt add_library segement(verify.cpp is auto generate by Ctrl + Enter short key, maybe other file name), hope my response can help some one.
my build environment: Gradle + CMake
I Faced the same problem, and in my case the reason was that I had underscore in package name "RFID_Test"
I renamed the Package and it worked.
Thanks user1222021
I faced the same problem twice. It happened, that the phone I tried to start the app from Android Studio used an API level that I haven't downloaded yet in Android Studio.
Upgrade Android Studio to the latest version
Download the necessary API from within Android Studio