1

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.

TruthSeeker
  • 1,539
  • 11
  • 24
  • 1
    You haven't provided a whole lot of information. For example, which thread are you on when you call `FindClass`? Have you read https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class ? – Michael Jul 26 '21 at 14:51
  • @Michael: I have updated the basic code flow. JNI call is from C++/Native thread as shown is the code – TruthSeeker Jul 26 '21 at 15:40
  • Ok, since you're on a native thread the behavior you describe is to be expected. See the page I linked to for an explanation and possible solutions. – Michael Jul 26 '21 at 16:31
  • @Michael: Sure thank you. i'll try to load the class in `JNI_OnLoad`. – TruthSeeker Jul 26 '21 at 16:45
  • @Michael: the solution is working w.r.t loading class on JNI_OnLoad. You can add the same in answer that i'll accept it. thank you again :) – TruthSeeker Jul 27 '21 at 06:09

1 Answers1

1

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.

Michael
  • 57,169
  • 9
  • 80
  • 125