Why isn't JNIOnLoad running? - java

I have an Android project with a Java base Activity, Java JNI interface class, and native code. I have the proper
System.loadlibrary(_libraryname_);
In my Java interface class and from the logcat output:
11-29 15:11:20.737: D/dalvikvm(8940): No JNI_OnLoad found in /data/data/com.example.testjni/lib/libTestJNI.so 0x406ef030, skipping init
In my cpp file header:
extern "C" {
JNIEXPORT jint JNICALL JNIOnLoad(JavaVM *, void *);
}
In the cpp file:
JNIEXPORT jint JNICALL JNIOnLoad(JavaVM *vm, void *reserved)
{
LOGI("JNIOnLoad");
jvm = vm;
return JNI_VERSION_1_6; /* the required JNI version */
}
But still the OnLoad function never is called. I've tried uninstalling the app and re-installing it but it never runs.

Function signature is JNI_OnLoad. There is an underscore / _ between JNI and OnLoad.

Related

JNI_OnUnload never called?

I'm trying to understand the lifecycle stages of an Android app with a native lib.
The native library is loaded like this in the MainActivity:
static {
System.loadLibrary("lifecycleevents");
}
The definition of JNI_onLoad and JNI_onUnLoad are as follows:
extern "C" JNIEXPORT jint JNICALL
JNI_OnLoad (JavaVM * pJavaVM, [[maybe_unused]] void * pReserved) {
JNIEnv * env;
if (pJavaVM->GetEnv ((void **) &env, JNI_VERSION_1_6) != JNI_OK)
return JNI_ERR;
__android_log_print (ANDROID_LOG_VERBOSE, (const char *) TAG, "JNI_OnLoad");
return env->GetVersion ();
}
extern "C" JNIEXPORT void JNICALL
JNI_OnUnload (JavaVM * pJavaVM, [[maybe_unused]] void * pReserved) {
__android_log_print (ANDROID_LOG_VERBOSE, (const char *) TAG, "JNI_OnUnload");
}
I'm able to trace JNI_onLoad but JNI_onUnLoad never hits.
According to the documentation, it will be called when the classloader of the native lib is garbage collected.
This will happen at some point after MainActivity's onDestroy but before the app terminates, right? So, why is JNI_onUnLoad not called?
Also, in the documentation, JNI_onUnLoad_L will be called when the classloader of the native lib L is garbage collected. Since my native lib name is lifecycleevents, I renamed the JNI_onUnLoad method to JNI_onUnLoad_lifecycleevents, but it still doesn't get called.
I'm confused. Are both the methods valid? Requesting help from anyone who is familiar with this topic.

A java runtime error with a native JNI static method for C++ implementation

I have a repo with two simple implementations for JNI with C/C++.
I have the java.lang.UnsatisfiedLinkError error for C++ static JNI method.
(base) GlushenkovYuri:java y.glushenkov$ /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/bin/java -Djava.library.path=. MyJNIExample
Hello World from C!
Exception in thread "main" java.lang.UnsatisfiedLinkError: MyJNIExample.sayHelloCpp()V
at MyJNIExample.sayHelloCpp(Native Method)
at MyJNIExample.main(MyJNIExample.java:51)
But for C native method the same approach work well.
For C++ works without static.
You can reproduce the same behaviour in the following way:
1) Uncomment lines with the static native method for C++ and this one. And comment lines with the NON static native method for C++ and this one;
2) And just perform the next steps described in my README.md file;
Can somebody explain to me why the native method static/non static works for C, but only the native NON static method works for C++?
UPD: my header file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyJNIExample */
#ifndef _Included_MyJNIExample
#define _Included_MyJNIExample
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MyJNIExample
* Method: sayHelloC
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloC
(JNIEnv *, jclass);
/*
* Class: MyJNIExample
* Method: sayHelloCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCpp
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
The type of the function that javah generates differs according to whether the native method is static or not:
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCppstatic
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCppnonstatic
(JNIEnv *, jobject);
In addition, the generated header contains an extern "C" declaration to make sure the compiler keeps the name intact of mangling it like __Z29Java_MyJNIExample_sayHelloCppP7JNIEnv_P8_jobject.
So, what happened here is that you generated a header file with a static native void sayHelloCpp, so there is an extern "C" declaration for the function with signature (JNIEnv *, jclass), but you provide a (JNIEnv *, jobject) function. The compiler uses its default mangling scheme as the signature does not match, and the Java runtime fails to find it.
So, long story short: always regenerate your header file and check C++ function signatures if you change your Java class. I could not reproduce your issue because I wrote a Makefile that always regenerated the header file after recompiling the Java file.

Android invoke JVMTI from java side via JNI failed, pointer is NULL

I had wrote a agent to use the JVMTI on android 9. Code like this, I create an AgentFunction object to monitor the VM. It work's fine.
AgentFunction *agent = 0;
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
agent = new AgentFunction();
agent->Init(vm);
agent->ParseOptions(options);
agent->AddCapability();
agent->ShowCapabilities();
agent->RegisterEvent();
return JNI_OK;
}
Then i want export some interface to java, than user can invoke the JVMTI function directly.
private native boolean applyChangeNative(List<ClassInfo> classes);
The JNI fumction in agent.so
extern "C"
JNIEXPORT jboolean JNICALL Java_com_cc_jvmtiagent_JVMTIFunction_applyChangeNative
(JNIEnv *jniEnv, jobject, jlong jvmti, jobject classInfo) {
...
jvmtiClassDefinition *def = new jvmtiClassDefinition[total_classes];
agent->RedefineClasses(total_classes, def);
}
But when invoke the native method applyChangeNative from JAVA, the agent->RedefineClasses crash caused by agent is null. After my test, i found i can't access the object create in JVMTI from JNI.
I had read the JDK souce code , I found it have an InvocationAdapter.cc, When Agent_OnAttach it create the JPLISAgent, then create java.lang.instrument.Instrumentation and save the JPLISAgent in it. Each function from Java will take the JPLISAgent point.
But i want to known , why access the JVMTI object is NULL directly from JNI?
Resolved:
If you want invoke the agent method via JNI, you should use System.Load(agentPath) instead of System.LoadLibrary(libName). It need use the same so file.
It work's on Android 9 and 10, But on Android 8.x, Can't access the agent, i do not know why.

JNI native method not found

I've got a package called com.example.remote in that package I have a Remote.java file with
public native static void send_feedback(String feedback);
static {
System.loadLibrary("com_example_remote_Remote");
}
then in my com_example_remote_Remote.c file I got this method:
JNIEXPORT void JNICALL Java_com_example_remote_Remote_send_feedback(JNIEnv *env, jclass clazz, jstring feedback)
Everything compiles. But when I do a call to the java function the program stops working and gives me:
12-19 12:21:31.183: E/AndroidRuntime(3196): FATAL EXCEPTION: main
12-19 12:21:31.183: E/AndroidRuntime(3196): java.lang.UnsatisfiedLinkError: Native method not found: com.example.remote.Remote.send_feedback:(Ljava/lang/String;)V
12-19 12:21:31.183: E/AndroidRuntime(3196): at com.example.remote.Remote.send_feedback(Native Method)
I think my syntax is conform the rules of JNI. I deleted the obj map once I thought maybe it would solve the problem. I rebuild the project and still gives me that error.
EDIT:
changed the name to sendFeedback and now I get this error:
12-19 12:49:26.335: A/libc(3280): Fatal signal 11 (SIGSEGV) at 0x00000cd0 (code=0), thread 3280 (.example.remote)
Add extern "C" in native method definition. i.e.
extern "C" JNIEXPORT void JNICALL Java_com_example_remote_Remote_send_feedback(JNIEnv *env, jclass clazz, jstring feedback){.......}
Or
If possible change MethodName in declaration and definition (in java file and .c file) because _ may be problem in method name. i.e.
public native static void sendFeedback(String feedback);
extern "C" JNIEXPORT void JNICALL Java_com_example_remote_Remote_sendFeedback(JNIEnv *env, jclass clazz, jstring feedback)
{
....
}
you may find a sample here
I've changed the name to sendFeedback so it's without the underscore. Also there was an error in the method what doesn't matter for this answer.

Another JNI, C++, DLL, UnsatisfiedLinkError <Native Method>

I've been looking for 2 days now and no solution could help me, so here we go again:
How to fix the UnsatisfiedLinkError... in JNI?
So here's my java code:
package org.lingenio.util;
import java.util.*;
public class PTAPIWrapperForOmegaT {
private native String translateWithPTAPI(String sentence);
private native void test();
public PTAPIWrapperForOmegaT(String sentence) throws Exception{
System.out.println(sentence);
test();
}
static {
System.load("C:/Users/michael/Desktop/OmegaT/OmegaT2.3_src/native/PTAPIWrapperForOmegaT.dll");
}
}
And here's my C++ Code:
#include <iostream>
#include <windows.h>
#include <jni.h>
#include "PTAPIWrapperForOmegaT.h"
using namespace std;
JNIEXPORT jstring JNICALL Java_PTAPIWrapperForOmegaT_translateWithPTAPI(JNIEnv *env, jobject obj, jstring sentence)
{
/* stuff */
}
JNIEXPORT void JNICALL Java_PTAPIWrapperForOmegaT_test(JNIEnv *, jobject)
{
cout << "This comes from PTAPIWrapperForOmegaT.cpp test();" << endl;
}
int main(){
return 0;
}
And the header file:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class PTAPIWrapperForOmegaT */
#ifndef _Included_PTAPIWrapperForOmegaT
#define _Included_PTAPIWrapperForOmegaT
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: PTAPIWrapperForOmegaT
* Method: translateWithPTAPI
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_PTAPIWrapperForOmegaT_translateWithPTAPI
(JNIEnv *, jobject, jstring);
/*
* Class: PTAPIWrapperForOmegaT
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_PTAPIWrapperForOmegaT_test
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
and how I build it:
call g++ -Wl,--add-stdcall-alias -c -DBUILDING_EXAMPLE_DLL -I G:/Software/Java/jdk1.7.0_01/include -I G:/Software/Java/jdk1.7.0_01/include/win32 PTAPIWrapperForOmegaT.cpp
call g++ -shared -Wl,-kill-at -o PTAPIWrapperForOmegaT.dll -I G:/Software/Java/jdk1.7.0_01/include -I G:/Software/Java/jdk1.7.0_01/include/win32 PTAPIWrapperForOmegaT.cpp
and finally, the error:
10211: Error: Uncatched exception in thread [Thread-14]
10211: Error: java.lang.UnsatisfiedLinkError: org.lingenio.util.PTAPIWrapperForOmegaT.test()V
10211: Error: at org.lingenio.util.PTAPIWrapperForOmegaT.test(Native Method)
10211: Error: at org.lingenio.util.PTAPIWrapperForOmegaT.<init>(PTAPIWrapperForOmegaT.java:13)
10211: Error: at org.omegat.core.machinetranslators.LingenioTranslate.translate(LingenioTranslate.java:32)
10211: Error: at org.omegat.core.machinetranslators.BaseTranslate.getTranslation(BaseTranslate.java:64)
10211: Error: at org.omegat.gui.exttrans.MachineTranslateTextArea$FindThread.search(MachineTranslateTextArea.java:122)
10211: Error: at org.omegat.gui.exttrans.MachineTranslateTextArea$FindThread.search(MachineTranslateTextArea.java:102)
10211: Error: at org.omegat.gui.common.EntryInfoSearchThread.run(EntryInfoSearchThread.java:85)
I don't know exactly about these two lines of g++ here, I think the second one would be sufficient, but some tutorial must have offered the other line as well and I kept it.
I'm on Windows 7, using MingW and the latest Java (1.7xxx I believe).
Any help is appreciated, I suspect the error lies in the compilation, but I just don't know how to go on from here.
EDIT:
Looking into the dll with DependencyWalker I can see the functions are named like I named them in the .cpp file. Of course I am calling them from the Java Wrapper with their respective names, i.e. test(). Could that be a problem? Can someone who used JNI often in the past tell me whether this is the correct way?
Turns out all the code is fine. Actually I did make mistakes compiling the header files. You can see if you look at the header files' function names, i.e.:
JNIEXPORT jstring JNICALL Java_PTAPIWrapperForOmegaT_translateWithPTAPI
(JNIEnv *, jobject, jstring);
Now, take a look at your Java files' package membership, in my case:
package org.lingenio.util;
Because I did compile the header file the wrong way, JNI was later not able to find the symbols it was looking for, because it was actually looking for this:
JNIEXPORT jstring JNICALL Java_org_lingenio_util_PTAPIWrapperForOmegaT_translateWithPTAPI(JNIEnv *env, jobject obj, jstring sentence)
So, good luck to the people out there dangling with the same problems. I'm obviously not the greatest Java programmer, that's why I had to worry about this for so long. I should have compiled my header files in the correct way in the first place.
Check your package and classpath!

Categories

Resources