NewGlobalRef 在不同的 .so 上调用时出现未决异常 java.lang.ClassNotFoundException

NewGlobalRef called with pending exception java.lang.ClassNotFoundException on different .so

我有一个使用 my_app_helper.so.

的库 my_app.so

jclass jc = env->FindClass("com.my_app.flutter_app.MainActivity");

my_app.so 上的任何地方都能完美运行,但给出:

A/zygote64: java_vm_ext.cc:523] JNI DETECTED ERROR IN APPLICATION: JNI 
NewGlobalRef called with pending exception java.lang.ClassNotFoundException: 
Didn't find class "com.my_app.flutter_app.MainActivity" on path: 
DexPathList[[dex file "InMemoryDexFile[cookie=[0, 
547409613216]]"],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64]]

my_app_helper.so

我的 JNI_Onloadmy_app.so 上,它将 JavaVM *vm 传递给 my_app_helper.so

为什么从 my_app_helper.so 内部调用时找不到 类?

更新:

这是回溯:

A/zygote64: java_vm_ext.cc:523] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "com.my_app.flutter_app.MainActivity" on path: DexPathList[[dex file "InMemoryDexFile[cookie=[0, 547694828128]]"],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64]]
    java_vm_ext.cc:523]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:93)
    java_vm_ext.cc:523]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
    java_vm_ext.cc:523]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
    java_vm_ext.cc:523]   at java.lang.Object com.rmsl.juce.JuceInvocationHandler.dispatchInvoke(long, java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) (JuceInvocationHandler.java:-2)
    java_vm_ext.cc:523]   at java.lang.Object com.rmsl.juce.JuceInvocationHandler.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) (JuceInvocationHandler.java:28)
    java_vm_ext.cc:523]   at java.lang.Object java.lang.reflect.Proxy.invoke(java.lang.reflect.Proxy, java.lang.reflect.Method, java.lang.Object[]) (Proxy.java:913)
    java_vm_ext.cc:523]   at void android.app.Application$ActivityLifecycleCallbacks.onActivityStarted(android.app.Activity) ((null):-1)
    java_vm_ext.cc:523]   at void android.app.Application.dispatchActivityStarted(android.app.Activity) (Application.java:207)
    java_vm_ext.cc:523]   at void android.app.Activity.onStart() (Activity.java:1249)
    java_vm_ext.cc:523]   at void io.flutter.embedding.android.FlutterActivity.onStart() (FlutterActivity.java:533)
    java_vm_ext.cc:523]   at void com.my_app.flutter_app.MainActivity.onStart() (MainActivity.kt:256)
    java_vm_ext.cc:523]   at void android.app.Instrumentation.callActivityOnStart(android.app.Activity) (Instrumentation.java:1355)
    java_vm_ext.cc:523]   at void android.app.Activity.performStart() (Activity.java:7001)
    java_vm_ext.cc:523]   at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2807)
    java_vm_ext.cc:523]   at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2923)
    java_vm_ext.cc:523]   at void android.app.ActivityThread.-wrap11(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1)
    java_vm_ext.cc:523]   at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1616)
    java_vm_ext.cc:523]   at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:105)
    java_vm_ext.cc:523]   at void android.os.Looper.loop() (Looper.java:164)
    java_vm_ext.cc:523]   at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6617)
    java_vm_ext.cc:523]   at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
    java_vm_ext.cc:523]   at void com.android.internal.os.Zygote$MethodAndArgsCaller.run() (Zygote.java:240)
    java_vm_ext.cc:523]   at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:769)
    java_vm_ext.cc:523] 
    java_vm_ext.cc:523]     in call to NewGlobalRef
    java_vm_ext.cc:523]     from java.lang.Object com.rmsl.juce.JuceInvocationHandler.dispatchInvoke(long, java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
    java_vm_ext.cc:523] "main" prio=5 tid=1 Runnable
    java_vm_ext.cc:523]   | group="main" sCount=0 dsCount=0 flags=0 obj=0x72a3f710 self=0x7f93ec3a00
    java_vm_ext.cc:523]   | sysTid=21008 nice=-10 cgrp=default sched=0/0 handle=0x7f986549b0
    java_vm_ext.cc:523]   | state=R schedstat=( 583813855 313733548 562 ) utm=46 stm=11 core=1 HZ=100
    java_vm_ext.cc:523]   | stack=0x7ff863b000-0x7ff863d000 stackSize=8MB
    java_vm_ext.cc:523]   | held mutexes= "mutator lock"(shared held)
A/zygote64: java_vm_ext.cc:523]   native: #00 pc 00000000003982fc  /system/lib64/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiP12BacktraceMapPKcPNS_9ArtMethodEPv+212)

您没有给我们太多帮助,但我认为您的问题源于 this Android JNI FAQ:

You can get into trouble if you create a thread yourself (perhaps by calling pthread_create and then attaching it with AttachCurrentThread). Now there are no stack frames from your application. If you call FindClass from this thread, the JavaVM will start in the "system" class loader instead of the one associated with your application, so attempts to find app-specific classes will fail.

因此,在 my_app_helper.so 的代码中,您应该:

  1. 确保使用特定于线程的 env(如果需要,通过在 vm 上调用 AttachCurrentThread 获得);
  2. 确保您需要的所有 class 参考资料都已提前获得。这就像从 my_app.so 调用 FindClass 并将 GlobalReference 存储在 static/global 变量中一样简单。 (g_my_class = env->NewGlobalRef(env->FindClass("...")))这是最简单的解决方法,但请参阅链接的 post 了解其他选项。

一般来说,您应该养成良好的 JNI 卫生习惯,并始终在 JNI 调用后检查错误,特别是对于 Android,请考虑在开发时打开 extended checking

编辑:在第二种情况下,FindClass 将始终有效:

Any FindClass calls made as part of executing JNI_OnLoad will use the class loader associated with the function that called System.loadLibrary (this is a special rule, provided to make library initialization more convenient)."

您可以在 Android 运行时源代码中看到这一点 here:

    // **: class_loader is the class loader of the code that called `loadLibrary`
    ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));
    self->SetClassLoaderOverride(class_loader); // **

    VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
    using JNI_OnLoadFn = int(*)(JavaVM*, void*);
    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
    int version = (*jni_on_load)(this, nullptr);

    self->SetClassLoaderOverride(old_class_loader.get()); // **