Reputation: 21
I'm trying to build a dynamic library (OpenXR api_layer) in c++ that communicates with a java SDK but I'm having issues with the JNI part of the implementation, from the OpenXR Create Layer function I receive a JavaVM and a jobject which is the activity,
now in my AndroidStudio project I have an AAR that also holds my classes.jar and I can see that its loading correctly since taking the classes.dex file and running it in dexdump I can see the classes I'm looking for and their functions
an important thing to mention is that since I'm working on top of the OpenXR interface I don't have access to the JNI_OnLoad function or the creation of the JVM in order to set the option strings
this is the c++ side of my code, I tried loading with my native activity class loader and just calling find class
option 1:
JNIEnv* jni_env;
VM->GetEnv(reinterpret_cast<void**>(&jni_env), JNI_VERSION_1_6);
jint result = VM->AttachCurrentThread(&jni_env, nullptr);
if (result != JNI_OK) {
LOGI("Failed to attach current thread");
return;
}
else {
LOGI(" attach current thread");
}
jclass nativeActivity = jni_env->GetObjectClass(activity);
jclass acl = jni_env->GetObjectClass(nativeActivity);
jmethodID getClassLoader = jni_env->GetMethodID(acl, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject cls = jni_env->CallObjectMethod(nativeActivity, getClassLoader);
jclass classLoader = jni_env->FindClass("java/lang/ClassLoader");
jmethodID findClass = jni_env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
jstring strClassName = jni_env->NewStringUTF("mudraAndroidSDK.model.MudraDevice");
jclass flurryClass = (jclass)(jni_env->CallObjectMethod(cls, findClass, strClassName));
jni_env->DeleteLocalRef(strClassName);
option 2
JNIEnv* jni_env;
VM->GetEnv(reinterpret_cast<void**>(&jni_env), JNI_VERSION_1_6);
jint result = VM->AttachCurrentThread(&jni_env, nullptr);
if (result != JNI_OK) {
LOGI("Failed to attach current thread");
return;
}
else {
LOGI(" attach current thread");
}
jclass nativeActivity = jni_env->GetObjectClass(activity);
jni_env->FindClass("mudraAndroidSDK/model/MudraDevice");
both result in an error not finding the class
is there something I'm misunderstanding?
Edit
The Class not being found is this "mudraAndroidSDK/model/MudraDevice", Im getting my activity straight from OpenXR, their documentation says this
"applicationActivity is a JNI reference to an android.app.Activity that will drive the session lifecycle of this instance, cast to a void pointer."
A/llo_xr.opengle: java_vm_ext.cc:579] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "mudraAndroidSDK.model.MudraDevice" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system_ext/lib64, /system/lib64, /system_ext/lib64]]
java_vm_ext.cc:579] (Throwable with no stack trace)
java_vm_ext.cc:579]
java_vm_ext.cc:579] in call to NewGlobalRef
Project Structure:
This is my android Studio project, its the hello_xr project that can be found in https://github.com/KhronosGroup/OpenXR-SDK-Source
Under asset/libs I included my aar and called implementation fileTree(include: ['*.aar'], dir: 'libs')
in the build.gradle file
now the actual JNI calls are in the libOpenXRMudraApiLayerAndroid.so dynamic library, but for testing purposes I tried calling find class from void android_main(struct android_app* app)
with the app->activity->vm and still no luck.
Upvotes: 2
Views: 107
Reputation: 31055
I managed to recreate your error using the OpenXR's hello_xr sample and the AAR you mentioned.
If you look at the AndroidManifest.xml included in hello_xr, you will see that it defines the application as follows:
<application
android:allowBackup="true"
android:hasCode="false"
The documentation has this to say about android:hasCode
:
Whether the application contains any DEX code—that is, code using the Kotlin or Java programming language. It's "true" if it does and "false" if not. When the value is "false", the system doesn't try to load any application code when launching components. The default value is "true".
This property must account for code included in the application by dependencies. If the application depends on an AAR that uses Java/Kotlin code, or directly on a JAR, app:hasCode must be "true", or omitted as that is the default.
Setting android:hasCode
to true
made my Env->FindClass
call in android_main
work instantly.
Upvotes: 0