I am developing a JNI application. However JNINativeInterface_ * inside the struct struct JNIEnv_ is null, hence causing any call for JNI (example : env->NewStringUTF(...)) functions to throw a segmentation fault error. JNIEnv_ struct looks like this :
struct JNIEnv_ {
const struct JNINativeInterface_ *functions;
.
.
.
I honestly dont know how to fix this, as I think java is supposed to fill this when you make a call to System.loadLibrary(...). I appreciate any help.
Two possibilities:
1) Your C++ code is called from Java as native function:
For example:
JNIEXPORT void JNICALL Java_MyJNative_doSomething(JNIEnv *env, jobject jo)
{
std::cout << "doSomething() : ";
}
The JNIEnv* pointer is given to you by the Java environment.
2) Your C++ code calls the Java code via JNI:
In this case you have to setup a JavaVM* and JNIEnv* pointer, following the JNI invocation logic. See for example this article.
A special case to be mentionned, if you have already invoked JNIEnv* but you work with multiple threads on C++ side. Then every thread has to attach to the JNIEnv* using:
JNIEnv *env; // Pointer to native interface
jint rc = jvm->AttachCurrentThread ((void **)&env, nullptr); // Attach without addutiobal parameters
// where jvm is a valid JavaVM*
Related
I am working on building a tool in Java. I need to integrate a big C project with my Java project. So I am using JNI.
I thought that, If I create a new C class that exactly does the same thing with the main class of the project (new C class would be in JNI style), and call it in Java code; I would be able to run the whole C project. I hope I am clear so far.
Here is the class that is supposed to the same things with main class of the C project:
JNIEXPORT void JNICALL Java_CallExact_C_1Main(JNIEnv *, jobject,
jint, jobjectArray) {
PomdpSolveParams param;
//**argc** should be replaced with **jint**
//**argv** should be replaced with **jobjectArray**
param = parseCmdLineAndCfgFile( argc, argv );
showPomdpSolveParams( param );
}
Can anybody tell me how to replace the variables argc and argv with correct parameters?
I am wondering is it possible to log every exception which occurs on JVM level without changing application code? By every exception I mean caught and uncaught exception... I would like to analyze those logs later and group them by exception type (class) and simply count exceptions by type. I am using HotSpot ;)
Maybe there is smarter why of doing it? For example by any free profiler (YourKit has it but it is not free)? I think that JRockit has exception counter in management console, but don't see anything similar for HotSpot.
I believe there are free tools to do it, but even making your own tool is easy. JVMTI will help.
Here is a simple JVMTI agent I made to trace all exceptions:
#include <jni.h>
#include <jvmti.h>
#include <string.h>
#include <stdio.h>
void JNICALL ExceptionCallback(jvmtiEnv* jvmti, JNIEnv* env, jthread thread,
jmethodID method, jlocation location, jobject exception,
jmethodID catch_method, jlocation catch_location) {
char* class_name;
jclass exception_class = (*env)->GetObjectClass(env, exception);
(*jvmti)->GetClassSignature(jvmti, exception_class, &class_name, NULL);
printf("Exception: %s\n", class_name);
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
jvmtiEnv* jvmti;
jvmtiEventCallbacks callbacks;
jvmtiCapabilities capabilities;
(*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0);
memset(&capabilities, 0, sizeof(capabilities));
capabilities.can_generate_exception_events = 1;
(*jvmti)->AddCapabilities(jvmti, &capabilities);
memset(&callbacks, 0, sizeof(callbacks));
callbacks.Exception = ExceptionCallback;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL);
return 0;
}
To use it, make a shared library (.so) from the given source code, and run Java with -agentpath option:
java -agentpath:libextrace.so MyApplication
This will log all exception class names on stdout. ExceptionCallback also receives a thread, a method and a location where the exception occured, so you can extend the callback to print much more details.
I'm in the process of doing some Java<->.NET interop code using a native library between them, so far things are going fairly well.
However for some reason I cannot run any methods under JNIEnv.
System::String^ JNIStringToNet(JNIEnv * env, jstring js)
{
const char *buf = env->GetStringUTFChars(js, 0); // segfault
Now I can pass variables back and forth and do all other kinds of communication, so I'm figuring I haven't initialized this correctly or something.
I'm loading it like this:
this.Lib = (LibHandler)Native.loadLibrary(this.Name, LibHandler.class);
(I prefer Native.loadLibrary because it seems to allow me to do more with it easier, such as class sharing between multiple libraries and unhooking and rehooking it from the JVM on the fly).
Edit:
Seriously any method:
std::cout << "Getting version:" << std::endl;
std::cout << env->GetVersion() << std::endl;
Getting version:
(segfault)
Any ideas on wht JNIEnv would segfault for every method? This should be set up by the JVM, correct?
Edit 2:
This is a Java application that is calling a C++ library that will interface with a .NET library (so it's a CLR compiled C++ library, if that makes any difference), to limit any external factors I'm not even calling the .NET DLL but just converting strings that come in back out (or well... trying).
So for example from Java:
this.Lib = (LibHandler)Native.loadLibrary(this.Name, LibHandler.class);
this.Lib.myCPPMethod(); // Segmentation fault during this call, JVM crashes.
Curious if it was the CLR that was causing it: Disabled clr compilation and stripped everything out that was CLR related, still does it.
Edit 3:
Got it to dump:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000000000000, pid=1596, tid=7248
#
# JRE version: 6.0_23-b05
# Java VM: Java HotSpot(TM) 64-Bit Server VM (19.0-b09 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C 0x0000000000000000
So yeah, looks like the JVM isn't giving me memory access for some reason.
Edit 4:
Actual call:
JNIEXPORT jstring JNICALL Query(JNIEnv * env, jobject jobj, jstring start, jstring end)
{
std::cout << "Getting version:" << std::endl;
jint j = env->GetVersion();
return jstring("test");
}
Edit 5:
Works with System.loadLibrary:
JNIEXPORT void JNICALL Java_LibTest_T(JNIEnv *env, jobject jobj)
{
std::cout << "Getting version:" << std::endl;
jint j = env->GetVersion();
std::cout << j << std::endl;
}
Output:
java -Djava.library.path="(dir)\lib\64" EntryPoint
Getting version:
65542
Ack! I mean some headway, but I can't unload libraries from the JVM that are loaded in System.loadLibrary can I?
I basically need to be able to unhook these libraries from the JVM and swap them out, on top of that they all need to "share" a single class and be able to be bound to the class at runtime... which is kinda why I went with Native.loadLibrary.
Currently I do this:
Load the DLL:
this.Lib = (LibHandler)Native.loadLibrary(this.Name, LibHandler.class);
Unhook it:
this.Lib = null;
Runtime.getRuntime().gc(); // Force the JVM to drop it immediately.
Class I load them all into:
public interface LibHandler extends Library{
void T();
}
Any way to work similarly with System.loadLibrary?
Edit 6:
Feel free to call me dumb, I'm using JNA, NOT JNI, which is completely different and a huge source of my problems.... is there a way to do this with JNI? Or can I get JNIEnv to register with JNA somehow? I'm guessing I can drop JNI from the C++ library and straight up use wstrings?
I'll get back with this tomorrow.
Well I feel bad.
Native.loadLibrary == JNA.
System.loadLibrary == JNI.
The purpose of JNA is to not require any real knowledge of the JVM environment, so you can run native libraries as is, so instead of jstring you can use char*...
I'm embedding Java into a C++ application. As part of this I need to expose native functions to java, as well as calling java functions from C++.
Do I need to put the functions I want to call from java into a shared library? Or can they be compiled into the host application somehow?
Here's what I've tried so far, but it gives a java.lang.UnsatisfiedLinkError
Compilation
I'm building on OS X 10.5 using
g++ -Wall -I/System/Library/Frameworks/JavaVM.framework/Headers/ -framework JavaVM -g test.cpp
Java Test File : TestObject.java
// To build this you need to do a `javac TestObject.java`
// To get the signatures do a `javap -d TestObject`
// To generate the .h file do a `javah TestObject`
public class TestObject
{
public native TestObject get_property( String k );
}
C++ Test File : test.cpp
#include <jni.h>
#include <assert.h>
JNIEXPORT jobject JNICALL Java_TestObject_get_1property(JNIEnv * jni_env, jobject obj, jstring key)
{
//Just a stub implementation for now.
jclass klass = jni_env->GetObjectClass( obj );
jmethodID constructor = jni_env->GetMethodID( klass, "<init>", "()V");
jobject retval = jni_env->NewObject(klass, constructor );
return retval;
}
int main()
{
JavaVM* jvm;
JavaVMInitArgs vm_args;
JavaVMOption options[1];
vm_args.version = JNI_VERSION_1_4;
vm_args.nOptions = 1;
options[0].optionString = "-Djava.class.path=.";
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_FALSE;
JNIEnv * env;
JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
jclass klass = (env)->FindClass("TestObject");
assert( klass );
jmethodID constructor = env->GetMethodID( klass, "<init>", "()V");
assert( constructor );
jobject obj = env->NewObject(klass, constructor );
jmethodID test_method = (env)->GetMethodID( klass, "get_property", "(Ljava/lang/String;)LTestObject;" );
assert( test_method );
jvalue args[1];
args[0].l = env->NewStringUTF("k");
jobject rv = env->CallObjectMethodA(obj, test_method, args );
jthrowable exc = env->ExceptionOccurred();
if(exc)
{
env->ExceptionDescribe();
env->ExceptionClear();
}
//TODO: do something with rv
}
Normally the JVM expects to find native method definitions in a shared library that has been loaded via System#load or System#loadLibrary, and in most cases that is the most convenient approach. However, there does exist an alternative for situations like yours, where you would prefer to include the implementations directly in your executable.
If you call JNIEnv::RegisterNatives, you can instead pass the JVM a list of function pointers corresponding to the native methods in a particular class. When some Java code calls one of those methods, the JVM will know to invoke the function pointer you passed to RegisterNatives instead of searching through dynamically-loaded libraries.
JNINativeMethod methods[] = {
{
"frobFabulously",
"(Ljava/lang/Object;)V",
reinterpret_cast<void*>(NativeFrobFabulouslyImpl)
},
};
env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(JNINativeMethod));
It's been a while since I've messed with JNI, so I'm a little rusty on the topic. I think your problem is that you're declaring the get_property method as native. This means that the JVM expects to find a shared library exposing the get_property method. Here's the documentation on java.lang.UnsatisfiedLinkError.
UnsatisfiedLinkError is thrown when (1) attempting to call a native
method that has not been loaded or (2) when loadLibrary or load method
in Runtime or System is called for a file that cannot be found.
You declare a Java method native only if you're going to implement that method in C or C++ and then call it from Java. Since you're trying to do the opposite, i.e call Java methods from native code, you need to actually implement the get_property method in Java. In native code you'll then create a class instance of TestObject and call the get_property method on this instance.
I found a Sun tutorial on how to embed the JVM in native code. The book itself begins with examples of how to call native code from Java.
Try this one:
When you execute the Java application, add the missing link file with "LD_LIBRARY_PATH"
Something like
LD_LIBRARY_PATH=[the link file path need be included] java xxx.class
The path can use absolute path. Hope this might be helpful.
I think you should try writing the JNI function in another file. When you javah TestObject.java, a file TestObject.h will be generated. Create a file TestObject.c with the implemented function. Then build a shared library using the native code.
( Something like g++ -G -I/pkgs/jdk1.4/include TestObject.C -o libTestObject.so)
Also in TestObject.java, load the library statically like static{ System.loadLibrary("TestIbject");
The libTestObject.so should be added to LD_LIBRARY_PATH ( On a Linux environment)
I have a custom dll that I access from Java using JNA. So far all is working perfect. Now however I would like to create Java classes from my C code. I assume this can't be done with JNA so what I did is to create a JNI method but this leads me to UnsatisfiedLinkError's. So my question is: Can I mix JNA and JNI when accessing the same DLL and if so, how should I go about doing that?
Of course can you mix access to the DLL, since it is only loaded once anyway. The problem is how the linking to your application works:
JNA:
When using JNA you call the native functions of the jna library, which by some kind of reflection bind to the functions in your DLL. This has the advantage that you don't have to worry about the name of the functions in the DLL, they don't have to meet any conventions.
JNI:
Simple works by a mapping from your java classes to method names which are expected in the DLL. If you have a Class com.company.SomeClass containing a function int doStuff(int i, long john) with this signature:
JNIEXPORT jint JNICALL Java_SomeClass_doStuff(JNIEnv *env, jint i, jlong john) {
return ...whatever...
}
If this function is missing, you get the UnsatisfiedLinkException.
Solution:
Since it seems you have written your own DLL, just add the functions required as wrapper functions, and you are done. To get the function signatures, you can create a header file automatically with the javah command.
I recommend reading Advanced Programming for the Java 2 Platform - Chapter 5: JNI Technology.
I want to add one thing to do that. Don't forget extern "C" for each JNIEXPORT and also function for JNA.
As a simple example:
// Example DLL header file MyDLL.dll
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
extern "C" {
MYDLL_API void HelloWorld(void);
}
extern "C" {
JNIEXPORT void JNICALL Java_MyJavaMain_HelloWorld(void);
}
//Example CPP file MyDLL.cpp
#include "MyDLL.h"
#include "stdio.h"
extern "C" declspec(dllexport)
void HelloWorld(void){
printf("Hello World From Dll");
}