Search code examples
javaandroidjava-native-interface

java.lang.ClassNotFoundException: on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/lib64]]


Currently libraries(.so) are built using visual studio and placed on to jniLibs directory. As shown below,

enter image description here

Getting below exception while finding the class in JNI call (here it is TWMainActivity but true with any other class),

2021-07-23 08:10:43.992 13617-1658/com.tally.twandroidconsolesimulator A/onsolesimulato: java_vm_ext.cc:578] JNI DETECTED ERROR IN APPLICATION: JNI GetMethodID called with pending exception java.lang.ClassNotFoundException: Didn't find class "com.tally.twandroidconsolesimulator.TWMainActivity" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/lib64]]
    java_vm_ext.cc:578]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:207)
    java_vm_ext.cc:578]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
    java_vm_ext.cc:578]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
    java_vm_ext.cc:578] 
    java_vm_ext.cc:578]     in call to GetMethodID

While via global reference to the object passed via JNI call (java to C++) able to get the jclass.

   //this is working
    jclass      cls = env->GetObjectClass (sMainActivityGlobalRef);

   //this is not working throwing mentioned exceptions
  //  jclass       cls = env->FindClass ("com/tally/twandroidconsolesimulator/TWMainActivity");

Note: the same code is working with Andrdoid Studio Native project without having jniLibs

Basic code flow as follows,

public class TWMainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("TWXPControlsGalleryApp_arm64-v8a");
    }
 @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);               
            InitializeMain();
        }
        public native void InitializeMain();
 }

//Native code

static void
NativeThread(JavaVM * pJavaVm, jint pJVersion, jobject pObjGblRfrnc){
    JNIEnv * env;
    auto    get_env_result = vm->GetEnv ((void **) &env, pJVersion);
    if (get_env_result == JNI_EDETACHED) {
        if (vm->AttachCurrentThread (env, nullptr) != JNI_OK) {
            return;
        }
    }
        jclass      cls = env->FindClass ("com/tally/twandroidconsolesimulator/TWMainActivity");

    //... rest of the code follows here
}

extern "C" JNIEXPORT void JNICALL 
Java_com_tally_twandroidconsolesimulator_TWMainActivity_InitializeMain (JNIEnv * pEnv, jobject pObj)
{
            JavaVM * sJavaVm;

        jint jv_version = pEnv->GetVersion ();
        pEnv->GetJavaVM (&sJavaVm);    
        jobject ref = pEnv->NewGlobalRef (pObj);

    std::thread thread1 (NativeThread, sJavaVm, jv_version, ref );
    thread1.detach ();
}

have referred this, this, this,this but didn't help to rectify the problem.

Environment:

    classpath "com.android.tools.build:gradle:4.2.1"

enter image description here

I appreciate any hint.


Solution

  • FindClass will not be able to find any of your app-specific classes if invoked on a purely native thread, due to the wrong classloader being used. See this section in the Android developer documentation for more information.

    There are various ways in which you could solve this, but the easiest is probably to resolve all classes in JNI_OnLoad, create global references to them, and save those global references somewhere where the rest of your code can access them.