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.
Related
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.
I have three C++ files that I want to use in Android studio.
Header.h
A.cpp (which contains the main method + other methods)
B.cpp
I have compiled them into a static library. Now I want to write the JNI wrapper around a C++ method and call it into the java part. Here is my wrapper so far :
#include <jni.h>
#include <string.h>
#include <stdlib.h>
extern "C" {
JNIEXPORT int JNICALL Java_cgi_pi_detect(? ,?) {
IplImage * byteQueryImage = loadByteImage ( ? );
if ( !byteQueryImage )
{
printf ( "couldn't load query image\n" );
return -1;
}
// Detect text in the image
IplImage * output = textDetection ( byteQueryImage, atoi(1));
cvReleaseImage ( &byteQueryImage );
cvSaveImage ( ? , output );
cvReleaseImage ( &output );
return 0;
}
}
I want to give it two pictures as arguments : the one to load IplImage * byteQueryImage = loadByteImage ( ? ); and the one to save cvSaveImage ( ? , output );.
What should be the jni types JNIEXPORT int JNICALL Java_cgi_pi_detect(? ,?) for these two arguments (if I consider that the pictures are .png) ?
Calling main() like that is fraught with peril. Which main() is going to be called? The JVM executable also has a main(). (And yes, I'm ignoring the "undefined behavior" as the question is about how to make it work.)
The hard way to get the main() you want is to compile it into a shared object, load that shared object, and find main() in that shared object yourself with runtime dynamic linking using dlopen() and dlsym() (error checking omitted):
#include <dlfcn.h>
...
// use a typedef for the function pointer
typedef int ( *main_func_t )( int, char ** );
...
// Handle to your .so with your "main()" in it
// make them static so they're only loaded once
static void *libHandle = NULL;
static main_func_t libMain = NULL;
if ( NULL == libHandle )
{
libHandle = dlopen( "yourLibName.so", RTLD_NOW );
libMain = ( main_func_t ) dlsym( libHandle, "main" );
}
...
// now call the main() in that library
int mainRetVal = libMain( argc, argv );
...
So that means you need two shared objects: the first "normal" one that holds your JNI calls, and the second that holds your "main()" that you want to call. The first "normal" JNI library will need to be linked with a dependency on libdl.so using an -ldl linker argument.
The easy way?
Rename the main() you want to call to something else and put it into your normal JNI shared object. Then just call it - it's no longer called main() so there's no longer any name conflict.
Even with all that, I suspect you still might run into problems - name collisions or incompatible libraries come to mind immediately.
An even easier way that will work?
Run it in a subprocess since that's the way it was designed to run, and it's effectively a black box anyway: you call it with arguments, it does whatever it does, and you get an int return value back. That's the same for a function call or a subprocess.
You can put the wrapper function in any file that will be compiled, new or existing. Unlike Java, in C++ the file name has no meaning for compiler.
You don't need to wrap other methods if you don't intend to call them independently from Java.
PS: note that the name Java_cgi_pi_detect of the wrapper function is derived from the Java class that defines this detect native method. Use javah tool to generate the correct name of the C function that implements a native Java method.
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.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am new to the JNI area and my aim is to study the native methods of java.lang.Thread such as registerNatives and start0() so that I get to understand at the OS level what are the OS operations that happen when a Thread is
a)created
b)started
So I cam across various tutorials for JNI so as to understand just the basics. It looks like there are 4 main steps
a) write the declaration of the native method(s) in a class (like start0() in Thread.java)
b) use javah tool in jdk/bin to generate a .h file
c) include these generated .h files and other common .h files in jdk/include to the c/c++ project env
d) write the required c++ function.
Please correct me if I have missed a step.
Questions-
1) When I apply the step b) to a standard java file like Thread.java, I couldn't find something like Thread.h in the JDK and it's source. What should be the exact location of the same ? I got the link of Thread.h in apache harmony http://svn.apache.org/repos/asf/harmony/enhanced/sandbox/bootjvm/bootJVM/jni/src/harmony/generic/0.0/include/java_lang_Thread.h and this is exactly the same file which I expected to be there in jdk.
2) I see a file called Thread.C at jdk\src\share\native\java, this file includes the file I expected in point number 1, java_lang_Thread.h. Thread.C file contains code
Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
}
Ideally I would have expected this code to be there in Thread.h, why is it there in Thread.C and what is it's significance ?
3)There is a file called thread.cpp at openjdk\hotspot\src\share\vm\runtime and it contains all the method definitions, now starting from Thread.h
JNIEXPORT void JNICALL Java_java_lang_Thread_start(JNIEnv *, jobject);
how can we map it to Thread.start because I couldn't notice a mapping between start0() to start().
4) Since I am a java programmer and may have hard time understanding c++ code in Thread.CPP, could someone guide me to a link which may contain theory of these methods like set_stack_base(NULL) etc ?
I do not have a link to the jdk or the java threading source. Perhaps if you provided one, I could solve your problem.
However, what I gathered from your question is: "How does the Thread.h link to the Thread.cpp?" If that is what you are asking then think of it this way:
Thread.h just contains a bunch of declarations. Similar to that of a Java interface.
Thread.c contains the implementation of that interface.
As for my second guess as to what you're asking: "How does java create a native thread?".
If I had to take a huge guess at Java creating a thread on Windows, I'd say the definition is either written using WINAPI (windows only) or the C++ stl (portable):
Suppose you have a java Threading class:
public class Threading {
static{ System.LoadLibrary("Threading"); }
private Runnable r = null;
private native void StartNativeThread(Runnable r);
public Threading(Runnable r) {
this.r = r;
}
public void start() {
StartNativeThread(this.r);
}
}
The above class is passed a runnable in its constructor. When you call start, it calls the native function "StartNativeThread" and that function is going to take the runnable as a parameter.
On the C++ side, it will create a thread and that thread will call Runnable.run which it got from the java side.
WINAPI-C++:
//object that will hold all thread information.
struct ThreadParams
{
JNIEnv* env;
jobject runnable;
};
//function that the thread will call.
DWORD __stdcall RunnableThreadProc(void* ptr)
{
ThreadParams* p = reinterpret_cast<ThreadParams*>(ptr); //get our thread info from the parameter.
JNIEnv* env = p->env; //grab our env.
jobject runnable = p->runnable; //grab our runnable object.
delete p; //since we allocated on the heap using new, we must delete from the heap.
//this is because c++ does not have garbage collection.
jclass RunnableInterface = env->GetObjectClass(runnable); //get our java runnable interface instance.
jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V"); //get the run method function pointer.
env->CallObjectMethod(RunnableInterface, Run); //call RunnableInterface.run();
}
JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
ThreadParams* ptr = new ThreadParams(); //create an object to store our parameters.
ptr->env = env; //store the env parameter.
ptr->runnable = runnable; //store the runnable object.
//create a thread that calls "RunnableThreadProc" and passes it "ptr" as a param.
CreateThread(0, 0, RunnableThreadProc, reinterpret_cast<void*>(ptr), 0, 0);
}
Now the above looks quite complicated to be completely honest but that is what WINAPI is. It is an API written for windows in the C Language.
If you have a C++x11 compiler and wish to avoid winapi and use STL-C++, this can be done in a couple lines.
Assume that we have the same java class as above, then our function becomes:
JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
std::thread([&]{
jclass RunnableInterface = env->GetObjectClass(runnable);
jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V");
env->CallObjectMethod(RunnableInterface, Run);
}).detach();
}
Note that [&]{....} is a Lambda Function. It means a function that can be created inside of another function or parameter.
The above can also be translated / is equivalent to:
void ThreadProc(JNIEnv* env, jobject runnable)
{
jclass RunnableInterface = env->GetObjectClass(runnable);
jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V");
env->CallObjectMethod(RunnableInterface, Run);
}
JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
std::thread(ThreadProc, env, obj).detach();
}
Now implementing other things like stop and pause is just as easy. You simply do that on the java side inside your runnable. OR you can do it on the C++ side using WINAPI's TerminateThread and WaitObject and the likes. OR if you choose to use STL-C++ then you'd use an std::condition_variable.
I hope that clears up some things. If you have any further questions, you can just post a comment or make a new thread. Up to you. Otherwise, if I missed something or interpreted your question wrong, then please clarify it.
EDIT.. So for the actual implementation, we can see that Thread.c includes jvm.h. Thus we must find jvm.h and jvm.cpp.
A quick search comes up with:
Thread.h: http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c
JVM.h: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/prims/jvm.h
JVM.cpp: http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/jvm.cpp
If we now search for any of the functions from thread.c.. We can see in thread.c that start0 is mapped to JVM_StartThread, and all other thread functions is mapped to JVM_XXXXSomeThreadFunc...
We must now look for these JVM_ functions within JVM.h and JVM.cpp. Once found, you have the source of how it is all done.
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.