JNI method: formal argument lists differ in length - java

I'm trying to emend a JNI function that takes a string argument from the java layer.
Initially, the java code from the .java file was:
callJNIMethod();
I'm trying to change it so that I can give it a string, like this:
String arg = "abcd";
callJNIMethod(arg);
In my JNI code, this is what the function previously looked like:
JNIEXPORT jboolean JNICALL Java_com_file_app_Activity_callJNIMethod(
JNIEnv *env, jclass clazz){
//use the string
}
This is what I changed it to (in the wrapper .cpp file and the header .h file):
JNIEXPORT jboolean JNICALL Java_com_file_app_Activity_callJNIMethod(
JNIEnv *env, jclass clazz, jstring str);
I'm getting an error that the method callJNIMethod cannot be applied to the given types.
required: no arguments
found: java.lang.String
reason: actual and formal argument lists differ in length
Note: Some input files use or override a deprecated API.
Any idea what's wrong?

You went astray by editing the .h file. Changes to native methods should begin in your Java source.
The .h file should be generated by javah from the compiled .class file. You can set up your build system to re-run javah with each build. That way you'll see right away if the native method implementations no longer match the native declarations in your Java source.

Related

Calling C function JNI from Java Class

I created a JNI folder in my APP in Android Studio, I copied all my C files, but I need to call only one: NeuralNetwork.c, there are also NeuralNetwork_initialize.c and NeuralNetwork_terminate.c. I already have my CMakeFile.
I know I need to create another C file with something like this (it's called main.c):
#import <jni.h>
JNIEXPORT jstring JNICALL Java_com_dsp_testapp_NewRecordingActivity_getString(JNIEnv *env, jobject thiz) {
return (*env)->NewStringUTF(env, "Hello World from C!");
}
But, I need it to call specifically my NeuralNetwork.c, I know also I have to use the initialize and terminate somehow, but don't really know how.
Now, in my Java class I did this:
System.loadLibrary("my_src");
my_src is the name of my library generated with my CMake file.
But I don't know how to call then my main.c function.
NeuralNetwork.c gives me just a double: 1, or 0 and has 5 vector inputs with length of 256.
Could you please help me with this?
You basically need to create a Java class with the qualified name (class + package) corresponding to what you used in your library (com.dsp.testapp.NewRecordingActivity). Then you need to declare the method as native:
public native getString(Object obj)
Afterwards, just create an object of this class and call the method.

Jni and shared libraries

I have made a program in Java that calls to some functions in native language C. Made a shared library of that C function file and made a shared library, and all worked perfectly.
My problem is when I try to call other functions for example in PBC (Pairing Based Cryptography) library. The C files that are in the shared library include the required .h files for knowing the functions in PBC but I can't use them, I don't know why. What should I do? How can I call functions that are in another libraries?
Java code for loading the libraries.
static {
System.loadLibrary("myLibrary");
System.loadLibrary("pbc");
}
Error when executing my own Java program:
undefined symbol: pairing_init_set_buf
Make sure to link your JNI code with shared library you want to use.
You can take a look at sample code here:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo023
In this sample you have JNI function:
JNIEXPORT void JNICALL Java_recipeNo023_HelloWorld_displayMessage
(JNIEnv *env, jclass obj) {
printf("Hello world!\n");
/* We are calling function from another source */
anotherFunction();
}
that calls function from some external shared library
void anotherFunction() {
// we are printing message from another C file
printf("Hello from another function!\n");
}
You have to make sure that your JNI library is linked with the library you want to use:
cc -g -shared -fpic -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(ARCH) c/recipeNo023_HelloWorld.c -L./lib -lAnotherFunction -o lib/libHelloWorld.$(EXT)
In this sample
-L./lib -lAnotherFunction
tells compiler to use this "other" library that contains symbols not available inside library that contains JNI code.

G++ compiled DLL has different function names

I'm trying to write a set of JNI calls to use some C++ code in my java project. When I write it as C code and compile with GCC, it seems to be fine and the function names are correct (Java_myPackage_MyClass_myFunction).
But I'm finding it easier to do what I want in C++ instead of C. When I try to compile the code I have with C++, the header files for all I can see are correct, everything looks fine, but when I compile it, the dll generated by g++ causes this error in my java code:
Exception in thread "main" java.lang.UnsatisfiedLinkError: package.class.function(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
at package.class.function(Native Method)
When I check the dll in dependency walker, the function has the wrong name to it, it's been changed to _Z52Java_package_class_functionP7JNIENV_P8_jobjectP8_jstringS4_
when I think it should just be showing up in dependency walker as Java_package_class_function
This is the command I'm using to compile the dll with g++
g++.exe -Wl,--add-stdcall-alias -I "C:\Program Files\Java\jdk1.8.0_73\include" -I "C:\Program Files\Java\jdk1.8.0_73\include\win32" -shared -o C:/repos/myproject.dll myproject.cpp -lssl -lcrypto
Is there something I'm missing in compilation? I do have the functions in my .h file listed as JNExport and wrapped in extern "C" {}. I'm just not entirely clear why the function naming/calls get changed when it compiles.
Environment is G++ compiling in Cygwin on Win7 with JDK 1.8 for Java.
function declarations in my .h file:
extern "C" {
JNIEXPORT jstring JNICALL Java_package_class_function(JNIEnv *, jclass, jstring, jstring);
JNIEXPORT jstring JNICALL Java_package_class_function(JNIEnv *, jclass, jstring, jstring);
char * aes_encrypt_string(char *, char *, char *);
char * aes_decrypt_string(char *, char *, char *);
}
I have the externc on there, and the aes functions are being exported correctly in the .dll file, but the other 2 functions are getting the extra decoration.
C++ compilers uses name mangling to create unique entries in the symbol table. This isn't needed in C code since each function must already be unique. To prevent name mangling wrap your function definitions in extern "C" { }
For more information see in-c-source-what-is-the-effect-of-extern-c and a duplicate of your question.

android ndk wrapped c++ file get android system file path

I have some code written in c++ by android JNI.
in one export function
"extern "C" JNIEXPORT int JNICALL Java_com_android_mymapsforge_create(JNIEnv *env, jobject obj)
{
...
ifstream infile("C:\\Users\\li\\Documents\\Visual Studio 2010\\Projects\\importANN\\Debug\\nodes.csv");
string line;
int index = 0;
while( getline( infile, line ))
{
....
}
}
when i using those original c++ code, i test under vs2010. Either i assign the infile() parameters with a fixed file path, or using some c++ get_file_path function, it's a thing related windows system, there is no problem. both work.
But now I want to using these code under JNI using by android. So the file path system change to android and some function need be adjusted.
My problem arise: because the code is using at last by my android java code under a android app, so the "C:\Users\li\Documents\Visual Studio 2010\Projects\importANN\Debug\nodes.csv", no longer take effect, it may be change to "/mnt/sdcard/somefolder/nodes.csv"
but i have experience when i in android app give a fixed file path it tell my some error, so under android jave envi, i using below code to get file path, similar code here:
String mpath ;
mpath = Environment.getExternalStorageDirectory().getPath();
mapView.setMapFile(new File(mpath+"/"+"berlin.map"));
(omit the filename , i just want to tell the method i use)
But these android code must can not use in my c++ wrapping function Java_com_android_mymapsforge_create,
So my question is :
how to cope with the file(android system) path things under the c++ export function? For example, i put the "nodes.csv" under my sdcard root folder, and want to do some processing under the JNI exported c++ function?
The easiest way is to pass the path as an argument of the function.
extern "C" JNIEXPORT int
JNICALL Java_com_android_mymapsforge_create(JNIEnv *env, jobject, jstring path)
Then you can turn jstring path to char* using JNI converting jstring to char *.
The second way is to call Android Environment.getExternalStorageDirectory().getPath() from JNI function like described here - Call a static java method of another package from native code.

Why am I getting an error using Jni onload but not using javah's output?

I have this java method:
public static native void processBuffer(ByteBuffer bb);
with javah
JNIEXPORT void JNICALL Java_com_lan_factorial_IssmJni_processBuffer
(JNIEnv *env, jclass klass , jobject buf)
work perfectly
with Jni onload
static JNINativeMethod method_table[] = {
{"fac" , "(J)J" , (void *) factorial},
{"getBuffer", "()[D" , (void *) getBufferNative},
//{"processBuffer", "(Ljava/nio/ByteBuffer)V", (void *) fillBuffer}};
The others method in this table works, exept the last one which correspond to the method generate from javah above. And of course if I do JNI onload i will have a method call fillBuffer.
Can someone explain why javah works but not jni_onload. Did I do something wrong?
I have other methods using jni_onload so I want to stay away from javah.
Thanks
You have a missing semicolon in the method signature. It doesn't 'correspond' at all. Don't guess at native method signatures: use the output of javap -s. Cut and paste.

Categories

Resources