calling java from native c++ JNI DIRECTLY - android

This question has been asked and answered in many posts like this!
But how can I call from c++ directly ? For this how can I get JNIEnv* and jobject ?
Is this possible ?

To get JNIEnv you can write global JNI_OnLoad function that will get called during loading of shared library. This function will get JavaVM pointer as argument. Using it you can get JNIEnv for current thread (or create new one if there was no JNIEnv previously).
As to where get jobject - if that is new object you are instantiating, then you use JNIEnv::NewObject method. Otherwise you need to pass object on which you want to call method from java side to C/C++.

You need to read the Invocation section of the JNI Specification.

Related

Get Java VM pointer in global object constructor in Android native code before JNI_OnLoad

I have a global object in native code which need to call Java code in it's constructor. Normally to get JavaVM pointer, I get the in JNI_OnLoad and cache it.
But the global object constructor is get called before JNI_OnLoad. And since you cannot really call JNI_GetCreatedJavaVMs or JNI_CreateJavaVM from Android native code.
Does anyone know how to get a JavaVM pointer before JNI_OnLoad get called?
Your help is appreciated.
For the sake of clarity, let's assume that you have libziron.so that has a global object with constructor that needs JavaVM* vm.
Build another library, lib1.so, which will have only
JavaVM* g_vm;
jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
g_vm = vm;
return JNI_VERSION_1_4;
}
In Java, you load lib1.so and after that libziron.so. In libziron.so, you can now access extern g_vm. Note that while libziron.so depends on lib1.so, you must load them manually, in the right order.

Android JNI/NDK Application Context

I'm using JNI to get the music library from Android with Qt. I call upon the following Java method (which is already implemented),
public String getArtists(Context context)
...
I need to be able to get the Context of the application in order for it to work.
If it helps, when I was using Java, the following code provided the correct context.
MainActivity.this
Could anybody be of assistance in this problem?
Many thanks!
It will depend where you are making the call. Ideally you will cache the MainActivity pointer in C++.
One way to cache a pointer to use in a later JNI call is to add a native function in java such as native void onCreateNative() to you MainActivity class. In C++ you'll implement the method and cache the "thiz" pointer:
JNIEXPORT void JNICALL com_package_MainActivity_onCreateNative(JNIEnv *env, jobject thiz)
{
gCachedActivity = env->NewGlobalRef(thiz);
}
Now you can use gCachedActivity where you would have used MainActivity.this
env->CallObjectMethod(obj, s_getArtistsGetArtistsMethodID, gCachedActivity);
Of course replacing obj with the object you are calling the method on.
Lastly onCreateNative() should be called in the onCreate() method of MainActivity.

UnsatisfiedLinkError when calling native function

I can succesfully load native library with System.loadLibrary(""), but when I call native method from that library, I receive UnsatisfiedLinkError, no implementation found for that method.
But this code works in another application, somehow in mine not.
Did you change the packageName in the jni method, it should be Java_com_example_yourapp_methodname(JNIEnv * env, jobject thiz) where com_example_yourapp is the reference to your package of the class you call the method.
and after that, did you call ndk-build again?
The method Erik N is suggested fine, but it has some performance impact as the VM need to search a function call with the above signature. Instead you can map the functions with signatures and register them on JNI_OnLoad() function call.
http://docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/functions.html#wp5833

Cannot renew jobject in JNI

My application is an Android app with some native code.
The Java code starts a thread via new Thread(new Runnable), in the native code, I attach that thread to the JVM via AttachCurrentThread.
The native function which is called in that thread is an endless loop which will listen for simple events(boolean variables) and call another native function which by using the proper JNIEnv pointer and jobject will fill 2 java variables on the Java side and call a void method to display the data. The reason for that loop is that the overhead to calling the function normally(has a lot of allocation and destruction to do) is most likely huge.
The only problem is that while I can renew a JNIEnv pointer, I have no idea how to do it for a jobject.
And by jobject I mean the jobject which is passed to the native code via the function call like so
jint Java_com_example_example_MainActivity_NativeFunc( JNIEnv* env,
jobject obj)
{
return;
}
The Java code starts a thread via new Thread(new Runnable), in the native code, I attach that thread to the JVM via AttachCurrentThread.
You don't have to attach the JVM to a thread that was created with Java code, it is already attached.
If I understood your question correctly you get a jobject once and want to access that object later in other native methods. To accomplish that, you can use NewGlobalRef:
jobject myGlobalReference = env->NewGlobalRef(obj);
You can store that jobject in a global C/C++ variable and use it later. It will stay valid until the JVM dies or you delete the reference with DeleteGlobalRef. Keep in mind that the garbage collection won't collect the referenced object if all Java references to it are gone as long as you don't delete your global reference!

Calling a Java function from the Native code using the NDK

I asked this question the other day, but wasn't too specific, so I want to re-clarify.
I am creating an Android Application which uses an existing library in C using the NDK. The problem I have run into is that the C code uses a lot of things java doesn't ( function pointers as parameters is the big problem ).
Anyway, I was wondering if I could write functions in my Java code that the C code calls. Now from what I can tell, you can do it, so I would appreciate it if no one just answered 'Yes you can, LINK." I have been looking into it but its very over my head as to what actually needs to be done.
Can anyone try to explain the process? I know it involves creating a JVM in the C code; any information that will help a newbie get on his feet will be greatly appreciated.
Thanks
EDIT :
So, I don't know what to do for these three steps.
To call a specific Java function from C, you need to do the following:
Obtain the class reference using the FindClass(,,) method.
Obtain the method IDs of the functions of the class that you want to call using the
GetStaticMethodID and GetMethodID function calls.
Call the functions using CallStaticVoidMethod, CallStaticIntMethod, and CallStaticObjectMethod.
This isn't explained too much and I have literally no experience in C. Is FindClass a C method?
Every C function that is callable from Java via JNI has a first parameter of type JNIEnv*. On the C end, this is a pointer to a pointer to a structure with a bunch of pointers to functions. Those functions are your interface to the Java world. FindClass, GetMethodID and the rest are among them.
So when you want to call FindClass from the C side, here's how you do it:
void Java_com_mypackage_MyClass_MyMethod(JNIEnv *jniEnv, jobject thiz)
{
jclass *clazz = (*(*jniEnv)->FindClass)(jniEnv, "com/mypackage/SomeClass");
jmethodID MethodID = (*(*jniEnv)->GetStaticMethodID)(jniEnv, clazz, "SomeMethod", "(I)I");
int result = (*(*jniEnv)->CallStaticIntMethod)(jniEnv, clazz, MethodID, 18);
And so forth. The line dereferences the jniEnv parameter, gets a function pointer and calls the function through it. Class and method names are completely bogus, naturally. How would I know yours.
Note: I'm talking of function pointers here, but not in the same sense as you do; those are function pointers to functions that JNI provides, not to your functions.
The verbosity of call syntax has to do with the limitations of C; in C++, you can write instead
jclass *cl = jniEnv->FindClass("com/mypackage/SomeClass");
as C++ supports function table pointers of this sort natively via virtual functions.
You can probably take some shortcuts along the way. If you're calling methods in the same class as your C point of entry, and it happens to be static, your second parameter already is a class object pointer. If you have a this pointer to the object you want to invoke a method on, you can use GetObjectClass.

Categories

Resources